Merge from master for release.
This commit is contained in:
commit
2cb1a8de73
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
exclude_paths:
|
||||
- '.github/**'
|
||||
- 'ci/build_verilator.sh'
|
||||
- 'include/vltstd/**'
|
||||
- 'nodist/fastcov.py'
|
||||
- ".github/**"
|
||||
- "ci/build_verilator.sh"
|
||||
- "include/vltstd/**"
|
||||
- "nodist/fastcov.py"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "Verilator Build Environment",
|
||||
"name": "Verilator Build Environment",
|
||||
|
||||
"build": {
|
||||
"build": {
|
||||
"dockerfile": "../ci/docker/buildenv/Dockerfile"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# This name is key to badges in README.rst, so we use the name build
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
|
@ -9,7 +10,7 @@ on:
|
|||
pull_request:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
|
|
@ -35,14 +36,14 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-20.04]
|
||||
os: [ubuntu-24.04, ubuntu-22.04, ubuntu-20.04]
|
||||
compiler:
|
||||
- { cc: clang, cxx: clang++ }
|
||||
- { cc: gcc, cxx: g++ }
|
||||
- {cc: clang, cxx: clang++}
|
||||
- {cc: gcc, cxx: g++}
|
||||
include:
|
||||
# Build GCC 10 on ubuntu-20.04
|
||||
- os: ubuntu-20.04
|
||||
compiler: { cc: gcc-10, cxx: g++-10 }
|
||||
compiler: {cc: gcc-10, cxx: g++-10}
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }}
|
||||
env:
|
||||
|
|
@ -51,41 +52,40 @@ jobs:
|
|||
CC: ${{ matrix.compiler.cc }}
|
||||
CXX: ${{ matrix.compiler.cxx }}
|
||||
CACHE_BASE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}
|
||||
CCACHE_MAXSIZE: 1000M # Per build matrix entry (* 5 = 5000M in total)
|
||||
CCACHE_MAXSIZE: 1000M # Per build matrix entry (* 5 = 5000M in total)
|
||||
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.CACHE_KEY }}-
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.CACHE_KEY }}-
|
||||
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
- name: Build
|
||||
run: ./ci/ci-script.bash
|
||||
- name: Build
|
||||
run: ./ci/ci-script.bash
|
||||
|
||||
- name: Tar up repository
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
||||
|
||||
- name: Upload tar archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
- name: Tar up repository
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
||||
|
||||
- name: Upload tar archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
|
||||
test:
|
||||
needs: build
|
||||
|
|
@ -94,25 +94,25 @@ jobs:
|
|||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-20.04]
|
||||
compiler:
|
||||
- { cc: clang, cxx: clang++ }
|
||||
- { cc: gcc, cxx: g++ }
|
||||
- {cc: clang, cxx: clang++}
|
||||
- {cc: gcc, cxx: g++}
|
||||
reloc: [0]
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1]
|
||||
include:
|
||||
# Test with GCC 10 on ubuntu-20.04
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-0}
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-1}
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-2}
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-3}
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: vltmt-0}
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: vltmt-1}
|
||||
# Test relocated installation - on most common platform only
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-0}
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-1}
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-2}
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-3}
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: vltmt-0}
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: vltmt-1}
|
||||
# Test with GCC 10 on ubuntu-20.04, also test relocation
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: dist-vlt-0}
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: dist-vlt-1}
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: dist-vlt-2}
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: dist-vlt-3}
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: vltmt-0}
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: vltmt-1}
|
||||
# Ubuntu 24.04 only on GCC; not passing on clang yet
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-0}
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-1}
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-2}
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-3}
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: vltmt-0}
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: vltmt-1}
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
||||
env:
|
||||
|
|
@ -122,37 +122,37 @@ jobs:
|
|||
CC: ${{ matrix.compiler.cc }}
|
||||
CXX: ${{ matrix.compiler.cxx }}
|
||||
CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-${{ matrix.reloc }}-${{ matrix.suite }}
|
||||
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
|
||||
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
|
||||
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz
|
||||
steps:
|
||||
|
||||
- name: Download tar archive
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
path: ${{ github.workspace }}
|
||||
- name: Download tar archive
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
path: ${{ github.workspace }}
|
||||
|
||||
- name: Unpack tar archive
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||
- name: Unpack tar archive
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.CACHE_KEY }}-
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.CACHE_KEY }}-
|
||||
|
||||
- name: Install test dependencies
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install test dependencies
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
TESTS: ${{ matrix.suite }}
|
||||
run: ./ci/ci-script.bash
|
||||
- name: Test
|
||||
env:
|
||||
TESTS: ${{ matrix.suite }}
|
||||
run: ./ci/ci-script.bash
|
||||
|
||||
lint-py:
|
||||
runs-on: ubuntu-22.04
|
||||
|
|
@ -161,21 +161,21 @@ jobs:
|
|||
CI_BUILD_STAGE_NAME: build
|
||||
CI_RUNS_ON: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
# We use specific version numbers, otherwise a Python package
|
||||
# update may add a warning and break our build
|
||||
- name: Install packages for lint
|
||||
run: sudo pip3 install pylint==3.0.2 ruff==0.1.3 clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
|
||||
- name: Install packages for lint
|
||||
run: sudo pip3 install pylint==3.0.2 ruff==0.1.3 clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
|
||||
|
||||
- name: Configure
|
||||
run: autoconf && ./configure --enable-longtests --enable-ccwarn
|
||||
- name: Configure
|
||||
run: autoconf && ./configure --enable-longtests --enable-ccwarn
|
||||
|
||||
- name: Lint
|
||||
run: make -k lint-py
|
||||
- name: Lint
|
||||
run: make -k lint-py
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
#
|
||||
name: Contributor Agreement
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
Test:
|
||||
name: "'docs/CONTRIBUTORS' was signed"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: test_regress/t/t_dist_contributors.pl
|
||||
- uses: actions/checkout@v4
|
||||
- run: test_regress/t/t_dist_contributors.py
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
|
|
@ -6,7 +7,7 @@ name: coverage
|
|||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
|
|
@ -21,7 +22,6 @@ defaults:
|
|||
|
||||
jobs:
|
||||
|
||||
|
||||
Build:
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
|
|
@ -29,49 +29,36 @@ jobs:
|
|||
CI_RUNS_ON: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
- name: Build
|
||||
run: ./ci/ci-script.bash
|
||||
- name: Build
|
||||
run: ./ci/ci-script.bash
|
||||
|
||||
- name: Tar up repository
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
||||
|
||||
- name: Upload tar archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
- name: Tar up repository
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
||||
|
||||
- name: Upload tar archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
|
||||
Test:
|
||||
needs: Build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test:
|
||||
- vlt-
|
||||
- vltmt-
|
||||
num:
|
||||
- 0
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- 4
|
||||
- 5
|
||||
- 6
|
||||
- 7
|
||||
- 8
|
||||
- 9
|
||||
test: [vlt-, vltmt-]
|
||||
num: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
include:
|
||||
- { test: dist, num: '' }
|
||||
- {test: dist, num: ''}
|
||||
runs-on: ubuntu-22.04
|
||||
name: test-${{ matrix.test }}${{ matrix.num }}
|
||||
env:
|
||||
|
|
@ -79,27 +66,27 @@ jobs:
|
|||
CI_RUNS_ON: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- name: Download tar archive
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
path: ${{ github.workspace }}
|
||||
- name: Download tar archive
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
path: ${{ github.workspace }}
|
||||
|
||||
- name: Unpack tar archive
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||
- name: Unpack tar archive
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||
|
||||
- name: Install test dependencies
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install test dependencies
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
TESTS: coverage-${{ matrix.test }}${{ matrix.num }}
|
||||
run: ./ci/ci-script.bash
|
||||
- name: Test
|
||||
env:
|
||||
TESTS: coverage-${{ matrix.test }}${{ matrix.num }}
|
||||
run: ./ci/ci-script.bash
|
||||
|
||||
- name: Upload coverage data to Codecov
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
run: |
|
||||
find . -name '*.gcno' -exec rm {} \;
|
||||
./ci/codecov -v upload-process -Z --sha ${{ github.sha }} -f nodist/obj_dir/coverage/app_total.info
|
||||
- name: Upload coverage data to Codecov
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
run: |
|
||||
find . -name '*.gcno' -exec rm {} \;
|
||||
./ci/codecov -v upload-process -Z --sha ${{ github.sha }} -f nodist/obj_dir/coverage/app_total.info
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
# Build and push verilator docker image when tags are pushed to the repository.
|
||||
# The following variable(s) must be configured in the github repository:
|
||||
# DOCKER_HUB_NAMESPACE: docker hub namespace.
|
||||
|
|
@ -8,7 +9,7 @@ name: Build Verilator Container
|
|||
|
||||
on:
|
||||
push:
|
||||
tags: [ 'v*' ]
|
||||
tags: ['v*']
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
manual_tag:
|
||||
|
|
@ -34,52 +35,52 @@ jobs:
|
|||
# - "ci/docker/buildenv:verilator-buildenv"
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Extract context variables
|
||||
run: |
|
||||
echo "${{ matrix.contexts }}" | sed -r 's/(.*):.*/build_context=\1/' >> "$GITHUB_ENV"
|
||||
echo "${{ matrix.contexts }}" | sed -r 's/.*:(.*)/image_name=\1/' >> "$GITHUB_ENV"
|
||||
echo "git_tag=${GITHUB_REF#refs/*/}" >> "$GITHUB_ENV"
|
||||
- name: Extract context variables
|
||||
run: |
|
||||
echo "${{ matrix.contexts }}" | sed -r 's/(.*):.*/build_context=\1/' >> "$GITHUB_ENV"
|
||||
echo "${{ matrix.contexts }}" | sed -r 's/.*:(.*)/image_name=\1/' >> "$GITHUB_ENV"
|
||||
echo "git_tag=${GITHUB_REF#refs/*/}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Use manual tag
|
||||
if: ${{ inputs.manual_tag }}
|
||||
run: |
|
||||
echo "git_tag=${{ inputs.manual_tag }}" >> "$GITHUB_ENV"
|
||||
- name: Use manual tag
|
||||
if: ${{ inputs.manual_tag }}
|
||||
run: |
|
||||
echo "git_tag=${{ inputs.manual_tag }}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Docker meta
|
||||
id: docker_meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
||||
tags: |
|
||||
type=match,pattern=(v.*),group=1,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
type=raw,value=${{ inputs.manual_tag }},enable=${{ inputs.manual_tag != '' }}
|
||||
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
||||
- name: Docker meta
|
||||
id: docker_meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
||||
tags: |
|
||||
type=match,pattern=(v.*),group=1,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
type=raw,value=${{ inputs.manual_tag }},enable=${{ inputs.manual_tag != '' }}
|
||||
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Build and Push to Docker
|
||||
uses: docker/build-push-action@v4
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
with:
|
||||
context: ${{ env.build_context }}
|
||||
build-args: SOURCE_COMMIT=${{ env.git_tag }}
|
||||
platforms: linux/arm64,linux/amd64
|
||||
push: ${{ !env.ACT && startsWith(github.ref, 'refs/tags/v') }}
|
||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||
- name: Build and Push to Docker
|
||||
uses: docker/build-push-action@v4
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
with:
|
||||
context: ${{ env.build_context }}
|
||||
build-args: SOURCE_COMMIT=${{ env.git_tag }}
|
||||
platforms: linux/arm64,linux/amd64
|
||||
push: ${{ !env.ACT && startsWith(github.ref, 'refs/tags/v') }}
|
||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
#
|
||||
name: format
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request_target:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-22.04
|
||||
|
|
|
|||
|
|
@ -1,55 +1,50 @@
|
|||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# This name is key to badges in README.rst, so we use the name build
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
#
|
||||
name: msbuild
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
|
||||
- cron: 0 0 * * 0 # weekly
|
||||
env:
|
||||
CI_OS_NAME: win
|
||||
CI_COMMIT: ${{ github.sha }}
|
||||
CCACHE_COMPRESS: 1
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: repo
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
windows:
|
||||
windows:
|
||||
name: run on windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: msbuild-msvc-cmake
|
||||
- name: compile
|
||||
env:
|
||||
WIN_FLEX_BISON: ${{ github.workspace }}/.ccache
|
||||
run: ./ci/ci-win-compile.ps1
|
||||
- name: test build
|
||||
run: ./ci/ci-win-test.ps1
|
||||
- name: Zip up repository
|
||||
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
|
||||
- name: Upload zip archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/repo/verilator.zip
|
||||
name: verilator-win.zip
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: msbuild-msvc-cmake
|
||||
- name: compile
|
||||
env:
|
||||
WIN_FLEX_BISON: ${{ github.workspace }}/.ccache
|
||||
run: ./ci/ci-win-compile.ps1
|
||||
- name: test build
|
||||
run: ./ci/ci-win-test.ps1
|
||||
- name: Zip up repository
|
||||
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
|
||||
- name: Upload zip archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/repo/verilator.zip
|
||||
name: verilator-win.zip
|
||||
|
|
|
|||
|
|
@ -29,14 +29,15 @@ dddrun*
|
|||
doxygen-doc
|
||||
gdbrun*
|
||||
gmon.out
|
||||
ncverilog.history
|
||||
internals.txt
|
||||
ncverilog.history
|
||||
nohup.out
|
||||
verilator-config-version.cmake
|
||||
verilator-config.cmake
|
||||
verilator.pc
|
||||
verilator.txt
|
||||
verilator_bin*
|
||||
verilator_coverage_bin*
|
||||
verilator.pc
|
||||
verilator-config.cmake
|
||||
verilator-config-version.cmake
|
||||
**/__pycache__/*
|
||||
**/_build/*
|
||||
**/obj_dir/*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
- id: verilator
|
||||
name: verilator-lint
|
||||
description: Runs verilator Docker image to lint (System) Verilog designs
|
||||
args: [--lint-only]
|
||||
language: docker_image
|
||||
entry: verilator/verilator:latest
|
||||
types_or: [verilog, system-verilog]
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[style]
|
||||
based_on_style = pep8
|
||||
column_limit = 99
|
||||
#split_before_arithmetic_operator=True
|
||||
101
CMakeLists.txt
101
CMakeLists.txt
|
|
@ -14,37 +14,44 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
||||
project(Verilator
|
||||
VERSION 5.028
|
||||
project(
|
||||
Verilator
|
||||
VERSION 5.030
|
||||
HOMEPAGE_URL https://verilator.org
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
option(DEBUG_AND_RELEASE_AND_COVERAGE
|
||||
"Builds both the debug and release binaries, overriding CMAKE_BUILD_TYPE. Not supported under MSBuild.")
|
||||
option(
|
||||
DEBUG_AND_RELEASE_AND_COVERAGE
|
||||
"Builds both the debug and release binaries, overriding CMAKE_BUILD_TYPE. Not supported under MSBuild."
|
||||
)
|
||||
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
set(PYTHON3 ${Python3_EXECUTABLE})
|
||||
set(CMAKE_INSTALL_DATADIR ${CMAKE_INSTALL_PREFIX})
|
||||
# See also CMake built-in; CMAKE_INSTALL_PREFIX is applied by the install command.
|
||||
set(CMAKE_INSTALL_DATADIR .)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CheckStructHasMember)
|
||||
include(ExternalProject)
|
||||
include(FindThreads)
|
||||
|
||||
if (NOT WIN32)
|
||||
if(NOT WIN32)
|
||||
message(WARNING "CMake support on Linux/OSX is experimental.")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
if (DEFINED ENV{WIN_FLEX_BISON})
|
||||
if(WIN32)
|
||||
if(DEFINED ENV{WIN_FLEX_BISON})
|
||||
set(WIN_FLEX_BISON "$ENV{WIN_FLEX_BISON}")
|
||||
endif()
|
||||
if (EXISTS ${WIN_FLEX_BISON})
|
||||
if(EXISTS ${WIN_FLEX_BISON})
|
||||
list(APPEND CMAKE_PREFIX_PATH ${WIN_FLEX_BISON})
|
||||
endif()
|
||||
if (NOT WIN_FLEX_BISON)
|
||||
message(FATAL_ERROR "Please install https://github.com/lexxmark/winflexbison and set WIN_FLEX_BISON environment variable. Please use install cmake target after a successful build.")
|
||||
if(NOT WIN_FLEX_BISON)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Please install https://github.com/lexxmark/winflexbison and set WIN_FLEX_BISON environment variable. Please use install cmake target after a successful build."
|
||||
)
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
endif()
|
||||
|
|
@ -52,20 +59,25 @@ endif()
|
|||
set(OBJCACHE "" CACHE STRING "Path for ccache, auto-detected if empty")
|
||||
option(OBJCACHE_ENABLED "Compile Verilator with ccache" ON)
|
||||
|
||||
if (OBJCACHE_ENABLED)
|
||||
if (OBJCACHE STREQUAL "")
|
||||
if(OBJCACHE_ENABLED)
|
||||
if(OBJCACHE STREQUAL "")
|
||||
find_program(OBJCACHE_PATH ccache)
|
||||
if (OBJCACHE_PATH STREQUAL "OBJCACHE_PATH-NOTFOUND")
|
||||
if(OBJCACHE_PATH STREQUAL "OBJCACHE_PATH-NOTFOUND")
|
||||
set(OBJCACHE_PATH "")
|
||||
endif()
|
||||
else()
|
||||
set(OBJCACHE_PATH "${OBJCACHE}")
|
||||
endif()
|
||||
if (NOT OBJCACHE_PATH STREQUAL "")
|
||||
execute_process(COMMAND "${OBJCACHE_PATH}" --version
|
||||
OUTPUT_VARIABLE objcache_version)
|
||||
if(NOT OBJCACHE_PATH STREQUAL "")
|
||||
execute_process(
|
||||
COMMAND "${OBJCACHE_PATH}" --version
|
||||
OUTPUT_VARIABLE objcache_version
|
||||
)
|
||||
string(REGEX MATCH "[^\n\r]+" objcache_version "${objcache_version}")
|
||||
message(STATUS "Found ccache: ${OBJCACHE_PATH} (\"${objcache_version}\")")
|
||||
message(
|
||||
STATUS
|
||||
"Found ccache: ${OBJCACHE_PATH} (\"${objcache_version}\")"
|
||||
)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "${OBJCACHE_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -76,8 +88,8 @@ find_package(FLEX)
|
|||
# Build
|
||||
#set_property(GLOBAL PROPERTY JOB_POOLS one_job=1)
|
||||
|
||||
if (DEBUG_AND_RELEASE_AND_COVERAGE)
|
||||
if (CMAKE_GENERATOR MATCHES "^Visual Studio ")
|
||||
if(DEBUG_AND_RELEASE_AND_COVERAGE)
|
||||
if(CMAKE_GENERATOR MATCHES "^Visual Studio ")
|
||||
error("%Error: The DEBUG_AND_RELEASE_AND_COVERAGE option is not supported in MSBuild-based builds.")
|
||||
endif()
|
||||
set(saved_build_type ${CMAKE_BUILD_TYPE})
|
||||
|
|
@ -102,22 +114,39 @@ set(AR ${CMAKE_AR})
|
|||
configure_file(include/verilated_config.h.in include/verilated_config.h @ONLY)
|
||||
configure_file(include/verilated.mk.in include/verilated.mk @ONLY)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/verilated_config.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/verilated.mk DESTINATION ${CMAKE_INSTALL_PREFIX}/include)
|
||||
|
||||
configure_package_config_file(verilator-config.cmake.in verilator-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/include/verilated_config.h
|
||||
DESTINATION include
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/include/verilated.mk
|
||||
DESTINATION include
|
||||
)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
|
||||
configure_package_config_file(verilator-config-version.cmake.in verilator-config-version.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}
|
||||
configure_package_config_file(
|
||||
verilator-config.cmake.in
|
||||
verilator-config.cmake
|
||||
INSTALL_DESTINATION .
|
||||
)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config-version.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config.cmake
|
||||
DESTINATION .
|
||||
)
|
||||
|
||||
foreach (program
|
||||
configure_package_config_file(
|
||||
verilator-config-version.cmake.in
|
||||
verilator-config-version.cmake
|
||||
INSTALL_DESTINATION .
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config-version.cmake
|
||||
DESTINATION .
|
||||
)
|
||||
|
||||
foreach(
|
||||
program
|
||||
verilator
|
||||
verilator_gantt
|
||||
verilator_ccache_report
|
||||
|
|
@ -128,13 +157,19 @@ foreach (program
|
|||
install(PROGRAMS bin/${program} TYPE BIN)
|
||||
endforeach()
|
||||
|
||||
install(DIRECTORY examples TYPE DATA FILES_MATCHING
|
||||
install(
|
||||
DIRECTORY examples
|
||||
TYPE DATA
|
||||
FILES_MATCHING
|
||||
PATTERN "examples/*/*.[chv]*"
|
||||
PATTERN "examples/*/Makefile*"
|
||||
PATTERN "examples/*/CMakeLists.txt"
|
||||
)
|
||||
|
||||
install(DIRECTORY include TYPE DATA FILES_MATCHING
|
||||
install(
|
||||
DIRECTORY include
|
||||
TYPE DATA
|
||||
FILES_MATCHING
|
||||
PATTERN "include/verilated_config.h"
|
||||
PATTERN "include/*.[chv]"
|
||||
PATTERN "include/*.cpp"
|
||||
|
|
|
|||
102
Changes
102
Changes
|
|
@ -8,6 +8,103 @@ The changes in each Verilator version are described below. The
|
|||
contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
Verilator 5.030 2024-10-27
|
||||
==========================
|
||||
|
||||
**Major:**
|
||||
|
||||
* Add `-output-groups` to build with concatenated .cpp files (#5257). [Mariusz Glebocki]
|
||||
* Self-tests have been converted to Python, run `{test_name}.py` instead of `{test_name}.pl`.
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Change .vlt config files to be read before .v files (#5185). [David Moberg]
|
||||
* Change to use maximum for cover point aggregation (#5402). [Andrew Nolte]
|
||||
* Change `--main` and `--binary` to use a TOP hierarchy name of "" (#5482).
|
||||
* Change install of public executables into bindir instead of pkgdatadir (#5140) (#5544). [Geza Lore]
|
||||
* Support IEEE-compliant intra-assign delays (#3711) (#5441). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support `wor`, `trior`, `wand`, `triand` (#5386) (#5496). [Zhou Shen]
|
||||
* Support unconstrained randomization for unions (#5395) (#5396). [Yilou Wang]
|
||||
* Support basic constrained queue randomization (#5413). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support packed/unpacked and dynamic array unconstrained randomization (#5414) (#5415). [Yilou Wang]
|
||||
* Support appending to queue via `[]` (#5421). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support named event locals (#5422). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support basic `dist` constraints (#5431). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support unpacked array constrained randomization (#5437) (#5489). [Yilou Wang]
|
||||
* Support inside array constraints (#5448). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support DPI imports and exports with double underscores (#5481).
|
||||
* Support ccache when compiling Verilated files with cmake.
|
||||
* Support `local` and `protected` on `typedef` (#5460).
|
||||
* Support unconstrained randomization for associative array and queue (#5515). [Yilou Wang]
|
||||
* Support `rand` dynamic arrays of objects (#5557) (#5564). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Add error on misused genvar (#408). [Alex Solomatnikov]
|
||||
* Add error on instances without parenthesis.
|
||||
* Add Docker pre-commit hook (#5238) (#5452). [Chris Bachhuber]
|
||||
* Add partial coverage symbol and branch data in lcov info files (#5388). [Andrew Nolte]
|
||||
* Add method to check if there are VPI callbacks of the given type (#5399). [Kaleb Barrett]
|
||||
* Remove warning on unsized numbers exceeding 32-bits.
|
||||
* Improve Verilation thread pool (#5161). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Improve performance of V3VariableOrder with parallelism (#5406). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Improve parser error handling (#5493). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Improve process trigger performance (#5483). [Geza Lore]
|
||||
* Fix suppression of WIDTH* warnings when immediately under a size cast (#3417).
|
||||
* Fix `$fatal` to not be affected by `+verilator+error+limit` (#5135). [Gökçe Aydos]
|
||||
* Fix equivalence checking when replacing type parameters (#5213) (#5255). [Han Qi]
|
||||
* Fix display with multiple string formats (#5311). [Luiza de Melo]
|
||||
* Fix performance of V3Trace when many activity blocks (#5372). [Deniz Güzel]
|
||||
* Fix REALCVT warning on integral timescale conversions (#5378). [Liam Braun]
|
||||
* Fix multidimensional function return value selects (#5382). [Gökçe Aydos]
|
||||
* Fix internal error in out-of-range select (#5393) (#5443). [Geza Lore]
|
||||
* Fix dot fallback finding wrong symbols (#5394). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix infinite recursion due to recursive functions/tasks (#5398). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix V3Randomize compile error on old GCC (#5403) (#5417). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix extra events in traces (#5405).
|
||||
* Fix empty `foreach` in `if` in constraints (#5408). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix queue `[$-i]` select as reference argument (#5411). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix `pre`/`post_randomize` on `randomize() with` (#5412). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix capturing params in `randomize() with` (#5416) (#5418). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix `sformatf` internal error on initial automatics (#5423). [Todd Strader]
|
||||
* Fix clearing trigger of events with no sensitivity trees (#5426). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix driving clocking block in reactive region (#5430). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix associative array next/prev/first/last mis-propagating constants (#5435). [Ethan Sifferman]
|
||||
* Fix randomize treated as std::randomize in classes (#5436). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix `foreach` colliding index names (#5444). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix fault on defparam with UNSUPPORTED ignored (#5450). [Luiza de Melo]
|
||||
* Fix class reference with pin that is a class reference (#5454).
|
||||
* Fix not reporting class reference with extra parameters (#5467).
|
||||
* Fix user-type parameter overlap (#5469). [Todd Strader]
|
||||
* Fix tracing when name() is empty (#5470). [Sam Shahrestani]
|
||||
* Fix timing mode not exiting on empty events (#5472).
|
||||
* Fix coverage counts missing due to table optimization (#5473) (#5474). [Vito Gamberini]
|
||||
* Fix `--binary` with .cpp PLI filenames under relative directory paths.
|
||||
* Fix extra dot in coverage point hierarchy when using name()=''.
|
||||
* Fix short-circuiting with associative array access (#5484). [Ethan Sifferman]
|
||||
* Fix short-circuiting on method calls (#5486). [Ethan Sifferman]
|
||||
* Fix exponential concatenate performance (#5488). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix V3Table trying to generate 'x' bits in the lookup table. (#5491). [Geza Lore]
|
||||
* Fix randomize with foreach constraints (#5492). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix explicit CMAKE_INSTALL_PREFIX usages (#5500). [Fabian Keßler]
|
||||
* Fix configure inserting absolute paths for Python and Perl (#5504) (#5505). [Nathan Graybeal]
|
||||
* Fix pattern initialization with typedef key (#5512). [Eugene Feinberg]
|
||||
* Fix `-j` option without argument in hierarchical Verilation (#5514). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix `foreach` with 2-D queues and dynamic arrays (#5525) (#5529). [Yilou Wang]
|
||||
* Fix struct array assignment (#5455) (#5537). [Yilou Wang]
|
||||
* Fix copy constructor of classes that use std::process (#5528). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix foreach on associative array (#5530). [Yilou Wang]
|
||||
* Fix multi-range indices assignment (#5534) (#5547). [Yilou Wang]
|
||||
* Fix static function wrappers (#5536). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix assignments of concatenation to queues and dynamic arrays (#5540). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix container reduction methods (#5542). [Krzysztof Boroński]
|
||||
* Fix complex user type problem with `--x-assign` (#5543). [Todd Strader]
|
||||
* Fix long module names crashing string handling (#5546). [Filip Badáň]
|
||||
* Fix array trace splitting (#5549). [Todd Strader]
|
||||
* Fix queue element access (#5551). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix struct literal on pattern assignment (#5552) (#5559). [Todd Strader]
|
||||
* Fix build on gcc when using the Spack wrapper (#5555). [Eric Müller]
|
||||
* Fix enum name method (#5563). [Todd Strader]
|
||||
* Fix `$countbits` in assert with non-tristates (#5566). [Shou-Li Hsu]
|
||||
|
||||
|
||||
Verilator 5.028 2024-08-21
|
||||
==========================
|
||||
|
||||
|
|
@ -208,9 +305,10 @@ Verilator 5.024 2024-04-05
|
|||
* Fix preprocessor to respect strings in joins (#5007).
|
||||
* Fix tracing class parameters (#5014).
|
||||
* Fix memory leaks (#5016). [Geza Lore]
|
||||
* Fix $readmem with missing newline (#5019). [Josse Van Delm]
|
||||
* Fix `$readmem` with missing newline (#5019). [Josse Van Delm]
|
||||
* Fix internal error on missing pattern key (#5023).
|
||||
* Fix tracing replicated hierarchical models (#5027).
|
||||
* Fix false LIFETIME warning on `repeat` in `fork-join` (#5456).
|
||||
|
||||
|
||||
Verilator 5.022 2024-02-24
|
||||
|
|
@ -549,7 +647,7 @@ Verilator 5.012 2023-06-13
|
|||
* Fix wide structure VL_TOSTRING_W generation (#4188) (#4189). [Aylon Chaim Porat]
|
||||
* Fix references to members of parameterized base classes (#4196). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix tracing undefined alignment (#4201) (#4288) [John Wehle]
|
||||
* Fix class specific same methods for AstVarScope, AstVar, and AstScope (#4203) (#4250). [John Wehle]
|
||||
* Fix class-specific same methods for AstVarScope, AstVar, and AstScope (#4203) (#4250). [John Wehle]
|
||||
* Fix dotted references in parameterized classes (#4206). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix bit selections under parameterized classes (#4210). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix duplicate std:: declaration with -I (#4215). [Harald Pretl]
|
||||
|
|
|
|||
124
Makefile.in
124
Makefile.in
|
|
@ -52,6 +52,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
|||
INSTALL_DATA = @INSTALL_DATA@
|
||||
MAKEINFO = makeinfo
|
||||
POD2TEXT = pod2text
|
||||
PYTHON3 = @PYTHON3@
|
||||
MKINSTALLDIRS = $(SHELL) $(srcdir)/src/mkinstalldirs
|
||||
|
||||
# Version (for docs/guide/conf.py)
|
||||
|
|
@ -76,7 +77,7 @@ datadir = @datadir@
|
|||
# Directory in which to install documentation info files.
|
||||
infodir = @infodir@
|
||||
|
||||
# Directory in which to install package specific files
|
||||
# Directory in which to install package-specific files
|
||||
# Generally ${prefix}/share/verilator
|
||||
pkgdatadir = @pkgdatadir@
|
||||
|
||||
|
|
@ -96,6 +97,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
|
|||
|
||||
#### End of system configuration section. ####
|
||||
######################################################################
|
||||
# Main build targets
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
|
|
@ -146,6 +148,9 @@ verilator_exe verilator_bin$(EXEEXT) verilator_bin_dbg$(EXEEXT) verilator_covera
|
|||
@echo "making verilator in src"
|
||||
$(MAKE) -C src $(OBJCACHE_JOBS)
|
||||
|
||||
######################################################################
|
||||
# Tests
|
||||
|
||||
.PHONY:msg_test
|
||||
msg_test: all_nomsg
|
||||
@echo "Build complete!"
|
||||
|
|
@ -156,7 +161,7 @@ msg_test: all_nomsg
|
|||
.PHONY: test
|
||||
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
|
||||
test: smoke-test test_regress
|
||||
# examples is part of test_regress's test_regress/t/t_a2_examples.pl
|
||||
# examples is part of test_regress's test_regress/t/t_a2_examples.py
|
||||
# (because that allows it to run in parallel with other test_regress's)
|
||||
else
|
||||
test: smoke-test examples
|
||||
|
|
@ -168,8 +173,8 @@ endif
|
|||
@echo
|
||||
|
||||
smoke-test: all_nomsg
|
||||
test_regress/t/t_a1_first_cc.pl
|
||||
test_regress/t/t_a2_first_sc.pl
|
||||
test_regress/t/t_a1_first_cc.py
|
||||
test_regress/t/t_a2_first_sc.py
|
||||
|
||||
test_regress: all_nomsg
|
||||
$(MAKE) -C test_regress
|
||||
|
|
@ -183,6 +188,9 @@ examples: all_nomsg
|
|||
$(MAKE) -C $$p VERILATOR_ROOT=`pwd` || exit 10; \
|
||||
done
|
||||
|
||||
######################################################################
|
||||
# Docs
|
||||
|
||||
.PHONY: docs
|
||||
docs: info
|
||||
|
||||
|
|
@ -204,6 +212,20 @@ verilator.html:
|
|||
verilator.pdf: Makefile
|
||||
$(MAKE) -C docs verilator.pdf
|
||||
|
||||
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
|
||||
${srcdir}/*.in ${srcdir}/*.pod
|
||||
|
||||
TAGS: $(TAGFILES)
|
||||
etags $(TAGFILES)
|
||||
|
||||
.PHONY: doxygen
|
||||
|
||||
doxygen:
|
||||
$(MAKE) -C docs doxygen
|
||||
|
||||
######################################################################
|
||||
# Install
|
||||
|
||||
# Public executables intended to be invoked directly by the user
|
||||
# Don't put wildcards in these variables, it might cause an uninstall of other stuff
|
||||
VL_INST_PUBLIC_SCRIPT_FILES = verilator \
|
||||
|
|
@ -244,11 +266,15 @@ mkbindirs:
|
|||
installbin: | mkbindirs
|
||||
cd $(srcdir)/bin; \
|
||||
for p in $(VL_INST_PUBLIC_SCRIPT_FILES) ; do \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/bin/$$p; \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \
|
||||
done
|
||||
perl -p -i -e 'use File::Spec;' \
|
||||
-e' $$path = File::Spec->abs2rel("$(realpath $(DESTDIR)$(pkgdatadir))", "$(realpath $(DESTDIR)$(bindir))");' \
|
||||
-e 's/my \$$verilator_pkgdatadir_relpath = .*/my \$$verilator_pkgdatadir_relpath = "$$path";/g' \
|
||||
-- "$(DESTDIR)/$(bindir)/verilator"
|
||||
cd bin; \
|
||||
for p in $(VL_INST_PUBLIC_BIN_FILES) ; do \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/bin/$$p; \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \
|
||||
done
|
||||
cd $(srcdir)/bin; \
|
||||
for p in $(VL_INST_PRIVATE_SCRIPT_FILES) ; do \
|
||||
|
|
@ -258,11 +284,11 @@ installbin: | mkbindirs
|
|||
installredirect: installbin | mkbindirs
|
||||
cp ${srcdir}/bin/redirect ${srcdir}/bin/redirect.tmp
|
||||
perl -p -i -e 'use File::Spec;' \
|
||||
-e' $$path = File::Spec->abs2rel("$(realpath $(DESTDIR)$(pkgdatadir)/bin)", "$(realpath $(DESTDIR)$(bindir))");' \
|
||||
-e' $$path = File::Spec->abs2rel("$(realpath $(DESTDIR)$(bindir))", "$(realpath $(DESTDIR)$(pkgdatadir)/bin)");' \
|
||||
-e 's/RELPATH.*/"$$path";/g' -- "${srcdir}/bin/redirect.tmp"
|
||||
cd $(srcdir)/bin; \
|
||||
for p in $(VL_INST_PUBLIC_SCRIPT_FILES) $(VL_INST_PUBLIC_BIN_FILES) ; do \
|
||||
$(INSTALL_PROGRAM) redirect.tmp $(DESTDIR)$(bindir)/$$p; \
|
||||
$(INSTALL_PROGRAM) redirect.tmp $(DESTDIR)$(pkgdatadir)/bin/$$p; \
|
||||
done
|
||||
rm ${srcdir}/bin/redirect.tmp
|
||||
|
||||
|
|
@ -344,6 +370,19 @@ install-all: installbin installredirect installman installdata install-msg
|
|||
|
||||
install-here: installman info
|
||||
|
||||
install-msg:
|
||||
@echo
|
||||
@echo "Installed binaries to $(DESTDIR)$(bindir)/verilator"
|
||||
@echo "Installed man to $(DESTDIR)$(mandir)/man1"
|
||||
@echo "Installed examples to $(DESTDIR)$(pkgdatadir)/examples"
|
||||
@echo
|
||||
@echo "For documentation see 'man verilator' or 'verilator --help'"
|
||||
@echo "For forums and to report bugs see https://verilator.org"
|
||||
@echo
|
||||
|
||||
######################################################################
|
||||
# Format/Lint
|
||||
|
||||
# Use --xml flag to see the cppcheck code to use for suppression
|
||||
CPPCHECK1_CPP = $(wildcard $(srcdir)/include/*.cpp)
|
||||
CPPCHECK2_CPP = $(wildcard $(srcdir)/examples/*/*.cpp)
|
||||
|
|
@ -411,7 +450,8 @@ analyzer-include:
|
|||
-rm -rf examples/*/obj*
|
||||
scan-build $(MAKE) -k examples
|
||||
|
||||
format: clang-format yapf format-pl-exec
|
||||
format:
|
||||
$(MAKE) -j 4 clang-format yapf format-exec
|
||||
|
||||
CLANGFORMAT = clang-format-14
|
||||
CLANGFORMAT_FLAGS = -i
|
||||
|
|
@ -422,6 +462,20 @@ clang-format:
|
|||
|| echo "*** You are not using clang-format-14, indents may differ from master's ***"
|
||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
|
||||
|
||||
YAMLFIX = YAMLFIX_WHITELINES=1 YAMLFIX_LINE_LENGTH=130 YAMLFIX_preserve_quotes=true yamlfix
|
||||
|
||||
yamlfix:
|
||||
$(YAMLFIX) .
|
||||
|
||||
# CMake files
|
||||
CMAKE_FILES = \
|
||||
CMakeLists.txt \
|
||||
examples/*/CMakeLists.txt \
|
||||
src/CMakeLists.txt \
|
||||
test_regress/CMakeLists.txt \
|
||||
*.cmake.in \
|
||||
|
||||
# Python programs, subject to format and lint
|
||||
PY_PROGRAMS = \
|
||||
bin/verilator_ccache_report \
|
||||
bin/verilator_difftree \
|
||||
|
|
@ -440,6 +494,7 @@ PY_PROGRAMS = \
|
|||
src/flexfix \
|
||||
src/vlcovgen \
|
||||
src/.gdbinit.py \
|
||||
test_regress/*.py \
|
||||
test_regress/t/*.pf \
|
||||
nodist/clang_check_attributes \
|
||||
nodist/code_coverage \
|
||||
|
|
@ -449,44 +504,53 @@ PY_PROGRAMS = \
|
|||
nodist/install_test \
|
||||
nodist/log_changes \
|
||||
|
||||
# Python files, subject to format but not lint
|
||||
PY_FILES = \
|
||||
$(PY_PROGRAMS) \
|
||||
nodist/code_coverage.dat \
|
||||
test_regress/t/*.py \
|
||||
|
||||
# Python files, test_regress tests
|
||||
PY_TEST_FILES = \
|
||||
test_regress/t/*.py \
|
||||
|
||||
YAPF = yapf3
|
||||
YAPF_FLAGS = -i
|
||||
YAPF_FLAGS = -i --parallel
|
||||
|
||||
yapf:
|
||||
$(YAPF) $(YAPF_FLAGS) $(PY_FILES)
|
||||
|
||||
GERSEMI = gersemi
|
||||
GERSEMI_FLAGS = -i
|
||||
|
||||
format-cmake:
|
||||
$(GERSEMI) $(GERSEMI_FLAGS) $(CMAKE_FILES)
|
||||
|
||||
PYLINT = pylint
|
||||
PYLINT_FLAGS = --score=n --disable=R0801
|
||||
PYLINT_FLAGS = --recursive=n --score=n --disable=R0801
|
||||
PYLINT_TEST_FLAGS = $(PYLINT_FLAGS) --disable=C0103,C0114,C0116,C0209,C0411,C0413,C0301,R0801,R0912,R0915,R0916,R1702,W0511,W0621
|
||||
|
||||
RUFF = ruff
|
||||
RUFF_FLAGS = check --ignore=E402,E501,E701
|
||||
|
||||
# "make -k" so can see all tool result errors
|
||||
lint-py:
|
||||
$(MAKE) -k lint-py-pylint lint-py-ruff
|
||||
$(MAKE) -k lint-py-pylint lint-py-pylint-tests lint-py-ruff
|
||||
|
||||
lint-py-pylint:
|
||||
$(PYLINT) $(PYLINT_FLAGS) $(PY_PROGRAMS)
|
||||
|
||||
lint-py-pylint-tests:
|
||||
$(PYLINT) $(PYLINT_TEST_FLAGS) $(PY_TEST_FILES) | $(PYTHON3) nodist/lint_py_test_filter
|
||||
|
||||
lint-py-ruff:
|
||||
$(RUFF) $(RUFF_FLAGS) $(PY_PROGRAMS)
|
||||
|
||||
format-pl-exec:
|
||||
-chmod a+x test_regress/t/*.pl
|
||||
format-exec:
|
||||
-chmod a+x test_regress/t/*.py
|
||||
|
||||
install-msg:
|
||||
@echo
|
||||
@echo "Installed binaries to $(DESTDIR)$(bindir)/verilator"
|
||||
@echo "Installed man to $(DESTDIR)$(mandir)/man1"
|
||||
@echo "Installed examples to $(DESTDIR)$(pkgdatadir)/examples"
|
||||
@echo
|
||||
@echo "For documentation see 'man verilator' or 'verilator --help'"
|
||||
@echo "For forums and to report bugs see https://verilator.org"
|
||||
@echo
|
||||
######################################################################
|
||||
# Configure
|
||||
|
||||
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
|
||||
|
||||
|
|
@ -507,6 +571,9 @@ else
|
|||
autoconf
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
# Clean
|
||||
|
||||
maintainer-clean::
|
||||
@echo "This command is intended for maintainers to use;"
|
||||
@echo "rebuilding the deleted files requires autoconf."
|
||||
|
|
@ -537,17 +604,6 @@ distclean maintainer-clean::
|
|||
rm -f bin/verilator_bin* bin/verilator_coverage_bin*
|
||||
rm -f include/verilated.mk include/verilated_config.h
|
||||
|
||||
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
|
||||
${srcdir}/*.in ${srcdir}/*.pod
|
||||
|
||||
TAGS: $(TAGFILES)
|
||||
etags $(TAGFILES)
|
||||
|
||||
.PHONY: doxygen
|
||||
|
||||
doxygen:
|
||||
$(MAKE) -C docs doxygen
|
||||
|
||||
######################################################################
|
||||
# Distributions
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,9 @@ if (! GetOptions(
|
|||
pod2usage(-exitstatus => 2, -verbose => 0);
|
||||
}
|
||||
|
||||
my $verilator_root = realpath("$RealBin/..");
|
||||
# WARNING: $verilator_pkgdatadir_relpath is substituted during Verilator 'make install'
|
||||
my $verilator_pkgdatadir_relpath = "..";
|
||||
my $verilator_root = realpath("$RealBin/$verilator_pkgdatadir_relpath");
|
||||
if (defined $ENV{VERILATOR_ROOT}) {
|
||||
if ((!-d $ENV{VERILATOR_ROOT}) || $verilator_root ne realpath($ENV{VERILATOR_ROOT})) {
|
||||
warn "%Error: verilator: VERILATOR_ROOT is set to inconsistent path. Suggest leaving it unset.\n";
|
||||
|
|
@ -405,6 +407,7 @@ detailed descriptions of these arguments.
|
|||
-O3 High-performance optimizations
|
||||
-O<optimization-letter> Selectable optimizations
|
||||
-o <executable> Name of final executable
|
||||
--output-groups <numfiles> Group .cpp files into larger ones
|
||||
--output-split <statements> Split .cpp files into pieces
|
||||
--output-split-cfuncs <statements> Split model functions
|
||||
--output-split-ctrace <statements> Split tracing functions
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ parser = argparse.ArgumentParser(
|
|||
|
||||
For documentation see
|
||||
https://verilator.org/guide/latest/exe_verilator_ccache_report.html""",
|
||||
epilog=
|
||||
"""Copyright 2002-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2002-2024 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
|
@ -67,30 +66,23 @@ else:
|
|||
wnames = max(len(_) for _ in results) + 1
|
||||
wresults = max(len(_) for _ in results.values()) + 1
|
||||
for k in sorted(results.keys()):
|
||||
args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format(
|
||||
k,
|
||||
results[k],
|
||||
elapsed[k].total_seconds(),
|
||||
wnames=wnames,
|
||||
wresults=wresults))
|
||||
args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format(k,
|
||||
results[k],
|
||||
elapsed[k].total_seconds(),
|
||||
wnames=wnames,
|
||||
wresults=wresults))
|
||||
|
||||
args.o.write("\nSummary:\n")
|
||||
counts = collections.Counter(_ for _ in results.values())
|
||||
total = sum(counts.values())
|
||||
for k in sorted(counts.keys()):
|
||||
c = counts[k]
|
||||
args.o.write("{:{width}}| {} ({:.2%})\n".format(k,
|
||||
c,
|
||||
c / total,
|
||||
width=wresults))
|
||||
args.o.write("{:{width}}| {} ({:.2%})\n".format(k, c, c / total, width=wresults))
|
||||
|
||||
args.o.write("\nLongest:\n")
|
||||
longest = sorted(list(elapsed.items()),
|
||||
key=lambda kv: -kv[1].total_seconds())
|
||||
longest = sorted(list(elapsed.items()), key=lambda kv: -kv[1].total_seconds())
|
||||
for i, (k, v) in enumerate(longest):
|
||||
args.o.write("{:{width}}| {}s\n".format(k,
|
||||
v.total_seconds(),
|
||||
width=wnames))
|
||||
args.o.write("{:{width}}| {}s\n".format(k, v.total_seconds(), width=wnames))
|
||||
if i > 4:
|
||||
break
|
||||
|
||||
|
|
|
|||
|
|
@ -47,8 +47,7 @@ def diff_dir(a, b):
|
|||
diff_file(a, b)
|
||||
anyfile = True
|
||||
if not anyfile:
|
||||
sys.stderr.write(
|
||||
"%Warning: No .tree files found that have similar base names\n")
|
||||
sys.stderr.write("%Warning: No .tree files found that have similar base names\n")
|
||||
|
||||
|
||||
def diff_file(a, b):
|
||||
|
|
@ -109,18 +108,14 @@ parser = argparse.ArgumentParser(
|
|||
Verilator_difftree is used for debugging Verilator tree output files.
|
||||
It performs a diff between two files, or all files common between two
|
||||
directories, ignoring irrelevant pointer differences.""",
|
||||
epilog=
|
||||
"""Copyright 2005-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2005-2024 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('--no-lineno',
|
||||
action='store_false',
|
||||
help='do not show differences in line numbering')
|
||||
|
|
|
|||
|
|
@ -15,11 +15,7 @@ LongestVcdStrValueLength = 0
|
|||
Threads = collections.defaultdict(lambda: []) # List of records per thread id
|
||||
Mtasks = collections.defaultdict(lambda: {'elapsed': 0, 'end': 0})
|
||||
Cpus = collections.defaultdict(lambda: {'mtask_time': 0})
|
||||
Global = {
|
||||
'args': {},
|
||||
'cpuinfo': collections.defaultdict(lambda: {}),
|
||||
'stats': {}
|
||||
}
|
||||
Global = {'args': {}, 'cpuinfo': collections.defaultdict(lambda: {}), 'stats': {}}
|
||||
ElapsedTime = None # total elapsed time
|
||||
ExecGraphTime = 0 # total elapsed time excuting an exec graph
|
||||
ExecGraphIntervals = [] # list of (start, end) pairs
|
||||
|
|
@ -31,8 +27,7 @@ def read_data(filename):
|
|||
with open(filename, "r", encoding="utf8") as fh:
|
||||
re_thread = re.compile(r'^VLPROFTHREAD (\d+)$')
|
||||
re_record = re.compile(r'^VLPROFEXEC (\S+) (\d+)(.*)$')
|
||||
re_payload_mtaskBegin = re.compile(
|
||||
r'id (\d+) predictStart (\d+) cpu (\d+)')
|
||||
re_payload_mtaskBegin = re.compile(r'id (\d+) predictStart (\d+) cpu (\d+)')
|
||||
re_payload_mtaskEnd = re.compile(r'id (\d+) predictCost (\d+)')
|
||||
|
||||
re_arg1 = re.compile(r'VLPROF arg\s+(\S+)\+([0-9.]*)\s*')
|
||||
|
|
@ -57,8 +52,7 @@ def read_data(filename):
|
|||
tick = int(tick)
|
||||
payload = payload.strip()
|
||||
if kind == "SECTION_PUSH":
|
||||
LongestVcdStrValueLength = max(LongestVcdStrValueLength,
|
||||
len(payload))
|
||||
LongestVcdStrValueLength = max(LongestVcdStrValueLength, len(payload))
|
||||
SectionStack.append(payload)
|
||||
Sections.append((tick, tuple(SectionStack)))
|
||||
elif kind == "SECTION_POP":
|
||||
|
|
@ -66,15 +60,13 @@ def read_data(filename):
|
|||
SectionStack.pop()
|
||||
Sections.append((tick, tuple(SectionStack)))
|
||||
elif kind == "MTASK_BEGIN":
|
||||
mtask, predict_start, ecpu = re_payload_mtaskBegin.match(
|
||||
payload).groups()
|
||||
mtask, predict_start, ecpu = re_payload_mtaskBegin.match(payload).groups()
|
||||
mtask = int(mtask)
|
||||
predict_start = int(predict_start)
|
||||
ecpu = int(ecpu)
|
||||
mTaskThread[mtask] = thread
|
||||
records = Threads[thread]
|
||||
assert not records or records[-1]['start'] <= records[-1][
|
||||
'end'] <= tick
|
||||
assert not records or records[-1]['start'] <= records[-1]['end'] <= tick
|
||||
records.append({
|
||||
'start': tick,
|
||||
'mtask': mtask,
|
||||
|
|
@ -85,8 +77,7 @@ def read_data(filename):
|
|||
Mtasks[mtask]['thread'] = thread
|
||||
Mtasks[mtask]['predict_start'] = predict_start
|
||||
elif kind == "MTASK_END":
|
||||
mtask, predict_cost = re_payload_mtaskEnd.match(
|
||||
payload).groups()
|
||||
mtask, predict_cost = re_payload_mtaskEnd.match(payload).groups()
|
||||
mtask = int(mtask)
|
||||
predict_cost = int(predict_cost)
|
||||
begin = Mtasks[mtask]['begin']
|
||||
|
|
@ -163,8 +154,7 @@ def report():
|
|||
|
||||
print("\nSummary:")
|
||||
print(" Total elapsed time = {} rdtsc ticks".format(ElapsedTime))
|
||||
print(" Parallelized code = {:.2%} of elapsed time".format(
|
||||
ExecGraphTime / ElapsedTime))
|
||||
print(" Parallelized code = {:.2%} of elapsed time".format(ExecGraphTime / ElapsedTime))
|
||||
print(" Total threads = %d" % nthreads)
|
||||
print(" Total CPUs used = %d" % ncpus)
|
||||
print(" Total mtasks = %d" % len(Mtasks))
|
||||
|
|
@ -176,15 +166,12 @@ def report():
|
|||
|
||||
if nthreads > ncpus:
|
||||
print()
|
||||
print("%%Warning: There were fewer CPUs (%d) than threads (%d)." %
|
||||
(ncpus, nthreads))
|
||||
print("%%Warning: There were fewer CPUs (%d) than threads (%d)." % (ncpus, nthreads))
|
||||
print(" : See docs on use of numactl.")
|
||||
else:
|
||||
if 'cpu_socket_cores_warning' in Global:
|
||||
print()
|
||||
print(
|
||||
"%Warning: Multiple threads scheduled on same hyperthreaded core."
|
||||
)
|
||||
print("%Warning: Multiple threads scheduled on same hyperthreaded core.")
|
||||
print(" : See docs on use of numactl.")
|
||||
if 'cpu_sockets_warning' in Global:
|
||||
print()
|
||||
|
|
@ -228,8 +215,7 @@ def report_mtasks():
|
|||
serialTime = ElapsedTime - ExecGraphTime
|
||||
|
||||
def subReport(elapsed, work):
|
||||
print(" Thread utilization = {:7.2%}".format(work /
|
||||
(elapsed * nthreads)))
|
||||
print(" Thread utilization = {:7.2%}".format(work / (elapsed * nthreads)))
|
||||
print(" Speedup = {:6.3}x".format(work / elapsed))
|
||||
|
||||
print("\nParallelized code, measured:")
|
||||
|
|
@ -256,8 +242,7 @@ def report_mtasks():
|
|||
if Mtasks[mtask]['elapsed'] > 0:
|
||||
if Mtasks[mtask]['predict_cost'] == 0:
|
||||
Mtasks[mtask]['predict_cost'] = 1 # don't log(0) below
|
||||
p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] /
|
||||
Mtasks[mtask]['elapsed'])
|
||||
p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] / Mtasks[mtask]['elapsed'])
|
||||
p2e_ratios.append(p2e_ratio)
|
||||
|
||||
if p2e_ratio > max_p2e:
|
||||
|
|
@ -269,18 +254,14 @@ def report_mtasks():
|
|||
|
||||
print("\nMTask statistics:")
|
||||
print(" Longest mtask id = {}".format(long_mtask))
|
||||
print(" Longest mtask time = {:.2%} of time elapsed in parallelized code".
|
||||
format(long_mtask_time / ExecGraphTime))
|
||||
print(" Longest mtask time = {:.2%} of time elapsed in parallelized code".format(
|
||||
long_mtask_time / ExecGraphTime))
|
||||
print(" min log(p2e) = %0.3f" % min_p2e, end="")
|
||||
|
||||
print(" from mtask %d (predict %d," %
|
||||
(min_mtask, Mtasks[min_mtask]['predict_cost']),
|
||||
end="")
|
||||
print(" from mtask %d (predict %d," % (min_mtask, Mtasks[min_mtask]['predict_cost']), end="")
|
||||
print(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
|
||||
print(" max log(p2e) = %0.3f" % max_p2e, end="")
|
||||
print(" from mtask %d (predict %d," %
|
||||
(max_mtask, Mtasks[max_mtask]['predict_cost']),
|
||||
end="")
|
||||
print(" from mtask %d (predict %d," % (max_mtask, Mtasks[max_mtask]['predict_cost']), end="")
|
||||
print(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
|
||||
|
||||
stddev = statistics.pstdev(p2e_ratios)
|
||||
|
|
@ -315,8 +296,8 @@ def report_cpus():
|
|||
model = cpuinfo['model_name']
|
||||
|
||||
print(" {:3d} | {:7.2%} / {:16d} | {:>6s} | {:>4s} | {}".format(
|
||||
cpu, Cpus[cpu]['mtask_time'] / ElapsedTime,
|
||||
Cpus[cpu]['mtask_time'], socket, core, model))
|
||||
cpu, Cpus[cpu]['mtask_time'] / ElapsedTime, Cpus[cpu]['mtask_time'], socket, core,
|
||||
model))
|
||||
|
||||
if len(Global['cpu_sockets']) > 1:
|
||||
Global['cpu_sockets_warning'] = True
|
||||
|
|
@ -366,8 +347,8 @@ def report_sections():
|
|||
|
||||
def printTree(prefix, name, entries, tree):
|
||||
print(" {:7.2%} | {:7.2%} | {:8} | {:10.2f} | {}".format(
|
||||
treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2],
|
||||
tree[2] / entries, prefix + name))
|
||||
treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2], tree[2] / entries,
|
||||
prefix + name))
|
||||
for k in sorted(tree[1], key=lambda _: -treeSum(tree[1][_])):
|
||||
printTree(prefix + " ", k, tree[2], tree[1][k])
|
||||
|
||||
|
|
@ -438,10 +419,8 @@ def write_vcd(filename):
|
|||
addValue(code, start, mtask)
|
||||
addValue(code, end, None)
|
||||
|
||||
tStart = sorted(_['start'] for records in Threads.values()
|
||||
for _ in records)
|
||||
tEnd = sorted(_['end'] for records in Threads.values()
|
||||
for _ in records)
|
||||
tStart = sorted(_['start'] for records in Threads.values() for _ in records)
|
||||
tEnd = sorted(_['end'] for records in Threads.values() for _ in records)
|
||||
|
||||
# Predicted graph
|
||||
for start, end in ExecGraphIntervals:
|
||||
|
|
@ -455,11 +434,10 @@ def write_vcd(filename):
|
|||
# Predict mtasks that fill the time the execution occupied
|
||||
for mtask in Mtasks:
|
||||
thread = Mtasks[mtask]['thread']
|
||||
pred_scaled_start = start + int(
|
||||
Mtasks[mtask]['predict_start'] * measured_scaling)
|
||||
pred_scaled_start = start + int(Mtasks[mtask]['predict_start'] * measured_scaling)
|
||||
pred_scaled_end = start + int(
|
||||
(Mtasks[mtask]['predict_start'] +
|
||||
Mtasks[mtask]['predict_cost']) * measured_scaling)
|
||||
(Mtasks[mtask]['predict_start'] + Mtasks[mtask]['predict_cost']) *
|
||||
measured_scaling)
|
||||
if pred_scaled_start == pred_scaled_end:
|
||||
continue
|
||||
|
||||
|
|
@ -545,8 +523,7 @@ Verilator_gantt creates a visual representation to help analyze Verilator
|
|||
|
||||
For documentation see
|
||||
https://verilator.org/guide/latest/exe_verilator_gantt.html""",
|
||||
epilog=
|
||||
"""Copyright 2018-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2018-2024 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
|
@ -554,12 +531,8 @@ Version 2.0.
|
|||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||
|
||||
parser.add_argument('--debug', action='store_true', help='enable debug')
|
||||
parser.add_argument('--no-vcd',
|
||||
help='disable creating vcd',
|
||||
action='store_true')
|
||||
parser.add_argument('--vcd',
|
||||
help='filename for vcd outpue',
|
||||
default='profile_exec.vcd')
|
||||
parser.add_argument('--no-vcd', help='disable creating vcd', action='store_true')
|
||||
parser.add_argument('--vcd', help='filename for vcd outpue', default='profile_exec.vcd')
|
||||
parser.add_argument('filename',
|
||||
help='input profile_exec.dat filename to process',
|
||||
default='profile_exec.dat')
|
||||
|
|
|
|||
|
|
@ -34,9 +34,8 @@ def profcfunc(filename):
|
|||
|
||||
# Older gprofs have no call column for single-call functions
|
||||
# %time cumesec selfsec {stuff} name
|
||||
match = re.match(
|
||||
r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$',
|
||||
line)
|
||||
match = re.match(r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$',
|
||||
line)
|
||||
if match:
|
||||
pct = float(match.group(1))
|
||||
sec = float(match.group(2))
|
||||
|
|
@ -136,19 +135,15 @@ def profcfunc(filename):
|
|||
|
||||
design_width = 1
|
||||
for func, func_item in vfuncs.items():
|
||||
if design_width < len(func_item['design']):
|
||||
design_width = len(func_item['design'])
|
||||
design_width = max(design_width, len(func_item['design']))
|
||||
|
||||
print("Verilog code profile:")
|
||||
print(" These are split into three categories:")
|
||||
print(" C++: Time in non-Verilated C++ code")
|
||||
print(" Prof: Time in profile overhead")
|
||||
print(" VBlock: Time attributable to a block in a" +
|
||||
" Verilog file and line")
|
||||
print(" VCommon: Time in a Verilated module," +
|
||||
" due to all parts of the design")
|
||||
print(" VLib: Time in Verilated common libraries," +
|
||||
" called by the Verilated code")
|
||||
print(" VBlock: Time attributable to a block in a" + " Verilog file and line")
|
||||
print(" VCommon: Time in a Verilated module," + " due to all parts of the design")
|
||||
print(" VLib: Time in Verilated common libraries," + " called by the Verilated code")
|
||||
print()
|
||||
|
||||
print(" % cumulative self ")
|
||||
|
|
@ -156,13 +151,11 @@ def profcfunc(filename):
|
|||
"s type filename and line number") % "design")
|
||||
|
||||
cume = 0
|
||||
for func in sorted(vfuncs.keys(),
|
||||
key=lambda f: vfuncs[f]['sec'],
|
||||
reverse=True):
|
||||
for func in sorted(vfuncs.keys(), key=lambda f: vfuncs[f]['sec'], reverse=True):
|
||||
cume += vfuncs[func]['sec']
|
||||
print(("%6.2f %9.2f %8.2f %10d %-" + str(design_width) + "s %s") %
|
||||
(vfuncs[func]['pct'], cume, vfuncs[func]['sec'],
|
||||
vfuncs[func]['calls'], vfuncs[func]['design'], func))
|
||||
(vfuncs[func]['pct'], cume, vfuncs[func]['sec'], vfuncs[func]['calls'],
|
||||
vfuncs[func]['design'], func))
|
||||
|
||||
|
||||
######################################################################
|
||||
|
|
@ -180,18 +173,14 @@ in each Verilog block.
|
|||
|
||||
For documentation see
|
||||
https://verilator.org/guide/latest/exe_verilator_profcfunc.html""",
|
||||
epilog=
|
||||
"""Copyright 2002-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2002-2024 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('filename', help='input gprof output to process')
|
||||
|
||||
Args = parser.parse_args()
|
||||
|
|
|
|||
|
|
@ -60,17 +60,14 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
|||
sudo apt-get install libgoogle-perftools-dev ||
|
||||
sudo apt-get install libgoogle-perftools-dev
|
||||
fi
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ] || [ "$CI_RUNS_ON" = "ubuntu-24.04" ]; then
|
||||
sudo apt-get install libsystemc libsystemc-dev ||
|
||||
sudo apt-get install libsystemc libsystemc-dev
|
||||
fi
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ] || [ "$CI_RUNS_ON" = "ubuntu-24.04" ]; then
|
||||
sudo apt-get install bear mold ||
|
||||
sudo apt-get install bear mold
|
||||
fi
|
||||
if [ "$COVERAGE" = 1 ]; then
|
||||
yes yes | sudo cpan -fi Parallel::Forker
|
||||
fi
|
||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
||||
brew update
|
||||
brew install ccache perl gperftools
|
||||
|
|
@ -94,12 +91,12 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|||
# libfl-dev needed for internal coverage's test runs
|
||||
sudo apt-get install gdb gtkwave lcov libfl-dev ccache jq z3 ||
|
||||
sudo apt-get install gdb gtkwave lcov libfl-dev ccache jq z3
|
||||
# Required for test_regress/t/t_dist_attributes.pl
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
|
||||
# Required for test_regress/t/t_dist_attributes.py
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ] || [ "$CI_RUNS_ON" = "ubuntu-24.04" ]; then
|
||||
sudo apt-get install python3-clang mold ||
|
||||
sudo apt-get install python3-clang mold
|
||||
fi
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ] || [ "$CI_RUNS_ON" = "ubuntu-24.04" ]; then
|
||||
sudo apt-get install libsystemc-dev ||
|
||||
sudo apt-get install libsystemc-dev
|
||||
fi
|
||||
|
|
@ -114,10 +111,6 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|||
fatal "Unknown os: '$CI_OS_NAME'"
|
||||
fi
|
||||
# Common installs
|
||||
if [ "$CI_RUNS_ON" != "ubuntu-14.04" ]; then
|
||||
CI_CPAN_REPO=https://cpan.org
|
||||
fi
|
||||
yes yes | sudo cpan -M $CI_CPAN_REPO -fi Parallel::Forker
|
||||
install-vcddiff
|
||||
# Workaround -fsanitize=address crash
|
||||
sudo sysctl -w vm.mmap_rnd_bits=28
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
|||
else
|
||||
fatal "Unknown os: '$CI_OS_NAME'"
|
||||
fi
|
||||
NPROC=$(expr $NPROC '+' 1)
|
||||
|
||||
if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
||||
##############################################################################
|
||||
|
|
@ -61,6 +62,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|||
# Run tests
|
||||
|
||||
export VERILATOR_TEST_NO_CONTRIBUTORS=1 # Separate workflow check
|
||||
export VERILATOR_TEST_NO_LINT_PY=1 # Separate workflow check
|
||||
|
||||
if [ "$CI_OS_NAME" = "osx" ]; then
|
||||
export VERILATOR_TEST_NO_GDB=1 # Pain to get GDB to work on OS X
|
||||
|
|
@ -85,7 +87,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|||
fi
|
||||
|
||||
# Run sanitize on Ubuntu 22.04 only
|
||||
[ "$CI_RUNS_ON" = 'ubuntu-22.04' ] && sanitize='--sanitize' || sanitize=''
|
||||
( [ "$CI_RUNS_ON" = 'ubuntu-22.04' ] || [ "$CI_RUNS_ON" = 'ubuntu-24.04' ] ) && sanitize='--sanitize' || sanitize=''
|
||||
|
||||
TEST_REGRESS=test_regress
|
||||
if [ "$CI_RELOC" == 1 ]; then
|
||||
|
|
@ -193,6 +195,8 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|||
;;
|
||||
esac
|
||||
|
||||
# To see load average (1 minute, 5 minute, 15 minute)
|
||||
uptime
|
||||
# 22.04: ccache -s -v
|
||||
ccache -s
|
||||
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@
|
|||
Set-PSDebug -Trace 1
|
||||
|
||||
if (-Not (Test-Path $PWD/../.ccache/win_bison.exe)) {
|
||||
git clone --depth 1 https://github.com/lexxmark/winflexbison
|
||||
cd winflexbison
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. --install-prefix $PWD/../../../.ccache
|
||||
cmake --build . --config Release -j 3
|
||||
cmake --install . --prefix $PWD/../../../.ccache
|
||||
cd ../..
|
||||
git clone --depth 1 https://github.com/lexxmark/winflexbison
|
||||
cd winflexbison
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. --install-prefix $PWD/../../../.ccache
|
||||
cmake --build . --config Release -j 3
|
||||
cmake --install . --prefix $PWD/../../../.ccache
|
||||
cd ../..
|
||||
}
|
||||
|
||||
mkdir build
|
||||
|
|
|
|||
|
|
@ -51,8 +51,6 @@ RUN apt-get update \
|
|||
|
||||
WORKDIR /tmp
|
||||
|
||||
RUN cpan install -fi Parallel::Forker
|
||||
|
||||
RUN git clone https://github.com/veripool/vcddiff.git && \
|
||||
make -C vcddiff && \
|
||||
cp -p vcddiff/vcddiff /usr/local/bin/vcddiff && \
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
.. Copyright 2003-2024 by Wilson Snyder.
|
||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
.. _Verilator Build Docker Container:
|
||||
|
||||
Verilator Build Docker Container
|
||||
================================
|
||||
|
||||
|
|
|
|||
32
codecov.yml
32
codecov.yml
|
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
# DESCRIPTION: codecov.io config
|
||||
#
|
||||
# Copyright 2020-2024 by Wilson Snyder. This program is free software; you
|
||||
|
|
@ -8,31 +9,28 @@
|
|||
####################
|
||||
# Validate:
|
||||
# curl --data-binary @codecov.yml https://codecov.io/validate
|
||||
|
||||
#
|
||||
codecov:
|
||||
require_ci_to_pass: no
|
||||
|
||||
require_ci_to_pass: false
|
||||
coverage:
|
||||
precision: 2
|
||||
round: down
|
||||
range: "50...100"
|
||||
range: 50...100
|
||||
ignore:
|
||||
- "ci"
|
||||
- "docs"
|
||||
- "examples"
|
||||
- "include/gtkwave"
|
||||
- "include/vltstd"
|
||||
- "test_regress"
|
||||
|
||||
- "ci" #
|
||||
- "docs" #
|
||||
- "examples" #
|
||||
- "include/gtkwave" #
|
||||
- "include/vltstd" #
|
||||
- "test_regress" #
|
||||
parsers:
|
||||
gcov:
|
||||
branch_detection:
|
||||
conditional: yes
|
||||
loop: yes
|
||||
method: no
|
||||
macro: no
|
||||
|
||||
conditional: true
|
||||
loop: true
|
||||
method: false
|
||||
macro: false
|
||||
comment:
|
||||
layout: "reach,diff,flags,tree"
|
||||
behavior: default
|
||||
require_changes: yes
|
||||
require_changes: true
|
||||
|
|
|
|||
23
configure.ac
23
configure.ac
|
|
@ -10,7 +10,7 @@
|
|||
# Then 'make maintainer-dist'
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[5.028 2024-08-21],
|
||||
AC_INIT([Verilator],[5.030 2024-10-27],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
|
||||
|
|
@ -29,6 +29,9 @@ AC_DEFINE_UNQUOTED([PACKAGE_VERSION_STRING_CHAR],
|
|||
[Package version as a number])
|
||||
AC_SUBST(PACKAGE_VERSION_STRING_CHAR)
|
||||
|
||||
######################################################################
|
||||
## Arguments/flag checking
|
||||
|
||||
# Ignore automake flags passed by Ubuntu builds
|
||||
AC_ARG_ENABLE([dependency-tracking],
|
||||
[AS_HELP_STRING([--disable-dependency-tracking], [ignored])])
|
||||
|
|
@ -156,6 +159,11 @@ AC_ARG_WITH([solver],
|
|||
AC_SUBST(CFG_WITH_SOLVER)
|
||||
AC_MSG_RESULT($CFG_WITH_SOLVER)
|
||||
|
||||
######################################################################
|
||||
## Compiler checks
|
||||
|
||||
AC_MSG_RESULT([compiler CXX inbound is set to... $CXX])
|
||||
|
||||
# Compiler flags (ensure they are not empty to avoid configure defaults)
|
||||
CFLAGS="$CFLAGS "
|
||||
CPPFLAGS="$CPPFLAGS "
|
||||
|
|
@ -182,24 +190,26 @@ if test "x$AR" = "x" ; then
|
|||
AC_MSG_ERROR([Cannot find "ar" in your PATH, please install it])
|
||||
fi
|
||||
|
||||
AC_PATH_PROG(PERL,perl)
|
||||
AC_CHECK_PROG(PERL,perl,perl)
|
||||
if test "x$PERL" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
|
||||
fi
|
||||
|
||||
AC_PATH_PROG(PYTHON3,python3)
|
||||
AC_CHECK_PROG(PYTHON3,python3,python3)
|
||||
if test "x$PYTHON3" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "python3" in your PATH, please install it])
|
||||
fi
|
||||
python3_version=$($PYTHON3 --version | head -1)
|
||||
AC_MSG_RESULT([$PYTHON3 --version = $python3_version])
|
||||
|
||||
AC_PATH_PROG(LEX,flex)
|
||||
AC_CHECK_PROG(LEX,flex,flex)
|
||||
if test "x$LEX" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])
|
||||
fi
|
||||
flex_version=$($LEX --version | head -1)
|
||||
AC_MSG_RESULT([$LEX --version = $flex_version])
|
||||
|
||||
AC_PATH_PROG(YACC,bison)
|
||||
AC_CHECK_PROG(YACC,bison,bison)
|
||||
if test "x$YACC" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
|
||||
fi
|
||||
|
|
@ -623,6 +633,9 @@ AC_SUBST(HAVE_SYSTEMC)
|
|||
|
||||
# Checks for system services
|
||||
|
||||
######################################################################
|
||||
## Output
|
||||
|
||||
# Other install directories
|
||||
pkgdatadir=${datadir}/verilator
|
||||
AC_SUBST(pkgdatadir)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Adam Bagley
|
|||
Adrian Sampson
|
||||
Adrien Le Masle
|
||||
Ahmed El-Mahmoudy
|
||||
Aidan McNay
|
||||
Aleksander Kiryk
|
||||
Alex Chadwick
|
||||
Alex Solomatnikov
|
||||
|
|
@ -44,9 +45,12 @@ Drew Ranck
|
|||
Drew Taussig
|
||||
Driss Hafdi
|
||||
Edgar E. Iglesias
|
||||
Eric Müller
|
||||
Eric Rippey
|
||||
Ethan Sifferman
|
||||
Eyck Jentzsch
|
||||
Furqan Nadir
|
||||
Fabian Keßler
|
||||
Fan Shupei
|
||||
february cozzocrea
|
||||
Felix Neumärker
|
||||
|
|
@ -64,6 +68,7 @@ Graham Rushton
|
|||
Guokai Chen
|
||||
Gus Smith
|
||||
Gustav Svensk
|
||||
Han Qi
|
||||
Harald Heckmann
|
||||
Hennadii Chernyshchyk
|
||||
Howard Su
|
||||
|
|
@ -148,6 +153,7 @@ Mladen Slijepcevic
|
|||
Morten Borup Petersen
|
||||
Mostafa Gamal
|
||||
Nandu Raj
|
||||
Nathan Graybeal
|
||||
Nathan Kohagen
|
||||
Nathan Myers
|
||||
Nolan Poe
|
||||
|
|
@ -215,6 +221,7 @@ Wilson Snyder
|
|||
Xi Zhang
|
||||
Yan Xu
|
||||
Yangyu Chen
|
||||
Yilou Wang
|
||||
Yinan Xu
|
||||
Yoda Lee
|
||||
Yossi Nivin
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ SPHINXBUILD ?= sphinx-build
|
|||
SOURCEDIR = guide
|
||||
BUILDDIR = _build
|
||||
|
||||
SPHINXOPTS ?= -c guide
|
||||
SPHINXOPTS ?= -c guide -j 4
|
||||
ifneq ($(VERILATOR_ANALYTICS_ID),)
|
||||
SPHINXOPTS += -D html_theme_options.analytics_id=$(VERILATOR_ANALYTICS_ID)
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ class VlSphinxExtract:
|
|||
outname = match.group(1)
|
||||
print("Writing %s" % outname)
|
||||
fhw = open(outname, "w", encoding="utf8") # pylint: disable=consider-using-with
|
||||
fhw.write(
|
||||
".. comment: generated by vl_sphinx_extract from " +
|
||||
filename + "\n")
|
||||
fhw.write(".. comment: generated by vl_sphinx_extract from " + filename + "\n")
|
||||
fhw.write(".. code-block::\n")
|
||||
elif re.match(r'^[=a-zA-Z0-9_]', line):
|
||||
fhw = None
|
||||
|
|
@ -39,18 +37,14 @@ parser = argparse.ArgumentParser(
|
|||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""Read a file and extract documentation data.""",
|
||||
epilog=
|
||||
""" Copyright 2021-2024 by Wilson Snyder. This package is free software;
|
||||
epilog=""" Copyright 2021-2024 by Wilson Snyder. This package is free software;
|
||||
you can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('path', help='path to extract from')
|
||||
Args = parser.parse_args()
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@ class VlSphinxFix:
|
|||
if os.path.isdir(path):
|
||||
for basefile in os.listdir(path):
|
||||
file = os.path.join(path, basefile)
|
||||
if ((basefile != ".") and (basefile != "..")
|
||||
and basefile not in self.SkipBasenames
|
||||
if ((basefile != ".") and (basefile != "..") and basefile not in self.SkipBasenames
|
||||
and not os.path.islink(file)):
|
||||
self.process(file)
|
||||
elif re.search(r'\.(html|tex)$', path):
|
||||
|
|
@ -54,18 +53,14 @@ parser = argparse.ArgumentParser(
|
|||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""Post-process Sphinx HTML.""",
|
||||
epilog=
|
||||
""" Copyright 2021-2024 by Wilson Snyder. This package is free software;
|
||||
epilog=""" Copyright 2021-2024 by Wilson Snyder. This package is free software;
|
||||
you can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('path', help='path to edit')
|
||||
Args = parser.parse_args()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
.. comment: generated by t_lint_multidriven_bad
|
||||
.. code-block::
|
||||
|
||||
%Warning-MULTIDRIVEN: example.v:1:22 Signal has multiple driving blocks with different clocking: 't.mem'
|
||||
%Warning-MULTIDRIVEN: example.v:1:22 Signal has multiple driving blocks with different clocking: 'out2'
|
||||
example.v:1:7 ... Location of first driving block
|
||||
example.v:1:7 ... Location of other driving block
|
||||
|
|
|
|||
|
|
@ -23,8 +23,7 @@ def get_vlt_version():
|
|||
filename = "../../Makefile"
|
||||
with open(filename, "r", encoding="utf8") as fh:
|
||||
for line in fh:
|
||||
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)",
|
||||
line)
|
||||
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)", line)
|
||||
if match:
|
||||
return match.group(1), match.group(2)
|
||||
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +devel", line)
|
||||
|
|
@ -75,8 +74,7 @@ extensions = []
|
|||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = [
|
||||
'_build', 'Thumbs.db', '.DS_Store', 'internals.rst', 'xml.rst', 'gen/ex_*',
|
||||
'CONTRIBUTING.rst'
|
||||
'_build', 'Thumbs.db', '.DS_Store', 'internals.rst', 'xml.rst', 'gen/ex_*', 'CONTRIBUTING.rst'
|
||||
]
|
||||
|
||||
# Warn about refs
|
||||
|
|
|
|||
|
|
@ -23,24 +23,24 @@ Next, try the :vlopt:`--debug` option. This will enable additional
|
|||
internal assertions, and may help identify the problem.
|
||||
|
||||
Finally, reduce your code to the smallest possible routine that exhibits
|
||||
the bug. Even better, create a test in the :file:`test_regress/t`
|
||||
directory, as follows:
|
||||
the bug (see: :ref:`Minimizing bug-inducing code`). Even better, create
|
||||
a test in the :file:`test_regress/t` directory, as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd test_regress
|
||||
cp -p t/t_EXAMPLE.pl t/t_BUG.pl
|
||||
cp -p t/t_EXAMPLE.py t/t_BUG.py
|
||||
cp -p t/t_EXAMPLE.v t/t_BUG.v
|
||||
|
||||
There are many hints on how to write a good test in the
|
||||
:file:`test_regress/driver.pl` documentation which can be seen by running:
|
||||
:file:`test_regress/driver.py` documentation which can be seen by running:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd $VERILATOR_ROOT # Need the original distribution kit
|
||||
test_regress/driver.pl --help
|
||||
test_regress/driver.py --help
|
||||
|
||||
Edit :file:`t/t_BUG.pl` to suit your example; you can do anything you want
|
||||
Edit :file:`t/t_BUG.py` to suit your example; you can do anything you want
|
||||
in the Verilog code there; just make sure it retains the single clk input
|
||||
and no outputs. Now, the following should fail:
|
||||
|
||||
|
|
@ -48,20 +48,38 @@ and no outputs. Now, the following should fail:
|
|||
|
||||
cd $VERILATOR_ROOT # Need the original distribution kit
|
||||
cd test_regress
|
||||
t/t_BUG.pl # Run on Verilator
|
||||
t/t_BUG.pl --debug # Run on Verilator, passing --debug to Verilator
|
||||
t/t_BUG.pl --vcs # Run on VCS simulator
|
||||
t/t_BUG.pl --nc|--iv|--ghdl # Likewise on other simulators
|
||||
t/t_BUG.py # Run on Verilator
|
||||
t/t_BUG.py --debug # Run on Verilator, passing --debug to Verilator
|
||||
t/t_BUG.py --vcs # Run on VCS simulator
|
||||
t/t_BUG.py --nc|--iv|--ghdl # Likewise on other simulators
|
||||
|
||||
The test driver accepts a number of options, many of which mirror the main
|
||||
Verilator options. For example the previous test could have been run with
|
||||
debugging enabled. The full set of test options can be seen by running
|
||||
:command:`driver.pl --help` as shown above.
|
||||
:command:`driver.py --help` as shown above.
|
||||
|
||||
Finally, report the bug at `Verilator Issues
|
||||
<https://verilator.org/issues>`_. The bug will become publicly visible; if
|
||||
this is unacceptable, mail the bug report to ``wsnyder@wsnyder.org``.
|
||||
|
||||
.. _Minimizing bug-inducing code:
|
||||
|
||||
Minimizing bug-inducing code
|
||||
============================
|
||||
|
||||
In some cases, the part of the code that causes the bug is clearly visible
|
||||
and the design can be easily manually reduced. In other cases, the bug is
|
||||
caused by a complex interaction of many parts of the design, and it is not
|
||||
clear which parts are necessary to reproduce the bug. In these cases, an
|
||||
Open Source tool called `sv-bugpoint
|
||||
<https://github.com/antmicro/sv-bugpoint>_` can be used to automatically
|
||||
reduce a SystemVerilog design to the smallest possible reproducer.
|
||||
It can be used to automatically reduce a design with hundreds of thousands of
|
||||
lines to a minimal test case while preserving the bug-inducing behavior.
|
||||
|
||||
Please refer to the `README
|
||||
<https://github.com/antmicro/sv-bugpoint/blob/main/README.md>`_ file for more
|
||||
information on how to use `sv-bugpoint`.
|
||||
|
||||
.. Contributing
|
||||
.. ============
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ C++14 compiler support
|
|||
Verilated models with --no-timing.
|
||||
|
||||
Verilator will require C++20 or newer compilers for both compiling
|
||||
Verilator and compiling all Verilated models no sooner than January 2025.
|
||||
Verilator and compiling all Verilated models no sooner than May 2025.
|
||||
|
||||
XML output
|
||||
Verilator currently supports XML parser output (enabled with `--xml-only`).
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ Now, let's create an example Verilog, and SystemC wrapper file:
|
|||
|
||||
cat >sc_main.cpp <<'EOF'
|
||||
#include "Vour.h"
|
||||
using namespace sc_core;
|
||||
int sc_main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
sc_clock clk{"clk", 10, SC_NS, 0.5, 3, SC_NS, true};
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ Summary:
|
|||
.. option:: +verilator+error+limit+<value>
|
||||
|
||||
Set number of non-fatal errors (e.g. assertion failures) before exiting
|
||||
simulation runtime. Also affects number of $stop calls needed before
|
||||
exit. Defaults to 1.
|
||||
simulation runtime. Also affects number of `$stop` calls needed before
|
||||
exit. Does not affect `$fatal`. Defaults to 1.
|
||||
|
||||
.. option:: +verilator+help
|
||||
|
||||
|
|
|
|||
|
|
@ -958,6 +958,22 @@ Summary:
|
|||
delayed assignments. This option should only be used when suggested by
|
||||
the developers.
|
||||
|
||||
.. option:: --output-groups <numfiles>
|
||||
|
||||
Enables concatenating the output .cpp files into the given number of
|
||||
effective output .cpp files. This is useful if the compiler startup
|
||||
overhead from compiling many small files becomes unacceptable,
|
||||
which can happen in designs making extensive use of SystemVerilog classes,
|
||||
templates or generate blocks.
|
||||
|
||||
Using :vlopt:`--output-groups` can adversely impact caching and stability
|
||||
(as in reproducibility) of compiled code. Compilation of larger .cpp
|
||||
files also has higher memory requirements. Too low values might result in
|
||||
swap thrashing with large designs, high values give no benefits. The
|
||||
value should range from 2 to 20 for small to medium designs.
|
||||
|
||||
Default is zero, which disables this feature.
|
||||
|
||||
.. option:: --output-split <statements>
|
||||
|
||||
Enables splitting the output .cpp files into multiple outputs. When a
|
||||
|
|
@ -1909,8 +1925,12 @@ Configuration Files
|
|||
|
||||
In addition to the command line, warnings and other features for the
|
||||
:command:`verilator` command may be controlled with configuration files,
|
||||
typically named with the .vlt extension (what makes it a configuration file
|
||||
is the :option:`\`verilator_config` directive). An example:
|
||||
typically named with the `.vlt` extension (what makes it a configuration
|
||||
file is the :option:`\`verilator_config` directive). These files, when
|
||||
named `.vlt`, are read before source code files; if this behavior is
|
||||
undesired, name the config file with a `.v` suffix.
|
||||
|
||||
An example:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
|
|
|
|||
|
|
@ -58,32 +58,36 @@ to read multiple inputs. If no data file is specified, by default,
|
|||
Specifies the directory name to which source files with annotated coverage
|
||||
data should be written.
|
||||
|
||||
Converting from the Verilator coverage data format to the info format is
|
||||
lossy; the info will have all forms of coverage merged line coverage, and
|
||||
if there are multiple coverage points on a single line they will merge.
|
||||
The minimum coverage across all merged points will be used to report
|
||||
coverage of the line.
|
||||
Points are children of each line coverage- branches or toggle points.
|
||||
When point counts are aggregated into a line, the minimum and maximum counts
|
||||
are used to determine the status of the line (complete, partial, failing)
|
||||
The count is equal to the maximum of the points.
|
||||
|
||||
Coverage data is annotated at the beginning of the line and is formatted
|
||||
as a special character followed by the number of coverage hits. The special
|
||||
characters " ,%,+,-" indicate summary of the coverage, and allow use of grep
|
||||
characters " ,%,~,+,-" indicate summary of the coverage, and allow use of grep
|
||||
to filter the report.
|
||||
|
||||
* " " (whitespace) indicates that all points on the line are above the coverage limit.
|
||||
* "%" indicates at least one point on the line was below the coverage limit.
|
||||
* "+" coverage point was at or above the limit. Only used with :option:`--annotate-points`.
|
||||
* "-" coverage point was below the limit. Only used with :option:`--annotate-points`.
|
||||
* " " (whitespace) indicates that all points on the line are above the coverage min.
|
||||
* "%" indicates that all points on the line are below the coverage min.
|
||||
* "~" indicates that some points on the line are above the coverage min and some are below.
|
||||
* "+" coverage point was at or above the min. Only used with :option:`--annotate-points`.
|
||||
* "-" coverage point was below the min. Only used with :option:`--annotate-points`.
|
||||
|
||||
.. code-block::
|
||||
|
||||
100000 input logic a; // Begins with whitespace, because
|
||||
// number of hits (100000) is above the limit.
|
||||
+100000 point: comment=a // Begins with +, because
|
||||
// number of hits (100000) is above the limit.
|
||||
%000000 input logic b; // Begins with %, because
|
||||
// number of hits (0) is below the limit.
|
||||
-000000 point: comment=b // Begins with -, because
|
||||
// number of hits (0) is below the limit.
|
||||
100000 input logic a; // Begins with whitespace, because
|
||||
// number of hits (100000) is above the min.
|
||||
+100000 point: comment=a // Begins with +, because
|
||||
// number of hits (100000) is above the min.
|
||||
%000000 input logic b; // Begins with %, because
|
||||
// number of hits (0) is below the min.
|
||||
-000000 point: comment=b // Begins with -, because
|
||||
// number of hits (0) is below the min.
|
||||
~000010 if (cyc!=0) begin // Begins with ~, because
|
||||
// branches are below and above the min.
|
||||
+000010 point: comment=if // The if branch is above the min.
|
||||
-000000 point: comment=else // The else branch is below the min.
|
||||
|
||||
.. option:: --annotate-all
|
||||
|
||||
|
|
@ -154,10 +158,7 @@ generated from random test runs) into one master coverage file.
|
|||
Specifies the aggregate coverage results, summed across all the files,
|
||||
should be written to the given filename in :command:`lcov` .info format.
|
||||
This may be used to feed into :command:`lcov` to aggregate or generate
|
||||
reports.
|
||||
|
||||
Converting from the Verilator coverage data format to the info format is
|
||||
lossy; the info will have all forms of coverage merged line coverage, and
|
||||
if there are multiple coverage points on a single line they will merge.
|
||||
The minimum coverage across all merged points will be used to report
|
||||
coverage of the line.
|
||||
reports. This format lacks the comments for cover points that the
|
||||
verilator_coverage format has. It can be used with :command:`genhtml`
|
||||
to generate an HTML report. :command:`genhtml --branch-coverage` will
|
||||
also display the branch coverage, analogous to :option:`--annotate-points`
|
||||
|
|
|
|||
|
|
@ -19,13 +19,33 @@ started. (Note packages are unlikely to have the most recent version, so
|
|||
:ref:`Git Install` might be a better alternative.) To install as a
|
||||
package:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
apt-get install verilator # On Ubuntu
|
||||
|
||||
For other distributions, refer to `Repology Verilator Distro Packages
|
||||
<https://repology.org/project/verilator>`__.
|
||||
|
||||
.. _pre-commit Quick Install:
|
||||
|
||||
pre-commit Quick Install
|
||||
=============================
|
||||
|
||||
You can use Verilator's `pre-commit <https://pre-commit.com/>`__ hook to
|
||||
lint your code before committing it. It encapsulates the :ref:`Verilator
|
||||
Build Docker Container`, so you need docker on your system to use it. The
|
||||
verilator image will be downloaded automatically.
|
||||
|
||||
To use the hook, add the following entry to your :code:`.pre-commit-config.yaml`:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/verilator/verilator
|
||||
rev: v5.026 # or later
|
||||
hooks:
|
||||
- id: verilator
|
||||
|
||||
.. _Git Install:
|
||||
|
||||
Git Quick Install
|
||||
|
|
@ -36,7 +56,7 @@ options and details, see :ref:`Detailed Build Instructions` below.
|
|||
|
||||
In brief, to install from git:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
# Prerequisites:
|
||||
#sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache
|
||||
|
|
@ -89,7 +109,7 @@ Install Prerequisites
|
|||
|
||||
To build or run Verilator, you need these standard packages:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install git help2man perl python3 make
|
||||
sudo apt-get install g++ # Alternatively, clang
|
||||
|
|
@ -101,7 +121,7 @@ To build or run Verilator, you need these standard packages:
|
|||
To build or run Verilator, the following are optional but should be installed
|
||||
for good performance:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install ccache # If present at build, needed for run
|
||||
sudo apt-get install mold # If present at build, needed for run
|
||||
|
|
@ -110,27 +130,26 @@ for good performance:
|
|||
The following is optional but is recommended for nicely rendered command line
|
||||
help when running Verilator:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install perl-doc
|
||||
|
||||
To build Verilator you will need to install these packages; these do not
|
||||
need to be present to run Verilator:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install git autoconf flex bison
|
||||
|
||||
Those developing Verilator itself may also want these (see internals.rst):
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install clang clang-format-14 cmake gdb gprof graphviz lcov
|
||||
sudo apt-get install python3-clang yapf3 bear jq
|
||||
sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
|
||||
sudo pip3 install git+https://github.com/antmicro/astsee.git
|
||||
cpan install Pod::Perldoc
|
||||
cpan install Parallel::Forker
|
||||
|
||||
|
||||
Install SystemC
|
||||
|
|
@ -171,14 +190,14 @@ Obtain Sources
|
|||
Get the sources from the git repository: (You need to do this only once,
|
||||
ever.)
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
git clone https://github.com/verilator/verilator # Only first time
|
||||
## Note the URL above is not a page you can see with a browser; it's for git only
|
||||
|
||||
Enter the checkout and determine what version/branch to use:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
cd verilator
|
||||
git pull # Make sure we're up-to-date
|
||||
|
|
@ -193,7 +212,7 @@ Auto Configure
|
|||
|
||||
Create the configuration script:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
autoconf # Create ./configure script
|
||||
|
||||
|
|
@ -219,7 +238,7 @@ directory (don't run ``make install``). This allows the easiest
|
|||
experimentation and upgrading, and allows many versions of Verilator to
|
||||
co-exist on a system.
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
export VERILATOR_ROOT=`pwd` # if your shell is bash
|
||||
setenv VERILATOR_ROOT `pwd` # if your shell is csh
|
||||
|
|
@ -241,7 +260,7 @@ that may support multiple versions of every tool. Tell configure the
|
|||
eventual destination directory name. We recommend that the destination
|
||||
location include the Verilator version name:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
unset VERILATOR_ROOT # if your shell is bash
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
|
|
@ -253,7 +272,7 @@ the ``bin`` directory to your ``PATH``. Or, if you use `modulecmd
|
|||
<http://modules.sourceforge.net/>`__, you'll want a module file like the
|
||||
following:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
set install_root /CAD_DISK/verilator/{version-number-used-above}
|
||||
unsetenv VERILATOR_ROOT
|
||||
|
|
@ -268,7 +287,7 @@ following:
|
|||
The final option is to eventually install Verilator globally, using
|
||||
configure's default system paths:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
unset VERILATOR_ROOT # if your shell is bash
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
|
|
@ -285,7 +304,7 @@ The command to configure the package was described in the previous step.
|
|||
Developers should configure to have more complete developer tests.
|
||||
Additional packages may be required for these tests.
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
export VERILATOR_AUTHOR_SITE=1 # Put in your .bashrc
|
||||
./configure --enable-longtests ...above options...
|
||||
|
|
@ -296,7 +315,7 @@ Compile
|
|||
|
||||
Compile Verilator:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
make -j `nproc` # Or if error on `nproc`, the number of CPUs in system
|
||||
|
||||
|
|
@ -306,7 +325,7 @@ Test
|
|||
|
||||
Check the compilation by running self-tests:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
make test
|
||||
|
||||
|
|
@ -318,7 +337,7 @@ If you used any install option other than the `1. Run-in-Place from
|
|||
VERILATOR_ROOT <#_1_run_in_place_from_verilator_root>`__ scheme, install
|
||||
the files:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
make install
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ Simulation Summary Report
|
|||
=========================
|
||||
|
||||
When simulation finishes, it will print a report to stdout summarizing the
|
||||
simulation. This requires the model being Verilated with :vlopt:`--main`.
|
||||
simulation. This requires the model being Verilated with :vlopt:`--main`,
|
||||
or the user's `main()` calling `VerilatedContext->statsPrintSummary()`.
|
||||
|
||||
The report may be disabled with :vlopt:`+verilator+quiet`.
|
||||
|
||||
For example:
|
||||
|
|
|
|||
|
|
@ -1472,9 +1472,6 @@ For all tests to pass, you must install the following packages:
|
|||
|
||||
- SystemC to compile the SystemC outputs, see http://systemc.org
|
||||
|
||||
- Parallel::Forker from CPAN to run tests in parallel; you can install
|
||||
this with e.g. "sudo cpan install Parallel::Forker".
|
||||
|
||||
- vcddiff to find differences in VCD outputs. See the readme at
|
||||
https://github.com/veripool/vcddiff
|
||||
|
||||
|
|
@ -1484,7 +1481,7 @@ For all tests to pass, you must install the following packages:
|
|||
Controlling the Test Driver
|
||||
---------------------------
|
||||
|
||||
The test driver script `driver.pl` runs tests; see the `Test Driver`
|
||||
The test driver script `driver.py` runs tests; see the `Test Driver`
|
||||
section. The individual test drivers are written in Perl; see `Test
|
||||
Language`.
|
||||
|
||||
|
|
@ -1497,7 +1494,7 @@ A specific regression test can be executed manually. To start the
|
|||
|
||||
::
|
||||
|
||||
test_regress/t/t_EXAMPLE.pl
|
||||
test_regress/t/t_EXAMPLE.py
|
||||
|
||||
|
||||
Regression Testing for Developers
|
||||
|
|
@ -1517,13 +1514,6 @@ Developers will also want to call ./configure with two extra flags:
|
|||
disabled by default, as SystemC installation problems would otherwise
|
||||
falsely indicate a Verilator problem.
|
||||
|
||||
When enabling the long tests, some additional Perl modules are needed,
|
||||
which you can install using cpan.
|
||||
|
||||
::
|
||||
|
||||
cpan install Parallel::Forker
|
||||
|
||||
There are some traps to avoid when running regression tests
|
||||
|
||||
- When checking the MANIFEST, the test will fail on unexpected code in the
|
||||
|
|
@ -1871,7 +1861,7 @@ represent the pointers (``op1p``, ``op2p``, etc) between the nodes.
|
|||
Debugging with GDB
|
||||
------------------
|
||||
|
||||
The `driver.pl` script accepts ``--debug --gdb`` to start
|
||||
The `driver.py` script accepts ``--debug --gdb`` to start
|
||||
Verilator under gdb and break when an error is hit, or the program is about
|
||||
to exit. You can also use ``--debug --gdbbt`` to just backtrace and then
|
||||
exit gdb. To debug the Verilated executable, use ``--gdbsim``.
|
||||
|
|
@ -1882,7 +1872,7 @@ can use ``--debug`` and look at the underlying invocation of
|
|||
|
||||
::
|
||||
|
||||
t/t_alw_dly.pl --debug
|
||||
t/t_alw_dly.py --debug
|
||||
|
||||
shows it invokes the command:
|
||||
|
||||
|
|
@ -1979,7 +1969,7 @@ Generally, what would you do to add a new feature?
|
|||
Follow the convention described above about the AstNode type hierarchy.
|
||||
Ordering of definitions is enforced by ``astgen``.
|
||||
|
||||
5. Now you can run ``test_regress/t/t_<newtestcase>.pl --debug`` and it'll
|
||||
5. Now you can run ``test_regress/t/t_<newtestcase>.py --debug`` and it'll
|
||||
probably fail, but you'll see a
|
||||
``test_regress/obj_dir/t_<newtestcase>/*.tree`` file which you can examine
|
||||
to see if the parsing worked. See also the sections above on debugging.
|
||||
|
|
@ -2028,7 +2018,7 @@ IEEE 1800-2023 33 Config
|
|||
Test Driver
|
||||
===========
|
||||
|
||||
This section documents the test driver script, `driver.pl`. driver.pl
|
||||
This section documents the test driver script, `driver.py`. driver.py
|
||||
invokes Verilator or another simulator on each test file. For test file
|
||||
contents description see `Test Language`.
|
||||
|
||||
|
|
@ -2040,7 +2030,7 @@ the regression tests with OBJCACHE enabled and in parallel on a machine
|
|||
with many cores. See the -j option and OBJCACHE environment variable.
|
||||
|
||||
|
||||
driver.pl Non-Scenario Arguments
|
||||
driver.py Non-Scenario Arguments
|
||||
--------------------------------
|
||||
|
||||
--benchmark [<cycles>]
|
||||
|
|
@ -2110,13 +2100,13 @@ driver.pl Non-Scenario Arguments
|
|||
memory leaks.
|
||||
|
||||
--site
|
||||
Run site specific tests also.
|
||||
Run site-specific tests also.
|
||||
|
||||
--stop
|
||||
Stop on the first error.
|
||||
|
||||
--trace
|
||||
Set the simulator specific flags to request waveform tracing.
|
||||
Set the simulator-specific flags to request waveform tracing.
|
||||
|
||||
--valgrind
|
||||
Same as ``verilator --valgrind``: Run Verilator under `Valgrind <https://valgrind.org/>`_.
|
||||
|
|
@ -2129,7 +2119,7 @@ driver.pl Non-Scenario Arguments
|
|||
For tests using the standard C++ wrapper, enable runtime debug mode.
|
||||
|
||||
|
||||
driver.pl Scenario Arguments
|
||||
driver.py Scenario Arguments
|
||||
----------------------------
|
||||
|
||||
The following options control which simulator is used, and which tests are
|
||||
|
|
@ -2171,7 +2161,7 @@ simultaneously.
|
|||
Run Xilinx XSim simulator tests.
|
||||
|
||||
|
||||
driver.pl Environment
|
||||
driver.py Environment
|
||||
---------------------
|
||||
|
||||
HARNESS_UPDATE_GOLDEN
|
||||
|
|
@ -2231,30 +2221,30 @@ VERILATOR_XVLOG
|
|||
Test Language
|
||||
=============
|
||||
|
||||
This section describes the format of the ``test_regress/t/*.pl`` test
|
||||
language files, executed by `driver.pl`.
|
||||
This section describes the format of the ``test_regress/t/*.py`` test
|
||||
language files, executed by `driver.py`.
|
||||
|
||||
Test Language Summary
|
||||
---------------------
|
||||
|
||||
For convenience, a summary of the most commonly used features is provided
|
||||
here, with a reference in a later section. All test files typically have a
|
||||
call to the ``lint`` or ``compile`` subroutine to compile the test. For
|
||||
run-time tests, this is followed by a call to the ``execute``
|
||||
subroutine. Both of these functions can optionally be provided with
|
||||
arguments specifying additional options.
|
||||
call to the ``test.lint`` or ``test.compile`` methods to compile the
|
||||
test. For run-time tests, this is followed by a call to the
|
||||
``test.execute`` method. Both of these functions can optionally be provided
|
||||
with arguments specifying additional options.
|
||||
|
||||
If those complete, the script calls ``ok`` to increment the count of
|
||||
successful tests and then returns 1 as its result.
|
||||
If those complete, the script calls ``test.passes`` to increment the count
|
||||
of successful tests.
|
||||
|
||||
The driver.pl script assumes by default that the source Verilog file name
|
||||
The driver.py script assumes by default that the source Verilog file name
|
||||
matches the test script name. So a test whose driver is
|
||||
``t/t_mytest.pl`` will expect a Verilog source file ``t/t_mytest.v``.
|
||||
``t/t_mytest.py`` will expect a Verilog source file ``t/t_mytest.v``.
|
||||
This can be changed using the ``top_filename`` subroutine, for example
|
||||
|
||||
::
|
||||
|
||||
top_filename("t/t_myothertest.v");
|
||||
test.top_filename = "t/t_myothertest.v"
|
||||
|
||||
By default, all tests will run with major simulators (Icarus Verilog, NC,
|
||||
VCS, ModelSim, etc.) as well as Verilator, to allow results to be
|
||||
|
|
@ -2263,26 +2253,25 @@ can use the following:
|
|||
|
||||
::
|
||||
|
||||
scenarios(vlt => 1);
|
||||
test.scenarios('vlt')
|
||||
|
||||
Of the many options that can be set through arguments to ``compiler`` and
|
||||
``execute``, the following are particularly useful:
|
||||
Of the many options that can be set through arguments to ``test.compiler``
|
||||
and ``test.execute``, the following are particularly useful:
|
||||
|
||||
``verilator_flags2``
|
||||
A list of flags to be passed to verilator when compiling.
|
||||
|
||||
``fails``
|
||||
Set to 1 to indicate that the compilation or execution is intended to fail.
|
||||
Set true to indicate that the compilation or execution is intended to fail.
|
||||
|
||||
For example, the following would specify that compilation requires two
|
||||
defines and is expected to fail.
|
||||
|
||||
::
|
||||
|
||||
compile(
|
||||
test.compile(
|
||||
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
|
||||
fails => 1,
|
||||
);
|
||||
fails = True)
|
||||
|
||||
Hints On Writing Tests
|
||||
----------------------
|
||||
|
|
@ -2295,10 +2284,10 @@ same name as the test, but with .cpp as suffix
|
|||
|
||||
::
|
||||
|
||||
compile(
|
||||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"], );
|
||||
test.compile(
|
||||
make_top_shell=False,
|
||||
make_main=False,
|
||||
verilator_flags2=["--exe", test.t_dir + "/" + test.name + ".cpp"])
|
||||
|
||||
Tests should be self-checking, rather than producing lots of output. If a
|
||||
test succeeds it should print ``*-* All Finished *-*`` to standard output
|
||||
|
|
@ -2338,9 +2327,8 @@ compile time, it is the only option. For example:
|
|||
::
|
||||
|
||||
compile(
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
fails=True,
|
||||
expect_filename=test.golden_filename)
|
||||
|
||||
Note ``expect_filename`` strips some debugging information from the logfile
|
||||
when comparing.
|
||||
|
|
@ -2349,9 +2337,9 @@ when comparing.
|
|||
Test Language Compile/Lint/Run Arguments
|
||||
----------------------------------------
|
||||
|
||||
This section describes common arguments to ``compile()``, ``lint()``, and
|
||||
``run()``. The full list of arguments can be found by looking at the
|
||||
``driver.pl`` source code.
|
||||
This section describes common arguments to ``test.compile``, ``test.lint``,
|
||||
and ``test.run``. The full list of arguments can be found by looking at
|
||||
the ``driver.py`` source code.
|
||||
|
||||
all_run_flags
|
||||
A list of flags to be passed when running the simulator (Verilated model
|
||||
|
|
@ -2362,11 +2350,6 @@ check_finished
|
|||
string ``*-* All Finished *-*`` being printed on standard output. This is
|
||||
the normal way for successful tests to finish.
|
||||
|
||||
expect
|
||||
A quoted list of strings or regular expression to be matched in the
|
||||
output. See `Hints On Writing Tests` for more detail on how this argument
|
||||
should be used.
|
||||
|
||||
fails
|
||||
True to indicate this step is expected to fail. Tests that are expected
|
||||
to fail generally have _bad in their filename.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ Ashutosh
|
|||
Ast
|
||||
Atmel
|
||||
Aurelien
|
||||
Badáň
|
||||
Bagri
|
||||
Balboni
|
||||
Baltazar
|
||||
|
|
@ -74,6 +75,7 @@ Deepa
|
|||
Defparams
|
||||
Delm
|
||||
Denio
|
||||
Deniz
|
||||
Deprecations
|
||||
Deroo
|
||||
Desai
|
||||
|
|
@ -109,8 +111,10 @@ Eugen
|
|||
Fabrizio
|
||||
Faucher
|
||||
Faure
|
||||
Feinberg
|
||||
Fekete
|
||||
Ferrandi
|
||||
Filip
|
||||
Flachs
|
||||
Flavien
|
||||
Florian
|
||||
|
|
@ -149,6 +153,7 @@ Grulfen
|
|||
Gu
|
||||
Gunter
|
||||
Guo
|
||||
Güzel
|
||||
Hameed
|
||||
Hao
|
||||
Haojin
|
||||
|
|
@ -243,6 +248,7 @@ Liwei
|
|||
Lockhart
|
||||
Longo
|
||||
Luca
|
||||
Luiza
|
||||
Lussier
|
||||
Lübeck
|
||||
MMD
|
||||
|
|
@ -273,6 +279,8 @@ MinW
|
|||
Mindspeed
|
||||
MingW
|
||||
Miodrag
|
||||
Moberg
|
||||
Mobert
|
||||
ModelSim
|
||||
Modport
|
||||
Moinak
|
||||
|
|
@ -354,6 +362,7 @@ Sasselli
|
|||
Scharrer
|
||||
Seitz
|
||||
Shahid
|
||||
Shahrestani
|
||||
Shankar
|
||||
Shanshan
|
||||
Sharad
|
||||
|
|
@ -364,6 +373,7 @@ Shi
|
|||
Shinkarovsky
|
||||
Shinya
|
||||
Shirakawa
|
||||
Shou
|
||||
Shuba
|
||||
Shunyao
|
||||
Slager
|
||||
|
|
@ -375,6 +385,7 @@ Solaris
|
|||
Solomatnikov
|
||||
Solt
|
||||
Southwell
|
||||
Spack
|
||||
Srini
|
||||
Srinivasan
|
||||
Stamness
|
||||
|
|
@ -516,6 +527,7 @@ basename
|
|||
bbox
|
||||
benchmarking
|
||||
biguint
|
||||
bindir
|
||||
biops
|
||||
bisonpre
|
||||
bitOpTree
|
||||
|
|
@ -585,6 +597,7 @@ datadir
|
|||
datafiles
|
||||
david
|
||||
ddd
|
||||
de
|
||||
deassign
|
||||
debugi
|
||||
defenv
|
||||
|
|
@ -865,6 +878,7 @@ phelter
|
|||
picoChip
|
||||
pinIndex
|
||||
pinout
|
||||
pkgdatadir
|
||||
plusargs
|
||||
pmos
|
||||
poping
|
||||
|
|
@ -929,6 +943,7 @@ redeclaring
|
|||
regs
|
||||
reloop
|
||||
replaceShiftOp
|
||||
reproducibility
|
||||
resetall
|
||||
respecified
|
||||
rodata
|
||||
|
|
@ -1018,6 +1033,8 @@ traceEverOn
|
|||
tran
|
||||
treei
|
||||
tri
|
||||
triand
|
||||
trior
|
||||
tristate
|
||||
tristates
|
||||
trunc
|
||||
|
|
@ -1093,6 +1110,7 @@ warmup
|
|||
waveforms
|
||||
whitespace
|
||||
widthed
|
||||
wor
|
||||
wreal
|
||||
writeb
|
||||
writeme
|
||||
|
|
@ -1112,4 +1130,3 @@ zdave
|
|||
Øyvind
|
||||
Алексеевич
|
||||
Исаак
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,11 @@ cmake_policy(SET CMP0074 NEW)
|
|||
project(cmake_hello_c)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
if (NOT verilator_FOUND)
|
||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
||||
if(NOT verilator_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Create a new executable target that will contain all your sources
|
||||
|
|
@ -35,4 +38,5 @@ target_compile_features(example PUBLIC cxx_std_14)
|
|||
# Add the Verilated circuit to the target
|
||||
verilate(example
|
||||
INCLUDE_DIRS "../make_hello_c"
|
||||
SOURCES ../make_hello_c/top.v)
|
||||
SOURCES ../make_hello_c/top.v
|
||||
)
|
||||
|
|
|
|||
|
|
@ -24,8 +24,11 @@ cmake_policy(SET CMP0074 NEW)
|
|||
project(cmake_hello_sc CXX)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
if (NOT verilator_FOUND)
|
||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
||||
if(NOT verilator_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||
)
|
||||
endif()
|
||||
|
||||
# SystemC dependencies
|
||||
|
|
@ -39,14 +42,12 @@ find_package(SystemCLanguage QUIET)
|
|||
add_executable(example ../make_hello_sc/sc_main.cpp)
|
||||
target_compile_features(example PUBLIC cxx_std_14)
|
||||
|
||||
set_property(
|
||||
TARGET example
|
||||
PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD}
|
||||
)
|
||||
set_property(TARGET example PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD})
|
||||
|
||||
# Add the Verilated circuit to the target
|
||||
verilate(example SYSTEMC
|
||||
INCLUDE_DIRS "../make_hello_sc"
|
||||
SOURCES ../make_hello_sc/top.v)
|
||||
SOURCES ../make_hello_sc/top.v
|
||||
)
|
||||
|
||||
verilator_link_systemc(example)
|
||||
|
|
|
|||
|
|
@ -24,8 +24,11 @@ cmake_policy(SET CMP0074 NEW)
|
|||
project(cmake_protect_lib)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
if (NOT verilator_FOUND)
|
||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
||||
if(NOT verilator_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Create the main executable target
|
||||
|
|
@ -55,9 +58,11 @@ verilate(verilated_secret
|
|||
VERILATOR_ARGS --protect-lib verilated_secret
|
||||
--protect-key ${PROTECT_KEY}
|
||||
DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/verilated_secret
|
||||
SOURCES ../make_protect_lib/secret_impl.v)
|
||||
SOURCES ../make_protect_lib/secret_impl.v
|
||||
)
|
||||
|
||||
# Include location of verilated_secret.sv wrapper
|
||||
verilate(example
|
||||
VERILATOR_ARGS "-I${CMAKE_CURRENT_BINARY_DIR}/verilated_secret"
|
||||
SOURCES ../make_protect_lib/top.v)
|
||||
SOURCES ../make_protect_lib/top.v
|
||||
)
|
||||
|
|
|
|||
|
|
@ -24,8 +24,11 @@ cmake_policy(SET CMP0074 NEW)
|
|||
project(cmake_tracing_c)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
if (NOT verilator_FOUND)
|
||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
||||
if(NOT verilator_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Create a new executable target that will contain all your sources
|
||||
|
|
@ -36,4 +39,5 @@ target_compile_features(example PUBLIC cxx_std_14)
|
|||
verilate(example COVERAGE TRACE
|
||||
INCLUDE_DIRS "../make_tracing_c"
|
||||
VERILATOR_ARGS -f ../make_tracing_c/input.vc -x-assign fast
|
||||
SOURCES ../make_tracing_c/top.v)
|
||||
SOURCES ../make_tracing_c/top.v
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,8 +25,11 @@ cmake_policy(SET CMP0074 NEW)
|
|||
project(cmake_tracing_sc_example CXX)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
if (NOT verilator_FOUND)
|
||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
||||
if(NOT verilator_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||
)
|
||||
endif()
|
||||
|
||||
# SystemC dependencies
|
||||
|
|
@ -40,15 +43,13 @@ find_package(SystemCLanguage QUIET)
|
|||
add_executable(example ../make_tracing_sc/sc_main.cpp)
|
||||
target_compile_features(example PUBLIC cxx_std_14)
|
||||
|
||||
set_property(
|
||||
TARGET example
|
||||
PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD}
|
||||
)
|
||||
set_property(TARGET example PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD})
|
||||
|
||||
# Add the Verilated circuit to the target
|
||||
verilate(example SYSTEMC COVERAGE TRACE
|
||||
INCLUDE_DIRS "../make_tracing_sc"
|
||||
VERILATOR_ARGS -f ../make_tracing_sc/input.vc -x-assign fast
|
||||
SOURCES ../make_tracing_sc/top.v)
|
||||
SOURCES ../make_tracing_sc/top.v
|
||||
)
|
||||
|
||||
verilator_link_systemc(example)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@ module sub
|
|||
);
|
||||
|
||||
// Some simple logic
|
||||
always_comb out = ~ in;
|
||||
always_comb out = ~in;
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@ class VlFileCopy:
|
|||
|
||||
self.debug = debug
|
||||
|
||||
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile(
|
||||
) as meta_temp:
|
||||
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile() as meta_temp:
|
||||
vargs = [
|
||||
'--json-only-output',
|
||||
tree_temp.name,
|
||||
|
|
@ -61,8 +60,7 @@ class VlFileCopy:
|
|||
print("\t%s " % command)
|
||||
status = subprocess.call(command, shell=True)
|
||||
if status != 0:
|
||||
raise RuntimeError("Command failed running Verilator with '" +
|
||||
command + "', stopped")
|
||||
raise RuntimeError("Command failed running Verilator with '" + command + "', stopped")
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
|
@ -71,8 +69,7 @@ if __name__ == '__main__':
|
|||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
description=
|
||||
"""Example of using Verilator JSON output to copy a list of files to an
|
||||
description="""Example of using Verilator JSON output to copy a list of files to an
|
||||
output directory (-odir, defaults to 'copied'), e.g. to easily create a
|
||||
tarball of the design to pass to others.
|
||||
|
||||
|
|
@ -95,11 +92,7 @@ This file ONLY is placed under the Creative Commons Public Domain, for
|
|||
any use, without warranty, 2019 by Wilson Snyder.
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
""")
|
||||
parser.add_argument('-debug',
|
||||
'--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('-debug', '--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('-odir',
|
||||
'--odir',
|
||||
action='store',
|
||||
|
|
@ -108,9 +101,7 @@ SPDX-License-Identifier: CC0-1.0
|
|||
help='target output directory')
|
||||
(args, rem) = parser.parse_known_args()
|
||||
|
||||
print(
|
||||
"NOTE: vl_file_copy is only an example starting point for writing your own tool."
|
||||
)
|
||||
print("NOTE: vl_file_copy is only an example starting point for writing your own tool.")
|
||||
# That is:
|
||||
# 1. We will accept basic patches
|
||||
# 2. We are not expecting to make this globally useful. (e.g. we don't cleanup obj_dir)
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ class VlHierGraph:
|
|||
self.next_vertex_number = 0
|
||||
self.addr_to_number = {}
|
||||
|
||||
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile(
|
||||
) as meta_temp:
|
||||
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile() as meta_temp:
|
||||
vargs = [
|
||||
'--json-only-output',
|
||||
tree_temp.name,
|
||||
|
|
@ -45,9 +44,7 @@ class VlHierGraph:
|
|||
fh.write("digraph {\n")
|
||||
fh.write(" dpi=300;\n")
|
||||
fh.write(" order=LR;\n")
|
||||
fh.write(
|
||||
" node [fontsize=8 shape=\"box\" margin=0.01 width=0 height=0]"
|
||||
)
|
||||
fh.write(" node [fontsize=8 shape=\"box\" margin=0.01 width=0 height=0]")
|
||||
fh.write(" edge [fontsize=6]")
|
||||
# Find cells
|
||||
modules = self.flatten(self.tree, lambda n: n['type'] == "MODULE")
|
||||
|
|
@ -101,8 +98,7 @@ class VlHierGraph:
|
|||
print("\t%s " % command)
|
||||
status = subprocess.call(command, shell=True)
|
||||
if status != 0:
|
||||
raise RuntimeError("Command failed running Verilator with '" +
|
||||
command + "', stopped")
|
||||
raise RuntimeError("Command failed running Verilator with '" + command + "', stopped")
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
|
@ -111,8 +107,7 @@ if __name__ == '__main__':
|
|||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
description=
|
||||
"""Example of using Verilator JSON output to create a .dot file showing the
|
||||
description="""Example of using Verilator JSON output to create a .dot file showing the
|
||||
design module hierarchy.
|
||||
|
||||
Example usage:
|
||||
|
|
@ -134,11 +129,7 @@ This file ONLY is placed under the Creative Commons Public Domain, for
|
|||
any use, without warranty, 2019 by Wilson Snyder.
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
""")
|
||||
parser.add_argument('-debug',
|
||||
'--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('-debug', '--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('-o',
|
||||
'--o',
|
||||
action='store',
|
||||
|
|
@ -147,18 +138,14 @@ SPDX-License-Identifier: CC0-1.0
|
|||
help='output filename')
|
||||
(args, rem) = parser.parse_known_args()
|
||||
|
||||
print(
|
||||
"NOTE: vl_hier_graph is only an example starting point for writing your own tool."
|
||||
)
|
||||
print("NOTE: vl_hier_graph is only an example starting point for writing your own tool.")
|
||||
# That is:
|
||||
# 1. We will accept basic patches
|
||||
# 2. We are not expecting to make this globally useful. (e.g. we don't cleanup obj_dir)
|
||||
# 3. "make install" will not install this.
|
||||
# 4. This has not had production-worthy validation.
|
||||
|
||||
fc = VlHierGraph(output_filename=args.o,
|
||||
debug=args.debug,
|
||||
verilator_args=rem)
|
||||
fc = VlHierGraph(output_filename=args.o, debug=args.debug, verilator_args=rem)
|
||||
|
||||
######################################################################
|
||||
# Local Variables:
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module sub
|
|||
|
||||
// Example counter/flop
|
||||
reg [31:0] count_c;
|
||||
always_ff @ (posedge clk) begin
|
||||
always_ff @(posedge clk) begin
|
||||
if (!reset_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
|
|
@ -32,11 +32,11 @@ module sub
|
|||
end
|
||||
|
||||
// An example assertion
|
||||
always_ff @ (posedge clk) begin
|
||||
AssertionExample: assert (!reset_l || count_c<100);
|
||||
always_ff @(posedge clk) begin
|
||||
AssertionExample : assert (!reset_l || count_c < 100);
|
||||
end
|
||||
|
||||
// And example coverage analysis
|
||||
cover property (@(posedge clk) count_c==3);
|
||||
cover property (@(posedge clk) count_c == 3);
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ module sub
|
|||
|
||||
// Example counter/flop
|
||||
reg [31:0] count_f;
|
||||
always_ff @ (posedge fastclk) begin
|
||||
always_ff @(posedge fastclk) begin
|
||||
if (!reset_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
|
|
@ -28,7 +28,7 @@ module sub
|
|||
|
||||
// Another example flop
|
||||
reg [31:0] count_c;
|
||||
always_ff @ (posedge clk) begin
|
||||
always_ff @(posedge clk) begin
|
||||
if (!reset_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
|
|
@ -38,8 +38,7 @@ module sub
|
|||
else begin
|
||||
count_c <= count_c + 1;
|
||||
if (count_c >= 3) begin
|
||||
$display("[%0t] fastclk is %0d times faster than clk\n",
|
||||
$time, count_f/count_c);
|
||||
$display("[%0t] fastclk is %0d times faster than clk\n", $time, count_f / count_c);
|
||||
// This write is a magic value the Makefile uses to make sure the
|
||||
// test completes successfully.
|
||||
$write("*-* All Finished *-*\n");
|
||||
|
|
@ -49,11 +48,11 @@ module sub
|
|||
end
|
||||
|
||||
// An example assertion
|
||||
always_ff @ (posedge clk) begin
|
||||
AssertionExample: assert(!reset_l || count_c<100);
|
||||
always_ff @(posedge clk) begin
|
||||
AssertionExample : assert (!reset_l || count_c < 100);
|
||||
end
|
||||
|
||||
// And example coverage analysis
|
||||
cover property (@(posedge clk) count_c==3);
|
||||
cover property (@(posedge clk) count_c == 3);
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -550,8 +550,9 @@ return(rc);
|
|||
|
||||
static uint32_t fstReaderVarint32(FILE *f)
|
||||
{
|
||||
int chk_len = 5; /* TALOS-2023-1783 */
|
||||
unsigned char buf[chk_len];
|
||||
const int chk_len_max = 5; /* TALOS-2023-1783 */
|
||||
int chk_len = chk_len_max;
|
||||
unsigned char buf[chk_len_max];
|
||||
unsigned char *mem = buf;
|
||||
uint32_t rc = 0;
|
||||
int ch;
|
||||
|
|
@ -582,8 +583,9 @@ return(rc);
|
|||
|
||||
static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen)
|
||||
{
|
||||
int chk_len = 5; /* TALOS-2023-1783 */
|
||||
unsigned char buf[chk_len];
|
||||
const int chk_len_max = 5; /* TALOS-2023-1783 */
|
||||
int chk_len = chk_len_max;
|
||||
unsigned char buf[chk_len_max];
|
||||
unsigned char *mem = buf;
|
||||
uint32_t rc = 0;
|
||||
int ch;
|
||||
|
|
@ -615,8 +617,9 @@ return(rc);
|
|||
|
||||
static uint64_t fstReaderVarint64(FILE *f)
|
||||
{
|
||||
int chk_len = 16; /* TALOS-2023-1783 */
|
||||
unsigned char buf[chk_len];
|
||||
const int chk_len_max = 16; /* TALOS-2023-1783 */
|
||||
int chk_len = chk_len_max;
|
||||
unsigned char buf[chk_len_max];
|
||||
unsigned char *mem = buf;
|
||||
uint64_t rc = 0;
|
||||
int ch;
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE
|
|||
|
||||
#ifndef VL_USER_STOP ///< Define this to override the vl_stop function
|
||||
void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
|
||||
// $stop or $fatal reporting; would break current API to add param as to which
|
||||
const char* const msg = "Verilog $stop";
|
||||
Verilated::threadContextp()->gotError(true);
|
||||
Verilated::threadContextp()->gotFinish(true);
|
||||
|
|
@ -172,6 +173,7 @@ void vl_fatal(const char* filename, int linenum, const char* hier, const char* m
|
|||
|
||||
#ifndef VL_USER_STOP_MAYBE ///< Define this to override the vl_stop_maybe function
|
||||
void vl_stop_maybe(const char* filename, int linenum, const char* hier, bool maybe) VL_MT_UNSAFE {
|
||||
// $stop or $fatal
|
||||
Verilated::threadContextp()->errorCountInc();
|
||||
if (maybe
|
||||
&& Verilated::threadContextp()->errorCount() < Verilated::threadContextp()->errorLimit()) {
|
||||
|
|
@ -1763,9 +1765,8 @@ IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
|
|||
return VL_SYSTEM_IW(VL_WQ_WORDS_E, lhsw);
|
||||
}
|
||||
IData VL_SYSTEM_IW(int lhswords, const WDataInP lhsp) VL_MT_SAFE {
|
||||
char filenamez[VL_VALUE_STRING_MAX_CHARS + 1];
|
||||
_vl_vint_to_string(lhswords * VL_EDATASIZE, filenamez, lhsp);
|
||||
return VL_SYSTEM_IN(filenamez);
|
||||
const std::string lhs = VL_CVT_PACK_STR_NW(lhswords, lhsp);
|
||||
return VL_SYSTEM_IN(lhs);
|
||||
}
|
||||
IData VL_SYSTEM_IN(const std::string& lhs) VL_MT_SAFE {
|
||||
const int code = std::system(lhs.c_str()); // Yes, std::system() is threadsafe
|
||||
|
|
@ -1915,20 +1916,16 @@ std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE {
|
|||
|
||||
std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE {
|
||||
// See also _vl_vint_to_string
|
||||
char destout[VL_VALUE_STRING_MAX_CHARS + 1];
|
||||
std::string result;
|
||||
result.reserve((lwords * VL_EDATASIZE) / 8 + 1);
|
||||
const int obits = lwords * VL_EDATASIZE;
|
||||
int lsb = obits - 1;
|
||||
char* destp = destout;
|
||||
size_t len = 0;
|
||||
for (; lsb >= 0; --lsb) {
|
||||
lsb = (lsb / 8) * 8; // Next digit
|
||||
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
|
||||
if (charval) {
|
||||
*destp++ = static_cast<char>(charval);
|
||||
++len;
|
||||
}
|
||||
if (charval) result += static_cast<char>(charval);
|
||||
}
|
||||
return std::string{destout, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string VL_CVT_PACK_STR_ND(const VlQueue<std::string>& q) VL_PURE {
|
||||
|
|
@ -3002,7 +2999,7 @@ const VerilatedScopeNameMap* VerilatedContext::scopeNameMap() VL_MT_SAFE {
|
|||
//======================================================================
|
||||
// VerilatedContext:: Methods - trace
|
||||
|
||||
void VerilatedContext::trace(VerilatedTraceBaseC* tfp, int levels, int options) VL_MT_SAFE {
|
||||
void VerilatedContext::trace(VerilatedTraceBaseC* tfp, int levels, int options) {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("+ VerilatedContext::trace\n"););
|
||||
if (tfp->isOpen()) {
|
||||
VL_FATAL_MT("", 0, "",
|
||||
|
|
|
|||
|
|
@ -221,19 +221,6 @@ public:
|
|||
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); }
|
||||
/// Try to acquire mutex. Returns true on success, and false on failure.
|
||||
bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE { return m_mutex.try_lock(); }
|
||||
/// Acquire/lock mutex and check for stop request
|
||||
/// It tries to lock the mutex and if it fails, it check if stop request was send.
|
||||
/// It returns after locking mutex.
|
||||
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
|
||||
/// limitations it needs to be placed here.
|
||||
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
|
||||
VL_ACQUIRE() VL_MT_SAFE {
|
||||
while (true) {
|
||||
checkStopRequestFunction();
|
||||
if (m_mutex.try_lock()) return;
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
|
||||
|
|
@ -809,8 +796,6 @@ class Verilated final {
|
|||
public:
|
||||
// METHODS - User called
|
||||
|
||||
/// Enable debug of internal verilated code
|
||||
static void debug(int level) VL_MT_SAFE;
|
||||
#ifdef VL_DEBUG
|
||||
/// Return debug level
|
||||
/// When multithreaded this may not immediately react to another thread
|
||||
|
|
@ -820,6 +805,8 @@ public:
|
|||
/// Return constant 0 debug level, so C++'s optimizer rips up
|
||||
static constexpr int debug() VL_PURE { return 0; }
|
||||
#endif
|
||||
/// Enable debug of internal verilated code
|
||||
static void debug(int level) VL_MT_SAFE;
|
||||
|
||||
/// Set the last VerilatedContext accessed
|
||||
/// Generally threadContextp(value) should be called instead
|
||||
|
|
@ -878,44 +865,44 @@ public:
|
|||
static const char* commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE {
|
||||
return Verilated::threadContextp()->commandArgsPlusMatch(prefixp);
|
||||
}
|
||||
/// Call VerilatedContext::errorLimit using current thread's VerilatedContext
|
||||
static void errorLimit(int val) VL_MT_SAFE { Verilated::threadContextp()->errorLimit(val); }
|
||||
/// Return VerilatedContext::errorLimit using current thread's VerilatedContext
|
||||
static int errorLimit() VL_MT_SAFE { return Verilated::threadContextp()->errorLimit(); }
|
||||
/// Call VerilatedContext::errorLimit using current thread's VerilatedContext
|
||||
static void errorLimit(int val) VL_MT_SAFE { Verilated::threadContextp()->errorLimit(val); }
|
||||
/// Return VerilatedContext::fatalOnError using current thread's VerilatedContext
|
||||
static bool fatalOnError() VL_MT_SAFE { return Verilated::threadContextp()->fatalOnError(); }
|
||||
/// Call VerilatedContext::fatalOnError using current thread's VerilatedContext
|
||||
static void fatalOnError(bool flag) VL_MT_SAFE {
|
||||
Verilated::threadContextp()->fatalOnError(flag);
|
||||
}
|
||||
/// Return VerilatedContext::fatalOnError using current thread's VerilatedContext
|
||||
static bool fatalOnError() VL_MT_SAFE { return Verilated::threadContextp()->fatalOnError(); }
|
||||
/// Call VerilatedContext::fatalOnVpiError using current thread's VerilatedContext
|
||||
static void fatalOnVpiError(bool flag) VL_MT_SAFE {
|
||||
Verilated::threadContextp()->fatalOnVpiError(flag);
|
||||
}
|
||||
/// Return VerilatedContext::fatalOnVpiError using current thread's VerilatedContext
|
||||
static bool fatalOnVpiError() VL_MT_SAFE {
|
||||
return Verilated::threadContextp()->fatalOnVpiError();
|
||||
}
|
||||
/// Call VerilatedContext::gotError using current thread's VerilatedContext
|
||||
static void gotError(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotError(flag); }
|
||||
/// Call VerilatedContext::fatalOnVpiError using current thread's VerilatedContext
|
||||
static void fatalOnVpiError(bool flag) VL_MT_SAFE {
|
||||
Verilated::threadContextp()->fatalOnVpiError(flag);
|
||||
}
|
||||
/// Return VerilatedContext::gotError using current thread's VerilatedContext
|
||||
static bool gotError() VL_MT_SAFE { return Verilated::threadContextp()->gotError(); }
|
||||
/// Call VerilatedContext::gotFinish using current thread's VerilatedContext
|
||||
static void gotFinish(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotFinish(flag); }
|
||||
/// Call VerilatedContext::gotError using current thread's VerilatedContext
|
||||
static void gotError(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotError(flag); }
|
||||
/// Return VerilatedContext::gotFinish using current thread's VerilatedContext
|
||||
static bool gotFinish() VL_MT_SAFE { return Verilated::threadContextp()->gotFinish(); }
|
||||
/// Call VerilatedContext::randReset using current thread's VerilatedContext
|
||||
static void randReset(int val) VL_MT_SAFE { Verilated::threadContextp()->randReset(val); }
|
||||
/// Call VerilatedContext::gotFinish using current thread's VerilatedContext
|
||||
static void gotFinish(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotFinish(flag); }
|
||||
/// Return VerilatedContext::randReset using current thread's VerilatedContext
|
||||
static int randReset() VL_MT_SAFE { return Verilated::threadContextp()->randReset(); }
|
||||
/// Call VerilatedContext::randSeed using current thread's VerilatedContext
|
||||
static void randSeed(int val) VL_MT_SAFE { Verilated::threadContextp()->randSeed(val); }
|
||||
/// Call VerilatedContext::randReset using current thread's VerilatedContext
|
||||
static void randReset(int val) VL_MT_SAFE { Verilated::threadContextp()->randReset(val); }
|
||||
/// Return VerilatedContext::randSeed using current thread's VerilatedContext
|
||||
static int randSeed() VL_MT_SAFE { return Verilated::threadContextp()->randSeed(); }
|
||||
/// Call VerilatedContext::time using current thread's VerilatedContext
|
||||
static void time(uint64_t val) VL_MT_SAFE { Verilated::threadContextp()->time(val); }
|
||||
/// Call VerilatedContext::randSeed using current thread's VerilatedContext
|
||||
static void randSeed(int val) VL_MT_SAFE { Verilated::threadContextp()->randSeed(val); }
|
||||
/// Return VerilatedContext::time using current thread's VerilatedContext
|
||||
static uint64_t time() VL_MT_SAFE { return Verilated::threadContextp()->time(); }
|
||||
/// Call VerilatedContext::time using current thread's VerilatedContext
|
||||
static void time(uint64_t val) VL_MT_SAFE { Verilated::threadContextp()->time(val); }
|
||||
/// Call VerilatedContext::timeInc using current thread's VerilatedContext
|
||||
static void timeInc(uint64_t add) VL_MT_UNSAFE { Verilated::threadContextp()->timeInc(add); }
|
||||
// Deprecated
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ public:
|
|||
std::string defaultFilename() VL_MT_SAFE;
|
||||
/// Make all data per_instance, overriding point's per_instance
|
||||
void forcePerInstance(bool flag) VL_MT_SAFE;
|
||||
void write() VL_MT_SAFE { write(defaultFilename()); }
|
||||
/// Write all coverage data to a file
|
||||
void write() VL_MT_SAFE { write(defaultFilename()); }
|
||||
void write(const std::string& filename) VL_MT_SAFE;
|
||||
/// Clear coverage points (and call delete on all items)
|
||||
void clear() VL_MT_SAFE;
|
||||
|
|
@ -165,8 +165,8 @@ public:
|
|||
/// Return default filename for the current thread
|
||||
static std::string defaultFilename() VL_MT_SAFE { return threadCovp()->defaultFilename(); }
|
||||
/// Write all coverage data to a file for the current thread
|
||||
static void write(const std::string& filename) VL_MT_SAFE { threadCovp()->write(filename); }
|
||||
static void write() VL_MT_SAFE { write(defaultFilename()); }
|
||||
static void write(const std::string& filename) VL_MT_SAFE { threadCovp()->write(filename); }
|
||||
/// Clear coverage points (and call delete on all items) for the current thread
|
||||
static void clear() VL_MT_SAFE { threadCovp()->clear(); }
|
||||
/// Clear items not matching the provided string for the current thread
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, uint32_t elemen
|
|||
// TODO: should return std::optional<fstScopeType>, but I can't have C++17
|
||||
static std::pair<bool, fstScopeType> toFstScopeType(VerilatedTracePrefixType type) {
|
||||
switch (type) {
|
||||
case VerilatedTracePrefixType::ROOTIO_MODULE: return {true, FST_ST_VCD_MODULE};
|
||||
case VerilatedTracePrefixType::SCOPE_MODULE: return {true, FST_ST_VCD_MODULE};
|
||||
case VerilatedTracePrefixType::SCOPE_INTERFACE: return {true, FST_ST_VCD_INTERFACE};
|
||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||
|
|
@ -137,7 +138,20 @@ static std::pair<bool, fstScopeType> toFstScopeType(VerilatedTracePrefixType typ
|
|||
}
|
||||
|
||||
void VerilatedFst::pushPrefix(const std::string& name, VerilatedTracePrefixType type) {
|
||||
const std::string newPrefix = m_prefixStack.back().first + name;
|
||||
assert(!m_prefixStack.empty()); // Constructor makes an empty entry
|
||||
std::string pname = name;
|
||||
// An empty name means this is the root of a model created with name()=="". The
|
||||
// tools get upset if we try to pass this as empty, so we put the signals under a
|
||||
// new scope, but the signals further down will be peers, not children (as usual
|
||||
// for name()!="")
|
||||
// Terminate earlier $root?
|
||||
if (m_prefixStack.back().second == VerilatedTracePrefixType::ROOTIO_MODULE) popPrefix();
|
||||
if (pname.empty()) { // Start new temporary root
|
||||
pname = "$rootio"; // VCD names are not backslash escaped
|
||||
m_prefixStack.emplace_back("", VerilatedTracePrefixType::ROOTIO_WRAPPER);
|
||||
type = VerilatedTracePrefixType::ROOTIO_MODULE;
|
||||
}
|
||||
const std::string newPrefix = m_prefixStack.back().first + pname;
|
||||
const auto pair = toFstScopeType(type);
|
||||
const bool properScope = pair.first;
|
||||
const fstScopeType scopeType = pair.second;
|
||||
|
|
@ -149,10 +163,11 @@ void VerilatedFst::pushPrefix(const std::string& name, VerilatedTracePrefixType
|
|||
}
|
||||
|
||||
void VerilatedFst::popPrefix() {
|
||||
assert(!m_prefixStack.empty());
|
||||
const bool properScope = toFstScopeType(m_prefixStack.back().second).first;
|
||||
if (properScope) fstWriterSetUpscope(m_fst);
|
||||
m_prefixStack.pop_back();
|
||||
assert(!m_prefixStack.empty());
|
||||
assert(!m_prefixStack.empty()); // Always one left, the constructor's initial one
|
||||
}
|
||||
|
||||
void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum,
|
||||
|
|
@ -294,7 +309,7 @@ void VerilatedFst::configure(const VerilatedTraceConfig& config) {
|
|||
// so always inline them.
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFstBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
|
||||
void VerilatedFstBuffer::emitEvent(uint32_t code) {
|
||||
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ private:
|
|||
friend VerilatedFstBuffer; // Give the buffer access to the private bits
|
||||
|
||||
//=========================================================================
|
||||
// FST specific internals
|
||||
// FST-specific internals
|
||||
|
||||
void* m_fst = nullptr;
|
||||
std::map<uint32_t, vlFstHandle> m_code2symbol;
|
||||
|
|
@ -177,7 +177,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
|
|||
|
||||
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||
// called from only one place (the full* methods), so always inline them.
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, const VlEventBase* newval);
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code);
|
||||
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
|
||||
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
||||
|
|
|
|||
|
|
@ -42,19 +42,20 @@ extern void vl_finish(const char* filename, int linenum, const char* hier) VL_MT
|
|||
/// Routine to call for $stop and non-fatal error
|
||||
/// User code may wish to replace this function, to do so, define VL_USER_STOP.
|
||||
/// This code does not have to be thread safe.
|
||||
/// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this.
|
||||
/// Verilator internal code must call VL_STOP_MT instead, which eventually calls this.
|
||||
extern void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE;
|
||||
|
||||
/// Routine to call for fatal messages
|
||||
/// User code may wish to replace this function, to do so, define VL_USER_FATAL.
|
||||
/// This code does not have to be thread safe.
|
||||
/// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this.
|
||||
/// Verilator internal code must call VL_FATAL_MT instead, which eventually calls this.
|
||||
extern void vl_fatal(const char* filename, int linenum, const char* hier,
|
||||
const char* msg) VL_MT_UNSAFE;
|
||||
|
||||
/// Routine to call for warning messages
|
||||
/// User code may wish to replace this function, to do so, define VL_USER_WARN.
|
||||
/// This code does not have to be thread safe.
|
||||
/// Verilator internal code must call VL_WARN_MT instead, which eventually calls this.
|
||||
extern void vl_warn(const char* filename, int linenum, const char* hier,
|
||||
const char* msg) VL_MT_UNSAFE;
|
||||
|
||||
|
|
@ -2206,84 +2207,94 @@ static inline void VL_UNPACK_II(int lbits, int rbits, VlQueue<CData>& q, IData f
|
|||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = (from >> (i * lbits)) & mask;
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlQueue<SData>& q, IData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = (from >> (i * lbits)) & mask;
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlQueue<IData>& q, IData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = (from >> (i * lbits)) & mask;
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlQueue<CData>& q, QData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = (from >> (i * lbits)) & mask;
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlQueue<SData>& q, QData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = (from >> (i * lbits)) & mask;
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlQueue<IData>& q, QData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = (from >> (i * lbits)) & mask;
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_QQ(int lbits, int rbits, VlQueue<QData>& q, QData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const QData mask = VL_MASK_Q(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = (from >> (i * lbits)) & mask;
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlQueue<CData>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = VL_SEL_IWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
q.atWrite(i) = VL_SEL_IWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlQueue<SData>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = VL_SEL_IWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
q.atWrite(i) = VL_SEL_IWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlQueue<IData>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = VL_SEL_IWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
q.atWrite(i) = VL_SEL_IWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_QW(int lbits, int rbits, VlQueue<QData>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const QData mask = VL_MASK_Q(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.at(i) = VL_SEL_QWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
q.atWrite(i) = VL_SEL_QWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
static inline void VL_UNPACK_WW(int lbits, int rbits, VlQueue<VlWide<N>>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
for (size_t i = 0; i < size; ++i) VL_SEL_WWII(lbits, rbits, q.at(i), rwp, i * lbits, lbits);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
VL_SEL_WWII(lbits, rbits, q.atWrite(i), rwp, i * lbits, lbits);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@
|
|||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator common target specific intrinsics header
|
||||
/// \brief Verilator common target-specific intrinsics header
|
||||
///
|
||||
/// This file is not part of the Verilated public-facing API.
|
||||
///
|
||||
/// It is only for internal use; code using machine specific intrinsics for
|
||||
/// It is only for internal use; code using machine-specific intrinsics for
|
||||
/// optimization should include this header rather than directly including
|
||||
/// he target specific headers. We provide macros to check for availability
|
||||
/// the target-specific headers. We provide macros to check for availability
|
||||
/// of instruction sets, and a common mechanism to disable them.
|
||||
///
|
||||
//*************************************************************************
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ static Process& getSolver() {
|
|||
|
||||
const char* const* const cmd = &s_argv[0];
|
||||
s_solver.open(cmd);
|
||||
s_solver << "(set-logic QF_BV)\n";
|
||||
s_solver << "(set-logic QF_ABV)\n";
|
||||
s_solver << "(check-sat)\n";
|
||||
s_solver << "(reset)\n";
|
||||
std::string s;
|
||||
|
|
@ -250,32 +250,78 @@ static Process& getSolver() {
|
|||
return s_solver;
|
||||
}
|
||||
|
||||
std::string readUntilBalanced(std::istream& stream) {
|
||||
std::string result;
|
||||
std::string token;
|
||||
int parenCount = 1;
|
||||
while (stream >> token) {
|
||||
for (const char c : token) {
|
||||
if (c == '(') {
|
||||
++parenCount;
|
||||
} else if (c == ')') {
|
||||
--parenCount;
|
||||
}
|
||||
}
|
||||
result += token + " ";
|
||||
if (parenCount == 0) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string parseNestedSelect(const std::string& nested_select_expr,
|
||||
std::vector<std::string>& indices) {
|
||||
std::istringstream nestedStream(nested_select_expr);
|
||||
std::string name, idx;
|
||||
nestedStream >> name;
|
||||
if (name == "(select") {
|
||||
const std::string further_nested_expr = readUntilBalanced(nestedStream);
|
||||
name = parseNestedSelect(further_nested_expr, indices);
|
||||
}
|
||||
std::getline(nestedStream, idx, ')');
|
||||
indices.push_back(idx);
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string flattenIndices(const std::vector<std::string>& indices, const VlRandomVar* const var) {
|
||||
int flattenedIndex = 0;
|
||||
int multiplier = 1;
|
||||
for (int i = indices.size() - 1; i >= 0; --i) {
|
||||
int indexValue = 0;
|
||||
std::string trimmedIndex = indices[i];
|
||||
|
||||
trimmedIndex.erase(0, trimmedIndex.find_first_not_of(" \t"));
|
||||
trimmedIndex.erase(trimmedIndex.find_last_not_of(" \t") + 1);
|
||||
|
||||
if (trimmedIndex.find("#x") == 0) {
|
||||
indexValue = std::strtoul(trimmedIndex.substr(2).c_str(), nullptr, 16);
|
||||
} else if (trimmedIndex.find("#b") == 0) {
|
||||
indexValue = std::strtoul(trimmedIndex.substr(2).c_str(), nullptr, 2);
|
||||
} else {
|
||||
indexValue = std::strtoul(trimmedIndex.c_str(), nullptr, 10);
|
||||
}
|
||||
const int length = var->getLength(i);
|
||||
if (length == -1) {
|
||||
VL_WARN_MT(__FILE__, __LINE__, "randomize",
|
||||
"Internal: Wrong Call: Only RandomArray can call getLength()");
|
||||
break;
|
||||
}
|
||||
flattenedIndex += indexValue * multiplier;
|
||||
multiplier *= length;
|
||||
}
|
||||
std::string hexString = std::to_string(flattenedIndex);
|
||||
while (hexString.size() < 8) { hexString.insert(0, "0"); }
|
||||
return "#x" + hexString;
|
||||
}
|
||||
//======================================================================
|
||||
// VlRandomizer:: Methods
|
||||
|
||||
void VlRandomVar::emit(std::ostream& s) const { s << m_name; }
|
||||
void VlRandomConst::emit(std::ostream& s) const {
|
||||
s << "#b";
|
||||
for (int i = 0; i < m_width; i++) s << (VL_BITISSET_Q(m_val, m_width - i - 1) ? '1' : '0');
|
||||
void VlRandomVar::emitGetValue(std::ostream& s) const { s << ' ' << m_name; }
|
||||
void VlRandomVar::emitExtract(std::ostream& s, int i) const {
|
||||
s << " ((_ extract " << i << ' ' << i << ") " << m_name << ')';
|
||||
}
|
||||
void VlRandomBinOp::emit(std::ostream& s) const {
|
||||
s << '(' << m_op << ' ';
|
||||
m_lhs->emit(s);
|
||||
s << ' ';
|
||||
m_rhs->emit(s);
|
||||
s << ')';
|
||||
}
|
||||
void VlRandomExtract::emit(std::ostream& s) const {
|
||||
s << "((_ extract " << m_idx << ' ' << m_idx << ") ";
|
||||
m_expr->emit(s);
|
||||
s << ')';
|
||||
}
|
||||
bool VlRandomVar::set(std::string&& val) const {
|
||||
VlWide<VL_WQ_WORDS_E> qowp;
|
||||
VL_SET_WQ(qowp, 0ULL);
|
||||
WDataOutP owp = qowp;
|
||||
int obits = width();
|
||||
if (obits > VL_QUADSIZE) owp = reinterpret_cast<WDataOutP>(datap());
|
||||
void VlRandomVar::emitType(std::ostream& s) const { s << "(_ BitVec " << width() << ')'; }
|
||||
int VlRandomVar::totalWidth() const { return m_width; }
|
||||
static bool parseSMTNum(int obits, WDataOutP owp, const std::string& val) {
|
||||
int i;
|
||||
for (i = 0; val[i] && val[i] != '#'; i++) {}
|
||||
if (val[i++] != '#') return false;
|
||||
|
|
@ -289,17 +335,31 @@ bool VlRandomVar::set(std::string&& val) const {
|
|||
"Internal: Unable to parse solver's randomized number");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool VlRandomVar::set(const std::string& idx, const std::string& val) const {
|
||||
VlWide<VL_WQ_WORDS_E> qowp;
|
||||
VL_SET_WQ(qowp, 0ULL);
|
||||
WDataOutP owp = qowp;
|
||||
const int obits = width();
|
||||
VlWide<VL_WQ_WORDS_E> qiwp;
|
||||
VL_SET_WQ(qiwp, 0ULL);
|
||||
if (!idx.empty() && !parseSMTNum(64, qiwp, idx)) return false;
|
||||
const int nidx = qiwp[0];
|
||||
if (obits > VL_QUADSIZE) owp = reinterpret_cast<WDataOutP>(datap(nidx));
|
||||
if (!parseSMTNum(obits, owp, val)) return false;
|
||||
|
||||
if (obits <= VL_BYTESIZE) {
|
||||
CData* const p = static_cast<CData*>(datap());
|
||||
CData* const p = static_cast<CData*>(datap(nidx));
|
||||
*p = VL_CLEAN_II(obits, obits, owp[0]);
|
||||
} else if (obits <= VL_SHORTSIZE) {
|
||||
SData* const p = static_cast<SData*>(datap());
|
||||
SData* const p = static_cast<SData*>(datap(nidx));
|
||||
*p = VL_CLEAN_II(obits, obits, owp[0]);
|
||||
} else if (obits <= VL_IDATASIZE) {
|
||||
IData* const p = static_cast<IData*>(datap());
|
||||
IData* const p = static_cast<IData*>(datap(nidx));
|
||||
*p = VL_CLEAN_II(obits, obits, owp[0]);
|
||||
} else if (obits <= VL_QUADSIZE) {
|
||||
QData* const p = static_cast<QData*>(datap());
|
||||
QData* const p = static_cast<QData*>(datap(nidx));
|
||||
*p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp));
|
||||
} else {
|
||||
_vl_clean_inplace_w(obits, owp);
|
||||
|
|
@ -307,27 +367,31 @@ bool VlRandomVar::set(std::string&& val) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<const VlRandomExpr> VlRandomizer::randomConstraint(VlRNG& rngr, int bits) {
|
||||
unsigned long long hash = VL_RANDOM_RNG_I(rngr) & ((1 << bits) - 1);
|
||||
std::shared_ptr<const VlRandomExpr> concat = nullptr;
|
||||
std::vector<std::shared_ptr<const VlRandomExpr>> varbits;
|
||||
for (const auto& var : m_vars) {
|
||||
for (int i = 0; i < var.second->width(); i++)
|
||||
varbits.emplace_back(std::make_shared<const VlRandomExtract>(var.second, i));
|
||||
}
|
||||
void VlRandomizer::randomConstraint(std::ostream& os, VlRNG& rngr, int bits) {
|
||||
const IData hash = VL_RANDOM_RNG_I(rngr) & ((1 << bits) - 1);
|
||||
int varBits = 0;
|
||||
for (const auto& var : m_vars) varBits += var.second->totalWidth();
|
||||
os << "(= #b";
|
||||
for (int i = bits - 1; i >= 0; i--) os << (VL_BITISSET_I(hash, i) ? '1' : '0');
|
||||
if (bits > 1) os << " (concat";
|
||||
for (int i = 0; i < bits; i++) {
|
||||
std::shared_ptr<const VlRandomExpr> bit = nullptr;
|
||||
for (unsigned j = 0; j * 2 < varbits.size(); j++) {
|
||||
unsigned idx = j + VL_RANDOM_RNG_I(rngr) % (varbits.size() - j);
|
||||
auto sel = varbits[idx];
|
||||
std::swap(varbits[idx], varbits[j]);
|
||||
bit = bit == nullptr ? sel : std::make_shared<const VlRandomBinOp>("bvxor", bit, sel);
|
||||
IData varBitsLeft = varBits;
|
||||
IData varBitsWant = (varBits + 1) / 2;
|
||||
if (varBits > 2) os << " (bvxor";
|
||||
for (const auto& var : m_vars) {
|
||||
for (int j = 0; j < var.second->totalWidth(); j++, varBitsLeft--) {
|
||||
const bool doEmit = (VL_RANDOM_RNG_I(rngr) % varBitsLeft) < varBitsWant;
|
||||
if (doEmit) {
|
||||
var.second->emitExtract(os, j);
|
||||
if (--varBitsWant == 0) break;
|
||||
}
|
||||
}
|
||||
if (varBitsWant == 0) break;
|
||||
}
|
||||
concat = concat == nullptr ? bit
|
||||
: std::make_shared<const VlRandomBinOp>("concat", concat, bit);
|
||||
if (varBits > 2) os << ')';
|
||||
}
|
||||
return std::make_shared<const VlRandomBinOp>(
|
||||
"=", concat, std::make_shared<const VlRandomConst>(hash, bits));
|
||||
if (bits > 1) os << ')';
|
||||
os << ')';
|
||||
}
|
||||
|
||||
bool VlRandomizer::next(VlRNG& rngr) {
|
||||
|
|
@ -336,12 +400,17 @@ bool VlRandomizer::next(VlRNG& rngr) {
|
|||
if (!f) return false;
|
||||
|
||||
f << "(set-option :produce-models true)\n";
|
||||
f << "(set-logic QF_BV)\n";
|
||||
f << "(set-logic QF_ABV)\n";
|
||||
f << "(define-fun __Vbv ((b Bool)) (_ BitVec 1) (ite b #b1 #b0))\n";
|
||||
f << "(define-fun __Vbool ((v (_ BitVec 1))) Bool (= #b1 v))\n";
|
||||
for (const auto& var : m_vars) {
|
||||
f << "(declare-fun " << var.second->name() << " () (_ BitVec " << var.second->width()
|
||||
<< "))\n";
|
||||
f << "(declare-fun " << var.second->name() << " () ";
|
||||
var.second->emitType(f);
|
||||
f << ")\n";
|
||||
}
|
||||
for (const std::string& constraint : m_constraints) {
|
||||
f << "(assert (= #b1 " << constraint << "))\n";
|
||||
}
|
||||
for (const std::string& constraint : m_constraints) { f << "(assert " << constraint << ")\n"; }
|
||||
f << "(check-sat)\n";
|
||||
|
||||
bool sat = parseSolution(f);
|
||||
|
|
@ -349,10 +418,9 @@ bool VlRandomizer::next(VlRNG& rngr) {
|
|||
f << "(reset)\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _VL_SOLVER_HASH_LEN_TOTAL && sat; i++) {
|
||||
f << "(assert ";
|
||||
randomConstraint(rngr, _VL_SOLVER_HASH_LEN)->emit(f);
|
||||
randomConstraint(f, rngr, _VL_SOLVER_HASH_LEN);
|
||||
f << ")\n";
|
||||
f << "\n(check-sat)\n";
|
||||
sat = parseSolution(f);
|
||||
|
|
@ -376,7 +444,7 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
|||
}
|
||||
|
||||
f << "(get-value (";
|
||||
for (const auto& var : m_vars) f << var.second->name() << ' ';
|
||||
for (const auto& var : m_vars) var.second->emitGetValue(f);
|
||||
f << "))\n";
|
||||
|
||||
// Quasi-parse S-expression of the form ((x #xVALUE) (y #bVALUE) (z #xVALUE))
|
||||
|
|
@ -396,21 +464,29 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
|||
"Internal: Unable to parse solver's response: invalid S-expression");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name, value;
|
||||
std::string name, idx, value;
|
||||
std::vector<std::string> indices;
|
||||
f >> name;
|
||||
indices.clear();
|
||||
if (name == "(select") {
|
||||
const std::string selectExpr = readUntilBalanced(f);
|
||||
name = parseNestedSelect(selectExpr, indices);
|
||||
idx = indices[0];
|
||||
}
|
||||
std::getline(f, value, ')');
|
||||
|
||||
auto it = m_vars.find(name);
|
||||
const auto it = m_vars.find(name);
|
||||
if (it == m_vars.end()) continue;
|
||||
const VlRandomVar& varr = *it->second;
|
||||
if (m_randmode && !varr.randModeIdxNone()) {
|
||||
if (!(m_randmode->at(varr.randModeIdx()))) continue;
|
||||
}
|
||||
|
||||
varr.set(std::move(value));
|
||||
if (indices.size() > 1) {
|
||||
const std::string flattenedIndex = flattenIndices(indices, &varr);
|
||||
varr.set(flattenedIndex, value);
|
||||
} else {
|
||||
varr.set(idx, value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,71 +27,163 @@
|
|||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
//=============================================================================
|
||||
// VlRandomExpr and subclasses represent expressions for the constraint solver.
|
||||
|
||||
class VlRandomExpr VL_NOT_FINAL {
|
||||
public:
|
||||
virtual void emit(std::ostream& s) const = 0;
|
||||
};
|
||||
class VlRandomVar final : public VlRandomExpr {
|
||||
class VlRandomVar VL_NOT_FINAL {
|
||||
const char* const m_name; // Variable name
|
||||
void* const m_datap; // Reference to variable data
|
||||
const int m_width; // Variable width in bits
|
||||
const int m_dimension; //Variable dimension, default is 0
|
||||
const std::uint32_t m_randModeIdx; // rand_mode index
|
||||
|
||||
public:
|
||||
VlRandomVar(const char* name, int width, void* datap, std::uint32_t randModeIdx)
|
||||
VlRandomVar(const char* name, int width, void* datap, int dimension, std::uint32_t randModeIdx)
|
||||
: m_name{name}
|
||||
, m_datap{datap}
|
||||
, m_width{width}
|
||||
, m_dimension{dimension}
|
||||
, m_randModeIdx{randModeIdx} {}
|
||||
virtual ~VlRandomVar() = default;
|
||||
const char* name() const { return m_name; }
|
||||
int width() const { return m_width; }
|
||||
void* datap() const { return m_datap; }
|
||||
int dimension() const { return m_dimension; }
|
||||
virtual void* datap(int idx) const { return m_datap; }
|
||||
std::uint32_t randModeIdx() const { return m_randModeIdx; }
|
||||
bool randModeIdxNone() const { return randModeIdx() == std::numeric_limits<unsigned>::max(); }
|
||||
bool set(std::string&&) const;
|
||||
void emit(std::ostream& s) const override;
|
||||
bool set(const std::string& idx, const std::string& val) const;
|
||||
virtual void emitGetValue(std::ostream& s) const;
|
||||
virtual void emitExtract(std::ostream& s, int i) const;
|
||||
virtual void emitType(std::ostream& s) const;
|
||||
virtual int totalWidth() const;
|
||||
virtual int getLength(int dimension) const { return -1; }
|
||||
};
|
||||
|
||||
class VlRandomConst final : public VlRandomExpr {
|
||||
const QData m_val; // Constant value
|
||||
const int m_width; // Constant width in bits
|
||||
|
||||
template <typename T>
|
||||
class VlRandomQueueVar final : public VlRandomVar {
|
||||
public:
|
||||
VlRandomConst(QData val, int width)
|
||||
: m_val{val}
|
||||
, m_width{width} {
|
||||
assert(width <= sizeof(m_val) * 8);
|
||||
VlRandomQueueVar(const char* name, int width, void* datap, int dimension,
|
||||
std::uint32_t randModeIdx)
|
||||
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
||||
void* datap(int idx) const override {
|
||||
return &static_cast<T*>(VlRandomVar::datap(idx))->atWrite(idx);
|
||||
}
|
||||
void emitSelect(std::ostream& s, int i) const {
|
||||
s << " (select " << name() << " #x";
|
||||
for (int j = 28; j >= 0; j -= 4) s << "0123456789abcdef"[(i >> j) & 0xf];
|
||||
s << ')';
|
||||
}
|
||||
void emitGetValue(std::ostream& s) const override {
|
||||
const int length = static_cast<T*>(VlRandomVar::datap(0))->size();
|
||||
for (int i = 0; i < length; i++) emitSelect(s, i);
|
||||
}
|
||||
void emitType(std::ostream& s) const override {
|
||||
s << "(Array (_ BitVec 32) (_ BitVec " << width() << "))";
|
||||
}
|
||||
int totalWidth() const override {
|
||||
const int length = static_cast<T*>(VlRandomVar::datap(0))->size();
|
||||
return width() * length;
|
||||
}
|
||||
void emitExtract(std::ostream& s, int i) const override {
|
||||
const int j = i / width();
|
||||
i = i % width();
|
||||
s << " ((_ extract " << i << ' ' << i << ')';
|
||||
emitSelect(s, j);
|
||||
s << ')';
|
||||
}
|
||||
void emit(std::ostream& s) const override;
|
||||
};
|
||||
|
||||
class VlRandomExtract final : public VlRandomExpr {
|
||||
const std::shared_ptr<const VlRandomExpr> m_expr; // Sub-expression
|
||||
const unsigned m_idx; // Extracted index
|
||||
|
||||
template <typename T>
|
||||
class VlRandomArrayVar final : public VlRandomVar {
|
||||
public:
|
||||
VlRandomExtract(std::shared_ptr<const VlRandomExpr> expr, unsigned idx)
|
||||
: m_expr{expr}
|
||||
, m_idx{idx} {}
|
||||
void emit(std::ostream& s) const override;
|
||||
VlRandomArrayVar(const char* name, int width, void* datap, int dimension,
|
||||
std::uint32_t randModeIdx)
|
||||
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
||||
|
||||
void* datap(int idx) const override {
|
||||
if (idx < 0) return &static_cast<T*>(VlRandomVar::datap(0))->operator[](0);
|
||||
std::vector<size_t> indices(dimension());
|
||||
for (int dim = dimension() - 1; dim >= 0; --dim) {
|
||||
const int length = getLength(dim);
|
||||
indices[dim] = idx % length;
|
||||
idx /= length;
|
||||
}
|
||||
return &static_cast<T*>(VlRandomVar::datap(0))->find_element(indices);
|
||||
}
|
||||
|
||||
void emitSelect(std::ostream& s, const std::vector<int>& indices) const {
|
||||
for (size_t idx = 0; idx < indices.size(); ++idx) s << "(select ";
|
||||
s << name();
|
||||
for (size_t idx = 0; idx < indices.size(); ++idx) {
|
||||
s << " #x";
|
||||
for (int j = 28; j >= 0; j -= 4) {
|
||||
s << "0123456789abcdef"[(indices[idx] >> j) & 0xf];
|
||||
}
|
||||
s << ")";
|
||||
}
|
||||
}
|
||||
|
||||
int getLength(int dimension) const override {
|
||||
const auto var = static_cast<const T*>(datap(-1));
|
||||
const int lenth = var->find_length(dimension);
|
||||
return lenth;
|
||||
}
|
||||
|
||||
void emitGetValue(std::ostream& s) const override {
|
||||
const int total_dimensions = dimension();
|
||||
std::vector<int> lengths;
|
||||
for (int dim = 0; dim < total_dimensions; dim++) {
|
||||
const int len = getLength(dim);
|
||||
lengths.push_back(len);
|
||||
}
|
||||
std::vector<int> indices(total_dimensions, 0);
|
||||
while (true) {
|
||||
emitSelect(s, indices);
|
||||
int currentDimension = total_dimensions - 1;
|
||||
while (currentDimension >= 0
|
||||
&& ++indices[currentDimension] >= lengths[currentDimension]) {
|
||||
indices[currentDimension] = 0;
|
||||
--currentDimension;
|
||||
}
|
||||
if (currentDimension < 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
void emitType(std::ostream& s) const override {
|
||||
if (dimension() > 0) {
|
||||
for (int i = 0; i < dimension(); ++i) s << "(Array (_ BitVec 32) ";
|
||||
s << "(_ BitVec " << width() << ")";
|
||||
for (int i = 0; i < dimension(); ++i) s << ")";
|
||||
}
|
||||
}
|
||||
|
||||
int totalWidth() const override {
|
||||
int totalLength = 1;
|
||||
for (int dim = 0; dim < dimension(); ++dim) {
|
||||
const int length = getLength(dim);
|
||||
if (length == -1) return 0;
|
||||
totalLength *= length;
|
||||
}
|
||||
return width() * totalLength;
|
||||
}
|
||||
|
||||
void emitExtract(std::ostream& s, int i) const override {
|
||||
const int j = i / width();
|
||||
i = i % width();
|
||||
std::vector<int> indices(dimension());
|
||||
int idx = j;
|
||||
for (int dim = dimension() - 1; dim >= 0; --dim) {
|
||||
int length = getLength(dim);
|
||||
indices[dim] = idx % length;
|
||||
idx /= length;
|
||||
}
|
||||
s << " ((_ extract " << i << ' ' << i << ')';
|
||||
emitSelect(s, indices);
|
||||
s << ')';
|
||||
}
|
||||
};
|
||||
|
||||
class VlRandomBinOp final : public VlRandomExpr {
|
||||
const char* const m_op; // Binary operation identifier
|
||||
const std::shared_ptr<const VlRandomExpr> m_lhs, m_rhs; // Sub-expressions
|
||||
|
||||
public:
|
||||
VlRandomBinOp(const char* op, std::shared_ptr<const VlRandomExpr> lhs,
|
||||
std::shared_ptr<const VlRandomExpr> rhs)
|
||||
: m_op{op}
|
||||
, m_lhs{lhs}
|
||||
, m_rhs{rhs} {}
|
||||
void emit(std::ostream& s) const override;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlRandomizer is the object holding constraints and variable references.
|
||||
|
||||
|
|
@ -103,19 +195,38 @@ class VlRandomizer final {
|
|||
const VlQueue<CData>* m_randmode; // rand_mode state;
|
||||
|
||||
// PRIVATE METHODS
|
||||
std::shared_ptr<const VlRandomExpr> randomConstraint(VlRNG& rngr, int bits);
|
||||
void randomConstraint(std::ostream& os, VlRNG& rngr, int bits);
|
||||
bool parseSolution(std::iostream& file);
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlRandomizer() = default;
|
||||
~VlRandomizer() = default;
|
||||
|
||||
// METHODS
|
||||
// Finds the next solution satisfying the constraints
|
||||
bool next(VlRNG& rngr);
|
||||
template <typename T>
|
||||
void write_var(T& var, int width, const char* name,
|
||||
void write_var(T& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
auto it = m_vars.find(name);
|
||||
if (it != m_vars.end()) return;
|
||||
m_vars[name] = std::make_shared<const VlRandomVar>(name, width, &var, randmodeIdx);
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
// TODO: make_unique once VlRandomizer is per-instance not per-ref
|
||||
m_vars[name]
|
||||
= std::make_shared<const VlRandomVar>(name, width, &var, dimension, randmodeIdx);
|
||||
}
|
||||
template <typename T>
|
||||
void write_var(VlQueue<T>& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
m_vars[name] = std::make_shared<const VlRandomQueueVar<VlQueue<T>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
void write_var(VlUnpacked<T, N>& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
m_vars[name] = std::make_shared<const VlRandomArrayVar<VlUnpacked<T, N>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
}
|
||||
void hard(std::string&& constraint);
|
||||
void clear();
|
||||
|
|
|
|||
|
|
@ -49,10 +49,12 @@ class VerilatedTraceOffloadBuffer;
|
|||
//=============================================================================
|
||||
// Common enumerations
|
||||
|
||||
enum class VerilatedTracePrefixType : uint32_t {
|
||||
enum class VerilatedTracePrefixType : uint8_t {
|
||||
// Note: Entries must match VTracePrefixType (by name, not necessarily by value)
|
||||
ARRAY_PACKED,
|
||||
ARRAY_UNPACKED,
|
||||
ROOTIO_MODULE, // $rootio, used when name()=="", other modules become peers
|
||||
ROOTIO_WRAPPER, // "Above" ROOTIO_MODULE
|
||||
SCOPE_MODULE,
|
||||
SCOPE_INTERFACE,
|
||||
STRUCT_PACKED,
|
||||
|
|
@ -61,7 +63,7 @@ enum class VerilatedTracePrefixType : uint32_t {
|
|||
};
|
||||
|
||||
// Direction attribute for ports
|
||||
enum class VerilatedTraceSigDirection : uint32_t {
|
||||
enum class VerilatedTraceSigDirection : uint8_t {
|
||||
NONE,
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
|
|
@ -69,7 +71,7 @@ enum class VerilatedTraceSigDirection : uint32_t {
|
|||
};
|
||||
|
||||
// Kind of signal. Similar to nettype but with a few more alternatives
|
||||
enum class VerilatedTraceSigKind : uint32_t {
|
||||
enum class VerilatedTraceSigKind : uint8_t {
|
||||
PARAMETER,
|
||||
SUPPLY0,
|
||||
SUPPLY1,
|
||||
|
|
@ -81,7 +83,7 @@ enum class VerilatedTraceSigKind : uint32_t {
|
|||
};
|
||||
|
||||
// Base data type of signal
|
||||
enum class VerilatedTraceSigType : uint32_t {
|
||||
enum class VerilatedTraceSigType : uint8_t {
|
||||
DOUBLE,
|
||||
INTEGER,
|
||||
BIT,
|
||||
|
|
@ -198,8 +200,8 @@ public:
|
|||
//=============================================================================
|
||||
// VerilatedTrace
|
||||
|
||||
// T_Trace is the format specific subclass of VerilatedTrace.
|
||||
// T_Buffer is the format specific base class of VerilatedTraceBuffer.
|
||||
// T_Trace is the format-specific subclass of VerilatedTrace.
|
||||
// T_Buffer is the format-specific base class of VerilatedTraceBuffer.
|
||||
template <class T_Trace, class T_Buffer>
|
||||
class VerilatedTrace VL_NOT_FINAL {
|
||||
public:
|
||||
|
|
@ -348,7 +350,7 @@ private:
|
|||
|
||||
protected:
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
// Internals available to format-specific implementations
|
||||
|
||||
mutable VerilatedMutex m_mutex; // Ensure dump() etc only called from single thread
|
||||
|
||||
|
|
@ -381,7 +383,7 @@ protected:
|
|||
}
|
||||
|
||||
//=========================================================================
|
||||
// Virtual functions to be provided by the format specific implementation
|
||||
// Virtual functions to be provided by the format-specific implementation
|
||||
|
||||
// Called when the trace moves forward to a new time point
|
||||
virtual void emitTimeChange(uint64_t timeui) = 0;
|
||||
|
|
@ -438,7 +440,7 @@ public:
|
|||
//=============================================================================
|
||||
// VerilatedTraceBuffer
|
||||
|
||||
// T_Buffer is the format specific base class of VerilatedTraceBuffer.
|
||||
// T_Buffer is the format-specific base class of VerilatedTraceBuffer.
|
||||
// The format-specific hot-path methods use duck-typing via T_Buffer for performance.
|
||||
template <class T_Buffer>
|
||||
class VerilatedTraceBuffer VL_NOT_FINAL : public T_Buffer {
|
||||
|
|
@ -464,7 +466,7 @@ public:
|
|||
// Hot path internal interface to Verilator generated code
|
||||
|
||||
// Implementation note: We rely on the following duck-typed implementations
|
||||
// in the derived class T_Derived. These emit* functions record a format
|
||||
// in the derived class T_Derived. These emit* functions record a format-
|
||||
// specific trace entry. Normally one would use pure virtual functions for
|
||||
// these here, but we cannot afford dynamic dispatch for calling these as
|
||||
// this is very hot code during tracing.
|
||||
|
|
@ -487,7 +489,8 @@ public:
|
|||
void fullQData(uint32_t* oldp, QData newval, int bits);
|
||||
void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
|
||||
void fullDouble(uint32_t* oldp, double newval);
|
||||
void fullEvent(uint32_t* oldp, const VlEventBase* newval);
|
||||
void fullEvent(uint32_t* oldp, const VlEventBase* newvalp);
|
||||
void fullEventTriggered(uint32_t* oldp);
|
||||
|
||||
// In non-offload mode, these are called directly by the trace callbacks,
|
||||
// and are called chg*. In offload mode, they are called by the worker
|
||||
|
|
@ -524,9 +527,10 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newval) {
|
||||
fullEvent(oldp, newval);
|
||||
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newvalp) {
|
||||
if (newvalp->isTriggered()) fullEvent(oldp, newvalp);
|
||||
}
|
||||
VL_ATTR_ALWINLINE void chgEventTriggered(uint32_t* oldp) { fullEventTriggered(oldp); }
|
||||
VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
|
||||
double old;
|
||||
std::memcpy(&old, oldp, sizeof(old));
|
||||
|
|
@ -537,7 +541,7 @@ public:
|
|||
//=============================================================================
|
||||
// VerilatedTraceOffloadBuffer
|
||||
|
||||
// T_Buffer is the format specific base class of VerilatedTraceBuffer.
|
||||
// T_Buffer is the format-specific base class of VerilatedTraceBuffer.
|
||||
// The format-specific hot-path methods use duck-typing via T_Buffer for performance.
|
||||
template <class T_Buffer>
|
||||
class VerilatedTraceOffloadBuffer final : public VerilatedTraceBuffer<T_Buffer> {
|
||||
|
|
@ -605,7 +609,10 @@ public:
|
|||
m_offloadBufferWritep += 4;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgEvent(uint32_t code, const VlEventBase* newval) {
|
||||
void chgEvent(uint32_t code, const VlEventBase* newvalp) {
|
||||
if (newvalp->isTriggered()) chgEventTriggered(code);
|
||||
}
|
||||
void chgEventTriggered(uint32_t code) {
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_EVENT;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep += 2;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
//=============================================================================
|
||||
//
|
||||
// Verilated tracing implementation code template common to all formats.
|
||||
// This file is included by the format specific implementations and
|
||||
// This file is included by the format-specific implementations and
|
||||
// should not be used otherwise.
|
||||
//
|
||||
//=============================================================================
|
||||
|
|
@ -169,7 +169,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
|||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_EVENT:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top);
|
||||
traceBufp->chgEvent(oldp, reinterpret_cast<const VlEventBase*>(readp));
|
||||
traceBufp->chgEventTriggered(oldp);
|
||||
continue;
|
||||
|
||||
//===
|
||||
|
|
@ -299,7 +299,7 @@ VerilatedTrace<VL_SUB_T, VL_BUF_T>::~VerilatedTrace() {
|
|||
}
|
||||
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
// Internals available to format-specific implementations
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
||||
|
|
@ -401,7 +401,7 @@ bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const std::stri
|
|||
}
|
||||
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
// Internals available to format-specific implementations
|
||||
|
||||
template <>
|
||||
std::string VerilatedTrace<VL_SUB_T, VL_BUF_T>::timeResStr() const {
|
||||
|
|
@ -543,7 +543,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
|
|||
|
||||
Verilated::quiesce();
|
||||
|
||||
// Call hook for format specific behaviour
|
||||
// Call hook for format-specific behaviour
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
if (!preFullDump()) return;
|
||||
} else {
|
||||
|
|
@ -667,7 +667,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addModel(VerilatedModel* modelp)
|
|||
VL_FATAL_MT(__FILE__, __LINE__, "", "Cannot use parallel tracing with offloading");
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
// Configure format specific sub class
|
||||
// Configure format-specific sub class
|
||||
configure(*(configp.get()));
|
||||
}
|
||||
|
||||
|
|
@ -818,8 +818,8 @@ VerilatedTraceBuffer<VL_BUF_T>::VerilatedTraceBuffer(Trace& owner)
|
|||
, m_sigs_enabledp{owner.m_sigs_enabledp} {}
|
||||
|
||||
// These functions must write the new value back into the old value store,
|
||||
// and subsequently call the format specific emit* implementations. Note
|
||||
// that this file must be included in the format specific implementation, so
|
||||
// and subsequently call the format-specific emit* implementations. Note
|
||||
// that this file must be included in the format-specific implementation, so
|
||||
// the emit* functions can be inlined for performance.
|
||||
|
||||
template <>
|
||||
|
|
@ -831,10 +831,17 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
|
|||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, const VlEventBase* newval) {
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, const VlEventBase* newvalp) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*oldp = 1; // Do we really store an "event" ?
|
||||
emitEvent(code, newval);
|
||||
// No need to update *oldp
|
||||
if (newvalp->isTriggered()) emitEvent(code);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullEventTriggered(uint32_t* oldp) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
// No need to update *oldp
|
||||
emitEvent(code);
|
||||
}
|
||||
|
||||
template <>
|
||||
|
|
|
|||
|
|
@ -485,6 +485,8 @@ private:
|
|||
|
||||
public:
|
||||
using const_iterator = typename Deque::const_iterator;
|
||||
template <class Func>
|
||||
using WithFuncReturnType = decltype(std::declval<Func>()(0, std::declval<T_Value>()));
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
|
|
@ -593,18 +595,28 @@ public:
|
|||
return v;
|
||||
}
|
||||
|
||||
// Setting. Verilog: assoc[index] = v
|
||||
// Can't just overload operator[] or provide a "at" reference to set,
|
||||
// because we need to be able to insert only when the value is set
|
||||
T_Value& at(int32_t index) {
|
||||
// Setting. Verilog: assoc[index] = v (should only be used by dynamic arrays)
|
||||
T_Value& atWrite(int32_t index) {
|
||||
// cppcheck-suppress variableScope
|
||||
static thread_local T_Value t_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
|
||||
t_throwAway = atDefault();
|
||||
return t_throwAway;
|
||||
} else {
|
||||
return m_deque[index];
|
||||
}
|
||||
return m_deque[index];
|
||||
}
|
||||
// Setting. Verilog: assoc[index] = v (should only be used by queues)
|
||||
T_Value& atWriteAppend(int32_t index) {
|
||||
// cppcheck-suppress variableScope
|
||||
static thread_local T_Value t_throwAway;
|
||||
if (VL_UNLIKELY(index < 0 || index > m_deque.size())) {
|
||||
t_throwAway = atDefault();
|
||||
return t_throwAway;
|
||||
} else if (VL_UNLIKELY(index == m_deque.size())) {
|
||||
push_back(atDefault());
|
||||
}
|
||||
return m_deque[index];
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(int32_t index) const {
|
||||
|
|
@ -616,7 +628,7 @@ public:
|
|||
}
|
||||
}
|
||||
// Access with an index counted from end (e.g. q[$])
|
||||
T_Value& atBack(int32_t index) { return at(m_deque.size() - 1 - index); }
|
||||
T_Value& atWriteAppendBack(int32_t index) { return atWriteAppend(m_deque.size() - 1 - index); }
|
||||
const T_Value& atBack(int32_t index) const { return at(m_deque.size() - 1 - index); }
|
||||
|
||||
// function void q.insert(index, value);
|
||||
|
|
@ -821,70 +833,63 @@ public:
|
|||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_sum(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
WithFuncReturnType<Func> r_sum(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out += with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_product() const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.cbegin();
|
||||
T_Value out{*it};
|
||||
++it;
|
||||
for (; it != m_deque.cend(); ++it) out *= *it;
|
||||
if (m_deque.empty()) return T_Value(0); // The big three do it this way
|
||||
T_Value out = T_Value(1);
|
||||
for (const auto& i : m_deque) out *= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_product(Func with_func) const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.cbegin();
|
||||
WithFuncReturnType<Func> r_product(Func with_func) const {
|
||||
if (m_deque.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1);
|
||||
IData index = 0;
|
||||
T_Value out{with_func(index, *it)};
|
||||
++it;
|
||||
++index;
|
||||
for (; it != m_deque.cend(); ++it) out *= with_func(index++, *it);
|
||||
for (const auto& i : m_deque) out *= with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_and() const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.cbegin();
|
||||
T_Value out{*it};
|
||||
++it;
|
||||
for (; it != m_deque.cend(); ++it) out &= *it;
|
||||
if (m_deque.empty()) return T_Value(0); // The big three do it this way
|
||||
T_Value out = ~T_Value(0);
|
||||
for (const auto& i : m_deque) out &= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_and(Func with_func) const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.cbegin();
|
||||
WithFuncReturnType<Func> r_and(Func with_func) const {
|
||||
if (m_deque.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
IData index = 0;
|
||||
T_Value out{with_func(index, *it)};
|
||||
++it;
|
||||
++index;
|
||||
for (; it != m_deque.cend(); ++it) out &= with_func(index, *it);
|
||||
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0);
|
||||
for (const auto& i : m_deque) out &= with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_or() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_deque) out |= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_or(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
WithFuncReturnType<Func> r_or(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out |= with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_xor() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
#ifdef VERILATOR_BIG3_NULLARY_ARITHMETICS_QUIRKS
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
#endif
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_deque) out ^= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_xor(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
WithFuncReturnType<Func> r_xor(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out ^= with_func(index++, i);
|
||||
return out;
|
||||
|
|
@ -921,6 +926,9 @@ private:
|
|||
|
||||
public:
|
||||
using const_iterator = typename Map::const_iterator;
|
||||
template <class Func>
|
||||
using WithFuncReturnType
|
||||
= decltype(std::declval<Func>()(std::declval<T_Key>(), std::declval<T_Value>()));
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
|
|
@ -1167,64 +1175,56 @@ public:
|
|||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_sum(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
WithFuncReturnType<Func> r_sum(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
for (const auto& i : m_map) out += with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_product() const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.cbegin();
|
||||
T_Value out{it->second};
|
||||
++it;
|
||||
for (; it != m_map.cend(); ++it) out *= it->second;
|
||||
if (m_map.empty()) return T_Value(0); // The big three do it this way
|
||||
T_Value out = T_Value(1);
|
||||
for (const auto& i : m_map) out *= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_product(Func with_func) const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.cbegin();
|
||||
T_Value out{with_func(it->first, it->second)};
|
||||
++it;
|
||||
for (; it != m_map.cend(); ++it) out *= with_func(it->first, it->second);
|
||||
WithFuncReturnType<Func> r_product(Func with_func) const {
|
||||
if (m_map.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1);
|
||||
for (const auto& i : m_map) out *= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_and() const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.cbegin();
|
||||
T_Value out{it->second};
|
||||
++it;
|
||||
for (; it != m_map.cend(); ++it) out &= it->second;
|
||||
if (m_map.empty()) return T_Value(0); // The big three do it this way
|
||||
T_Value out = ~T_Value(0);
|
||||
for (const auto& i : m_map) out &= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_and(Func with_func) const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.cbegin();
|
||||
T_Value out{with_func(it->first, it->second)};
|
||||
++it;
|
||||
for (; it != m_map.cend(); ++it) out &= with_func(it->first, it->second);
|
||||
WithFuncReturnType<Func> r_and(Func with_func) const {
|
||||
if (m_map.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0);
|
||||
for (const auto& i : m_map) out &= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_or() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_map) out |= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_or(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_map) out |= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_xor() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_map) out ^= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_xor(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
WithFuncReturnType<Func> r_xor(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
for (const auto& i : m_map) out ^= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
|
|
@ -1312,6 +1312,43 @@ public:
|
|||
WData* data() { return &m_storage[0]; }
|
||||
const WData* data() const { return &m_storage[0]; }
|
||||
|
||||
std::size_t size() const { return T_Depth; }
|
||||
// To fit C++14
|
||||
template <std::size_t CurrentDimension = 0, typename U = T_Value>
|
||||
int find_length(int dimension, std::false_type) const {
|
||||
return size();
|
||||
}
|
||||
|
||||
template <std::size_t CurrentDimension = 0, typename U = T_Value>
|
||||
int find_length(int dimension, std::true_type) const {
|
||||
if (dimension == CurrentDimension) {
|
||||
return size();
|
||||
} else {
|
||||
return m_storage[0].template find_length<CurrentDimension + 1>(dimension);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t CurrentDimension = 0>
|
||||
int find_length(int dimension) const {
|
||||
return find_length<CurrentDimension>(dimension, std::is_class<T_Value>{});
|
||||
}
|
||||
|
||||
template <std::size_t CurrentDimension = 0, typename U = T_Value>
|
||||
auto& find_element(const std::vector<size_t>& indices, std::false_type) {
|
||||
return m_storage[indices[CurrentDimension]];
|
||||
}
|
||||
|
||||
template <std::size_t CurrentDimension = 0, typename U = T_Value>
|
||||
auto& find_element(const std::vector<size_t>& indices, std::true_type) {
|
||||
return m_storage[indices[CurrentDimension]].template find_element<CurrentDimension + 1>(
|
||||
indices);
|
||||
}
|
||||
|
||||
template <std::size_t CurrentDimension = 0>
|
||||
auto& find_element(const std::vector<size_t>& indices) {
|
||||
return find_element<CurrentDimension>(indices, std::is_class<T_Value>{});
|
||||
}
|
||||
|
||||
T_Value& operator[](size_t index) { return m_storage[index]; }
|
||||
const T_Value& operator[](size_t index) const { return m_storage[index]; }
|
||||
|
||||
|
|
@ -1794,9 +1831,9 @@ public:
|
|||
|
||||
struct VlNull final {
|
||||
operator bool() const { return false; }
|
||||
bool operator==(void* ptr) const { return !ptr; }
|
||||
bool operator==(const void* ptr) const { return !ptr; }
|
||||
};
|
||||
inline bool operator==(void* ptr, VlNull) { return !ptr; }
|
||||
inline bool operator==(const void* ptr, VlNull) { return !ptr; }
|
||||
|
||||
//===================================================================
|
||||
// Verilog class reference container
|
||||
|
|
|
|||
|
|
@ -305,8 +305,22 @@ void VerilatedVcd::printIndent(int level_change) {
|
|||
}
|
||||
|
||||
void VerilatedVcd::pushPrefix(const std::string& name, VerilatedTracePrefixType type) {
|
||||
std::string newPrefix = m_prefixStack.back().first + name;
|
||||
assert(!m_prefixStack.empty()); // Constructor makes an empty entry
|
||||
std::string pname = name;
|
||||
// An empty name means this is the root of a model created with name()=="". The
|
||||
// tools get upset if we try to pass this as empty, so we put the signals under a
|
||||
// new scope, but the signals further down will be peers, not children (as usual
|
||||
// for name()!="")
|
||||
// Terminate earlier $root?
|
||||
if (m_prefixStack.back().second == VerilatedTracePrefixType::ROOTIO_MODULE) popPrefix();
|
||||
if (pname.empty()) { // Start new temporary root
|
||||
pname = "$rootio"; // VCD names are not backslash escaped
|
||||
m_prefixStack.emplace_back("", VerilatedTracePrefixType::ROOTIO_WRAPPER);
|
||||
type = VerilatedTracePrefixType::ROOTIO_MODULE;
|
||||
}
|
||||
std::string newPrefix = m_prefixStack.back().first + pname;
|
||||
switch (type) {
|
||||
case VerilatedTracePrefixType::ROOTIO_MODULE:
|
||||
case VerilatedTracePrefixType::SCOPE_MODULE:
|
||||
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||
|
|
@ -326,7 +340,9 @@ void VerilatedVcd::pushPrefix(const std::string& name, VerilatedTracePrefixType
|
|||
}
|
||||
|
||||
void VerilatedVcd::popPrefix() {
|
||||
assert(!m_prefixStack.empty());
|
||||
switch (m_prefixStack.back().second) {
|
||||
case VerilatedTracePrefixType::ROOTIO_MODULE:
|
||||
case VerilatedTracePrefixType::SCOPE_MODULE:
|
||||
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||
|
|
@ -338,7 +354,7 @@ void VerilatedVcd::popPrefix() {
|
|||
default: break;
|
||||
}
|
||||
m_prefixStack.pop_back();
|
||||
assert(!m_prefixStack.empty());
|
||||
assert(!m_prefixStack.empty()); // Always one left, the constructor's initial one
|
||||
}
|
||||
|
||||
void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, bool array,
|
||||
|
|
@ -573,16 +589,11 @@ void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) {
|
|||
// so always inline them.
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedVcdBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
|
||||
const bool triggered = newval->isTriggered();
|
||||
// TODO : It seems that untriggered events are not filtered
|
||||
// should be tested before this last step
|
||||
if (triggered) {
|
||||
// Don't prefetch suffix as it's a bit too late;
|
||||
char* wp = m_writep;
|
||||
*wp++ = '1';
|
||||
finishLine(code, wp);
|
||||
}
|
||||
void VerilatedVcdBuffer::emitEvent(uint32_t code) {
|
||||
// Don't prefetch suffix as it's a bit too late;
|
||||
char* wp = m_writep;
|
||||
*wp++ = '1';
|
||||
finishLine(code, wp);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ private:
|
|||
friend VerilatedVcdBuffer; // Give the buffer access to the private bits
|
||||
|
||||
//=========================================================================
|
||||
// VCD specific internals
|
||||
// VCD-specific internals
|
||||
|
||||
VerilatedVcdFile* m_filep; // File we're writing to
|
||||
bool m_fileNewed; // m_filep needs destruction
|
||||
|
|
@ -214,7 +214,7 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
|
|||
// Implementation of VerilatedTraceBuffer interface
|
||||
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||
// called from only one place (the full* methods), so always inline them.
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, const VlEventBase* newval);
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code);
|
||||
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
|
||||
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
||||
|
|
|
|||
|
|
@ -896,6 +896,9 @@ public:
|
|||
if (VL_LIKELY(it != s().m_futureCbs.cend())) return it->first.first;
|
||||
return ~0ULL; // maxquad
|
||||
}
|
||||
static bool hasCbs(const uint32_t reason) VL_MT_UNSAFE_ONE {
|
||||
return !s().m_cbCurrentLists[reason].empty();
|
||||
}
|
||||
static bool callCbs(const uint32_t reason) VL_MT_UNSAFE_ONE {
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: callCbs reason=%u\n", reason););
|
||||
assertOneCheck();
|
||||
|
|
@ -1056,6 +1059,10 @@ bool VerilatedVpi::callCbs(uint32_t reason) VL_MT_UNSAFE_ONE {
|
|||
return VerilatedVpiImp::callCbs(reason);
|
||||
}
|
||||
|
||||
bool VerilatedVpi::hasCbs(uint32_t reason) VL_MT_UNSAFE_ONE {
|
||||
return VerilatedVpiImp::hasCbs(reason);
|
||||
}
|
||||
|
||||
// Historical, before we had multiple kinds of timed callbacks
|
||||
void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callCbs(cbAfterDelay); }
|
||||
|
||||
|
|
@ -2468,7 +2475,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
vl_strprintf(t_outDynamicStr, "%u",
|
||||
static_cast<unsigned int>(*(reinterpret_cast<IData*>(varDatap))));
|
||||
} else if (varp->vltype() == VLVT_UINT64) {
|
||||
vl_strprintf(t_outDynamicStr, "%llu",
|
||||
vl_strprintf(t_outDynamicStr, "%llu", // lintok-format-ll
|
||||
static_cast<unsigned long long>(*(reinterpret_cast<QData*>(varDatap))));
|
||||
}
|
||||
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||
|
|
@ -2690,7 +2697,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
} else if (valuep->format == vpiDecStrVal) {
|
||||
char remainder[16];
|
||||
unsigned long long val;
|
||||
const int success = std::sscanf(valuep->value.str, "%30llu%15s", &val, remainder);
|
||||
const int success = std::sscanf(valuep->value.str, "%30llu%15s", // lintok-format-ll
|
||||
&val, remainder);
|
||||
if (success < 1) {
|
||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
|
||||
__func__, valuep->value.str,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@ public:
|
|||
/// Call callbacks of arbitrary types.
|
||||
/// User wrapper code should call this from their main loops.
|
||||
static bool callCbs(uint32_t reason) VL_MT_UNSAFE_ONE;
|
||||
/// Returns true if there are callbacks of the given reason registered.
|
||||
/// User wrapper code should call this from their main loops.
|
||||
static bool hasCbs(uint32_t reason) VL_MT_UNSAFE_ONE;
|
||||
/// Returns time of the next registered VPI callback, or
|
||||
/// ~(0ULL) if none are registered
|
||||
static QData cbNextDeadline() VL_MT_UNSAFE_ONE;
|
||||
|
|
|
|||
|
|
@ -200,6 +200,11 @@
|
|||
|
||||
// Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
||||
#define VL_PURE VL_CLANG_ATTR(annotate("PURE"))
|
||||
// Annotated function can be called only in MT_DISABLED context, i.e. either in a code unit
|
||||
// compiled with VL_MT_DISABLED_CODE_UNIT preprocessor definition, or in the main thread.
|
||||
#define VL_MT_DISABLED \
|
||||
VL_CLANG_ATTR(annotate("MT_DISABLED")) \
|
||||
VL_EXCLUDES(VlOs::MtScopeMutex::s_haveThreadScope)
|
||||
// Comment tag that function is threadsafe
|
||||
#define VL_MT_SAFE VL_CLANG_ATTR(annotate("MT_SAFE"))
|
||||
// Comment tag that function is threadsafe, only if
|
||||
|
|
@ -216,7 +221,7 @@
|
|||
// protected to make sure single-caller
|
||||
#define VL_MT_UNSAFE_ONE VL_CLANG_ATTR(annotate("MT_UNSAFE_ONE"))
|
||||
// Comment tag that function is entry point of parallelization
|
||||
#define VL_MT_START VL_CLANG_ATTR(annotate("MT_START"))
|
||||
#define VL_MT_START VL_CLANG_ATTR(annotate("MT_START")) VL_REQUIRES(VlOs::MtScopeMutex::s_haveThreadScope)
|
||||
|
||||
#ifndef VL_NO_LEGACY
|
||||
# define VL_ULL(c) (c##ULL) // Add appropriate suffix to 64-bit constant (deprecated)
|
||||
|
|
@ -463,8 +468,6 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
|
|||
#define VL_VALUE_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
||||
#endif
|
||||
|
||||
#define VL_VALUE_STRING_MAX_CHARS (VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE / VL_BYTESIZE)
|
||||
|
||||
//=========================================================================
|
||||
// Base macros
|
||||
|
||||
|
|
@ -588,9 +591,9 @@ static inline double VL_ROUND(double n) {
|
|||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Macros controlling target specific optimizations
|
||||
// Macros controlling target-specific optimizations
|
||||
|
||||
// Define VL_PORTABLE_ONLY to disable all target specific optimizations
|
||||
// Define VL_PORTABLE_ONLY to disable all target-specific optimizations
|
||||
#ifndef VL_PORTABLE_ONLY
|
||||
# ifdef __x86_64__
|
||||
# define VL_X86_64 1
|
||||
|
|
@ -653,6 +656,14 @@ public:
|
|||
return (m_start == 0.0) ? 0.0 : gettime() - m_start;
|
||||
}
|
||||
};
|
||||
|
||||
// Used by clang's -fthread-safety, ensures that only one instance of V3ThreadScope
|
||||
// is created at a time
|
||||
class VL_CAPABILITY("mutex") MtScopeMutex final {
|
||||
public:
|
||||
static MtScopeMutex s_haveThreadScope;
|
||||
};
|
||||
|
||||
} //namespace VlOs
|
||||
|
||||
//=========================================================================
|
||||
|
|
|
|||
|
|
@ -48,9 +48,11 @@ def fully_qualified_name(node):
|
|||
if node.kind == CursorKind.TRANSLATION_UNIT:
|
||||
return []
|
||||
res = fully_qualified_name(node.semantic_parent)
|
||||
displayname = node.displayname
|
||||
displayname = [displayname] if displayname else []
|
||||
if res:
|
||||
return res + ([node.displayname] if node.displayname else [])
|
||||
return [node.displayname] if node.displayname else []
|
||||
return res + displayname
|
||||
return displayname
|
||||
|
||||
|
||||
# Returns True, if `class_node` contains node
|
||||
|
|
@ -106,9 +108,8 @@ class VlAnnotations:
|
|||
|
||||
def is_mt_safe_call(self):
|
||||
return (not self.is_mt_unsafe_call()
|
||||
and (self.mt_safe or self.mt_safe_postinit or self.pure
|
||||
or self.requires or self.excludes or self.acquire
|
||||
or self.release))
|
||||
and (self.mt_safe or self.mt_safe_postinit or self.pure or self.requires
|
||||
or self.excludes or self.acquire or self.release))
|
||||
|
||||
def is_pure_call(self):
|
||||
return self.pure
|
||||
|
|
@ -140,31 +141,32 @@ class VlAnnotations:
|
|||
result = VlAnnotations()
|
||||
for node in nodes:
|
||||
if node.kind == CursorKind.ANNOTATE_ATTR:
|
||||
if node.displayname == "MT_START":
|
||||
displayname = node.displayname
|
||||
if displayname == "MT_START":
|
||||
result.mt_start = True
|
||||
elif node.displayname == "MT_SAFE":
|
||||
elif displayname == "MT_SAFE":
|
||||
result.mt_safe = True
|
||||
elif node.displayname == "MT_STABLE":
|
||||
elif displayname == "MT_STABLE":
|
||||
result.stable_tree = True
|
||||
elif node.displayname == "MT_SAFE_POSTINIT":
|
||||
elif displayname == "MT_SAFE_POSTINIT":
|
||||
result.mt_safe_postinit = True
|
||||
elif node.displayname == "MT_UNSAFE":
|
||||
elif displayname == "MT_UNSAFE":
|
||||
result.mt_unsafe = True
|
||||
elif node.displayname == "MT_UNSAFE_ONE":
|
||||
elif displayname == "MT_UNSAFE_ONE":
|
||||
result.mt_unsafe_one = True
|
||||
elif node.displayname == "MT_DISABLED":
|
||||
elif displayname == "MT_DISABLED":
|
||||
result.mt_disabled = True
|
||||
elif node.displayname == "PURE":
|
||||
elif displayname == "PURE":
|
||||
result.pure = True
|
||||
elif node.displayname in ["ACQUIRE", "ACQUIRE_SHARED"]:
|
||||
elif displayname in ["ACQUIRE", "ACQUIRE_SHARED"]:
|
||||
result.acquire = True
|
||||
elif node.displayname in ["RELEASE", "RELEASE_SHARED"]:
|
||||
elif displayname in ["RELEASE", "RELEASE_SHARED"]:
|
||||
result.release = True
|
||||
elif node.displayname == "REQUIRES":
|
||||
elif displayname == "REQUIRES":
|
||||
result.requires = True
|
||||
elif node.displayname in ["EXCLUDES", "MT_SAFE_EXCLUDES"]:
|
||||
elif displayname in ["EXCLUDES", "MT_SAFE_EXCLUDES"]:
|
||||
result.excludes = True
|
||||
elif node.displayname == "GUARDED_BY":
|
||||
elif displayname == "GUARDED_BY":
|
||||
result.guarded = True
|
||||
# Attributes are always at the beginning
|
||||
elif not node.kind.is_attribute():
|
||||
|
|
@ -203,9 +205,7 @@ class FunctionInfo:
|
|||
annotations: VlAnnotations
|
||||
ftype: FunctionType
|
||||
|
||||
_hash: Optional[int] = dataclasses.field(default=None,
|
||||
init=False,
|
||||
repr=False)
|
||||
_hash: Optional[int] = dataclasses.field(default=None, init=False, repr=False)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
|
@ -220,15 +220,13 @@ class FunctionInfo:
|
|||
return self._hash
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.usr == other.usr and self.file == other.file
|
||||
and self.line == other.line)
|
||||
return (self.usr == other.usr and self.file == other.file and self.line == other.line)
|
||||
|
||||
def copy(self, /, **changes):
|
||||
return dataclasses.replace(self, **changes)
|
||||
|
||||
@staticmethod
|
||||
def from_decl_file_line_and_refd_node(file: str, line: int,
|
||||
refd: clang.cindex.Cursor,
|
||||
def from_decl_file_line_and_refd_node(file: str, line: int, refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
file = os.path.abspath(file)
|
||||
refd = refd.canonical
|
||||
|
|
@ -277,14 +275,11 @@ class Diagnostic:
|
|||
source_ctx: FunctionInfo
|
||||
kind: DiagnosticKind
|
||||
|
||||
_hash: Optional[int] = dataclasses.field(default=None,
|
||||
init=False,
|
||||
repr=False)
|
||||
_hash: Optional[int] = dataclasses.field(default=None, init=False, repr=False)
|
||||
|
||||
def __hash__(self):
|
||||
if not self._hash:
|
||||
self._hash = hash(
|
||||
hash(self.target) ^ hash(self.source_ctx) ^ hash(self.kind))
|
||||
self._hash = hash(hash(self.target) ^ hash(self.source_ctx) ^ hash(self.kind))
|
||||
return self._hash
|
||||
|
||||
|
||||
|
|
@ -292,9 +287,9 @@ class CallAnnotationsValidator:
|
|||
|
||||
def __init__(self, diagnostic_cb: Callable[[Diagnostic], None],
|
||||
is_ignored_top_level: Callable[[clang.cindex.Cursor], bool],
|
||||
is_ignored_def: Callable[
|
||||
[clang.cindex.Cursor, clang.cindex.Cursor], bool],
|
||||
is_ignored_call: Callable[[clang.cindex.Cursor], bool]):
|
||||
is_ignored_def: Callable[[clang.cindex.Cursor, clang.cindex.Cursor],
|
||||
bool], is_ignored_call: Callable[[clang.cindex.Cursor],
|
||||
bool]):
|
||||
self._diagnostic_cb = diagnostic_cb
|
||||
self._is_ignored_top_level = is_ignored_top_level
|
||||
self._is_ignored_call = is_ignored_call
|
||||
|
|
@ -312,6 +307,7 @@ class CallAnnotationsValidator:
|
|||
self._defines: dict[str, str] = {}
|
||||
self._call_location: Optional[FunctionInfo] = None
|
||||
self._caller: Optional[FunctionInfo] = None
|
||||
self._base_func_declarations: dict[str, clang.cindex.Cursor] = {}
|
||||
self._constructor_context: list[clang.cindex.Cursor] = []
|
||||
self._level: int = 0
|
||||
|
||||
|
|
@ -329,8 +325,7 @@ class CallAnnotationsValidator:
|
|||
with open(source_file, "r", encoding="utf-8") as file:
|
||||
for line in file:
|
||||
line = line.strip()
|
||||
match = re.fullmatch(
|
||||
r"^#\s*(define\s+(\w+)(?:\s+(.*))?|include\s+.*)$", line)
|
||||
match = re.fullmatch(r"^#\s*(define\s+(\w+)(?:\s+(.*))?|include\s+.*)$", line)
|
||||
if match:
|
||||
if match.group(1).startswith("define"):
|
||||
key = match.group(2)
|
||||
|
|
@ -341,16 +336,14 @@ class CallAnnotationsValidator:
|
|||
return defs
|
||||
|
||||
@staticmethod
|
||||
def filter_out_unsupported_compiler_args(
|
||||
args: list[str]) -> tuple[list[str], dict[str, str]]:
|
||||
def filter_out_unsupported_compiler_args(args: list[str]) -> tuple[list[str], dict[str, str]]:
|
||||
filtered_args = []
|
||||
defines = {}
|
||||
args_iter = iter(args)
|
||||
try:
|
||||
while arg := next(args_iter):
|
||||
# Skip positional arguments (input file name).
|
||||
if not arg.startswith("-") and (arg.endswith(".cpp")
|
||||
or arg.endswith(".c")
|
||||
if not arg.startswith("-") and (arg.endswith(".cpp") or arg.endswith(".c")
|
||||
or arg.endswith(".h")):
|
||||
continue
|
||||
|
||||
|
|
@ -367,8 +360,7 @@ class CallAnnotationsValidator:
|
|||
# Preserved options with separate value argument.
|
||||
if arg in [
|
||||
"-x"
|
||||
"-Xclang", "-I", "-isystem", "-iquote", "-include",
|
||||
"-include-pch"
|
||||
"-Xclang", "-I", "-isystem", "-iquote", "-include", "-include-pch"
|
||||
]:
|
||||
filtered_args += [arg, next(args_iter)]
|
||||
continue
|
||||
|
|
@ -406,14 +398,12 @@ class CallAnnotationsValidator:
|
|||
|
||||
return (filtered_args, defines)
|
||||
|
||||
def compile_and_analyze_file(self, source_file: str,
|
||||
compiler_args: list[str],
|
||||
def compile_and_analyze_file(self, source_file: str, compiler_args: list[str],
|
||||
build_dir: Optional[str]):
|
||||
filename = os.path.abspath(source_file)
|
||||
initial_cwd = "."
|
||||
|
||||
filtered_args, defines = self.filter_out_unsupported_compiler_args(
|
||||
compiler_args)
|
||||
filtered_args, defines = self.filter_out_unsupported_compiler_args(compiler_args)
|
||||
defines.update(self.parse_initial_defines(source_file))
|
||||
|
||||
if build_dir:
|
||||
|
|
@ -451,8 +441,7 @@ class CallAnnotationsValidator:
|
|||
self._diagnostic_cb(Diagnostic(target, source, source_ctx, kind))
|
||||
else:
|
||||
self._diagnostic_cb(
|
||||
Diagnostic(FunctionInfo.from_node(target), source, source_ctx,
|
||||
kind))
|
||||
Diagnostic(FunctionInfo.from_node(target), source, source_ctx, kind))
|
||||
|
||||
def iterate_children(self, children: Iterable[clang.cindex.Cursor],
|
||||
handler: Callable[[clang.cindex.Cursor], None]):
|
||||
|
|
@ -465,8 +454,7 @@ class CallAnnotationsValidator:
|
|||
@staticmethod
|
||||
def get_referenced_node_info(
|
||||
node: clang.cindex.Cursor
|
||||
) -> tuple[bool, Optional[clang.cindex.Cursor], VlAnnotations,
|
||||
Iterable[clang.cindex.Cursor]]:
|
||||
) -> tuple[bool, Optional[clang.cindex.Cursor], VlAnnotations, Iterable[clang.cindex.Cursor]]:
|
||||
if not node.spelling and not node.displayname:
|
||||
return (False, None, VlAnnotations(), [])
|
||||
|
||||
|
|
@ -480,8 +468,7 @@ class CallAnnotationsValidator:
|
|||
annotations = VlAnnotations.from_nodes_list(children)
|
||||
return (True, refd, annotations, children)
|
||||
|
||||
def check_mt_safe_call(self, node: clang.cindex.Cursor,
|
||||
refd: clang.cindex.Cursor,
|
||||
def check_mt_safe_call(self, node: clang.cindex.Cursor, refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
is_mt_safe = False
|
||||
|
||||
|
|
@ -513,8 +500,7 @@ class CallAnnotationsValidator:
|
|||
# we are calling local method. It is MT safe
|
||||
# only if this method is also only calling local methods or
|
||||
# MT-safe methods
|
||||
self.iterate_children(refd.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition)
|
||||
is_mt_safe = True
|
||||
# class/struct member
|
||||
elif refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced:
|
||||
|
|
@ -525,18 +511,15 @@ class CallAnnotationsValidator:
|
|||
if self.is_constructor_context() and refn.semantic_parent:
|
||||
# we are in constructor, so calling local members is MT_SAFE,
|
||||
# make sure object that we are calling is local to the constructor
|
||||
constructor_class = self._constructor_context[
|
||||
-1].semantic_parent
|
||||
constructor_class = self._constructor_context[-1].semantic_parent
|
||||
if refn.semantic_parent.spelling == constructor_class.spelling:
|
||||
if check_class_member_exists(constructor_class, refn):
|
||||
is_mt_safe = True
|
||||
else:
|
||||
# check if this class inherits from some base class
|
||||
base_class = get_base_class(constructor_class,
|
||||
refn.semantic_parent)
|
||||
base_class = get_base_class(constructor_class, refn.semantic_parent)
|
||||
if base_class:
|
||||
if check_class_member_exists(
|
||||
base_class.get_declaration(), refn):
|
||||
if check_class_member_exists(base_class.get_declaration(), refn):
|
||||
is_mt_safe = True
|
||||
# variable
|
||||
elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced:
|
||||
|
|
@ -567,8 +550,7 @@ class CallAnnotationsValidator:
|
|||
|
||||
# Call handling
|
||||
|
||||
def process_method_call(self, node: clang.cindex.Cursor,
|
||||
refd: clang.cindex.Cursor,
|
||||
def process_method_call(self, node: clang.cindex.Cursor, refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
assert self._call_location
|
||||
ctx = self._call_location.annotations
|
||||
|
|
@ -576,58 +558,48 @@ class CallAnnotationsValidator:
|
|||
# MT-safe context
|
||||
if ctx.is_mt_safe_context():
|
||||
if not self.check_mt_safe_call(node, refd, annotations):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
if annotations.is_mt_unsafe_call() or not (
|
||||
annotations.is_stabe_tree_call()
|
||||
or annotations.is_pure_call()
|
||||
annotations.is_stabe_tree_call() or annotations.is_pure_call()
|
||||
or self.check_mt_safe_call(node, refd, annotations)):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call():
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
|
||||
def process_function_call(self, refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
def process_function_call(self, refd: clang.cindex.Cursor, annotations: VlAnnotations):
|
||||
assert self._call_location
|
||||
ctx = self._call_location.annotations
|
||||
|
||||
# MT-safe context
|
||||
if ctx.is_mt_safe_context():
|
||||
if not annotations.is_mt_safe_call():
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
if annotations.is_mt_unsafe_call() or not (
|
||||
annotations.is_pure_call()
|
||||
or annotations.is_mt_safe_call()
|
||||
or annotations.is_stabe_tree_call()):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
if annotations.is_mt_unsafe_call() or not (annotations.is_pure_call()
|
||||
or annotations.is_mt_safe_call()
|
||||
or annotations.is_stabe_tree_call()):
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call():
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
|
||||
def process_constructor_call(self, refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
def process_constructor_call(self, refd: clang.cindex.Cursor, annotations: VlAnnotations):
|
||||
assert self._call_location
|
||||
ctx = self._call_location.annotations
|
||||
|
||||
|
|
@ -635,31 +607,26 @@ class CallAnnotationsValidator:
|
|||
# only if they call local methods or MT-safe functions.
|
||||
if ctx.is_mt_safe_context() or self.is_constructor_context():
|
||||
self._constructor_context.append(refd)
|
||||
self.iterate_children(refd.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition)
|
||||
self._constructor_context.pop()
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
self._constructor_context.append(refd)
|
||||
self.iterate_children(refd.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition)
|
||||
self._constructor_context.pop()
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call(
|
||||
) and not refd.is_default_constructor():
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
if not annotations.is_pure_call() and not refd.is_default_constructor():
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
|
||||
def dispatch_call_node(self, node: clang.cindex.Cursor):
|
||||
[supported, refd, annotations, _] = self.get_referenced_node_info(node)
|
||||
|
||||
if not supported:
|
||||
self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self.iterate_children(node.get_children(), self.dispatch_node_inside_definition)
|
||||
return True
|
||||
|
||||
assert refd is not None
|
||||
|
|
@ -676,19 +643,14 @@ class CallAnnotationsValidator:
|
|||
|
||||
assert self._call_location is not None
|
||||
node_file = os.path.abspath(node.location.file.name)
|
||||
self._call_location = self._call_location.copy(file=node_file,
|
||||
line=node.location.line)
|
||||
self._call_location = self._call_location.copy(file=node_file, line=node.location.line)
|
||||
|
||||
# Standalone functions and static class methods
|
||||
if (refd.kind == CursorKind.FUNCTION_DECL
|
||||
or refd.kind == CursorKind.CXX_METHOD
|
||||
and refd.is_static_method()):
|
||||
or refd.kind == CursorKind.CXX_METHOD and refd.is_static_method()):
|
||||
self.process_function_call(refd, annotations)
|
||||
# Function pointer
|
||||
elif refd.kind in [
|
||||
CursorKind.VAR_DECL, CursorKind.FIELD_DECL,
|
||||
CursorKind.PARM_DECL
|
||||
]:
|
||||
elif refd.kind in [CursorKind.VAR_DECL, CursorKind.FIELD_DECL, CursorKind.PARM_DECL]:
|
||||
self.process_function_call(refd, annotations)
|
||||
# Non-static class methods
|
||||
elif refd.kind == CursorKind.CXX_METHOD:
|
||||
|
|
@ -726,18 +688,25 @@ class CallAnnotationsValidator:
|
|||
if self.dispatch_call_node(node) is False:
|
||||
return None
|
||||
elif node.is_definition() and node.kind in [
|
||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL,
|
||||
CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION
|
||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, CursorKind.CONSTRUCTOR,
|
||||
CursorKind.CONVERSION_FUNCTION
|
||||
]:
|
||||
self.process_function_definition(node)
|
||||
return None
|
||||
|
||||
return self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
return self.iterate_children(node.get_children(), self.dispatch_node_inside_definition)
|
||||
|
||||
def process_function_definition(self, node: clang.cindex.Cursor):
|
||||
[supported, refd, annotations, _] = self.get_referenced_node_info(node)
|
||||
|
||||
# Fetch virtual annotations from base class.
|
||||
# Set refd to virtual definition if present.
|
||||
signature = node.displayname
|
||||
if signature in self._base_func_declarations:
|
||||
refd = self._base_func_declarations[signature]
|
||||
virtual_annotations = VlAnnotations.from_nodes_list(refd.get_children())
|
||||
annotations = annotations | virtual_annotations
|
||||
|
||||
if refd and self._is_ignored_def(node, refd):
|
||||
return None
|
||||
|
||||
|
|
@ -752,30 +721,29 @@ class CallAnnotationsValidator:
|
|||
# Implicitly mark definitions in VL_MT_DISABLED_CODE_UNIT .cpp files as
|
||||
# VL_MT_DISABLED. Existence of the annotation on declarations in .h
|
||||
# files is verified below.
|
||||
# Also sets VL_REQUIRES, as this annotation is added together with
|
||||
# Also sets VL_EXCLUDES, as this annotation is added together with
|
||||
# explicit VL_MT_DISABLED.
|
||||
if self.is_mt_disabled_code_unit():
|
||||
if node.location.file.name == self._main_source_file:
|
||||
annotations.mt_disabled = True
|
||||
annotations.requires = True
|
||||
annotations.excludes = True
|
||||
if refd.location.file.name == self._main_source_file:
|
||||
def_annotations.mt_disabled = True
|
||||
def_annotations.requires = True
|
||||
def_annotations.excludes = True
|
||||
|
||||
if not (def_annotations.is_empty() or def_annotations == annotations):
|
||||
if def_annotations != annotations:
|
||||
# Use definition's annotations for the diagnostic
|
||||
# source (i.e. the definition)
|
||||
self._caller = FunctionInfo.from_node(node, refd, def_annotations)
|
||||
self._call_location = self._caller
|
||||
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH)
|
||||
|
||||
# Use concatenation of definition and declaration annotations
|
||||
# for calls validation.
|
||||
self._caller = FunctionInfo.from_node(node, refd,
|
||||
def_annotations | annotations)
|
||||
else:
|
||||
# Use concatenation of definition and declaration annotations
|
||||
# for calls validation.
|
||||
self._caller = FunctionInfo.from_node(node, refd, def_annotations | annotations)
|
||||
prev_call_location = self._call_location
|
||||
self._call_location = self._caller
|
||||
|
||||
|
|
@ -793,8 +761,7 @@ class CallAnnotationsValidator:
|
|||
if declarations:
|
||||
del self._external_decls[usr]
|
||||
|
||||
self.iterate_children(node_children,
|
||||
self.dispatch_node_inside_definition)
|
||||
self.iterate_children(node_children, self.dispatch_node_inside_definition)
|
||||
|
||||
self._call_location = prev_call_location
|
||||
self._caller = prev_call_location
|
||||
|
|
@ -804,25 +771,37 @@ class CallAnnotationsValidator:
|
|||
# Nodes not located inside definition
|
||||
|
||||
def dispatch_node(self, node: clang.cindex.Cursor):
|
||||
if node.kind in [
|
||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL,
|
||||
CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION
|
||||
kind = node.kind
|
||||
if kind is CursorKind.CXX_BASE_SPECIFIER:
|
||||
# Get referenced virtual declarations from base class.
|
||||
for base in node.get_children():
|
||||
if base.referenced:
|
||||
for declaration in base.referenced.get_children():
|
||||
self._base_func_declarations[declaration.displayname] = declaration
|
||||
elif kind in [
|
||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, CursorKind.CONSTRUCTOR,
|
||||
CursorKind.CONVERSION_FUNCTION
|
||||
]:
|
||||
if node.is_definition():
|
||||
return self.process_function_definition(node)
|
||||
# else:
|
||||
return self.process_function_declaration(node)
|
||||
|
||||
return self.iterate_children(node.get_children(), self.dispatch_node)
|
||||
result = self.iterate_children(node.get_children(), self.dispatch_node)
|
||||
|
||||
def process_translation_unit(
|
||||
self, translation_unit: clang.cindex.TranslationUnit):
|
||||
# Clean declarations if class declaration processing is finished.
|
||||
if kind in [
|
||||
CursorKind.CLASS_DECL, CursorKind.STRUCT_DECL, CursorKind.UNION_DECL,
|
||||
CursorKind.ENUM_DECL, CursorKind.UNEXPOSED_DECL
|
||||
]:
|
||||
self._base_func_declarations = {}
|
||||
return result
|
||||
|
||||
def process_translation_unit(self, translation_unit: clang.cindex.TranslationUnit):
|
||||
self._level += 1
|
||||
kv_defines = sorted([f"{k}={v}" for k, v in self._defines.items()])
|
||||
concat_defines = '\n'.join(kv_defines)
|
||||
# List of headers already processed in a TU with specified set of defines.
|
||||
tu_processed_headers = self._processed_headers.setdefault(
|
||||
concat_defines, set())
|
||||
tu_processed_headers = self._processed_headers.setdefault(concat_defines, set())
|
||||
for child in translation_unit.cursor.get_children():
|
||||
if self._is_ignored_top_level(child):
|
||||
continue
|
||||
|
|
@ -833,10 +812,8 @@ class CallAnnotationsValidator:
|
|||
self.dispatch_node(child)
|
||||
self._level -= 1
|
||||
|
||||
tu_processed_headers.update([
|
||||
os.path.abspath(str(hdr.source))
|
||||
for hdr in translation_unit.get_includes()
|
||||
])
|
||||
tu_processed_headers.update(
|
||||
[os.path.abspath(str(hdr.source)) for hdr in translation_unit.get_includes()])
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
@ -857,8 +834,7 @@ def get_filter_funcs(verilator_root: str):
|
|||
filename = os.path.abspath(node.location.file.name)
|
||||
return not filename.startswith(verilator_root)
|
||||
|
||||
def is_ignored_def(node: clang.cindex.Cursor,
|
||||
refd: clang.cindex.Cursor) -> bool:
|
||||
def is_ignored_def(node: clang.cindex.Cursor, refd: clang.cindex.Cursor) -> bool:
|
||||
# __*
|
||||
if str(refd.spelling).startswith("__"):
|
||||
return True
|
||||
|
|
@ -901,8 +877,7 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str:
|
|||
os.chdir(compile_command.directory)
|
||||
|
||||
index = Index.create()
|
||||
translation_unit = index.parse(compile_command.filename,
|
||||
compile_command.args)
|
||||
translation_unit = index.parse(compile_command.filename, compile_command.args)
|
||||
for diag in translation_unit.diagnostics:
|
||||
if diag.severity >= clang.cindex.Diagnostic.Error:
|
||||
errors.append(str(diag))
|
||||
|
|
@ -910,23 +885,20 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str:
|
|||
if len(errors) == 0:
|
||||
pch_file = os.path.join(
|
||||
tmp_dir,
|
||||
f"{compile_command.refid:02}_{os.path.basename(compile_command.filename)}.pch"
|
||||
)
|
||||
f"{compile_command.refid:02}_{os.path.basename(compile_command.filename)}.pch")
|
||||
translation_unit.save(pch_file)
|
||||
|
||||
if pch_file:
|
||||
return pch_file
|
||||
|
||||
except (TranslationUnitSaveError, TranslationUnitLoadError,
|
||||
OSError) as exception:
|
||||
except (TranslationUnitSaveError, TranslationUnitLoadError, OSError) as exception:
|
||||
print(f"%Warning: {exception}", file=sys.stderr)
|
||||
|
||||
finally:
|
||||
os.chdir(initial_cwd)
|
||||
|
||||
print(
|
||||
f"%Warning: Precompilation failed, skipping: {compile_command.filename}",
|
||||
file=sys.stderr)
|
||||
print(f"%Warning: Precompilation failed, skipping: {compile_command.filename}",
|
||||
file=sys.stderr)
|
||||
for error in errors:
|
||||
print(f" {error}", file=sys.stderr)
|
||||
return ""
|
||||
|
|
@ -934,10 +906,8 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str:
|
|||
|
||||
# Compile and analyze inputs in a single process.
|
||||
def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
||||
diagnostic_cb: Callable[[Diagnostic],
|
||||
None], verilator_root: str):
|
||||
(is_ignored_top_level, is_ignored_def,
|
||||
is_ignored_call) = get_filter_funcs(verilator_root)
|
||||
diagnostic_cb: Callable[[Diagnostic], None], verilator_root: str):
|
||||
(is_ignored_top_level, is_ignored_def, is_ignored_call) = get_filter_funcs(verilator_root)
|
||||
|
||||
prefix = "verilator_clang_check_attributes_"
|
||||
with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir:
|
||||
|
|
@ -947,8 +917,8 @@ def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
|||
if pch_file:
|
||||
extra_args += ["-include-pch", pch_file]
|
||||
|
||||
cav = CallAnnotationsValidator(diagnostic_cb, is_ignored_top_level,
|
||||
is_ignored_def, is_ignored_call)
|
||||
cav = CallAnnotationsValidator(diagnostic_cb, is_ignored_top_level, is_ignored_def,
|
||||
is_ignored_call)
|
||||
for compile_command in ccl:
|
||||
cav.compile_and_analyze_file(compile_command.filename,
|
||||
extra_args + compile_command.args,
|
||||
|
|
@ -963,12 +933,11 @@ class ParallelAnalysisProcess:
|
|||
|
||||
@staticmethod
|
||||
def init_data(verilator_root: str, tmp_dir: str):
|
||||
(is_ignored_top_level, is_ignored_def,
|
||||
is_ignored_call) = get_filter_funcs(verilator_root)
|
||||
(is_ignored_top_level, is_ignored_def, is_ignored_call) = get_filter_funcs(verilator_root)
|
||||
|
||||
ParallelAnalysisProcess.cav = CallAnnotationsValidator(
|
||||
ParallelAnalysisProcess._diagnostic_handler, is_ignored_top_level,
|
||||
is_ignored_def, is_ignored_call)
|
||||
ParallelAnalysisProcess._diagnostic_handler, is_ignored_top_level, is_ignored_def,
|
||||
is_ignored_call)
|
||||
ParallelAnalysisProcess.tmp_dir = tmp_dir
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -979,31 +948,27 @@ class ParallelAnalysisProcess:
|
|||
def analyze_cpp_file(compile_command: CompileCommand) -> set[Diagnostic]:
|
||||
ParallelAnalysisProcess.diags = set()
|
||||
assert ParallelAnalysisProcess.cav is not None
|
||||
ParallelAnalysisProcess.cav.compile_and_analyze_file(
|
||||
compile_command.filename, compile_command.args,
|
||||
compile_command.directory)
|
||||
ParallelAnalysisProcess.cav.compile_and_analyze_file(compile_command.filename,
|
||||
compile_command.args,
|
||||
compile_command.directory)
|
||||
return ParallelAnalysisProcess.diags
|
||||
|
||||
@staticmethod
|
||||
def precompile_header(compile_command: CompileCommand) -> str:
|
||||
return precompile_header(compile_command,
|
||||
ParallelAnalysisProcess.tmp_dir)
|
||||
return precompile_header(compile_command, ParallelAnalysisProcess.tmp_dir)
|
||||
|
||||
|
||||
# Compile and analyze inputs in multiple processes.
|
||||
def run_parallel_analysis(ccl: Iterable[CompileCommand],
|
||||
pccl: Iterable[CompileCommand],
|
||||
diagnostic_cb: Callable[[Diagnostic], None],
|
||||
jobs_count: int, verilator_root: str):
|
||||
def run_parallel_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
||||
diagnostic_cb: Callable[[Diagnostic],
|
||||
None], jobs_count: int, verilator_root: str):
|
||||
prefix = "verilator_clang_check_attributes_"
|
||||
with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir:
|
||||
with multiprocessing.Pool(
|
||||
processes=jobs_count,
|
||||
initializer=ParallelAnalysisProcess.init_data,
|
||||
initargs=[verilator_root, tmp_dir]) as pool:
|
||||
with multiprocessing.Pool(processes=jobs_count,
|
||||
initializer=ParallelAnalysisProcess.init_data,
|
||||
initargs=[verilator_root, tmp_dir]) as pool:
|
||||
extra_args = []
|
||||
for pch_file in pool.imap_unordered(
|
||||
ParallelAnalysisProcess.precompile_header, pccl):
|
||||
for pch_file in pool.imap_unordered(ParallelAnalysisProcess.precompile_header, pccl):
|
||||
if pch_file:
|
||||
extra_args += ["-include-pch", pch_file]
|
||||
|
||||
|
|
@ -1011,8 +976,7 @@ def run_parallel_analysis(ccl: Iterable[CompileCommand],
|
|||
for compile_command in ccl:
|
||||
compile_command.args = compile_command.args + extra_args
|
||||
|
||||
for diags in pool.imap_unordered(
|
||||
ParallelAnalysisProcess.analyze_cpp_file, ccl, 1):
|
||||
for diags in pool.imap_unordered(ParallelAnalysisProcess.analyze_cpp_file, ccl, 1):
|
||||
for diag in diags:
|
||||
diagnostic_cb(diag)
|
||||
|
||||
|
|
@ -1057,8 +1021,7 @@ class TopDownSummaryPrinter():
|
|||
row_groups: dict[str, list[list[str]]] = {}
|
||||
column_widths = [0, 0]
|
||||
for func in sorted(self._funcs.values(),
|
||||
key=lambda func:
|
||||
(func.info.file, func.info.line, func.info.usr)):
|
||||
key=lambda func: (func.info.file, func.info.line, func.info.usr)):
|
||||
func_info = func.info
|
||||
relfile = os.path.relpath(func_info.file, root_dir)
|
||||
|
||||
|
|
@ -1082,31 +1045,23 @@ class TopDownSummaryPrinter():
|
|||
if func.mismatch:
|
||||
mrelfile = os.path.relpath(func.mismatch.file, root_dir)
|
||||
row_group.append([
|
||||
f"{mrelfile}:{func.mismatch.line}:",
|
||||
f"[{func.mismatch.annotations}]",
|
||||
f"{mrelfile}:{func.mismatch.line}:", f"[{func.mismatch.annotations}]",
|
||||
func.mismatch.name + " [declaration]"
|
||||
])
|
||||
|
||||
row_group.append([
|
||||
f"{relfile}:{func_info.line}:", f"[{func_info.annotations}]",
|
||||
func_info.name
|
||||
])
|
||||
row_group.append(
|
||||
[f"{relfile}:{func_info.line}:", f"[{func_info.annotations}]", func_info.name])
|
||||
|
||||
for callee in sorted(func.calees,
|
||||
key=lambda func:
|
||||
(func.file, func.line, func.usr)):
|
||||
for callee in sorted(func.calees, key=lambda func: (func.file, func.line, func.usr)):
|
||||
crelfile = os.path.relpath(callee.file, root_dir)
|
||||
row_group.append([
|
||||
f"{crelfile}:{callee.line}:", f"[{callee.annotations}]",
|
||||
" " + callee.name
|
||||
])
|
||||
row_group.append(
|
||||
[f"{crelfile}:{callee.line}:", f"[{callee.annotations}]", " " + callee.name])
|
||||
|
||||
row_groups[name] = row_group
|
||||
|
||||
for row in row_group:
|
||||
for row_id, value in enumerate(row[0:-1]):
|
||||
column_widths[row_id] = max(column_widths[row_id],
|
||||
len(value))
|
||||
column_widths[row_id] = max(column_widths[row_id], len(value))
|
||||
|
||||
for label, rows in sorted(row_groups.items(), key=lambda kv: kv[0]):
|
||||
self.begin_group(label)
|
||||
|
|
@ -1114,21 +1069,17 @@ class TopDownSummaryPrinter():
|
|||
print(f"{row[0]:<{column_widths[0]}} "
|
||||
f"{row[1]:<{column_widths[1]}} "
|
||||
f"{row[2]}")
|
||||
print(
|
||||
f"Number of functions reported unsafe: {len(self._unsafe_in_safe)}"
|
||||
)
|
||||
print(f"Number of functions reported unsafe: {len(self._unsafe_in_safe)}")
|
||||
|
||||
|
||||
def main():
|
||||
default_verilator_root = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), ".."))
|
||||
default_verilator_root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""Check function annotations for correctness""",
|
||||
epilog=
|
||||
"""Copyright 2022-2024 by Wilson Snyder. Verilator is free software;
|
||||
epilog="""Copyright 2022-2024 by Wilson Snyder. Verilator is free software;
|
||||
you can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Apache License 2.0.
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Apache-2.0""")
|
||||
|
|
@ -1142,29 +1093,23 @@ def main():
|
|||
type=int,
|
||||
default=0,
|
||||
help="Number of parallel jobs to use.")
|
||||
parser.add_argument(
|
||||
"--compile-commands-dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Path to directory containing compile_commands.json.")
|
||||
parser.add_argument("--compile-commands-dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Path to directory containing compile_commands.json.")
|
||||
parser.add_argument("--cxxflags",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Extra flags passed to clang++.")
|
||||
parser.add_argument(
|
||||
"--compilation-root",
|
||||
type=str,
|
||||
default=os.getcwd(),
|
||||
help="Directory used as CWD when compiling source files.")
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--precompile",
|
||||
action="append",
|
||||
help="Header file to be precompiled and cached at the start.")
|
||||
parser.add_argument("file",
|
||||
parser.add_argument("--compilation-root",
|
||||
type=str,
|
||||
nargs="+",
|
||||
help="Source file to analyze.")
|
||||
default=os.getcwd(),
|
||||
help="Directory used as CWD when compiling source files.")
|
||||
parser.add_argument("-c",
|
||||
"--precompile",
|
||||
action="append",
|
||||
help="Header file to be precompiled and cached at the start.")
|
||||
parser.add_argument("file", type=str, nargs="+", help="Source file to analyze.")
|
||||
|
||||
cmdline = parser.parse_args()
|
||||
|
||||
|
|
@ -1179,8 +1124,7 @@ def main():
|
|||
|
||||
compdb: Optional[CompilationDatabase] = None
|
||||
if cmdline.compile_commands_dir:
|
||||
compdb = CompilationDatabase.fromDirectory(
|
||||
cmdline.compile_commands_dir)
|
||||
compdb = CompilationDatabase.fromDirectory(cmdline.compile_commands_dir)
|
||||
|
||||
if cmdline.cxxflags is not None:
|
||||
common_cxxflags = shlex.split(cmdline.cxxflags)
|
||||
|
|
@ -1230,8 +1174,7 @@ def main():
|
|||
summary_printer.handle_diagnostic, verilator_root)
|
||||
else:
|
||||
run_parallel_analysis(compile_commands_list, precompile_commands_list,
|
||||
summary_printer.handle_diagnostic, cmdline.jobs,
|
||||
verilator_root)
|
||||
summary_printer.handle_diagnostic, cmdline.jobs, verilator_root)
|
||||
|
||||
summary_printer.print_summary(verilator_root)
|
||||
|
||||
|
|
|
|||
|
|
@ -58,15 +58,12 @@ def test():
|
|||
if not Args.scenarios or re.match('dist', Args.scenarios):
|
||||
run("make examples VERILATOR_NO_OPT_BUILD=1")
|
||||
run("make test_regress VERILATOR_NO_OPT_BUILD=1" +
|
||||
(" SCENARIOS='" + Args.scenarios +
|
||||
"'" if Args.scenarios else "") +
|
||||
(" DRIVER_HASHSET='--hashset=" + Args.hashset +
|
||||
"'" if Args.hashset else "") +
|
||||
(" SCENARIOS='" + Args.scenarios + "'" if Args.scenarios else "") +
|
||||
(" DRIVER_HASHSET='--hashset=" + Args.hashset + "'" if Args.hashset else "") +
|
||||
('' if Args.stop else ' || true'))
|
||||
else:
|
||||
for test in Args.tests:
|
||||
if not os.path.exists(test) and os.path.exists(
|
||||
"test_regress/t/" + test):
|
||||
if not os.path.exists(test) and os.path.exists("test_regress/t/" + test):
|
||||
test = "test_regress/t/" + test
|
||||
run(test)
|
||||
ci_fold_end()
|
||||
|
|
@ -78,8 +75,7 @@ def test():
|
|||
os.makedirs(cc_dir, exist_ok=True)
|
||||
os.makedirs(cc_dir + "/info", exist_ok=True)
|
||||
|
||||
with subprocess.Popen("find . -print | grep .gcda",
|
||||
shell=True,
|
||||
with subprocess.Popen("find . -print | grep .gcda", shell=True,
|
||||
stdout=subprocess.PIPE) as sp:
|
||||
datout = sp.stdout.read()
|
||||
|
||||
|
|
@ -98,8 +94,7 @@ def test():
|
|||
del dats[dat]
|
||||
break
|
||||
|
||||
with subprocess.Popen("find . -print | grep .gcno",
|
||||
shell=True,
|
||||
with subprocess.Popen("find . -print | grep .gcno", shell=True,
|
||||
stdout=subprocess.PIPE) as sp:
|
||||
datout = sp.stdout.read()
|
||||
|
||||
|
|
@ -116,8 +111,7 @@ def test():
|
|||
if gbase in gcnos:
|
||||
os.symlink(gcnos[gbase], gcno)
|
||||
else:
|
||||
print("MISSING .gcno for a .gcda: " + gcno,
|
||||
file=sys.stderr)
|
||||
print("MISSING .gcno for a .gcda: " + gcno, file=sys.stderr)
|
||||
ci_fold_end()
|
||||
|
||||
if Args.stage_enabled[5]:
|
||||
|
|
@ -142,8 +136,7 @@ def test():
|
|||
if Args.stage_enabled[11]:
|
||||
ci_fold_start("dirs")
|
||||
print("Stage 11: Cleanup paths")
|
||||
cleanup_abs_paths_info(cc_dir, cc_dir + "/app_total.info",
|
||||
cc_dir + "/app_total.info")
|
||||
cleanup_abs_paths_info(cc_dir, cc_dir + "/app_total.info", cc_dir + "/app_total.info")
|
||||
ci_fold_end()
|
||||
|
||||
if Args.stage_enabled[12]:
|
||||
|
|
@ -164,17 +157,15 @@ def test():
|
|||
inc = "--include " + inc
|
||||
if exc != '':
|
||||
exc = "--exclude " + exc
|
||||
run("cd " + cc_dir + " ; " + RealPath +
|
||||
"/fastcov.py -C app_total.info " + inc + " " + exc +
|
||||
" -x --lcov -o app_total_f.info")
|
||||
run("cd " + cc_dir + " ; " + RealPath + "/fastcov.py -C app_total.info " + inc + " " +
|
||||
exc + " -x --lcov -o app_total_f.info")
|
||||
ci_fold_end()
|
||||
|
||||
if Args.stage_enabled[17]:
|
||||
ci_fold_start("report")
|
||||
print("Stage 17: Create HTML")
|
||||
run("cd " + cc_dir + " ; genhtml app_total_f.info --demangle-cpp" +
|
||||
" --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html"
|
||||
)
|
||||
" --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html")
|
||||
ci_fold_end()
|
||||
|
||||
if Args.stage_enabled[18]:
|
||||
|
|
@ -186,8 +177,7 @@ def test():
|
|||
# So, remove gcno files before calling codecov
|
||||
upload_dir = "nodist/obj_dir/upload"
|
||||
os.makedirs(upload_dir, exist_ok=True)
|
||||
cmd = ("ci/codecov -v upload-process -Z" + " -f " + cc_dir +
|
||||
"/app_total.info )")
|
||||
cmd = "ci/codecov -v upload-process -Z" + " -f " + cc_dir + "/app_total.info )"
|
||||
print("print: Not running:")
|
||||
print(" export CODECOV_TOKEN=<hidden>")
|
||||
print(" find . -name '*.gcno' -exec rm {} \\;")
|
||||
|
|
@ -198,9 +188,7 @@ def test():
|
|||
print("*-* All Finished *-*")
|
||||
print("")
|
||||
print("* See report in " + cc_dir + "/html/index.html")
|
||||
print(
|
||||
"* Remember to make distclean && ./configure before working on non-coverage"
|
||||
)
|
||||
print("* Remember to make distclean && ./configure before working on non-coverage")
|
||||
|
||||
|
||||
def clone_sources(cc_dir):
|
||||
|
|
@ -209,9 +197,8 @@ def clone_sources(cc_dir):
|
|||
for globf in Source_Globs:
|
||||
for infile in glob.glob(globf):
|
||||
if re.match(r'^/', infile):
|
||||
sys.exit(
|
||||
"%Error: source globs should be relative not absolute filenames, "
|
||||
+ infile)
|
||||
sys.exit("%Error: source globs should be relative not absolute filenames, " +
|
||||
infile)
|
||||
outfile = cc_dir + "/" + infile
|
||||
outpath = re.sub(r'/[^/]*$', '', outfile, count=1)
|
||||
os.makedirs(outpath, exist_ok=True)
|
||||
|
|
@ -252,10 +239,8 @@ def clone_sources(cc_dir):
|
|||
done = True
|
||||
|
||||
ofh.write(line + "\n")
|
||||
print("Number of source lines automatically LCOV_EXCL_LINE'ed: %d" %
|
||||
excluded_lines)
|
||||
print("Number of source lines automatically LCOV_EXCL_BR_LINE'ed: %d" %
|
||||
excluded_br_lines)
|
||||
print("Number of source lines automatically LCOV_EXCL_LINE'ed: %d" % excluded_lines)
|
||||
print("Number of source lines automatically LCOV_EXCL_BR_LINE'ed: %d" % excluded_br_lines)
|
||||
|
||||
|
||||
def cleanup_abs_paths_info(cc_dir, infile, outfile):
|
||||
|
|
@ -263,20 +248,11 @@ def cleanup_abs_paths_info(cc_dir, infile, outfile):
|
|||
with open(infile, "r", encoding="utf8") as fh:
|
||||
for line in fh:
|
||||
if re.search(r'^SF:', line) and not re.search(r'^SF:/usr/', line):
|
||||
line = re.sub(os.environ['VERILATOR_ROOT'] + '/',
|
||||
'',
|
||||
line,
|
||||
count=1)
|
||||
line = re.sub(os.environ['VERILATOR_ROOT'] + '/', '', line, count=1)
|
||||
line = re.sub(cc_dir + '/', '', line, count=1)
|
||||
line = re.sub(r'^SF:.*?/include/',
|
||||
'SF:include/',
|
||||
line,
|
||||
count=1)
|
||||
line = re.sub(r'^SF:.*?/include/', 'SF:include/', line, count=1)
|
||||
line = re.sub(r'^SF:.*?/src/', 'SF:src/', line, count=1)
|
||||
line = re.sub(r'^SF:.*?/test_regress/',
|
||||
'SF:test_regress/',
|
||||
line,
|
||||
count=1)
|
||||
line = re.sub(r'^SF:.*?/test_regress/', 'SF:test_regress/', line, count=1)
|
||||
line = re.sub(r'obj_dbg/verilog.y$', 'verilog.y', line)
|
||||
# print("Remaining SF: "+line)
|
||||
lines.append(line)
|
||||
|
|
@ -358,15 +334,13 @@ def ci_fold_end():
|
|||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=
|
||||
"""code_coverage builds Verilator with C++ coverage support and runs
|
||||
description="""code_coverage builds Verilator with C++ coverage support and runs
|
||||
tests with coverage enabled. This will rebuild the current object
|
||||
files. Run as:
|
||||
|
||||
cd $VERILATOR_ROOT
|
||||
nodist/code_coverage""",
|
||||
epilog=
|
||||
"""Copyright 2019-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2019-2024 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
|
@ -376,23 +350,20 @@ SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
|||
parser.add_argument('--debug', action='store_true', help='enable debug')
|
||||
parser.add_argument('--hashset',
|
||||
action='store',
|
||||
help='pass test hashset onto driver.pl test harness')
|
||||
help='pass test hashset onto driver.py test harness')
|
||||
parser.add_argument('--scenarios',
|
||||
action='store',
|
||||
help='pass test scenarios onto driver.pl test harness')
|
||||
parser.add_argument(
|
||||
'--stages',
|
||||
'--stage',
|
||||
action='store',
|
||||
help='runs a specific stage or range of stages (see the script)')
|
||||
help='pass test scenarios onto driver.py test harness')
|
||||
parser.add_argument('--stages',
|
||||
'--stage',
|
||||
action='store',
|
||||
help='runs a specific stage or range of stages (see the script)')
|
||||
parser.add_argument(
|
||||
'--tests',
|
||||
'--test',
|
||||
action='append',
|
||||
default=[],
|
||||
help=
|
||||
'Instead of normal regressions, run the specified test(s), may be used multiple times'
|
||||
)
|
||||
help='Instead of normal regressions, run the specified test(s), may be used multiple times')
|
||||
parser.add_argument('--no-stop',
|
||||
dest='stop',
|
||||
action='store_false',
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@ def dotread(filename):
|
|||
vnum = 0
|
||||
|
||||
vertex_re = re.compile(r'^\t([a-zA-Z0-9_]+)\t(.*)$')
|
||||
edge_re = re.compile(
|
||||
r'^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s*(.*)$')
|
||||
edge_re = re.compile(r'^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s*(.*)$')
|
||||
|
||||
for line in fh:
|
||||
vertex_match = re.search(vertex_re, line)
|
||||
|
|
@ -29,11 +28,7 @@ def dotread(filename):
|
|||
if vertex_match:
|
||||
if vertex_match.group(1) != 'nTITLE':
|
||||
header = False
|
||||
Vertexes.append({
|
||||
'num': vnum,
|
||||
'line': line,
|
||||
'name': vertex_match.group(1)
|
||||
})
|
||||
Vertexes.append({'num': vnum, 'line': line, 'name': vertex_match.group(1)})
|
||||
vnum += 1
|
||||
elif edge_match:
|
||||
fromv = edge_match.group(1)
|
||||
|
|
@ -65,14 +60,13 @@ def cwrite(filename):
|
|||
fh.write("void V3GraphTestImport::dotImport() {\n")
|
||||
fh.write(" auto* gp = &m_graph;\n")
|
||||
for ver in sorted(Vertexes, key=lambda ver: ver['num']):
|
||||
fh.write(
|
||||
" auto* %s = new V3GraphTestVertex{gp, \"%s\"}; if (%s) {}\n"
|
||||
% (ver['name'], ver['name'], ver['name']))
|
||||
fh.write(" auto* %s = new V3GraphTestVertex{gp, \"%s\"}; if (%s) {}\n" %
|
||||
(ver['name'], ver['name'], ver['name']))
|
||||
fh.write("\n")
|
||||
for edge in Edges:
|
||||
fh.write(" new V3GraphEdge{gp, %s, %s, %s, %s};\n" %
|
||||
(edge['from'], edge['to'], edge['weight'],
|
||||
"true" if edge['cutable'] else "false"))
|
||||
fh.write(
|
||||
" new V3GraphEdge{gp, %s, %s, %s, %s};\n" %
|
||||
(edge['from'], edge['to'], edge['weight'], "true" if edge['cutable'] else "false"))
|
||||
fh.write("}\n")
|
||||
|
||||
|
||||
|
|
@ -82,22 +76,17 @@ def cwrite(filename):
|
|||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=
|
||||
"""dot_importer takes a graphvis .dot file and converts into .cpp file.
|
||||
description="""dot_importer takes a graphvis .dot file and converts into .cpp file.
|
||||
This x.cpp file is then manually included in V3GraphTest.cpp to verify
|
||||
various xsub-algorithms.""",
|
||||
epilog=
|
||||
"""Copyright 2005-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2005-2024 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('filename', help='input .dot filename to process')
|
||||
|
||||
Args = parser.parse_args()
|
||||
|
|
|
|||
|
|
@ -19,9 +19,12 @@ from argparse import ArgumentParser
|
|||
|
||||
|
||||
def interesting(s):
|
||||
if 'assert' in s: return 1
|
||||
if 'Assert' in s: return 1
|
||||
if 'Aborted' in s: return 1
|
||||
if 'assert' in s:
|
||||
return 1
|
||||
if 'Assert' in s:
|
||||
return 1
|
||||
if 'Aborted' in s:
|
||||
return 1
|
||||
if 'terminate' in s:
|
||||
if 'unterminated' in s:
|
||||
return 0
|
||||
|
|
@ -41,8 +44,7 @@ def main():
|
|||
for infile in glob(args.dir + '/*'):
|
||||
# Input filenames are known not to contain spaces or other unusual
|
||||
# characters, therefore this works.
|
||||
status, output = getstatusoutput('../../bin/verilator_bin --cc ' +
|
||||
infile)
|
||||
status, output = getstatusoutput('../../bin/verilator_bin --cc ' + infile)
|
||||
if interesting(output):
|
||||
print(infile)
|
||||
print(status)
|
||||
|
|
|
|||
|
|
@ -51,9 +51,11 @@ def write_file(filename, contents):
|
|||
|
||||
def parse_line(s):
|
||||
# str->maybe str
|
||||
if len(s) == 0: return None
|
||||
if len(s) == 0:
|
||||
return None
|
||||
part = skip_while(lambda x: x != '"', s)
|
||||
if len(part) == 0 or part[0] != '"': return None
|
||||
if len(part) == 0 or part[0] != '"':
|
||||
return None
|
||||
literal_part = take_while(lambda x: x != '"', part[1:])
|
||||
return ''.join(filter(lambda x: x != '\\', literal_part))
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,10 @@ def test():
|
|||
print("== stage 0")
|
||||
run("/bin/rm -rf " + blddir)
|
||||
run("/bin/mkdir -p " + blddir)
|
||||
run("cd " + blddir + " && " + srcdir + "/configure --prefix " + prefix)
|
||||
# Matches Ubuntu's e.g. /usr/share/pkgconfig/verilator.pc
|
||||
run("cd " + blddir + " && " + srcdir + "/configure --prefix " + prefix +
|
||||
" --exec-prefix " + prefix + " --datarootdir " + prefix + "/share" + " --includedir " +
|
||||
prefix + "/share/verilator/include")
|
||||
run("cd " + blddir + " && make -j " + str(calc_jobs()))
|
||||
|
||||
# Install it under the prefix
|
||||
|
|
@ -41,8 +44,7 @@ def test():
|
|||
run("/bin/mkdir -p " + prefix)
|
||||
run("cd " + blddir + " && make install")
|
||||
run("test -e " + prefix + "/share/man/man1/verilator.1")
|
||||
run("test -e " + prefix +
|
||||
"/share/verilator/examples/make_tracing_c/Makefile")
|
||||
run("test -e " + prefix + "/share/verilator/examples/make_tracing_c/Makefile")
|
||||
run("test -e " + prefix + "/share/verilator/include/verilated.h")
|
||||
run("test -e " + prefix + "/bin/verilator")
|
||||
run("test -e " + prefix + "/bin/verilator_bin")
|
||||
|
|
@ -58,10 +60,8 @@ def test():
|
|||
run("/bin/mkdir -p " + odir)
|
||||
path = prefix + "/bin" + ":" + prefix + "/share/bin"
|
||||
write_verilog(odir)
|
||||
run("cd " + odir + " && PATH=" + path +
|
||||
":$PATH verilator --cc top.v --exe sim_main.cpp")
|
||||
run("cd " + odir + "/obj_dir && PATH=" + path +
|
||||
":$PATH make -f Vtop.mk")
|
||||
run("cd " + odir + " && PATH=" + path + ":$PATH verilator --cc top.v --exe sim_main.cpp")
|
||||
run("cd " + odir + "/obj_dir && PATH=" + path + ":$PATH make -f Vtop.mk")
|
||||
run("cd " + odir + " && PATH=" + path + ":$PATH obj_dir/Vtop")
|
||||
|
||||
# run a test using exact path to binary
|
||||
|
|
@ -72,8 +72,7 @@ def test():
|
|||
run("/bin/mkdir -p " + odir)
|
||||
write_verilog(odir)
|
||||
bin1 = prefix + "/bin"
|
||||
run("cd " + odir + " && " + bin1 +
|
||||
"/verilator --cc top.v --exe sim_main.cpp")
|
||||
run("cd " + odir + " && " + bin1 + "/verilator --cc top.v --exe sim_main.cpp")
|
||||
run("cd " + odir + "/obj_dir && make -f Vtop.mk")
|
||||
run("cd " + odir + "/obj_dir && ./Vtop")
|
||||
|
||||
|
|
@ -88,8 +87,7 @@ def write_verilog(odir):
|
|||
|
||||
def cleanenv():
|
||||
for var in os.environ:
|
||||
if var in ('VERILATOR_ROOT', 'VERILATOR_INCLUDE',
|
||||
'VERILATOR_NO_OPT_BUILD'):
|
||||
if var in ('VERILATOR_ROOT', 'VERILATOR_INCLUDE', 'VERILATOR_NO_OPT_BUILD'):
|
||||
print("unset %s # Was '%s'" % (var, os.environ[var]))
|
||||
del os.environ[var]
|
||||
|
||||
|
|
@ -113,21 +111,16 @@ def run(command):
|
|||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=
|
||||
"""install_test performs several make-and-install iterations to verify the
|
||||
description="""install_test performs several make-and-install iterations to verify the
|
||||
Verilator kit. It isn't part of the normal "make test" due to the number
|
||||
of builds required.""",
|
||||
epilog=
|
||||
"""Copyright 2009-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2009-2024 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('--stage',
|
||||
type=int,
|
||||
default=0,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/env python3
|
||||
# pylint: disable=
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
|
||||
SUPPRESSES = [
|
||||
"**********",
|
||||
"E0602: Undefined variable 'test' (undefined-variable)",
|
||||
"E0602: Undefined variable 're' (undefined-variable)",
|
||||
"E0602: Undefined variable 'os' (undefined-variable)",
|
||||
"E0602: Undefined variable 'glob' (undefined-variable)",
|
||||
"W0611: Unused import vltest_bootstrap (unused-import)",
|
||||
]
|
||||
|
||||
######################################################################
|
||||
|
||||
def process():
|
||||
anymsg = False
|
||||
for line in sys.stdin:
|
||||
line = line.rstrip();
|
||||
show = True
|
||||
for msg in SUPPRESSES:
|
||||
if msg in line:
|
||||
show = False
|
||||
continue
|
||||
if show:
|
||||
print(line)
|
||||
anymsg = True
|
||||
|
||||
if anymsg:
|
||||
sys.exit("%Error: See messages above")
|
||||
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""lint_py_test_filter is used to filter
|
||||
pylint output for expected errors in Verilator test_regress/*.py tests.""",
|
||||
epilog="""Copyright 2024-2024 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||
|
||||
parser.add_argument('--debug', action='store_true', help='enable debug')
|
||||
|
||||
Args = parser.parse_args()
|
||||
process()
|
||||
|
||||
######################################################################
|
||||
# Local Variables:
|
||||
# compile-command: "cd .. ; make lint-py-pylint-tests"
|
||||
# End:
|
||||
|
|
@ -101,8 +101,7 @@ parser = argparse.ArgumentParser(
|
|||
allow_abbrev=False,
|
||||
prog="log_changes",
|
||||
description="Create example entries for 'Changes' from parsing 'git log'",
|
||||
epilog=
|
||||
"""Copyright 2019-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2019-2024 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
|
|
|||
|
|
@ -47,9 +47,12 @@ class AstseeCmd(gdb.Command):
|
|||
|
||||
def _null_check(self, old, new):
|
||||
err = ""
|
||||
if old == "<nullptr>\n": err += "old == <nullptr>\n"
|
||||
if new == "<nullptr>\n": err += "new == <nullptr>"
|
||||
if err: raise gdb.GdbError(err.strip("\n"))
|
||||
if old == "<nullptr>\n":
|
||||
err += "old == <nullptr>\n"
|
||||
if new == "<nullptr>\n":
|
||||
err += "new == <nullptr>"
|
||||
if err:
|
||||
raise gdb.GdbError(err.strip("\n"))
|
||||
|
||||
def invoke(self, arg_str, from_tty):
|
||||
from astsee import verilator_cli as astsee # pylint: disable=import-error,import-outside-toplevel
|
||||
|
|
@ -58,8 +61,8 @@ class AstseeCmd(gdb.Command):
|
|||
# We hack `astsee_verilator`'s arg parser to find arguments with nodes
|
||||
# After finding them, we replace them with proper files
|
||||
astsee_args = astsee.parser.parse_args(gdb.string_to_argv(arg_str))
|
||||
with _vltgdb_tmpfile() as oldfile, _vltgdb_tmpfile(
|
||||
) as newfile, _vltgdb_tmpfile() as metafile:
|
||||
with _vltgdb_tmpfile() as oldfile, _vltgdb_tmpfile() as newfile, _vltgdb_tmpfile(
|
||||
) as metafile:
|
||||
if astsee_args.file:
|
||||
_vltgdb_fwrite(oldfile, _vltgdb_get_dump(astsee_args.file))
|
||||
astsee_args.file = oldfile.name
|
||||
|
|
@ -68,8 +71,7 @@ class AstseeCmd(gdb.Command):
|
|||
astsee_args.newfile = newfile.name
|
||||
if astsee_args.meta is None:
|
||||
# pass
|
||||
gdb.execute(
|
||||
f'call AstNode::dumpJsonMetaFileGdb("{metafile.name}")')
|
||||
gdb.execute(f'call AstNode::dumpJsonMetaFileGdb("{metafile.name}")')
|
||||
astsee_args.meta = metafile.name
|
||||
try:
|
||||
astsee.main(astsee_args)
|
||||
|
|
|
|||
|
|
@ -14,14 +14,23 @@
|
|||
|
||||
#
|
||||
# Utilities
|
||||
macro (addBuildType sourceConfig newConfig)
|
||||
macro(addBuildType sourceConfig newConfig)
|
||||
get_cmake_property(variableNames VARIABLES)
|
||||
foreach (variableName ${variableNames})
|
||||
if (variableName MATCHES "^CMAKE_.*_${sourceConfig}(|_.*)$")
|
||||
string(REPLACE _${sourceConfig} _${newConfig} newVariableName ${variableName})
|
||||
foreach(variableName ${variableNames})
|
||||
if(variableName MATCHES "^CMAKE_.*_${sourceConfig}(|_.*)$")
|
||||
string(
|
||||
REPLACE
|
||||
_${sourceConfig}
|
||||
_${newConfig}
|
||||
newVariableName
|
||||
${variableName}
|
||||
)
|
||||
set(${newVariableName} ${${variableName}})
|
||||
mark_as_advanced(${newVariableName})
|
||||
message(DEBUG " Propagating ${variableName} to ${newVariableName} = ${${newVariableName}}")
|
||||
message(
|
||||
DEBUG
|
||||
" Propagating ${variableName} to ${newVariableName} = ${${newVariableName}}"
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
|
@ -163,7 +172,6 @@ set(HEADERS
|
|||
V3Table.h
|
||||
V3Task.h
|
||||
V3ThreadPool.h
|
||||
V3ThreadSafety.h
|
||||
V3Timing.h
|
||||
V3Trace.h
|
||||
V3TraceDecl.h
|
||||
|
|
@ -328,15 +336,11 @@ set(COMMON_SOURCES
|
|||
V3PreProc.cpp
|
||||
)
|
||||
|
||||
SET(COVERAGE_SOURCES
|
||||
VlcMain.cpp
|
||||
)
|
||||
set(COVERAGE_SOURCES VlcMain.cpp)
|
||||
|
||||
# Note about tests:
|
||||
# VlcMain.cpp #includes the following files:
|
||||
# V3Error.cpp, V3String.cpp, V3Os.cpp and VlcTop.cpp
|
||||
# V3Number_test.cpp #includes the following files:
|
||||
# V3FileLine.cpp
|
||||
|
||||
#
|
||||
# Generated sources and headers for the verilator binary
|
||||
|
|
@ -355,34 +359,49 @@ configure_file(config_package.h.in config_package.h @ONLY)
|
|||
add_custom_command(
|
||||
OUTPUT V3Ast__gen_forward_class_decls.h V3Dfg__gen_forward_class_decls.h
|
||||
DEPENDS ./V3Ast.h ${ASTGEN}
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h --classes
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef
|
||||
V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h
|
||||
--classes
|
||||
)
|
||||
list(
|
||||
APPEND
|
||||
GENERATED_FILES
|
||||
V3Ast__gen_forward_class_decls.h
|
||||
V3Dfg__gen_forward_class_decls.h
|
||||
)
|
||||
list(APPEND GENERATED_FILES V3Ast__gen_forward_class_decls.h V3Dfg__gen_forward_class_decls.h)
|
||||
# Output used directly by the `verilator` target
|
||||
|
||||
set(verilog_y "${srcdir}/verilog.y" )
|
||||
set(BISON_V3ParseBison_OUTPUT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/V3ParseBison.h")
|
||||
set(BISON_V3ParseBison_OUTPUT_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/V3ParseBison.c")
|
||||
set(verilog_y "${srcdir}/verilog.y")
|
||||
set(BISON_V3ParseBison_OUTPUT_HEADER
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/V3ParseBison.h"
|
||||
)
|
||||
set(BISON_V3ParseBison_OUTPUT_SOURCE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/V3ParseBison.c"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT V3ParseBison.c V3ParseBison.h
|
||||
MAIN_DEPENDENCY ./verilog.y
|
||||
DEPENDS ${BISONPRE}
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${BISONPRE} --yacc "${BISON_EXECUTABLE}" -d -v
|
||||
-o "${BISON_V3ParseBison_OUTPUT_SOURCE}" "${verilog_y}"
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${BISONPRE} --yacc "${BISON_EXECUTABLE}" -d -v -o
|
||||
"${BISON_V3ParseBison_OUTPUT_SOURCE}" "${verilog_y}"
|
||||
)
|
||||
list(APPEND GENERATED_FILES V3ParseBison.c V3ParseBison.h)
|
||||
# Output used directly by the `verilator` target
|
||||
|
||||
set(verilog_l "${srcdir}/verilog.l")
|
||||
set(FLEX_V3Lexer_pregen_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/V3Lexer_pregen.yy.cpp")
|
||||
set(FLEX_V3Lexer_pregen_OUTPUTS
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/V3Lexer_pregen.yy.cpp"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT V3Lexer_pregen.yy.cpp
|
||||
MAIN_DEPENDENCY ./verilog.l
|
||||
DEPENDS ${BISON_V3ParseBison_OUTPUT_HEADER} ${HEADERS}
|
||||
COMMAND ${FLEX_EXECUTABLE} ARGS
|
||||
${LFLAGS} -o "${FLEX_V3Lexer_pregen_OUTPUTS}" "${verilog_l}"
|
||||
COMMAND ${FLEX_EXECUTABLE}
|
||||
ARGS ${LFLAGS} -o "${FLEX_V3Lexer_pregen_OUTPUTS}" "${verilog_l}"
|
||||
)
|
||||
# Output used by another command
|
||||
|
||||
|
|
@ -391,19 +410,26 @@ add_custom_command(
|
|||
OUTPUT V3Lexer.yy.cpp
|
||||
MAIN_DEPENDENCY ${FLEX_V3Lexer_pregen_OUTPUTS}
|
||||
DEPENDS ${FLEXFIX}
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${FLEXFIX} V3Lexer < "$<SHELL_PATH:${FLEX_V3Lexer_pregen_OUTPUTS}>" > "$<SHELL_PATH:${FLEX_V3Lexer_OUTPUTS}>"
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${FLEXFIX} V3Lexer < "$<SHELL_PATH:${FLEX_V3Lexer_pregen_OUTPUTS}>" >
|
||||
"$<SHELL_PATH:${FLEX_V3Lexer_OUTPUTS}>"
|
||||
)
|
||||
add_custom_target(
|
||||
V3Lexer_yy_cpp${CMAKE_BUILD_TYPE}
|
||||
DEPENDS ${FLEX_V3Lexer_OUTPUTS}
|
||||
)
|
||||
add_custom_target(V3Lexer_yy_cpp${CMAKE_BUILD_TYPE} DEPENDS ${FLEX_V3Lexer_OUTPUTS})
|
||||
# Output included by another source file
|
||||
|
||||
set(FLEX_V3PreLex_pregen_OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/V3PreLex_pregen.yy.cpp)
|
||||
set(FLEX_V3PreLex_pregen_OUTPUTS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/V3PreLex_pregen.yy.cpp
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT V3PreLex_pregen.yy.cpp
|
||||
MAIN_DEPENDENCY ./V3PreLex.l
|
||||
DEPENDS ${HEADERS}
|
||||
COMMAND ${FLEX_EXECUTABLE} ARGS
|
||||
${LFLAGS} -o "${FLEX_V3PreLex_pregen_OUTPUTS}" "${srcdir}/V3PreLex.l"
|
||||
COMMAND ${FLEX_EXECUTABLE}
|
||||
ARGS ${LFLAGS} -o "${FLEX_V3PreLex_pregen_OUTPUTS}" "${srcdir}/V3PreLex.l"
|
||||
)
|
||||
# Output used by another command
|
||||
|
||||
|
|
@ -412,37 +438,45 @@ add_custom_command(
|
|||
OUTPUT V3PreLex.yy.cpp
|
||||
MAIN_DEPENDENCY ${FLEX_V3PreLex_pregen_OUTPUTS}
|
||||
DEPENDS ${FLEXFIX}
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${FLEXFIX} V3PreLex < "$<SHELL_PATH:${FLEX_V3PreLex_pregen_OUTPUTS}>" > "$<SHELL_PATH:${FLEX_V3PreLex_OUTPUTS}>"
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${FLEXFIX} V3PreLex < "$<SHELL_PATH:${FLEX_V3PreLex_pregen_OUTPUTS}>" >
|
||||
"$<SHELL_PATH:${FLEX_V3PreLex_OUTPUTS}>"
|
||||
)
|
||||
add_custom_target(
|
||||
V3PreLex_yy_cpp${CMAKE_BUILD_TYPE}
|
||||
DEPENDS ${FLEX_V3PreLex_OUTPUTS}
|
||||
)
|
||||
add_custom_target(V3PreLex_yy_cpp${CMAKE_BUILD_TYPE} DEPENDS ${FLEX_V3PreLex_OUTPUTS})
|
||||
# Output included by another source file
|
||||
|
||||
set(gitHead ${srcdir}/../.git/logs/HEAD)
|
||||
if (NOT EXISTS ${githead})
|
||||
if(NOT EXISTS ${githead})
|
||||
set(gitHead "")
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT config_rev.h
|
||||
MAIN_DEPENDENCY ${gitHead}
|
||||
DEPENDS ${CONFIG_REV}
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${CONFIG_REV} "${srcdir}" > "$<SHELL_PATH:${CMAKE_CURRENT_BINARY_DIR}/config_rev.h>"
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${CONFIG_REV} "${srcdir}" >
|
||||
"$<SHELL_PATH:${CMAKE_CURRENT_BINARY_DIR}/config_rev.h>"
|
||||
)
|
||||
list(APPEND GENERATED_FILES config_rev.h)
|
||||
# Output used directly by the `verilator` target
|
||||
|
||||
set(ASTGENERATED_NAMES
|
||||
V3Const
|
||||
)
|
||||
set(ASTGENERATED_NAMES V3Const)
|
||||
|
||||
foreach(astgen_name ${ASTGENERATED_NAMES})
|
||||
add_custom_command(
|
||||
OUTPUT ${astgen_name}__gen.cpp
|
||||
MAIN_DEPENDENCY ${astgen_name}.cpp
|
||||
DEPENDS ${ASTGEN} V3Ast.h
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h ${astgen_name}.cpp
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef
|
||||
V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h
|
||||
${astgen_name}.cpp
|
||||
)
|
||||
list(APPEND GENERATED_FILES ${astgen_name}__gen.cpp)
|
||||
endforeach()
|
||||
|
|
@ -450,7 +484,7 @@ endforeach()
|
|||
#
|
||||
# Set up the Coverage build type
|
||||
|
||||
addBuildType(DEBUG COVERAGE)
|
||||
addbuildtype(DEBUG COVERAGE)
|
||||
|
||||
# This regenerates include/verilated_cov_key.h in the source tree.
|
||||
# It is a custom_target, not custom_command, because vlcovgen.d is
|
||||
|
|
@ -459,8 +493,7 @@ add_custom_target(
|
|||
vlcovgen.d${CMAKE_BUILD_TYPE}
|
||||
DEPENDS ../include/verilated_cov_key.h ${VLCOVGEN}
|
||||
COMMENT "Updating include/verilated_cov_key.h"
|
||||
COMMAND ${PYTHON3}
|
||||
${VLCOVGEN} --srcdir ${srcdir}
|
||||
COMMAND ${PYTHON3} ${VLCOVGEN} --srcdir ${srcdir}
|
||||
)
|
||||
|
||||
#
|
||||
|
|
@ -468,24 +501,29 @@ add_custom_target(
|
|||
|
||||
set(verilator verilator${CMAKE_BUILD_TYPE})
|
||||
|
||||
add_executable(${verilator}
|
||||
add_executable(
|
||||
${verilator}
|
||||
$<$<NOT:$<CONFIG:COVERAGE>>:${COMMON_SOURCES}>
|
||||
$<$<NOT:$<CONFIG:COVERAGE>>:${GENERATED_FILES}>
|
||||
$<$<CONFIG:COVERAGE>:${COVERAGE_SOURCES} config_rev.h>
|
||||
$<$<CONFIG:COVERAGE>:${COVERAGE_SOURCES}
|
||||
config_rev.h>
|
||||
)
|
||||
|
||||
set_target_properties(${verilator} PROPERTIES
|
||||
OUTPUT_NAME_RELEASE verilator_bin
|
||||
OUTPUT_NAME_DEBUG verilator_bin_dbg
|
||||
OUTPUT_NAME_COVERAGE verilator_coverage_bin_dbg
|
||||
#UNITY_BUILD $<IF:$<CONFIG:DEBUG>,FALSE,${CMAKE_UNITY_BUILD}>
|
||||
MSVC_RUNTIME_LIBRARY MultiThreaded$<IF:$<CONFIG:Release>,,DebugDLL>
|
||||
#JOB_POOL_LINK one_job # Linking takes lots of resources
|
||||
INTERPROCEDURAL_OPTIMIZATION_RELEASE $<IF:MINGW,FALSE,TRUE>
|
||||
INCLUDE_DIRECTORIES ${FLEX_INCLUDE_DIR}
|
||||
set_target_properties(
|
||||
${verilator}
|
||||
PROPERTIES
|
||||
OUTPUT_NAME_RELEASE verilator_bin
|
||||
OUTPUT_NAME_DEBUG verilator_bin_dbg
|
||||
OUTPUT_NAME_COVERAGE verilator_coverage_bin_dbg
|
||||
#UNITY_BUILD $<IF:$<CONFIG:DEBUG>,FALSE,${CMAKE_UNITY_BUILD}>
|
||||
MSVC_RUNTIME_LIBRARY MultiThreaded$<IF:$<CONFIG:Release>,,DebugDLL>
|
||||
#JOB_POOL_LINK one_job # Linking takes lots of resources
|
||||
INTERPROCEDURAL_OPTIMIZATION_RELEASE $<IF:MINGW,FALSE,TRUE>
|
||||
INCLUDE_DIRECTORIES ${FLEX_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
add_dependencies(${verilator}
|
||||
add_dependencies(
|
||||
${verilator}
|
||||
V3Lexer_yy_cpp${CMAKE_BUILD_TYPE}
|
||||
V3PreLex_yy_cpp${CMAKE_BUILD_TYPE}
|
||||
)
|
||||
|
|
@ -495,41 +533,49 @@ target_link_libraries(${verilator} PRIVATE Threads::Threads)
|
|||
# verilated_cov_key.h is only regenerated in a single-configuration environment.
|
||||
# This limitation can be lifted when `add_dependencies` will support generator
|
||||
# expressions. See https://gitlab.kitware.com/cmake/cmake/issues/19467
|
||||
if (CMAKE_BUILD_TYPE STREQUAL Coverage)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Coverage)
|
||||
add_dependencies(${verilator} vlcovgen.d${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
|
||||
if (NOT MSVC)
|
||||
if(NOT MSVC)
|
||||
target_compile_features(${verilator} PRIVATE cxx_std_11)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${verilator} PRIVATE
|
||||
YYDEBUG # Required to get nice error messages
|
||||
$<$<CONFIG:DEBUG>:VL_DEBUG>
|
||||
$<$<CONFIG:DEBUG>:_GLIBCXX_DEBUG>
|
||||
)
|
||||
|
||||
target_include_directories(${verilator}
|
||||
target_compile_definitions(
|
||||
${verilator}
|
||||
PRIVATE
|
||||
../include
|
||||
${WIN_FLEX_BISON}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
YYDEBUG # Required to get nice error messages
|
||||
$<$<CONFIG:DEBUG>:VL_DEBUG>
|
||||
$<$<CONFIG:DEBUG>:_GLIBCXX_DEBUG>
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
target_include_directories(
|
||||
${verilator}
|
||||
PRIVATE
|
||||
../include
|
||||
${WIN_FLEX_BISON}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
if(MINGW)
|
||||
target_compile_options(${verilator} PRIVATE -Wa,-mbig-obj)
|
||||
target_link_options(${verilator} PRIVATE -Wl,--stack,10000000 -mconsole -lcomctl32 -DWIN_32_LEAN_AND_MEAN)
|
||||
target_link_options(
|
||||
${verilator}
|
||||
PRIVATE
|
||||
-Wl,--stack,10000000
|
||||
-mconsole
|
||||
-lcomctl32
|
||||
-DWIN_32_LEAN_AND_MEAN
|
||||
)
|
||||
else()
|
||||
target_compile_options(${verilator} PRIVATE /bigobj)
|
||||
target_link_options(${verilator} PRIVATE /STACK:10000000)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${verilator} PRIVATE
|
||||
YY_NO_UNISTD_H
|
||||
)
|
||||
target_compile_definitions(${verilator} PRIVATE YY_NO_UNISTD_H)
|
||||
target_include_directories(${verilator} PRIVATE ../platform/win32)
|
||||
target_link_libraries(${verilator} PRIVATE bcrypt psapi)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ prefix = @prefix@
|
|||
# Directory in which to install data across multiple architectures
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
# Directory in which to install package specific files
|
||||
# Directory in which to install package-specific files
|
||||
# Generally ${prefix}/share/verilator
|
||||
pkgdatadir = @pkgdatadir@
|
||||
|
||||
|
|
@ -210,6 +210,7 @@ RAW_OBJS_PCH_ASTMT = \
|
|||
V3Options.o \
|
||||
V3Stats.o \
|
||||
V3StatsReport.o \
|
||||
V3VariableOrder.o \
|
||||
|
||||
RAW_OBJS_PCH_ASTNOMT = \
|
||||
V3Active.o \
|
||||
|
|
@ -309,7 +310,6 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||
V3Undriven.o \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
V3VariableOrder.o \
|
||||
V3Width.o \
|
||||
V3WidthCommit.o \
|
||||
V3WidthSel.o \
|
||||
|
|
@ -355,9 +355,6 @@ $(TGT): $(PREDEP_H) $(OBJS)
|
|||
@echo " Linking $@..."
|
||||
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
|
||||
|
||||
V3Number_test: V3Number_test.o
|
||||
${LINK} ${LDFLAGS} -o $@ $^ ${LIBS}
|
||||
|
||||
#### Modules
|
||||
|
||||
%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) $(DFG_DEFS)
|
||||
|
|
@ -366,7 +363,7 @@ V3Number_test: V3Number_test.o
|
|||
.SECONDARY:
|
||||
|
||||
%.gch: %
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH} $< -o $@
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH} -c $< -o $@
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||
%.o: %.c
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ class AssertVisitor final : public VNVisitor {
|
|||
AstNodeStmt* const bodysp = dispp;
|
||||
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
||||
if (exprsp) dispp->fmtp()->exprsp()->addNext(exprsp);
|
||||
if (v3Global.opt.stopFail()) bodysp->addNext(new AstStop{nodep->fileline(), true});
|
||||
if (v3Global.opt.stopFail()) bodysp->addNext(new AstStop{nodep->fileline(), false});
|
||||
return bodysp;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
|
|
|||
|
|
@ -216,8 +216,16 @@ private:
|
|||
skewedReadRefp->cloneTree(false)});
|
||||
if (skewp->isZero()) {
|
||||
// Drive the var in Re-NBA (IEEE 1800-2023 14.16)
|
||||
m_clockingp->addNextHere(new AstAlwaysReactive{
|
||||
flp, new AstSenTree{flp, m_clockingp->sensesp()->cloneTree(false)}, ifp});
|
||||
AstSenTree* senTreep
|
||||
= new AstSenTree{flp, m_clockingp->sensesp()->cloneTree(false)};
|
||||
senTreep->addSensesp(
|
||||
new AstSenItem{flp, VEdgeType::ET_CHANGED, skewedReadRefp->cloneTree(false)});
|
||||
AstCMethodHard* const trigp = new AstCMethodHard{
|
||||
nodep->fileline(),
|
||||
new AstVarRef{flp, m_clockingp->ensureEventp(), VAccess::READ}, "isTriggered"};
|
||||
trigp->dtypeSetBit();
|
||||
ifp->condp(new AstLogAnd{flp, ifp->condp()->unlinkFrBack(), trigp});
|
||||
m_clockingp->addNextHere(new AstAlwaysReactive{flp, senTreep, ifp});
|
||||
} else if (skewp->fileline()->timingOn()) {
|
||||
// Create a fork so that this AlwaysObserved can be retriggered before the
|
||||
// assignment happens. Also then it can be combo, avoiding the need for creating
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
|
|
|||
29
src/V3Ast.h
29
src/V3Ast.h
|
|
@ -215,7 +215,7 @@ public:
|
|||
return names[m_e];
|
||||
}
|
||||
const char* arrow() const {
|
||||
static const char* const names[] = {"[RV] <-", "[LV] =>", "[LV] <=>", "--"};
|
||||
static const char* const names[] = {"[RV] <-", "[LV] =>", "[LRV] <=>", "--"};
|
||||
return names[m_e];
|
||||
}
|
||||
VAccess()
|
||||
|
|
@ -899,6 +899,8 @@ public:
|
|||
SUPPLY1,
|
||||
WIRE,
|
||||
WREAL,
|
||||
TRIAND,
|
||||
TRIOR,
|
||||
TRIWIRE,
|
||||
TRI0,
|
||||
TRI1,
|
||||
|
|
@ -919,20 +921,24 @@ public:
|
|||
constexpr operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* const names[]
|
||||
= {"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1",
|
||||
"WIRE", "WREAL", "TRIWIRE", "TRI0", "TRI1", "PORT", "BLOCKTEMP",
|
||||
"MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
|
||||
= {"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1",
|
||||
"WIRE", "WREAL", "TRIAND", "TRIOR", "TRIWIRE", "TRI0", "TRI1",
|
||||
"PORT", "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
|
||||
return names[m_e];
|
||||
}
|
||||
bool isParam() const { return m_e == GPARAM || m_e == LPARAM; }
|
||||
bool isSignal() const {
|
||||
return (m_e == WIRE || m_e == WREAL || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|
||||
|| m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR);
|
||||
|| m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR || m_e == TRIOR
|
||||
|| m_e == TRIAND);
|
||||
}
|
||||
bool isNet() const {
|
||||
return (m_e == WIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 || m_e == SUPPLY0
|
||||
|| m_e == SUPPLY1);
|
||||
|| m_e == SUPPLY1 || m_e == TRIOR || m_e == TRIAND);
|
||||
}
|
||||
bool isWor() const { return (m_e == TRIOR); }
|
||||
bool isWand() const { return (m_e == TRIAND); }
|
||||
bool isWiredNet() const { return (m_e == TRIOR || m_e == TRIAND); }
|
||||
bool isContAssignable() const { // In Verilog, always ok in SystemVerilog
|
||||
return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL || m_e == TRIWIRE
|
||||
|| m_e == TRI0 || m_e == TRI1 || m_e == PORT || m_e == BLOCKTEMP
|
||||
|
|
@ -963,6 +969,8 @@ public:
|
|||
/* SUPPLY1: */ "SUPPLY1",
|
||||
/* WIRE: */ "WIRE",
|
||||
/* WREAL: */ "WIRE",
|
||||
/* TRIAND: */ "TRIAND",
|
||||
/* TRIOR: */ "TRIOR",
|
||||
/* TRIWIRE: */ "TRI",
|
||||
/* TRI0: */ "TRI0",
|
||||
/* TRI1: */ "TRI1",
|
||||
|
|
@ -2182,7 +2190,7 @@ public:
|
|||
virtual void tag(const string& text) {}
|
||||
virtual string tag() const { return ""; }
|
||||
virtual string verilogKwd() const { return ""; }
|
||||
string nameProtect() const; // Name with --protect-id applied
|
||||
string nameProtect() const VL_MT_STABLE; // Name with --protect-id applied
|
||||
string origNameProtect() const; // origName with --protect-id applied
|
||||
string shortName() const; // Name with __PVT__ removed for concatenating scopes
|
||||
static string dedotName(const string& namein); // Name with dots removed
|
||||
|
|
@ -2362,8 +2370,9 @@ public:
|
|||
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
|
||||
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
|
||||
AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin,
|
||||
VSigning numeric) const;
|
||||
AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin, VSigning numeric) const;
|
||||
VSigning numeric) const VL_MT_STABLE;
|
||||
AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin,
|
||||
VSigning numeric) const VL_MT_STABLE;
|
||||
AstNodeDType* findBasicDType(VBasicDTypeKwd kwd) const;
|
||||
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
||||
|
||||
|
|
@ -2440,7 +2449,7 @@ public:
|
|||
static void dumpTreeFileGdb(const AstNode* nodep, const char* filenamep = nullptr);
|
||||
void dumpTreeDot(std::ostream& os = std::cout) const;
|
||||
void dumpTreeDotFile(const string& filename, bool doDump = true);
|
||||
virtual void dumpJson(std::ostream& os) const { dumpJsonGen(os); }; // node specific fields
|
||||
virtual void dumpJson(std::ostream& os) const { dumpJsonGen(os); }; // node-specific fields
|
||||
// Generated by 'astgen'. Dumps node-specific pointers and calls 'dumpJson()' of parent class
|
||||
// Note that we don't make it virtual as it would result in infinite recursion
|
||||
void dumpJsonGen(std::ostream& os) const {};
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public:
|
|||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
virtual void dumpSmall(std::ostream& str) const VL_MT_STABLE;
|
||||
bool hasDType() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
/// Require VlUnpacked, instead of [] for POD elements.
|
||||
/// A non-POD object is always compound, but some POD elements
|
||||
/// are compound when methods calls operate on object, or when
|
||||
|
|
@ -74,7 +74,7 @@ public:
|
|||
virtual int widthAlignBytes() const = 0;
|
||||
// (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
virtual int widthTotalBytes() const = 0;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
// Iff has a non-null refDTypep(), as generic node function
|
||||
virtual AstNodeDType* virtRefDTypep() const { return nullptr; }
|
||||
// Iff has refDTypep(), set as generic node function
|
||||
|
|
@ -86,7 +86,7 @@ public:
|
|||
// Assignable equivalence. Call skipRefp() on this and samep before calling
|
||||
virtual bool similarDType(const AstNodeDType* samep) const = 0;
|
||||
// Iff has a non-null subDTypep(), as generic node function
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_SAFE { return nullptr; }
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_STABLE { return nullptr; }
|
||||
virtual bool isFourstate() const;
|
||||
// Ideally an IEEE $typename
|
||||
virtual string prettyDTypeName(bool) const { return prettyTypeName(); }
|
||||
|
|
@ -105,14 +105,14 @@ public:
|
|||
m_numeric = nodep->m_numeric;
|
||||
}
|
||||
//
|
||||
int width() const VL_MT_SAFE { return m_width; }
|
||||
int width() const VL_MT_STABLE { return m_width; }
|
||||
void numeric(VSigning flag) { m_numeric = flag; }
|
||||
bool isSigned() const VL_MT_SAFE { return m_numeric.isSigned(); }
|
||||
bool isSigned() const VL_MT_STABLE { return m_numeric.isSigned(); }
|
||||
bool isNosign() const VL_MT_SAFE { return m_numeric.isNosign(); }
|
||||
VSigning numeric() const { return m_numeric; }
|
||||
int widthWords() const VL_MT_SAFE { return VL_WORDS_I(width()); }
|
||||
int widthMin() const VL_MT_SAFE { // If sized, the size,
|
||||
// if unsized the min digits to represent it
|
||||
VSigning numeric() const VL_MT_STABLE { return m_numeric; }
|
||||
int widthWords() const VL_MT_STABLE { return VL_WORDS_I(width()); }
|
||||
int widthMin() const VL_MT_STABLE { // If sized, the size,
|
||||
// if unsized the min digits to represent it
|
||||
return m_widthMin ? m_widthMin : m_width;
|
||||
}
|
||||
int widthPow2() const;
|
||||
|
|
@ -209,6 +209,12 @@ protected:
|
|||
m_packed = (numericUnpack != VSigning::NOSIGN);
|
||||
numeric(VSigning::fromBool(numericUnpack.isSigned()));
|
||||
}
|
||||
AstNodeUOrStructDType(const AstNodeUOrStructDType& other)
|
||||
: AstNodeDType(other)
|
||||
, m_name(other.m_name)
|
||||
, m_uniqueNum(uniqueNumInc())
|
||||
, m_packed(other.m_packed)
|
||||
, m_isFourstate(other.m_isFourstate) {}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstNodeUOrStructDType;
|
||||
|
|
@ -218,7 +224,7 @@ public:
|
|||
string prettyDTypeName(bool) const override;
|
||||
bool isCompound() const override { return !packed(); }
|
||||
// For basicp() we reuse the size to indicate a "fake" basic type of same size
|
||||
AstBasicDType* basicp() const override {
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE {
|
||||
if (!m_packed) return nullptr;
|
||||
return (isFourstate()
|
||||
? VN_AS(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
|
||||
|
|
@ -244,9 +250,11 @@ public:
|
|||
static bool packedUnsup() { return true; }
|
||||
void isFourstate(bool flag) { m_isFourstate = flag; }
|
||||
bool isFourstate() const override VL_MT_SAFE { return m_isFourstate; }
|
||||
static int lo() { return 0; }
|
||||
int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays
|
||||
VNumRange declRange() const { return VNumRange{hi(), lo()}; }
|
||||
static int lo() VL_MT_STABLE { return 0; }
|
||||
int hi() const VL_MT_STABLE {
|
||||
return dtypep()->width() - 1;
|
||||
} // Packed classes look like arrays
|
||||
VNumRange declRange() const VL_MT_STABLE { return VNumRange{hi(), lo()}; }
|
||||
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
||||
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
|
||||
};
|
||||
|
|
@ -269,8 +277,8 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstEnumItem;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
};
|
||||
|
||||
|
|
@ -416,8 +424,8 @@ public:
|
|||
return m.m_keyword;
|
||||
}
|
||||
bool isBitLogic() const { return keyword().isBitLogic(); }
|
||||
bool isDouble() const VL_MT_SAFE { return keyword().isDouble(); }
|
||||
bool isEvent() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::EVENT; }
|
||||
bool isDouble() const VL_MT_STABLE { return keyword().isDouble(); }
|
||||
bool isEvent() const VL_MT_STABLE { return keyword() == VBasicDTypeKwd::EVENT; }
|
||||
bool isTriggerVec() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::TRIGGERVEC; }
|
||||
bool isForkSync() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::FORK_SYNC; }
|
||||
bool isProcessRef() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::PROCESS_REFERENCE; }
|
||||
|
|
@ -434,7 +442,7 @@ public:
|
|||
return keyword() == VBasicDTypeKwd::RANDOM_GENERATOR;
|
||||
}
|
||||
bool isOpaque() const VL_MT_SAFE { return keyword().isOpaque(); }
|
||||
bool isString() const VL_MT_SAFE { return keyword().isString(); }
|
||||
bool isString() const VL_MT_STABLE { return keyword().isString(); }
|
||||
bool isZeroInit() const { return keyword().isZeroInit(); }
|
||||
bool isRanged() const { return rangep() || m.m_nrange.ranged(); }
|
||||
bool isDpiBitVec() const { // DPI uses svBitVecVal
|
||||
|
|
@ -479,7 +487,7 @@ public:
|
|||
// METHODS
|
||||
// Will be removed in V3Width, which relies on this
|
||||
// being a child not a dtype pointed node
|
||||
bool maybePointedTo() const override { return false; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return false; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
|
|
@ -563,7 +571,7 @@ public:
|
|||
int widthTotalBytes() const override { return 0; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||
AstClass* classp() const VL_MT_STABLE { return m_classp; }
|
||||
|
|
@ -624,10 +632,10 @@ public:
|
|||
dtypep(this);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstConstraintRefDType;
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool undead() const override { return true; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
|
|
@ -662,6 +670,11 @@ public:
|
|||
childDTypep(dtp); // Only for parser
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
AstDefImplicitDType(const AstDefImplicitDType& other)
|
||||
: AstNodeDType(other)
|
||||
, m_name(other.m_name)
|
||||
, m_containerp(other.m_containerp)
|
||||
, m_uniqueNum(uniqueNumInc()) {}
|
||||
ASTGEN_MEMBERS_AstDefImplicitDType;
|
||||
int uniqueNum() const { return m_uniqueNum; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
|
|
@ -749,10 +762,10 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstEmptyQueueDType;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool undead() const override { return true; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
|
|
@ -791,6 +804,10 @@ public:
|
|||
dtypep(nullptr); // V3Width will resolve
|
||||
widthFromSub(subDTypep());
|
||||
}
|
||||
AstEnumDType(const AstEnumDType& other)
|
||||
: AstNodeDType(other)
|
||||
, m_name(other.m_name)
|
||||
, m_uniqueNum(uniqueNumInc()) {}
|
||||
ASTGEN_MEMBERS_AstEnumDType;
|
||||
|
||||
const char* broken() const override;
|
||||
|
|
@ -931,8 +948,8 @@ public:
|
|||
ASTGEN_MEMBERS_AstMemberDType;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeUOrStructDType* getChildStructp() const;
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
|
|
@ -979,11 +996,11 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstNBACommitQueueDType;
|
||||
|
||||
AstNodeDType* subDTypep() const override { return m_subDTypep; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE { return m_subDTypep; }
|
||||
bool partial() const { return m_partial; }
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
AstBasicDType* basicp() const override { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return 1; }
|
||||
|
|
@ -1025,8 +1042,8 @@ public:
|
|||
int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); }
|
||||
// METHODS
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
VVarType varType() const { return m_varType; } // * = Type of variable
|
||||
bool isParam() const { return true; }
|
||||
|
|
@ -1044,7 +1061,7 @@ public:
|
|||
explicit AstParseTypeDType(FileLine* fl)
|
||||
: ASTGEN_SUPER_ParseTypeDType(fl) {}
|
||||
ASTGEN_MEMBERS_AstParseTypeDType;
|
||||
AstNodeDType* dtypep() const { return nullptr; }
|
||||
AstNodeDType* dtypep() const VL_MT_STABLE { return nullptr; }
|
||||
// METHODS
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
|
|
@ -1119,7 +1136,7 @@ public:
|
|||
bool isCompound() const override { return true; }
|
||||
};
|
||||
class AstRefDType final : public AstNodeDType {
|
||||
// @astgen op1 := typeofp : Optional[AstNode]
|
||||
// @astgen op1 := typeofp : Optional[AstNode<AstNodeExpr|AstNodeDType>]
|
||||
// @astgen op2 := classOrPackageOpp : Optional[AstNodeExpr]
|
||||
// @astgen op3 := paramsp : List[AstPin]
|
||||
//
|
||||
|
|
@ -1263,10 +1280,10 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstStreamDType;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool undead() const override { return true; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
|
|
@ -1331,10 +1348,10 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstVoidDType;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool undead() const override { return true; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
|
||||
AstNodeDType* subDTypep() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* virtRefDTypep() const override { return nullptr; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override {}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public:
|
|||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
// TODO: The only AstNodeExpr without dtype is AstArg. Otherwise this could be final.
|
||||
bool hasDType() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV
|
||||
// For documentation on emitC format see EmitCFunc::emitOpName
|
||||
virtual string emitC() = 0;
|
||||
|
|
@ -420,7 +420,7 @@ public:
|
|||
const V3Number& ths) override;
|
||||
string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; }
|
||||
string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; }
|
||||
string emitSMT() const override { return "(ite %l %r %t)"; }
|
||||
string emitSMT() const override { return "(ite (__Vbool %l) %r %t)"; }
|
||||
bool cleanOut() const override { return false; } // clean if e1 & e2 clean
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool cleanRhs() const override { return false; }
|
||||
|
|
@ -525,7 +525,7 @@ public:
|
|||
int instrCount() const override { return widthInstrs(); }
|
||||
VAccess access() const { return m_access; }
|
||||
void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor
|
||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
|
||||
void varp(AstVar* varp) {
|
||||
m_varp = varp;
|
||||
dtypeFrom((AstNode*)varp);
|
||||
|
|
@ -578,7 +578,7 @@ public:
|
|||
this->exprp(exprp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstArg;
|
||||
bool hasDType() const override { return false; }
|
||||
bool hasDType() const override VL_MT_SAFE { return false; }
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); }
|
||||
|
|
@ -589,7 +589,7 @@ public:
|
|||
};
|
||||
class AstAttrOf final : public AstNodeExpr {
|
||||
// Return a value of a attribute, for example a LSB or array LSB of a signal
|
||||
// @astgen op1 := fromp : Optional[AstNode] // Expr or DType
|
||||
// @astgen op1 := fromp : Optional[AstNode<AstNodeExpr|AstNodeDType>]
|
||||
// @astgen op2 := dimp : Optional[AstNodeExpr]
|
||||
VAttrType m_attrType; // What sort of extraction
|
||||
public:
|
||||
|
|
@ -1660,6 +1660,17 @@ public:
|
|||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
};
|
||||
class AstParseHolder final : public AstNodeExpr {
|
||||
// A reference to something soon to replace, used in a select at parse time
|
||||
// that needs conversion to pull the upper lvalue later
|
||||
public:
|
||||
AstParseHolder(FileLine* fl)
|
||||
: ASTGEN_SUPER_ParseHolder(fl) {}
|
||||
ASTGEN_MEMBERS_AstParseHolder;
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
|
||||
};
|
||||
class AstParseRef final : public AstNodeExpr {
|
||||
// A reference to a variable, function or task
|
||||
// We don't know which at parse time due to bison constraints
|
||||
|
|
@ -2014,12 +2025,12 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstSelLoopVars;
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
bool maybePointedTo() const override { return false; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return false; }
|
||||
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
|
||||
bool hasDType() const override { return false; }
|
||||
bool hasDType() const override VL_MT_SAFE { return false; }
|
||||
};
|
||||
class AstSetAssoc final : public AstNodeExpr {
|
||||
// Set an assoc array element and return object, '{}
|
||||
|
|
@ -2583,7 +2594,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f==? %r)"; }
|
||||
string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(= %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (= %l %r))"; }
|
||||
string emitSimpleOperator() override { return "=="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -2706,7 +2717,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f> %r)"; }
|
||||
string emitC() override { return "VL_GT_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvugt %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvugt %l %r))"; }
|
||||
string emitSimpleOperator() override { return ">"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -2777,7 +2788,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f> %r)"; }
|
||||
string emitC() override { return "VL_GTS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvsgt %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvsgt %l %r))"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -2801,7 +2812,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f>= %r)"; }
|
||||
string emitC() override { return "VL_GTE_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvuge %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvuge %l %r))"; }
|
||||
string emitSimpleOperator() override { return ">="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -2872,7 +2883,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f>= %r)"; }
|
||||
string emitC() override { return "VL_GTES_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvsge %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvsge %l %r))"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -2896,7 +2907,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f&& %r)"; }
|
||||
string emitC() override { return "VL_LOGAND_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(and %l %r)"; }
|
||||
string emitSMT() const override { return "(bvand %l %r)"; }
|
||||
string emitSimpleOperator() override { return "&&"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -2920,7 +2931,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f-> %r)"; }
|
||||
string emitC() override { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(=> %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (=> (__Vbool %l) (__Vbool %r)))"; }
|
||||
string emitSimpleOperator() override { return "->"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -2944,7 +2955,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f|| %r)"; }
|
||||
string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(or %l %r)"; }
|
||||
string emitSMT() const override { return "(bvor %l %r)"; }
|
||||
string emitSimpleOperator() override { return "||"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -2968,7 +2979,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f< %r)"; }
|
||||
string emitC() override { return "VL_LT_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvult %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvult %l %r))"; }
|
||||
string emitSimpleOperator() override { return "<"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -3039,7 +3050,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f< %r)"; }
|
||||
string emitC() override { return "VL_LTS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvslt %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvslt %l %r))"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -3063,7 +3074,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f<= %r)"; }
|
||||
string emitC() override { return "VL_LTE_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvule %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvule %l %r))"; }
|
||||
string emitSimpleOperator() override { return "<="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -3134,7 +3145,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f<= %r)"; }
|
||||
string emitC() override { return "VL_LTES_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvsle %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvsle %l %r))"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -3637,7 +3648,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f== %r)"; }
|
||||
string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(= %l %r)"; }
|
||||
string emitSMT() const override { return "(__Vbv (= %l %r))"; }
|
||||
string emitSimpleOperator() override { return "=="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -3779,7 +3790,7 @@ public:
|
|||
string emitVerilog() override { return "%k(%l %f!= %r)"; }
|
||||
string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return "!="; }
|
||||
string emitSMT() const override { return "(not (= %l %r))"; }
|
||||
string emitSMT() const override { return "(__Vbv (not (= %l %r)))"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool cleanRhs() const override { return true; }
|
||||
|
|
@ -4136,6 +4147,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l%f[%r])"; }
|
||||
string emitC() override { return "%li%k[%ri]"; }
|
||||
string emitSMT() const override { return "(select %l %r)"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return false; }
|
||||
bool cleanRhs() const override { return true; }
|
||||
|
|
@ -4176,8 +4188,9 @@ public:
|
|||
bool cleanRhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
bool isGateOptimizable() const override { return true; } // esp for V3Const::ifSameAssign
|
||||
bool isGateOptimizable() const override { return false; } // AssocSel creates on miss
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() override { return false; } // AssocSel creates on miss
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
};
|
||||
|
|
@ -4411,6 +4424,8 @@ class AstSelBit final : public AstNodePreSel {
|
|||
// Single bit range extraction, perhaps with non-constant selection or array selection
|
||||
// Gets replaced during link with AstArraySel or AstSel
|
||||
// @astgen alias op2 := bitp
|
||||
private:
|
||||
VAccess m_access; // Left hand side assignment
|
||||
public:
|
||||
AstSelBit(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* bitp)
|
||||
: ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) {
|
||||
|
|
@ -4418,6 +4433,8 @@ public:
|
|||
"not coded to create after dtypes resolved");
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSelBit;
|
||||
VAccess access() const { return m_access; }
|
||||
void access(const VAccess& flag) { m_access = flag; }
|
||||
};
|
||||
class AstSelExtract final : public AstNodePreSel {
|
||||
// Range extraction, gets replaced with AstSel
|
||||
|
|
@ -4692,8 +4709,8 @@ public:
|
|||
int widthConst() const { return VN_AS(widthp(), Const)->toSInt(); }
|
||||
int lsbConst() const { return VN_AS(lsbp(), Const)->toSInt(); }
|
||||
int msbConst() const { return lsbConst() + widthConst() - 1; }
|
||||
VNumRange& declRange() { return m_declRange; }
|
||||
const VNumRange& declRange() const { return m_declRange; }
|
||||
VNumRange& declRange() VL_MT_STABLE { return m_declRange; }
|
||||
const VNumRange& declRange() const VL_MT_STABLE { return m_declRange; }
|
||||
void declRange(const VNumRange& flag) { m_declRange = flag; }
|
||||
int declElWidth() const { return m_declElWidth; }
|
||||
void declElWidth(int flag) { m_declElWidth = flag; }
|
||||
|
|
@ -4727,8 +4744,8 @@ public:
|
|||
bool same(const AstNode*) const override { return true; }
|
||||
int instrCount() const override { return 10; } // Removed before matters
|
||||
// For widthConst()/loConst etc, see declRange().elements() and other VNumRange methods
|
||||
VNumRange& declRange() { return m_declRange; }
|
||||
const VNumRange& declRange() const { return m_declRange; }
|
||||
VNumRange& declRange() VL_MT_STABLE { return m_declRange; }
|
||||
const VNumRange& declRange() const VL_MT_STABLE { return m_declRange; }
|
||||
void declRange(const VNumRange& flag) { m_declRange = flag; }
|
||||
};
|
||||
class AstSubstrN final : public AstNodeTriop {
|
||||
|
|
@ -5150,7 +5167,7 @@ public:
|
|||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLogNot(lhs); }
|
||||
string emitVerilog() override { return "%f(! %l)"; }
|
||||
string emitC() override { return "VL_LOGNOT_%nq%lq(%nw,%lw, %P, %li)"; }
|
||||
string emitSMT() const override { return "(not %l)"; }
|
||||
string emitSMT() const override { return "(__Vbv (not (__Vbool %l)))"; }
|
||||
string emitSimpleOperator() override { return "!"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ public:
|
|||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpJson(std::ostream& str = std::cout) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool isGateOptimizable() const override {
|
||||
return !((m_dpiExport || m_dpiImport) && !m_dpiPure);
|
||||
}
|
||||
|
|
@ -193,6 +193,7 @@ public:
|
|||
isHideLocal(fromp->isHideLocal());
|
||||
isHideProtected(fromp->isHideProtected());
|
||||
isVirtual(fromp->isVirtual());
|
||||
isStatic(fromp->isStatic());
|
||||
lifetime(fromp->lifetime());
|
||||
underGenerate(fromp->underGenerate());
|
||||
}
|
||||
|
|
@ -263,7 +264,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstNodeModule;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
virtual bool timescaleMatters() const = 0;
|
||||
// ACCESSORS
|
||||
|
|
@ -371,7 +372,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstNodeAssign;
|
||||
// Clone single node, just get same type back.
|
||||
virtual AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) = 0;
|
||||
bool hasDType() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
virtual bool cleanRhs() const { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode*) const override { return true; }
|
||||
|
|
@ -421,7 +422,7 @@ public:
|
|||
void name(const string& name) override { m_name = name; }
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpJson(std::ostream& str = std::cout) const override;
|
||||
VAssertType type() const { return m_type; }
|
||||
VAssertType type() const VL_MT_SAFE { return m_type; }
|
||||
VAssertDirectiveType directive() const { return m_directive; }
|
||||
bool immediate() const {
|
||||
return this->type().containsAny(VAssertType::SIMPLE_IMMEDIATE
|
||||
|
|
@ -673,7 +674,7 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstCFunc;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpJson(std::ostream& str = std::cout) const override;
|
||||
bool same(const AstNode* samep) const override {
|
||||
|
|
@ -830,7 +831,7 @@ public:
|
|||
void cloneRelink() override {} // TODO V3Param shouldn't require avoiding cloneRelinkGen
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
// ACCESSORS
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
|
|
@ -872,7 +873,7 @@ public:
|
|||
void dumpJson(std::ostream& str) const override;
|
||||
// ACCESSORS
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
|
||||
void name(const string& name) override { m_name = name; }
|
||||
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
||||
|
|
@ -900,7 +901,7 @@ public:
|
|||
void dumpJson(std::ostream& str) const override;
|
||||
// ACCESSORS
|
||||
string name() const override VL_MT_STABLE { return m_cellp->name(); }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under
|
||||
string origModName() const {
|
||||
return m_cellp->origModName();
|
||||
|
|
@ -926,7 +927,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstClassExtends;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
bool hasDType() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
string verilogKwd() const override { return isImplements() ? "implements" : "extends"; }
|
||||
// Class being extended (after link and instantiation if needed)
|
||||
AstClass* classOrNullp() const;
|
||||
|
|
@ -961,6 +962,7 @@ public:
|
|||
std::string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool isDefault() const { return m_isDefault; }
|
||||
bool isGlobal() const { return m_isGlobal; }
|
||||
AstVar* ensureEventp(bool childDType = false);
|
||||
};
|
||||
class AstClockingItem final : public AstNode {
|
||||
// Parents: CLOCKING
|
||||
|
|
@ -987,7 +989,7 @@ public:
|
|||
VDirection direction() const { return m_direction; }
|
||||
AstClockingItem* outputp() const { return m_outputp; }
|
||||
void outputp(AstClockingItem* outputp) { m_outputp = outputp; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
};
|
||||
class AstConstPool final : public AstNode {
|
||||
// Container for const static data
|
||||
|
|
@ -1003,7 +1005,7 @@ class AstConstPool final : public AstNode {
|
|||
public:
|
||||
explicit AstConstPool(FileLine* fl);
|
||||
ASTGEN_MEMBERS_AstConstPool;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
void cloneRelink() override { V3ERROR_NA; }
|
||||
AstModule* modp() const { return m_modp; }
|
||||
|
||||
|
|
@ -1035,7 +1037,7 @@ public:
|
|||
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
void isStatic(bool flag) { m_isStatic = flag; }
|
||||
bool isStatic() const { return m_isStatic; }
|
||||
|
|
@ -1173,8 +1175,8 @@ public:
|
|||
this->valuep(valuep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstInitItem;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return false; } // See valuep()'s dtype instead
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return false; } // See valuep()'s dtype instead
|
||||
};
|
||||
class AstIntfRef final : public AstNode {
|
||||
// An interface reference
|
||||
|
|
@ -1223,7 +1225,7 @@ public:
|
|||
this->addVarsp(varsp);
|
||||
}
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
ASTGEN_MEMBERS_AstModport;
|
||||
};
|
||||
class AstModportFTaskRef final : public AstNode {
|
||||
|
|
@ -1268,7 +1270,7 @@ public:
|
|||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void direction(const VDirection& flag) { m_direction = flag; }
|
||||
VDirection direction() const { return m_direction; }
|
||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
|
||||
void varp(AstVar* varp) { m_varp = varp; }
|
||||
};
|
||||
class AstNetlist final : public AstNode {
|
||||
|
|
@ -1338,19 +1340,32 @@ class AstPackageExport final : public AstNode {
|
|||
// A package export declaration
|
||||
//
|
||||
// @astgen ptr := m_packagep : Optional[AstPackage] // Package hierarchy
|
||||
string m_name;
|
||||
string m_name; // What imported e.g. "*"
|
||||
string m_pkgName; // Module the cell instances
|
||||
|
||||
public:
|
||||
AstPackageExport(FileLine* fl, AstPackage* packagep, const string& name)
|
||||
: ASTGEN_SUPER_PackageExport(fl)
|
||||
, m_name{name}
|
||||
, m_packagep{packagep} {}
|
||||
, m_packagep{packagep} {
|
||||
pkgNameFrom();
|
||||
}
|
||||
AstPackageExport(FileLine* fl, const string& pkgName, const string& name)
|
||||
: ASTGEN_SUPER_PackageExport(fl)
|
||||
, m_name{name}
|
||||
, m_pkgName{pkgName}
|
||||
, m_packagep{nullptr} {}
|
||||
ASTGEN_MEMBERS_AstPackageExport;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
string pkgName() const VL_MT_STABLE { return m_pkgName; }
|
||||
string prettyPkgNameQ() const { return "'" + prettyName(pkgName()) + "'"; }
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep = nodep; }
|
||||
|
||||
private:
|
||||
void pkgNameFrom();
|
||||
};
|
||||
class AstPackageExportStarStar final : public AstNode {
|
||||
// A package export *::* declaration
|
||||
|
|
@ -1364,23 +1379,36 @@ class AstPackageImport final : public AstNode {
|
|||
// A package import declaration
|
||||
//
|
||||
// @astgen ptr := m_packagep : Optional[AstPackage] // Package hierarchy
|
||||
string m_name;
|
||||
string m_name; // What imported e.g. "*"
|
||||
string m_pkgName; // Module the cell instances
|
||||
|
||||
public:
|
||||
AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name)
|
||||
: ASTGEN_SUPER_PackageImport(fl)
|
||||
, m_name{name}
|
||||
, m_packagep{packagep} {}
|
||||
, m_packagep{packagep} {
|
||||
pkgNameFrom();
|
||||
}
|
||||
AstPackageImport(FileLine* fl, const string& pkgName, const string& name)
|
||||
: ASTGEN_SUPER_PackageImport(fl)
|
||||
, m_name{name}
|
||||
, m_pkgName{pkgName}
|
||||
, m_packagep{nullptr} {}
|
||||
ASTGEN_MEMBERS_AstPackageImport;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
string pkgName() const VL_MT_STABLE { return m_pkgName; }
|
||||
string prettyPkgNameQ() const { return "'" + prettyName(pkgName()) + "'"; }
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep = nodep; }
|
||||
|
||||
private:
|
||||
void pkgNameFrom();
|
||||
};
|
||||
class AstPin final : public AstNode {
|
||||
// A port or parameter assignment on an instantiation
|
||||
// @astgen op1 := exprp : Optional[AstNode] // NodeExpr or NodeDType (nullptr if unconnected)
|
||||
// @astgen op1 := exprp : Optional[AstNode<AstNodeExpr|AstNodeDType>] // nullptr=unconnected
|
||||
//
|
||||
// @astgen ptr := m_modVarp : Optional[AstVar] // Input/output connects to on submodule
|
||||
// @astgen ptr := m_modPTypep : Optional[AstParamTypeDType] // Param type connects to on sub
|
||||
|
|
@ -1462,7 +1490,7 @@ public:
|
|||
this->propp(propp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstPropSpec;
|
||||
bool hasDType() const override {
|
||||
bool hasDType() const override VL_MT_SAFE {
|
||||
return true;
|
||||
} // Used under Cover, which expects a bool child
|
||||
};
|
||||
|
|
@ -1511,7 +1539,7 @@ public:
|
|||
BROKEN_RTN(!m_modp);
|
||||
return nullptr;
|
||||
}
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
void dump(std::ostream& str) const override;
|
||||
|
|
@ -1593,7 +1621,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstSenTree;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool isMulti() const { return m_multi; }
|
||||
void multi(bool flag) { m_multi = true; }
|
||||
// METHODS
|
||||
|
|
@ -1643,7 +1671,7 @@ class AstTopScope final : public AstNode {
|
|||
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstTopScope;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
};
|
||||
class AstTypeTable final : public AstNode {
|
||||
// Container for hash of standard data types
|
||||
|
|
@ -1662,7 +1690,7 @@ class AstTypeTable final : public AstNode {
|
|||
public:
|
||||
explicit AstTypeTable(FileLine* fl);
|
||||
ASTGEN_MEMBERS_AstTypeTable;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
void cloneRelink() override { V3ERROR_NA; }
|
||||
AstBasicDType* findBasicDType(FileLine* fl, VBasicDTypeKwd kwd);
|
||||
AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width, int widthMin,
|
||||
|
|
@ -1687,12 +1715,16 @@ class AstTypedef final : public AstNode {
|
|||
string m_name;
|
||||
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
||||
bool m_attrPublic = false;
|
||||
bool m_isHideLocal : 1; // Verilog local
|
||||
bool m_isHideProtected : 1; // Verilog protected
|
||||
|
||||
public:
|
||||
AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType,
|
||||
AstNodeDType* dtp)
|
||||
: ASTGEN_SUPER_Typedef(fl)
|
||||
, m_name{name} {
|
||||
, m_name{name}
|
||||
, m_isHideLocal{false}
|
||||
, m_isHideProtected{false} {
|
||||
childDTypep(dtp); // Only for parser
|
||||
addAttrsp(attrsp);
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
|
|
@ -1706,11 +1738,15 @@ public:
|
|||
}
|
||||
// METHODS
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
bool attrPublic() const { return m_attrPublic; }
|
||||
void attrPublic(bool flag) { m_attrPublic = flag; }
|
||||
bool isHideLocal() const { return m_isHideLocal; }
|
||||
void isHideLocal(bool flag) { m_isHideLocal = flag; }
|
||||
bool isHideProtected() const { return m_isHideProtected; }
|
||||
void isHideProtected(bool flag) { m_isHideProtected = flag; }
|
||||
void tag(const string& text) override { m_tag = text; }
|
||||
string tag() const override { return m_tag; }
|
||||
};
|
||||
|
|
@ -1725,7 +1761,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstTypedefFwd;
|
||||
// METHODS
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
};
|
||||
class AstUdpTable final : public AstNode {
|
||||
// @astgen op1 := linesp : List[AstUdpTableLine]
|
||||
|
|
@ -1745,7 +1781,7 @@ public:
|
|||
, m_text{text} {}
|
||||
ASTGEN_MEMBERS_AstUdpTableLine;
|
||||
string name() const override VL_MT_STABLE { return m_text; }
|
||||
string text() const { return m_text; }
|
||||
string text() const VL_MT_SAFE { return m_text; }
|
||||
};
|
||||
class AstVar final : public AstNode {
|
||||
// A variable (in/out/wire/reg/param) inside a module
|
||||
|
|
@ -1754,7 +1790,8 @@ class AstVar final : public AstNode {
|
|||
// @astgen op2 := delayp : Optional[AstDelay] // Net delay
|
||||
// Initial value that never changes (static const), or constructor argument for
|
||||
// MTASKSTATE variables
|
||||
// @astgen op3 := valuep : Optional[AstNode] // May be a DType for type parameter defaults
|
||||
// @astgen op3 := valuep : Optional[AstNode<AstNodeExpr|AstNodeDType>]
|
||||
// Value is a DType for type parameter defaults
|
||||
// @astgen op4 := attrsp : List[AstNode] // Attributes during early parse
|
||||
// @astgen ptr := m_sensIfacep : Optional[AstIface] // Interface type to which reads from this
|
||||
// var are sensitive
|
||||
|
|
@ -1811,6 +1848,7 @@ class AstVar final : public AstNode {
|
|||
bool m_isForcedByCode : 1; // May be forced/released from AstAssignForce/AstRelease
|
||||
bool m_isWrittenByDpi : 1; // This variable can be written by a DPI Export
|
||||
bool m_isWrittenBySuspendable : 1; // This variable can be written by a suspendable process
|
||||
bool m_ignorePostWrite : 1; // Ignore writes in 'Post' blocks during ordering
|
||||
|
||||
void init() {
|
||||
m_ansi = false;
|
||||
|
|
@ -1855,6 +1893,7 @@ class AstVar final : public AstNode {
|
|||
m_isForcedByCode = false;
|
||||
m_isWrittenByDpi = false;
|
||||
m_isWrittenBySuspendable = false;
|
||||
m_ignorePostWrite = false;
|
||||
m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN;
|
||||
}
|
||||
|
||||
|
|
@ -1906,9 +1945,9 @@ public:
|
|||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
bool same(const AstNode* samep) const override;
|
||||
string name() const override VL_MT_STABLE VL_MT_SAFE { return m_name; } // * = Var name
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
string origName() const override { return m_origName; } // * = Original name
|
||||
void origName(const string& name) { m_origName = name; }
|
||||
VVarType varType() const VL_MT_SAFE { return m_varType; } // * = Type of variable
|
||||
|
|
@ -2010,6 +2049,8 @@ public:
|
|||
void setWrittenByDpi() { m_isWrittenByDpi = true; }
|
||||
bool isWrittenBySuspendable() const { return m_isWrittenBySuspendable; }
|
||||
void setWrittenBySuspendable() { m_isWrittenBySuspendable = true; }
|
||||
bool ignorePostWrite() const { return m_ignorePostWrite; }
|
||||
void setIgnorePostWrite() { m_ignorePostWrite = true; }
|
||||
|
||||
// METHODS
|
||||
void name(const string& name) override { m_name = name; }
|
||||
|
|
@ -2026,13 +2067,16 @@ public:
|
|||
bool isRef() const VL_MT_SAFE { return m_direction.isRef(); }
|
||||
bool isWritable() const VL_MT_SAFE { return m_direction.isWritable(); }
|
||||
bool isTristate() const { return m_tristate; }
|
||||
bool isPrimaryIO() const { return m_primaryIO; }
|
||||
bool isPrimaryIO() const VL_MT_SAFE { return m_primaryIO; }
|
||||
bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); }
|
||||
bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); }
|
||||
bool isIfaceParent() const { return m_isIfaceParent; }
|
||||
bool isInternal() const { return m_isInternal; }
|
||||
bool isSignal() const { return varType().isSignal(); }
|
||||
bool isNet() const { return varType().isNet(); }
|
||||
bool isWor() const { return varType().isWor(); }
|
||||
bool isWand() const { return varType().isWand(); }
|
||||
bool isWiredNet() const { return varType().isWiredNet(); }
|
||||
bool isTemp() const { return varType().isTemp(); }
|
||||
bool isToggleCoverable() const {
|
||||
return ((isIO() || isSignal())
|
||||
|
|
@ -2050,15 +2094,15 @@ public:
|
|||
AstBasicDType* bdtypep = basicp();
|
||||
return bdtypep && bdtypep->isBitLogic();
|
||||
}
|
||||
bool isUsedClock() const { return m_usedClock; }
|
||||
bool isUsedClock() const VL_MT_SAFE { return m_usedClock; }
|
||||
bool isUsedParam() const { return m_usedParam; }
|
||||
bool isUsedLoopIdx() const { return m_usedLoopIdx; }
|
||||
bool isSc() const VL_MT_SAFE { return m_sc; }
|
||||
bool isScQuad() const;
|
||||
bool isScBv() const;
|
||||
bool isScBv() const VL_MT_STABLE;
|
||||
bool isScUint() const;
|
||||
bool isScUintBool() const;
|
||||
bool isScBigUint() const;
|
||||
bool isScBigUint() const VL_MT_STABLE;
|
||||
bool isScSensitive() const { return m_scSensitive; }
|
||||
bool isSigPublic() const;
|
||||
bool isSigModPublic() const { return m_sigModPublic; }
|
||||
|
|
@ -2150,12 +2194,12 @@ public:
|
|||
}
|
||||
cloneRelinkGen();
|
||||
}
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); }
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
bool same(const AstNode* samep) const override;
|
||||
bool hasDType() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
|
||||
AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under
|
||||
void scopep(AstScope* nodep) { m_scopep = nodep; }
|
||||
|
|
@ -2216,7 +2260,7 @@ public:
|
|||
this->fvarp(fvarp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstFunc;
|
||||
bool hasDType() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
AstNodeFTask* cloneType(const string& name) override {
|
||||
return new AstFunc{fileline(), name, nullptr, nullptr};
|
||||
}
|
||||
|
|
@ -2229,7 +2273,7 @@ public:
|
|||
AstLet(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_Let(fl, name, nullptr) {}
|
||||
ASTGEN_MEMBERS_AstLet;
|
||||
bool hasDType() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!VN_IS(stmtsp(), StmtExpr));
|
||||
return nullptr;
|
||||
|
|
@ -2242,7 +2286,7 @@ public:
|
|||
AstProperty(FileLine* fl, const string& name, AstNode* stmtp)
|
||||
: ASTGEN_SUPER_Property(fl, name, stmtp) {}
|
||||
ASTGEN_MEMBERS_AstProperty;
|
||||
bool hasDType() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
AstNodeFTask* cloneType(const string& name) override {
|
||||
return new AstProperty{fileline(), name, nullptr};
|
||||
}
|
||||
|
|
@ -2262,6 +2306,7 @@ public:
|
|||
class AstCFile final : public AstNodeFile {
|
||||
// C++ output file
|
||||
// Parents: NETLIST
|
||||
uint64_t m_complexityScore = 0;
|
||||
bool m_slow : 1; ///< Compile w/o optimization
|
||||
bool m_source : 1; ///< Source file (vs header file)
|
||||
bool m_support : 1; ///< Support file (non systemc)
|
||||
|
|
@ -2274,6 +2319,8 @@ public:
|
|||
ASTGEN_MEMBERS_AstCFile;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpJson(std::ostream& str = std::cout) const override;
|
||||
uint64_t complexityScore() const { return m_complexityScore; }
|
||||
void complexityScore(uint64_t newScore) { m_complexityScore = newScore; }
|
||||
bool slow() const { return m_slow; }
|
||||
void slow(bool flag) { m_slow = flag; }
|
||||
bool source() const { return m_source; }
|
||||
|
|
@ -2310,13 +2357,13 @@ public:
|
|||
: ASTGEN_SUPER_Class(fl, name) {}
|
||||
ASTGEN_MEMBERS_AstClass;
|
||||
string verilogKwd() const override { return "class"; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
bool timescaleMatters() const override { return false; }
|
||||
AstClassPackage* classOrPackagep() const VL_MT_SAFE { return m_classOrPackagep; }
|
||||
AstClassPackage* classOrPackagep() const VL_MT_STABLE { return m_classOrPackagep; }
|
||||
void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; }
|
||||
AstNode* membersp() const { return stmtsp(); }
|
||||
AstNode* membersp() const VL_MT_STABLE { return stmtsp(); }
|
||||
void addMembersp(AstNode* nodep) { addStmtsp(nodep); }
|
||||
bool isExtended() const { return m_extended; }
|
||||
void isExtended(bool flag) { m_extended = flag; }
|
||||
|
|
@ -2349,8 +2396,8 @@ public:
|
|||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Callable 'f' must have a signature compatible with 'void(AstClass*, T_Node*)', "
|
||||
"with 'T_Node' being a subtype of 'AstNode'");
|
||||
if (AstClassExtends* const extendsp = this->extendsp()) {
|
||||
extendsp->classp()->foreachMember(f);
|
||||
if (AstClassExtends* const cextendsp = this->extendsp()) {
|
||||
cextendsp->classp()->foreachMember(f);
|
||||
}
|
||||
for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstNode::privateTypeTest<T_Node>(stmtp)) f(this, static_cast<T_Node*>(stmtp));
|
||||
|
|
@ -2364,8 +2411,8 @@ public:
|
|||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Predicate 'p' must have a signature compatible with 'bool(const AstClass*, "
|
||||
"const T_Node*)', with 'T_Node' being a subtype of 'AstNode'");
|
||||
if (AstClassExtends* const extendsp = this->extendsp()) {
|
||||
if (extendsp->classp()->existsMember(p)) return true;
|
||||
if (AstClassExtends* const cextendsp = this->extendsp()) {
|
||||
if (cextendsp->classp()->existsMember(p)) return true;
|
||||
}
|
||||
for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstNode::privateTypeTest<T_Node>(stmtp)) {
|
||||
|
|
@ -2529,7 +2576,7 @@ public:
|
|||
class AstBracketRange final : public AstNodeRange {
|
||||
// Parser only concept "[lhsp]", an AstUnknownRange, QueueRange or Range,
|
||||
// unknown until lhsp type is determined
|
||||
// @astgen op1 := elementsp : AstNode // Expr or DType
|
||||
// @astgen op1 := elementsp : AstNode<AstNodeExpr|AstNodeDType>
|
||||
public:
|
||||
AstBracketRange(FileLine* fl, AstNode* elementsp)
|
||||
: ASTGEN_SUPER_BracketRange(fl) {
|
||||
|
|
@ -2541,7 +2588,7 @@ public:
|
|||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
// Will be removed in V3Width, which relies on this
|
||||
// being a child not a dtype pointed node
|
||||
bool maybePointedTo() const override { return false; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return false; }
|
||||
};
|
||||
class AstRange final : public AstNodeRange {
|
||||
// Range specification, for use under variables and cells
|
||||
|
|
@ -2780,7 +2827,7 @@ public:
|
|||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
int binNum() const { return m_binNum; }
|
||||
void binNum(int flag) { m_binNum = flag; }
|
||||
int offset() const { return m_offset; }
|
||||
|
|
@ -3065,7 +3112,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstJumpBlock;
|
||||
const char* broken() const override;
|
||||
int instrCount() const override { return 0; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
int labelNum() const { return m_labelNum; }
|
||||
void labelNum(int flag) { m_labelNum = flag; }
|
||||
|
|
@ -3111,7 +3158,7 @@ public:
|
|||
: ASTGEN_SUPER_JumpLabel(fl)
|
||||
, m_blockp{blockp} {}
|
||||
ASTGEN_MEMBERS_AstJumpLabel;
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!blockp()->brokeExistsAbove());
|
||||
BROKEN_RTN(blockp()->labelp() != this);
|
||||
|
|
@ -3269,10 +3316,14 @@ public:
|
|||
bool isPure() override { return exprp()->isPure(); }
|
||||
};
|
||||
class AstStop final : public AstNodeStmt {
|
||||
const bool m_isFatal; // $fatal not $stop
|
||||
public:
|
||||
AstStop(FileLine* fl, bool maybe)
|
||||
: ASTGEN_SUPER_Stop(fl) {}
|
||||
AstStop(FileLine* fl, bool isFatal)
|
||||
: ASTGEN_SUPER_Stop(fl)
|
||||
, m_isFatal(isFatal) {}
|
||||
ASTGEN_MEMBERS_AstStop;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
|
|
@ -3280,6 +3331,8 @@ public:
|
|||
bool isUnlikely() const override { return true; }
|
||||
int instrCount() const override { return 0; } // Rarely executes
|
||||
bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); }
|
||||
string emitVerilog() const { return m_isFatal ? "$fatal" : "$stop"; }
|
||||
bool isFatal() const { return m_isFatal; }
|
||||
};
|
||||
class AstSysFuncAsTask final : public AstNodeStmt {
|
||||
// TODO: This is superseded by AstStmtExpr, remove
|
||||
|
|
@ -3370,8 +3423,8 @@ public:
|
|||
int instrCount() const override { return 100; } // Large...
|
||||
ASTGEN_MEMBERS_AstTraceDecl;
|
||||
string name() const override VL_MT_STABLE { return m_showname; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
bool same(const AstNode* samep) const override { return false; }
|
||||
string showname() const { return m_showname; } // * = Var name
|
||||
// Details on what we're tracing
|
||||
|
|
@ -3412,7 +3465,7 @@ public:
|
|||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; }
|
||||
bool hasDType() const override { return true; }
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return declp() == VN_DBG_AS(samep, TraceInc)->declp();
|
||||
}
|
||||
|
|
@ -3610,6 +3663,7 @@ public:
|
|||
});
|
||||
}
|
||||
bool brokeLhsMustBeLvalue() const override { return true; }
|
||||
AstDelay* getLhsNetDelay() const;
|
||||
AstAlways* convertToAlways();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,12 @@ bool AstNodeFTaskRef::isPure() {
|
|||
// cached.
|
||||
return false;
|
||||
} else {
|
||||
if (!m_purity.isCached()) m_purity.set(this->getPurityRecurse());
|
||||
if (!m_purity.isCached()) {
|
||||
m_purity.set(true); // To prevent infinite recursion, set to true before getting
|
||||
// the actual purity. If there are impure statements in the
|
||||
// task/function, they'll taint this call anyway.
|
||||
m_purity.set(this->getPurityRecurse());
|
||||
}
|
||||
return m_purity.get();
|
||||
}
|
||||
}
|
||||
|
|
@ -322,6 +327,24 @@ AstNodeExpr* AstInsideRange::newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* l
|
|||
return new AstLogAnd{fileline(), ap, bp};
|
||||
}
|
||||
|
||||
AstVar* AstClocking::ensureEventp(bool childDType) {
|
||||
if (!eventp()) {
|
||||
AstVar* const evp
|
||||
= childDType ? new AstVar{fileline(), VVarType::MODULETEMP, m_name, VFlagChildDType{},
|
||||
new AstBasicDType{fileline(), VBasicDTypeKwd::EVENT}}
|
||||
: new AstVar{fileline(), VVarType::MODULETEMP, m_name,
|
||||
findBasicDType(VBasicDTypeKwd::EVENT)};
|
||||
evp->lifetime(VLifetime::STATIC);
|
||||
eventp(evp);
|
||||
// Trigger the clocking event in Observed (IEEE 1800-2023 14.13)
|
||||
addNextHere(new AstAlwaysObserved{
|
||||
fileline(), new AstSenTree{fileline(), sensesp()->cloneTree(false)},
|
||||
new AstFireEvent{fileline(), new AstVarRef{fileline(), evp, VAccess::WRITE}, false}});
|
||||
v3Global.setHasEvents();
|
||||
}
|
||||
return eventp();
|
||||
}
|
||||
|
||||
void AstConsDynArray::dump(std::ostream& str) const {
|
||||
this->AstNodeExpr::dump(str);
|
||||
if (lhsIsValue()) str << " [LVAL]";
|
||||
|
|
@ -2008,9 +2031,10 @@ void AstRefDType::dump(std::ostream& str) const {
|
|||
if (!s_recursing) { // Prevent infinite dump if circular typedefs
|
||||
s_recursing = true;
|
||||
str << " -> ";
|
||||
if (const auto subp = typedefp()) {
|
||||
if (const auto subp = subDTypep()) {
|
||||
if (typedefp()) str << "typedef=" << static_cast<void*>(typedefp()) << " -> ";
|
||||
subp->dump(str);
|
||||
} else if (const auto subp = subDTypep()) {
|
||||
} else if (const auto subp = typedefp()) {
|
||||
subp->dump(str);
|
||||
}
|
||||
s_recursing = false;
|
||||
|
|
@ -2173,14 +2197,28 @@ void AstNodeModule::dumpJson(std::ostream& str) const {
|
|||
}
|
||||
void AstPackageExport::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " -> " << packagep();
|
||||
if (packagep()) {
|
||||
str << " -> " << packagep();
|
||||
} else {
|
||||
str << " ->UNLINKED:" << pkgName();
|
||||
}
|
||||
}
|
||||
void AstPackageExport::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||
void AstPackageExport::pkgNameFrom() {
|
||||
if (packagep()) m_pkgName = packagep()->name();
|
||||
}
|
||||
void AstPackageImport::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " -> " << packagep();
|
||||
if (packagep()) {
|
||||
str << " -> " << packagep();
|
||||
} else {
|
||||
str << " ->UNLINKED:" << pkgName();
|
||||
}
|
||||
}
|
||||
void AstPackageImport::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||
void AstPackageImport::pkgNameFrom() {
|
||||
if (packagep()) m_pkgName = packagep()->name();
|
||||
}
|
||||
void AstPatMember::dump(std::ostream& str) const {
|
||||
this->AstNodeExpr::dump(str);
|
||||
if (isDefault()) str << " [DEFAULT]";
|
||||
|
|
@ -2676,6 +2714,14 @@ void AstFork::dumpJson(std::ostream& str) const {
|
|||
dumpJsonStr(str, "joinType", joinType().ascii());
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstStop::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (isFatal()) str << " [FATAL]";
|
||||
}
|
||||
void AstStop::dumpJson(std::ostream& str) const {
|
||||
dumpJsonBoolFunc(str, isFatal);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstTraceDecl::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (code()) str << " [code=" << code() << "]";
|
||||
|
|
@ -2788,6 +2834,7 @@ void AstCMethodHard::setPurity() {
|
|||
{"assign", false},
|
||||
{"at", true},
|
||||
{"atBack", true},
|
||||
{"atWrite", true},
|
||||
{"awaitingCurrentTime", true},
|
||||
{"clear", false},
|
||||
{"clearFired", false},
|
||||
|
|
@ -2851,9 +2898,28 @@ void AstCMethodHard::setPurity() {
|
|||
{"word", true},
|
||||
{"write_var", false}};
|
||||
|
||||
if (name() == "atWriteAppend" || name() == "atWriteAppendBack") {
|
||||
m_pure = false;
|
||||
// Treat atWriteAppend as pure if the argument is a loop iterator
|
||||
if (AstNodeExpr* const argp = pinsp()) {
|
||||
if (AstVarRef* const varrefp = VN_CAST(argp, VarRef)) {
|
||||
if (varrefp->varp()->isUsedLoopIdx()) m_pure = true;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto isPureIt = isPureMethod.find(name());
|
||||
UASSERT_OBJ(isPureIt != isPureMethod.end(), this, "Unknown purity of method " + name());
|
||||
m_pure = isPureIt->second;
|
||||
if (!m_pure) return;
|
||||
if (!fromp()->isPure()) m_pure = false;
|
||||
if (!m_pure) return;
|
||||
for (AstNodeExpr* argp = pinsp(); argp; argp = VN_AS(argp->nextp(), NodeExpr)) {
|
||||
if (!argp->isPure()) {
|
||||
m_pure = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AstCUse::dump(std::ostream& str) const {
|
||||
|
|
@ -2865,6 +2931,15 @@ void AstCUse::dumpJson(std::ostream& str) const {
|
|||
dumpJsonGen(str);
|
||||
}
|
||||
|
||||
static AstDelay* getLhsNetDelayRecurse(const AstNodeExpr* const nodep) {
|
||||
if (const AstNodeVarRef* const refp = VN_CAST(nodep, NodeVarRef)) {
|
||||
if (refp->varp()->delayp()) return refp->varp()->delayp();
|
||||
} else if (const AstNodeSel* const selp = VN_CAST(nodep, NodeSel)) {
|
||||
return getLhsNetDelayRecurse(selp->fromp());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
AstDelay* AstAssignW::getLhsNetDelay() const { return getLhsNetDelayRecurse(lhsp()); }
|
||||
AstAlways* AstAssignW::convertToAlways() {
|
||||
const bool hasTimingControl = isTimingControl();
|
||||
AstNodeExpr* const lhs1p = lhsp()->unlinkFrBack();
|
||||
|
|
|
|||
|
|
@ -427,7 +427,9 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
|
|||
AstNode* bodyPointp = new AstBegin{nodep->fileline(), "[EditWrapper]", nullptr};
|
||||
AstNode* newp = nullptr;
|
||||
AstNode* lastp = nodep;
|
||||
|
||||
// subfromp used to traverse each dimension of multi-d variable-sized unpacked array (queue,
|
||||
// dyn-arr and associative-arr)
|
||||
AstNodeExpr* subfromp = fromp->cloneTreePure(false);
|
||||
// Major dimension first
|
||||
for (AstNode *argsp = loopsp->elementsp(), *next_argsp; argsp; argsp = next_argsp) {
|
||||
next_argsp = argsp->nextp();
|
||||
|
|
@ -458,7 +460,10 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
|
|||
} else if (VN_IS(fromDtp, DynArrayDType) || VN_IS(fromDtp, QueueDType)) {
|
||||
AstConst* const leftp = new AstConst{fl, 0};
|
||||
AstNodeExpr* const rightp
|
||||
= new AstCMethodHard{fl, fromp->cloneTreePure(false), "size"};
|
||||
= new AstCMethodHard{fl, subfromp->cloneTreePure(false), "size"};
|
||||
AstVarRef* varRefp = new AstVarRef{fl, varp, VAccess::READ};
|
||||
subfromp = new AstCMethodHard{fl, subfromp, "at", varRefp};
|
||||
subfromp->dtypep(fromDtp);
|
||||
rightp->dtypeSetSigned32();
|
||||
rightp->protect(false);
|
||||
loopp = createForeachLoop(nodep, bodyPointp, varp, leftp, rightp, VNType::atLt);
|
||||
|
|
@ -473,13 +478,16 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
|
|||
first_varp->usedLoopIdx(true);
|
||||
first_varp->lifetime(VLifetime::AUTOMATIC);
|
||||
AstNodeExpr* const firstp
|
||||
= new AstCMethodHard{fl, fromp->cloneTreePure(false), "first",
|
||||
= new AstCMethodHard{fl, subfromp->cloneTreePure(false), "first",
|
||||
new AstVarRef{fl, varp, VAccess::READWRITE}};
|
||||
firstp->dtypeSetSigned32();
|
||||
AstNodeExpr* const nextp
|
||||
= new AstCMethodHard{fl, fromp->cloneTreePure(false), "next",
|
||||
= new AstCMethodHard{fl, subfromp->cloneTreePure(false), "next",
|
||||
new AstVarRef{fl, varp, VAccess::READWRITE}};
|
||||
nextp->dtypeSetSigned32();
|
||||
AstVarRef* varRefp = new AstVarRef{fl, varp, VAccess::READ};
|
||||
subfromp = new AstCMethodHard{fl, subfromp, "at", varRefp};
|
||||
subfromp->dtypep(fromDtp);
|
||||
AstNode* const first_clearp
|
||||
= new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE},
|
||||
new AstConst{fl, AstConst::BitFalse{}}};
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
class AstNode;
|
||||
class AstForeach;
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3CCtors final {
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3CUse final {
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
class AstNodeCase;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue