Merge from master for release.

This commit is contained in:
Wilson Snyder 2024-10-27 10:06:28 -04:00
commit 2cb1a8de73
5785 changed files with 70256 additions and 84489 deletions

View File

@ -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"

View File

@ -1,7 +1,7 @@
{
"name": "Verilator Build Environment",
"name": "Verilator Build Environment",
"build": {
"build": {
"dockerfile": "../ci/docker/buildenv/Dockerfile"
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 }}

View File

@ -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

View File

@ -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

9
.gitignore vendored
View File

@ -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/*

8
.pre-commit-hooks.yaml Normal file
View File

@ -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]

4
.style.yapf Normal file
View File

@ -0,0 +1,4 @@
[style]
based_on_style = pep8
column_limit = 99
#split_before_arithmetic_operator=True

View File

@ -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
View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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')

View File

@ -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')

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 && \

View File

@ -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
================================

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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
.. ============

View File

@ -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`).

View File

@ -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};

View File

@ -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

View File

@ -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

View File

@ -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`

View File

@ -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

View File

@ -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:

View File

@ -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.

View File

@ -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
Алексеевич
Исаак

View File

@ -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
)

View File

@ -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)

View File

@ -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
)

View File

@ -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
)

View File

@ -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)

View File

@ -13,6 +13,6 @@ module sub
);
// Some simple logic
always_comb out = ~ in;
always_comb out = ~in;
endmodule

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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, "",

View File

@ -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

View File

@ -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

View File

@ -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");
}

View File

@ -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);

View File

@ -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>

View File

@ -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.
///
//*************************************************************************

View File

@ -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;
}

View File

@ -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();

View File

@ -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;

View File

@ -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 <>

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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
//=========================================================================

View File

@ -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)

View File

@ -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',

View File

@ -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()

View File

@ -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)

View File

@ -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))

View File

@ -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,

59
nodist/lint_py_test_filter Executable file
View File

@ -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:

View File

@ -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.

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -20,8 +20,6 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================

View File

@ -20,8 +20,6 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================

View File

@ -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;
}

View File

@ -21,7 +21,6 @@
#include "verilatedos.h"
#include "V3Ast.h"
#include "V3ThreadSafety.h"
//============================================================================

View File

@ -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

View File

@ -20,8 +20,6 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================

View File

@ -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 {};

View File

@ -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; }

View File

@ -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; }

View File

@ -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();
};

View File

@ -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();

View File

@ -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{}}};

View File

@ -20,8 +20,6 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
class AstNode;
class AstForeach;

View File

@ -20,8 +20,6 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================

View File

@ -20,8 +20,6 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
//============================================================================
class V3CCtors final {

View File

@ -20,8 +20,6 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
//============================================================================
class V3CUse final {

View File

@ -20,8 +20,6 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
class AstNodeCase;

View File

@ -20,8 +20,6 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3ThreadSafety.h"
class AstNetlist;
//============================================================================

View File

@ -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