Merge from master for release.

This commit is contained in:
Wilson Snyder 2025-04-27 13:04:49 -04:00
commit 0dc93c1d5c
1201 changed files with 1117033 additions and 19668 deletions

View File

@ -9,7 +9,7 @@ assignees: ''
Thanks for taking the time to report this.
Can you attach an example that shows the issue? (Must be openly licensed, completely self-contaned so can directly run what you provide. Ideally use test_regress format, see https://veripool.org/guide/latest/contributing.html?highlight=test_regress#reporting-bugs
Can you attach an example that shows the issue? (Must be openly licensed, completely self-contained and self-checking so can directly run what you provide. Ideally use test_regress format, see https://veripool.org/guide/latest/contributing.html?highlight=test_regress#reporting-bugs
What 'verilator' command line do we use to run your example?

View File

@ -13,6 +13,6 @@ What would you like added/supported?
What 'verilator --version' are you using? Did you try it with the git master version?
Can you attach an example that runs on other simulators? (Must be openly licensed, ideally in test_regress format.)
Can you attach an example that runs on other simulators? (Must be openly licensed, completely self-contained and self-checking so can directly run what you provide. Ideally use test_regress format, see https://veripool.org/guide/latest/contributing.html?highlight=test_regress#reporting-bugs
May we assist you in trying to fix this in Verilator yourself?

View File

@ -12,15 +12,6 @@ on:
schedule:
- cron: '0 0 * * 0' # weekly
env:
CI_OS_NAME: linux
CI_COMMIT: ${{ github.sha }}
CCACHE_COMPRESS: 1
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_LIMIT_MULTIPLE: 0.95
INSTALL_DIR: ${{ github.workspace }}/install
RELOC_DIR: ${{ github.workspace }}/relloc
defaults:
run:
shell: bash
@ -32,134 +23,155 @@ concurrency:
jobs:
build:
build-2404-gcc:
name: Build
uses: ./.github/workflows/reusable-build.yml
with:
os: ${{ matrix.os }}
cc: ${{ matrix.cc }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, ubuntu-22.04, ubuntu-20.04]
compiler:
- {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}
runs-on: ${{ matrix.os }}
name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }}
env:
CI_BUILD_STAGE_NAME: build
CI_RUNS_ON: ${{ matrix.os }}
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)
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz
steps:
- {os: ubuntu-24.04, cc: gcc}
- 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: Install packages for build
run: ./ci/ci-install.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 }}
test:
needs: build
build-2404-clang:
name: Build
uses: ./.github/workflows/reusable-build.yml
with:
os: ${{ matrix.os }}
cc: ${{ matrix.cc }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, ubuntu-20.04]
compiler:
- {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, 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:
CI_BUILD_STAGE_NAME: test
CI_RUNS_ON: ${{ matrix.os }}
CI_RELOC: ${{ matrix.reloc }}
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)
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz
steps:
- {os: ubuntu-24.04, cc: clang}
- name: Download tar archive
uses: actions/download-artifact@v4
with:
name: ${{ env.VERILATOR_ARCHIVE }}
path: ${{ github.workspace }}
build-2204-gcc:
name: Build
uses: ./.github/workflows/reusable-build.yml
with:
os: ${{ matrix.os }}
cc: ${{ matrix.cc }}
strategy:
fail-fast: false
matrix:
include:
- {os: ubuntu-22.04, cc: gcc}
- name: Unpack tar archive
working-directory: ${{ github.workspace }}
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
build-2204-clang:
name: Build
uses: ./.github/workflows/reusable-build.yml
with:
os: ${{ matrix.os }}
cc: ${{ matrix.cc }}
strategy:
fail-fast: false
matrix:
include:
- {os: ubuntu-22.04, cc: clang}
- 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 }}-
test-2404-gcc:
name: Test | ${{ matrix.os }} | ${{ matrix.cc }}
needs: build-2404-gcc
uses: ./.github/workflows/reusable-test.yml
with:
os: ${{ matrix.os }}
cc: ${{ matrix.cc }}
reloc: ${{ matrix.reloc }}
suite: ${{ matrix.suite }}
strategy:
fail-fast: false
matrix:
include:
# Ubuntu 24.04 gcc
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-0}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-1}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-2}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-3}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-0}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-1}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-2}
- name: Install test dependencies
run: ./ci/ci-install.bash
test-2404-clang:
name: Test | ${{ matrix.os }} | ${{ matrix.cc }}
needs: build-2404-clang
uses: ./.github/workflows/reusable-test.yml
with:
os: ${{ matrix.os }}
cc: ${{ matrix.cc }}
reloc: ${{ matrix.reloc }}
suite: ${{ matrix.suite }}
strategy:
fail-fast: false
matrix:
include:
# Ubuntu 24.04 clang
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-0}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-1}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-2}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-3}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-0}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-1}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-2}
- name: Test
env:
TESTS: ${{ matrix.suite }}
run: ./ci/ci-script.bash
test-2204-gcc:
name: Test | ${{ matrix.os }} | ${{ matrix.cc }}
needs: build-2204-gcc
uses: ./.github/workflows/reusable-test.yml
with:
os: ${{ matrix.os }}
cc: ${{ matrix.cc }}
reloc: ${{ matrix.reloc }}
suite: ${{ matrix.suite }}
strategy:
fail-fast: false
matrix:
include:
# Ubuntu 22.04 gcc
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-0}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-1}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-2}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-3}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-0}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-1}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-2}
test-2204-clang:
name: Test | ${{ matrix.os }} | ${{ matrix.cc }}
needs: build-2204-clang
uses: ./.github/workflows/reusable-test.yml
with:
os: ${{ matrix.os }}
cc: ${{ matrix.cc }}
reloc: ${{ matrix.reloc }}
suite: ${{ matrix.suite }}
strategy:
fail-fast: false
matrix:
include:
# Ubuntu 22.04 clang, also test relocation
- {os: ubuntu-22.04, cc: clang, reloc: 1, suite: dist-vlt-0}
- {os: ubuntu-22.04, cc: clang, reloc: 1, suite: dist-vlt-1}
- {os: ubuntu-22.04, cc: clang, reloc: 1, suite: dist-vlt-2}
- {os: ubuntu-22.04, cc: clang, reloc: 1, suite: dist-vlt-3}
- {os: ubuntu-22.04, cc: clang, reloc: 1, suite: vltmt-0}
- {os: ubuntu-22.04, cc: clang, reloc: 1, suite: vltmt-1}
- {os: ubuntu-22.04, cc: clang, reloc: 1, suite: vltmt-2}
lint-py:
runs-on: ubuntu-22.04
name: Lint Python
env:
CI_OS_NAME: linux
CI_COMMIT: ${{ github.sha }}
CI_BUILD_STAGE_NAME: build
CI_RUNS_ON: ubuntu-22.04
CCACHE_COMPRESS: 1
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_LIMIT_MULTIPLE: 0.95
strategy:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4

View File

@ -76,11 +76,11 @@ jobs:
- name: Build and Push to Docker
uses: docker/build-push-action@v4
if: startsWith(github.ref, 'refs/tags/v')
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
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') }}
push: ${{ !env.ACT && (startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch') }}
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}

76
.github/workflows/reusable-build.yml vendored Normal file
View File

@ -0,0 +1,76 @@
---
# 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: reusable-build
on:
workflow_call:
inputs:
os: # e.g. ubuntu-24.04
required: true
type: string
cc: # gcc or clang
required: true
type: string
env:
CI_OS_NAME: linux
CI_COMMIT: ${{ github.sha }}
CCACHE_COMPRESS: 1
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_LIMIT_MULTIPLE: 0.95
INSTALL_DIR: ${{ github.workspace }}/install
RELOC_DIR: ${{ github.workspace }}/relloc
defaults:
run:
shell: bash
working-directory: repo
jobs:
build:
runs-on: ${{ inputs.os }}
name: Sub-build | ${{ inputs.os }} | ${{ inputs.cc }}
env:
CI_BUILD_STAGE_NAME: build
CI_RUNS_ON: ${{ inputs.os }}
CC: ${{ inputs.cc }}
CXX: ${{ inputs.cc == 'clang' && 'clang++' || 'g++' }}
CACHE_BASE_KEY: build-${{ inputs.os }}-${{ inputs.cc }}
CCACHE_MAXSIZE: 1000M # Per build matrix entry (* 5 = 5000M in total)
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ inputs.os }}-${{ inputs.cc }}.tar.gz
steps:
- 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: Install packages for build
run: ./ci/ci-install.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 }}

View File

@ -0,0 +1,73 @@
---
# 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: reusable-rtlmeter-build
on:
workflow_call:
inputs:
runs-on:
description: "Runner to use, e.g.: ubuntu-24.04"
type: string
required: true
cc:
description: "Compiler to use: 'gcc' or 'clang'"
type: string
required: true
defaults:
run:
shell: bash
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
CCACHE_MAXSIZE: 512M
jobs:
build:
runs-on: ${{ inputs.runs-on }}
name: Build
steps:
- name: Install dependencies
run: |
sudo apt update
sudo apt install ccache mold help2man libfl-dev libgoogle-perftools-dev libsystemc-dev
- name: Use saved ccache
uses: actions/cache@v4
with:
path: ccache
key: rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}
- name: Checkout
uses: actions/checkout@v4
with:
path: repo
fetch-depth: 0 # Required for 'git describe' used for 'verilator --version'
- name: Configure
working-directory: repo
run: |
autoconf
./configure --prefix=${{ github.workspace }}/install CXX=${{ inputs.cc == 'clang' && 'clang++' || 'g++' }}
- name: Make
working-directory: repo
run: make -j $(nproc)
- name: Install
working-directory: repo
run: make install
- name: Tar up installation
run: tar --posix -c -z -f verilator-rtlmeter.tar.gz install
- name: Upload Verilator installation archive
uses: actions/upload-artifact@v4
with:
path: verilator-rtlmeter.tar.gz
name: verilator-rtlmeter-${{ inputs.runs-on }}-${{ inputs.cc }}
overwrite: true

View File

@ -0,0 +1,118 @@
---
# 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: reusable-rtlmeter-run
on:
workflow_call:
inputs:
runs-on:
description: "Runner to use, e.g.: ubuntu-24.04"
type: string
required: true
cc:
description: "Compiler to use: 'gcc' or 'clang'"
type: string
required: true
cases:
description: "RTLMeter cases to run"
type: string
required: true
compileArgs:
description: "Additional Verilator command line arguments"
type: string
default: ""
executeArgs:
description: "Additional simulator command line arguments"
type: string
default: ""
defaults:
run:
shell: bash
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
CCACHE_MAXSIZE: 512M
CCACHE_DISABLE: 1
jobs:
run:
runs-on: ${{ inputs.runs-on }}
name: Run
steps:
- name: Install dependencies
run: |
sudo apt update
sudo apt install ccache mold libfl-dev libgoogle-perftools-dev libsystemc-dev
- name: Download Verilator installation archive
uses: actions/download-artifact@v4
with:
name: verilator-rtlmeter-${{ inputs.runs-on }}-${{ inputs.cc }}
- name: Unpack Verilator installation archive
run: |
tar -x -z -f verilator-rtlmeter.tar.gz
echo "${{ github.workspace }}/install/bin" >> $GITHUB_PATH
- name: Use saved ccache
if: ${{ env.CCACHE_DISABLE == 0 }}
uses: actions/cache@v4
with:
path: ${{ env.CCACHE_DIR }}
key: rtlmeter-run-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.cases }}-${{ inputs.compileArgs }}-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: rtlmeter-run-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.cases }}-${{ inputs.compileArgs }}
- name: Checkout RTLMeter
uses: actions/checkout@v4
with:
repository: "verilator/rtlmeter"
path: rtlmeter
- name: Setup RTLMeter venv
working-directory: rtlmeter
run: make venv
- name: Compile cases
working-directory: rtlmeter
run: |
./rtlmeter run --verbose --cases='${{ inputs.cases }}' --compileArgs='${{ inputs.compileArgs }}' --executeArgs='${{ inputs.executeArgs }}' --nExecute=0
# My YAML highlighter sucks, so I put this comment here wiht a phony closing quote mark to make it work: '
- name: Execute cases
working-directory: rtlmeter
continue-on-error: true # Do not fail on error, so we can at leat save the successful results
run: |
./rtlmeter run --verbose --cases='${{ inputs.cases }}' --compileArgs='${{ inputs.compileArgs }}' --executeArgs='${{ inputs.executeArgs }}'
# My YAML highlighter sucks, so I put this comment here wiht a phony closing quote mark to make it work: '
- name: Collate results
id: results
working-directory: rtlmeter
run: |
# 'inputs.cases' has special characters, use its md5sum as unique id
hash=$(md5sum <<< '${{ inputs.cases }}' | awk '{print $1}')
echo "hash=${hash}" >> $GITHUB_OUTPUT
./rtlmeter collate > ../results-${hash}.json
- name: Report results
working-directory: rtlmeter
run: |
./rtlmeter report --steps '*' --metrics '*' ../results-${{ steps.results.outputs.hash }}.json
- name: Upload results
uses: actions/upload-artifact@v4
with:
path: results-${{ steps.results.outputs.hash }}.json
name: rtlmeter-results-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ steps.results.outputs.hash }}
overwrite: true
retention-days: 2
- name: Report status
working-directory: rtlmeter
run: | # This will fail the job if any of the runs failed
./rtlmeter run --verbose --cases='${{ inputs.cases }}' --compileArgs='${{ inputs.compileArgs }}' --executeArgs='${{ inputs.executeArgs }}'
# My YAML highlighter sucks, so I put this comment here wiht a phony closing quote mark to make it work: '

80
.github/workflows/reusable-test.yml vendored Normal file
View File

@ -0,0 +1,80 @@
---
# 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: reusable-build
on:
workflow_call:
inputs:
os: # e.g. ubuntu-24.04
required: true
type: string
cc: # gcc or clang
required: true
type: string
reloc: # 0 or 1
required: true
type: number
suite: # e.g. dist-vlt-0
required: true
type: string
env:
CI_OS_NAME: linux
CI_COMMIT: ${{ github.sha }}
CCACHE_COMPRESS: 1
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_LIMIT_MULTIPLE: 0.95
INSTALL_DIR: ${{ github.workspace }}/install
RELOC_DIR: ${{ github.workspace }}/relloc
defaults:
run:
shell: bash
working-directory: repo
jobs:
test:
runs-on: ${{ inputs.os }}
name: Sub-test | ${{ inputs.os }} | ${{ inputs.cc }} | ${{inputs.reloc && 'reloc | ' || '' }} ${{ inputs.suite }}
env:
CI_BUILD_STAGE_NAME: test
CI_RUNS_ON: ${{ inputs.os }}
CI_RELOC: ${{inputs.reloc }}
CC: ${{ inputs.cc }}
CXX: ${{ inputs.cc == 'clang' && 'clang++' || 'g++' }}
CACHE_BASE_KEY: test-${{ inputs.os }}-${{ inputs.cc }}-${{inputs.reloc }}-${{ inputs.suite }}
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ inputs.os }}-${{ inputs.cc }}.tar.gz
steps:
- 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: 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: Test
env:
TESTS: ${{ inputs.suite }}
run: ./ci/ci-script.bash

158
.github/workflows/rtlmeter.yml vendored Normal file
View File

@ -0,0 +1,158 @@
---
# 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: RTLMeter
on:
workflow_dispatch:
schedule:
- cron: '0 2 * * *' # Daily, starting at 02:00 UTC
defaults:
run:
shell: bash
concurrency:
group: RTLMeter
cancel-in-progress: false
jobs:
build-gcc:
name: Build GCC
uses: ./.github/workflows/reusable-rtlmeter-build.yml
with:
runs-on: ubuntu-24.04
cc: gcc
build-clang:
name: Build Clang
uses: ./.github/workflows/reusable-rtlmeter-build.yml
with:
runs-on: ubuntu-24.04
cc: clang
run-gcc:
name: Run GCC | ${{ matrix.cases }}
needs: build-gcc
uses: ./.github/workflows/reusable-rtlmeter-run.yml
with:
runs-on: ubuntu-24.04
cc: gcc
cases: ${{ matrix.cases }}
compileArgs: ""
executeArgs: ""
strategy:
fail-fast: false
max-parallel: 2
matrix:
cases:
- "NVDLA:*"
- "OpenPiton:1x1:*"
- "OpenPiton:2x2:*"
- "OpenPiton:4x4:*"
# - "OpenTitan:*"
- "VeeR-EH1:asic*"
- "VeeR-EH1:default*"
- "VeeR-EH1:hiperf*"
- "VeeR-EH2:asic*"
- "VeeR-EH2:default*"
- "VeeR-EH2:hiperf*"
- "VeeR-EL2:asic*"
- "VeeR-EL2:default*"
- "VeeR-EL2:hiperf*"
- "Vortex:mini:*"
- "Vortex:sane:*"
# - "XiangShan:default-chisel3:* !*:linux"
# - "XiangShan:default-chisel6:* !*:linux"
- "XiangShan:mini-chisel3:* !*:linux"
# - "XiangShan:mini-chisel6:* !*:linux"
- "XuanTie-E902:*"
- "XuanTie-E906:*"
- "XuanTie-C906:*"
- "XuanTie-C910:*"
run-clang:
name: Run Clang | ${{ matrix.cases }}
needs: build-clang
uses: ./.github/workflows/reusable-rtlmeter-run.yml
with:
runs-on: ubuntu-24.04
cc: clang
cases: ${{ matrix.cases }}
compileArgs: "--threads 4"
executeArgs: ""
strategy:
fail-fast: false
max-parallel: 2
matrix:
cases:
- "NVDLA:*"
- "OpenPiton:1x1:*"
- "OpenPiton:2x2:*"
- "OpenPiton:4x4:*"
# - "OpenTitan:*"
- "VeeR-EH1:asic*"
- "VeeR-EH1:default*"
- "VeeR-EH1:hiperf*"
- "VeeR-EH2:asic*"
- "VeeR-EH2:default*"
- "VeeR-EH2:hiperf*"
- "VeeR-EL2:asic*"
- "VeeR-EL2:default*"
- "VeeR-EL2:hiperf*"
- "Vortex:mini:*"
- "Vortex:sane:*"
- "XiangShan:default-chisel3:* !*:linux"
- "XiangShan:default-chisel6:* !*:linux"
- "XiangShan:mini-chisel3:* !*:linux"
- "XiangShan:mini-chisel6:* !*:linux"
- "XuanTie-E902:*"
- "XuanTie-E906:*"
- "XuanTie-C906:*"
- "XuanTie-C910:*"
combine-results:
name: Combine results
needs:
- run-gcc
- run-clang
if: ${{ always() }} # Run even if dependencies failed
runs-on: ubuntu-24.04
steps:
- name: Download all GCC results
uses: actions/download-artifact@v4
with:
pattern: rtlmeter-results-ubuntu-24.04-gcc-*
path: all-results-gcc-${{ github.run_id }}
merge-multiple: true
- name: Download all Clang results
uses: actions/download-artifact@v4
with:
pattern: rtlmeter-results-ubuntu-24.04-clang-*
path: all-results-clang-${{ github.run_id }}
merge-multiple: true
- name: Tar up results
run: |
# Ensure combined result directories exists in case of no results
mkdir -p all-results-gcc-${{ github.run_id }}
mkdir -p all-results-clang-${{ github.run_id }}
ls -la all-results*
# Tar up each directory
tar --posix -c -z -f all-results-gcc-${{ github.run_id }}.tar.gz all-results-gcc-${{ github.run_id }}
tar --posix -c -z -f all-results-clang-${{ github.run_id }}.tar.gz all-results-clang-${{ github.run_id }}
- name: Upload combined GCC results
uses: actions/upload-artifact@v4
with:
path: all-results-gcc-${{ github.run_id }}.tar.gz
name: "all-results-gcc"
overwrite: true
retention-days: 30
- name: Upload combined Clang results
uses: actions/upload-artifact@v4
with:
path: all-results-clang-${{ github.run_id }}.tar.gz
name: "all-results-clang"
overwrite: true
retention-days: 30

View File

@ -16,7 +16,7 @@ cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
project(
Verilator
VERSION 5.034
VERSION 5.036
HOMEPAGE_URL https://verilator.org
LANGUAGES CXX
)
@ -134,10 +134,7 @@ configure_package_config_file(
INSTALL_DESTINATION .
)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config.cmake
DESTINATION .
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config.cmake DESTINATION .)
configure_package_config_file(
verilator-config-version.cmake.in

117
Changes
View File

@ -8,6 +8,87 @@ The changes in each Verilator version are described below. The
contributors that suggested a given feature are shown in []. Thanks!
Verilator 5.036 2025-04-27
==========================
**Important:**
* Change `--output-groups` to default to value of `--build-jobs` (#5751).
Those using build farms may need to now use `--output-groups 0` or otherwise.
* Support user-defined primitives (UDPs) (#468) (#5807) (#5936). [Zhou Shen, Krzysztof Sychla, et al]
* Add `--trace-saif` for SAIF power traces (#5812) (#5914). [Mateusz Gancarz]
**Other:**
* Change `--trace` to `--trace-vcd`.
* Support simple `checker` blocks (#4066). [Srinivasan Venkataramanan]
* Support force/release with a variable reference (#5721) (#5810). [Bartłomiej Chmiel, Antmicro Ltd.]
* Support constraint random for StructArray (#5805) (#5937). [Yilou Wang]
* Support command-line overriding `define (#5900) (#5908). [Brian Li]
* Support soft unions (#5912) (#5932). [Robin Heinemann]
* Support `$setuphold` (#5884). [Krzysztof Sychla]
* Support assigning unpacked arrays to queues (#5924) (#5928). [Brian Li]
* Support `systemc_interface and related inside `class`.
* Support class extends with arguments.
* Add multi-thread hierarchical simulation (#2583) (#5871). [Bartłomiej Chmiel, Antmicro Ltd.]
* Add check for `let` misused in statement context (#5733).
* Add used language to `--preproc-resolve` output (#5795). [Kamil Rakoczy, Antmicro Ltd.]
* Add `--make json` to enable integration with non-make/cmake build systems (#5799). [Andrew Voznytsa]
* Add numactl-like automatic assignment of processor affinity (#5911).
* Add ccache support for generated cmake files (#5926) (#5930). [Andrew Voznytsa]
* Add visualization of multi-threaded waiting time with verilator_gantt (#5929). [Bartłomiej Chmiel, Antmicro Ltd.]
* Add suggesting isolate_assignments to UNOPTFLAT (#5942). [John Khoo]
* Add profiling of hierarchical mtasks with verilator_gantt (#5956). [Bartłomiej Chmiel, Antmicro Ltd.]
* Add empty veriuser.h for legacy compatibility.
* Add DEPRECATED warning on `--xml-only` and `--xml-output`.
* Remove unused gtkwave/wavealloca.h. [Geza Lore]
* Optimize automatic splitting of some packed variables (#5843). [Geza Lore]
* Optimize trigger vector in whole words (#5857). [Geza Lore]
* Fix parameters referencing interface fields (#1593) (#5910). [Ryszard Rozak, Antmicro Ltd.]
* Fix interface array assignments (#5270) (#5633) (#5869). [Nick Brereton]
* Fix change detection at time 0 (#5499) (#5864). [Geza Lore]
* Fix foreach of associative array inside a constraint block (#5727) (#5841). [Yilou Wang]
* Fix reset of automatic function variables (#5747). [Augustin Fabre]
* Fix invalid code motion over branches (#5811) (#5814). [Geza Lore]
* Fix sorting of wide SenItems (#5816). [Geza Lore]
* Fix tcmalloc static link and non-22.04 builds (#5817) (#5818). [Geza Lore]
* Fix error on out-of-range lvalue part select (#5820).
* Fix UNOPTFLAT warnings with `--coverage-trace` and always_comb (#5821).
* Fix function locals in SenExprBuilder (#5822). [Geza Lore]
* Fix type_id package scope resolution (#5826). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix `rand_mode` method with cast (#5831).
* Fix invalidating variable caches in SenExprBulider (#5834) (#5835). [Geza Lore]
* Fix assignment pattern as function argument (#5839).
* Fix checking built-in method arguments (#5839).
* Fix splitting of packed ports with non-zero based ranges (#5842). [Geza Lore]
* Fix delays inside interface functions, and classes inside interfaces (#5846).
* Fix NBA shared flag reuse (#5848). [Geza Lore]
* Fix multiple expression coverage issues (#5849 partial) (#5867) (#5870). [Todd Strader]
* Fix unresolved typedefs as parameters (#5850). [Eugene Feinberg, Brian Li]
* Fix removal of callbacks no longer in current list (#5851) (#5852). [Gilberto Abram]
* Fix segmentation fault on member compare (#5853).
* Fix recursive error on virtual interfaces (#5854). [Yilou Wang]
* Fix streaming of unpacked arrays concatenations (#5856). [Ryszard Rozak, Antmicro Ltd.]
* Fix Windows paths in Perl (#5858) (#5860). [Tobias Jensen]
* Fix algorithm header portability in V3Os.cpp (for std::replace) (#5861). [William D. Jones]
* Fix `$fscanf` not returning -1 on EOF (#5881).
* Fix PGO profiling for multi-threaded hierarchical scenarios (#5888). [Bartłomiej Chmiel, Antmicro Ltd.]
* Fix V3Gate assertion on eliminated circular logic (#5889) (#5898). [Geza Lore]
* Fix process comparisons (#5896).
* Fix ccache with clang (#5899). [Geza Lore]
* Fix delayed assignment malformed LHS assertion (#5904).
* Fix segfault in fork synchronization (#5906). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix `new this` (#5909).
* Fix assignments with stream expressions and unpacked arrays (#5915). [Ryszard Rozak, Antmicro Ltd.]
* Fix LATCH warning for automatic variables (#5918). [Yutetsu TAKATSUKASA]
* Fix %% on elaboration severity tasks (#5922). [Ethan Sifferman]
* Fix port default values with `--coverage-line` creating `0=0` (#5920). [Drew Ranck]
* Fix vlSelf error on fork repeats (#5927). [Drew Ranck]
* Fix missing C++ regeneration when Verilog files are updated (#5934). [Zhouyi Shen]
* Fix stream expressions (#5938). [Ryszard Rozak, Antmicro Ltd.]
* Fix packed selection using over 32-bit index (#5957).
Verilator 5.034 2025-02-24
==========================
@ -195,7 +276,7 @@ Verilator 5.030 2024-10-27
* 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 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]
@ -253,7 +334,7 @@ Verilator 5.028 2024-08-21
* Add parsing but otherwise ignore std::randomize (#5354). [Arkadiusz Kozdra, Antmicro Ltd.]
* Add Verilated cc define when `--timing` used (#5383). [Kaleb Barrett]
* Improve emitted code to use a reference for VlSelf (#5254). [Yangyu Chen]
* Fix monitor block sensitivity items (#4400) (#5294). [Udaya Raj Subedi]
* Fix monitor block sensitivity items (#4040) (#4400) (#5294). [Udaya Raj Subedi]
* Fix fusing macro arguments to not ignore whitespace (#5061). [Tudor Timi]
* Fix optimized-out sensitivity trees with `--timing` (#5080) (#5349). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix classes/modules of case-similar names (#5109). [Arkadiusz Kozdra]
@ -280,7 +361,7 @@ Verilator 5.028 2024-08-21
* Fix static variable initializers in procedures (#5296). [Bartłomiej Chmiel, Antmicro Ltd.]
* Fix randomizing current object with `rand` class instance member (#5292). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix handling of rand fields not referenced in constraints (#5305). [Ryszard Rozak, Antmicro Ltd.]
* Fix Python3 path discovery in make flows to avoid mixing system and user python interpreters (#5307) [Markus Krause]
* Fix Python3 path discovery in make flows to avoid mixing system and user python interpreters (#5307). [Markus Krause]
* Fix make flows to pass PYTHON3 (like PERL) (#5307) (#5308). [Markus Krause]
* Fix assert on wide expression (#5319) (#5324). [Varun Koyyalagunta]
* Fix output clock variable overwriting signal (#5320) (#5347). [Krzysztof Bieganski, Antmicro Ltd.]
@ -459,7 +540,7 @@ Verilator 5.022 2024-02-24
* Fix `vpi_get()` and `vpi_get64()` to return vpiUndefined on errors (#4795). [Marlon James]
* Fix VPI parameter iteration (#4798). [Marlon James]
* Fix delays using wrong timeunit when modules inlined (#4806). [Paul Wright]
* Fix warnings in verilated_sc_trace.h for Clang. (#4807) (#4827). [Anthony Donlon]
* Fix warnings in verilated_sc_trace.h for Clang (#4807) (#4827). [Anthony Donlon]
* Fix null pointer dereference (#4810) (#4825). [Adrian Sampson]
* Fix compilation error on multi-inherited interface class usage (#4819).
* Fix maybe-uninitialized compiler warning (#4820) (#4822). [Larry Doolittle]
@ -537,7 +618,7 @@ Verilator 5.020 2024-01-01
* Fix conflicted namespace for coroutines (#4701) (#4707). [Jinyan Xu]
* Fix compilers seeing empty input due to file system races (#4708). [Flavien Solt]
* Fix shift of > 32-bit number (#4719). [Flavien Solt]
* Fix Windows include gates in filesystem Flush implementation. (#4720). [William D. Jones]
* Fix Windows include gates in filesystem Flush implementation (#4720). [William D. Jones]
* Fix power operator with wide numbers and constants (#4721) (#4763). [Flavien Solt]
* Fix parameter passing to ports (#4723). [Ryszard Rozak, Antmicro Ltd.]
* Fix block names of nested do..while loops (#4728). [Ryszard Rozak, Antmicro Ltd.]
@ -546,7 +627,7 @@ Verilator 5.020 2024-01-01
* Fix $finish twice to no longer exit (#4757). [Tim Hutt]
* Fix dynamic NBA conditions (#4773). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix `V3Fork` stage to run only if `--timing` is set (#4778). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix max multiply width and add runtime assertions if too small. (#4781)
* Fix max multiply width and add runtime assertions if too small (#4781).
* Fix select value too wide (#5148) (#5153). [Dercury]
@ -1211,7 +1292,7 @@ Verilator 4.218 2022-01-17
* Support class static members (#2233).
* Support force/release (#2431) (#2593). [Shunyao CAD]
* Add 'forceable' attribute to allow forcing from C++. (#3272). [Geza Lore, Shunyao CAD]
* Add 'forceable' attribute to allow forcing from C++ (#3272). [Geza Lore, Shunyao CAD]
* Support lower dimension looping in foreach loops (#3172). [Ehab Ibrahim]
* Support up to 64 bit enums for .next/.prev/.name (#3244). [Alexander Grobman]
* Reduce .rodata footprint of trace initialization (#3250). [Geza Lore, Shunyao CAD]
@ -1435,7 +1516,7 @@ Verilator 4.200 2021-03-12
**Major:**
* Add simulation context (VerilatedContext) to allow multiple fully independent
models to be in the same process. Please see the updated examples. (#2660)
models to be in the same process. Please see the updated examples (#2660).
* Add context->time() and context->timeInc() API calls, to set simulation time.
These now are recommended in place of the legacy sc_time_stamp().
@ -1446,7 +1527,7 @@ Verilator 4.200 2021-03-12
* Fix slice-assign overflow (#2803) (#2811). [David Turner]
* Fix interface array connection ordering broken in v4.110 (#2827). [Don Owen]
* Fix or-reduction on different scopes broken in 4.110 (#2828). [Yinan Xu]
* Fix MSVC++ compile error. (#2831) (#2833) [Drew Taussig]
* Fix MSVC++ compile error (#2831) (#2833). [Drew Taussig]
Verilator 4.110 2021-02-25
@ -1501,7 +1582,7 @@ Verilator 4.108 2021-01-10
* Fix vpiLeftRange on little-endian memories (#2696). [Marlon James]
* Fix VPI module tree (#2704). [Todd Strader]
* Fix vpi_release_handle to be called implicitly per IEEE (#2706).
* Fix to allow inheriting 'VerilatedVcdFile' class. (#2720) [HyungKi Jeong]
* Fix to allow inheriting 'VerilatedVcdFile' class (#2720). [HyungKi Jeong]
* Fix $urandom_range maximum value (#2723). [Nandu Raj]
* Fix tracing empty sc module (#2729).
* Fix generate for unrolling to be signed (#2730). [yanx21]
@ -1607,11 +1688,11 @@ Verilator 4.040 2020-08-15
**Minor:**
* Fix arrayed interfaces, broke in 4.038 (#2468). [Josh Redford]
* Support $stable, $rose and $fell. (#2148) (#2501) [Peter Monsson]
* Support $stable, $rose and $fell (#2148) (#2501). [Peter Monsson]
* Support simple function localparams (#2461). [James Hanlon]
* Miscellaneous parsing error changes towards UVM support.
* Fix arrayed interfaces (#2469). [Josh Redford]
* Fix protect lib VCS warning. (#2479) [Julien Margetts]
* Fix protect lib VCS warning (#2479). [Julien Margetts]
* Fix combining different-width parameters (#2484). [abirkmanis]
* Fix protect-lib without sequential logic (#2492). [Yutetsu TAKATSUKASA]
* Fix V3Unknown from running with flat XML output (#2494). [James Hanlon]
@ -1667,16 +1748,16 @@ Verilator 4.036 2020-06-06
waivers to the warnings emitted during a Verilator run.
* Support verilator_coverage --write-info for lcov HTML reports.
* Line Coverage now tracks all statement lines, not just branch lines.
* The run-time library is now compiled with -Os by default. (#2369, #2373)
* The run-time library is now compiled with -Os by default (#2369, #2373).
* Support multi channel descriptor I/O (#2190) [Stephen Henry]
* Support $countbits. (#2287) [Yossi Nivin]
* Support $isunbounded and parameter $. (#2104)
* Support $countbits (#2287). [Yossi Nivin]
* Support $isunbounded and parameter $ (#2104).
* Support unpacked array .sum and .product.
* Support prefix/postfix increment/decrement. (#2223) [Maciej Sobkowski]
* Support prefix/postfix increment/decrement (#2223). [Maciej Sobkowski]
* Fix FST tracing of little bit endian signals. [Geza Lore]
* Fix +: and -: on unpacked arrays. (#2304) [engr248]
* Fix +: and -: on unpacked arrays (#2304). [engr248]
* Fix $isunknown with constant Z's.
* Fix queues and dynamic array wide ops. (#2352) [Vassilis Papaefstathiou]
* Fix queues and dynamic array wide ops (#2352). [Vassilis Papaefstathiou]
Verilator 4.034 2020-05-03

View File

@ -528,6 +528,8 @@ GERSEMI_FLAGS = -i
format-cmake:
$(GERSEMI) $(GERSEMI_FLAGS) $(CMAKE_FILES)
format-yaml: yamlfix
PYLINT = pylint
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
@ -595,6 +597,8 @@ clean mostlyclean distclean maintainer-clean::
rm -f *.tex
rm -rf examples/*/obj_dir* examples/*/logs
rm -rf test_*/obj_dir
rm -rf src/*.tidy include/*.tidy examples/*/*.tidy
rm -rf .ruff_cache
rm -rf nodist/fuzzer/dictionary
rm -rf nodist/obj_dir
rm -rf verilator.txt

View File

@ -1,7 +1,7 @@
.. Github doesn't render images unless absolute URL
.. Do not know of a conditional tag, "only: github" nor "github display" works
|badge1| |badge2| |badge3| |badge4| |badge5| |badge6| |badge7|
|badge1| |badge2| |badge3| |badge4| |badge5| |badge7|
.. |badge1| image:: https://img.shields.io/badge/Website-Verilator.org-181717.svg
:target: https://verilator.org
@ -13,8 +13,6 @@
:target: https://repology.org/project/verilator/versions
.. |badge5| image:: https://img.shields.io/docker/pulls/verilator/verilator
:target: https://hub.docker.com/r/verilator/verilator
.. |badge6| image:: https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f
:target: https://www.codacy.com/gh/verilator/verilator
.. |badge7| image:: https://github.com/verilator/verilator/workflows/build/badge.svg
:target: https://github.com/verilator/verilator/actions?query=workflow%3Abuild
@ -134,7 +132,7 @@ Related Projects
- `GTKwave <http://gtkwave.sourceforge.net/>`_ - Waveform viewer for
Verilator traces.
- `Icarus Verilog`_ - Icarus is a full-featured interpreted Verilog
- `Icarus Verilog`_ - Icarus is a highly-featured interpreted Verilog
simulator. If Verilator does not support your needs, perhaps Icarus may.

View File

@ -256,7 +256,7 @@ sub sh_escape {
# This is similar to quotemeta() but less aggressive.
# There's no need to escape hyphens, periods, or forward slashes
# for the shell as these have no special meaning to the shell.
$arg =~ s/([^0-9a-zA-Z_\-\+\=\.\/])/\\$1/g;
$arg =~ s/([^0-9a-zA-Z_\-\+\=\.\/:])/\\$1/g;
return $arg;
}
@ -341,11 +341,12 @@ detailed descriptions of these arguments.
--no-debug-leak Disable leaking memory in --debug mode
--debugi <level> Enable debugging at a specified level
--debugi-<srcfile> <level> Enable debugging a source file at a level
--decorations <level> Set output comment and spacing level
--no-decoration Disable comments and lower spacing level
--decorations <level> Set output comment and spacing level
--default-language <lang> Default language to parse
+define+<var>=<value> Set preprocessor define
--dpi-hdr-only Only produce the DPI header file
--dump-<srcfile> Enable dumping everything in source file
--dump-defines Show preprocessor defines with -E
--dump-dfg Enable dumping DfgGraphs to .dot files
--dump-graph Enable dumping V3Graphs to .dot files
@ -353,12 +354,11 @@ detailed descriptions of these arguments.
--dump-tree-addrids Use short identifiers instead of addresses
--dump-tree-dot Enable dumping Ast .tree.dot debug files
--dump-tree-json Enable dumping Ast .tree.json files and .tree.meta.json file
--dump-<srcfile> Enable dumping everything in source file
--dumpi-<srcfile> <level> Enable dumping everything in source file at level
--dumpi-dfg <level> Enable dumping DfgGraphs to .dot files at level
--dumpi-graph <level> Enable dumping V3Graphs to .dot files at level
--dumpi-tree <level> Enable dumping Ast .tree files at level
--dumpi-tree-json <level> Enable dumping Ast .tree.json files at level
--dumpi-<srcfile> <level> Enable dumping everything in source file at level
-E Preprocess, but do not compile
--emit-accessors Emit getter and setter methods for model top class
--error-limit <value> Abort after this number of errors
@ -390,8 +390,8 @@ detailed descriptions of these arguments.
--no-json-edit-nums Don't dump editNum in .tree.json files
--no-json-ids Don't use short identifiers instead of adresses/paths in .tree.json
--json-only Create JSON parser output (.tree.json and .meta.json)
--json-only-output .tree.json output filename
--json-only-meta-output .tree.meta.json output filename
--json-only-output .tree.json output filename
--l2-name <value> Verilog scope name of the top module
--language <lang> Default language standard to parse
-LDFLAGS <flags> Linker pre-object arguments for makefile
@ -399,20 +399,20 @@ detailed descriptions of these arguments.
+libext+<ext>+[ext]... Extensions for finding modules
--lint-only Lint, but do not make output
--localize-max-size <value> Tune localize optimization variable size
--make <build-tool> Generate scripts for specified build tool
-MAKEFLAGS <flags> Arguments to pass to make during --build
--main Generate C++ main() file
--main-top-name Specify top name passed to Verilated model in generated C++ main
--make <build-tool> Generate scripts for specified build tool
-MAKEFLAGS <flags> Arguments to pass to make during --build
--max-num-width <value> Maximum number width (default: 64K)
--Mdir <directory> Name of output object directory
--MMD Create .d dependency files
--mod-prefix <topname> Name to prepend to lower classes
--MP Create phony dependency targets
+notimingchecks Ignored
-o <executable> Name of final executable
-O0 Disable optimizations
-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
@ -467,23 +467,25 @@ detailed descriptions of these arguments.
--threads <threads> Enable multithreading
--threads-dpi <mode> Enable multithreaded DPI
--threads-max-mtasks <mtasks> Tune maximum mtask partitioning
--timing Enable timing support
--no-timing Disable timing support
--timescale <timescale> Sets default timescale
--timescale-override <timescale> Overrides all timescales
--timing Enable timing support
--no-timing Disable timing support
--top <topname> Alias of --top-module
--top-module <topname> Name of top-level input module
--trace Enable waveform creation
--trace Enable VCD waveform creation
--trace-coverage Enable tracing of coverage
--trace-depth <levels> Depth of tracing
--trace-fst Enable FST waveform creation
--trace-max-array <depth> Maximum array depth for tracing
--trace-max-width <width> Maximum bit width for tracing
--trace-params Enable tracing of parameters
--trace-saif Enable SAIF file creation
--trace-structs Enable tracing structure names
--trace-threads <threads> Enable FST waveform creation on separate threads
--no-trace-top Do not emit traces for signals in the top module generated by verilator
--trace-underscore Enable tracing of _signals
--trace-vcd Enable VCD waveform creation
-U<var> Undefine preprocessor define
--no-unlimited-stack Don't disable stack size limit
--unroll-count <loops> Tune maximum loop iterations
@ -492,8 +494,8 @@ detailed descriptions of these arguments.
-V Verbose version and config
-v <filename> Verilog library
--valgrind Run Verilator under valgrind
--verilate-jobs Job threads for Verilation stage
--no-verilate Skip Verilation and just compile previously Verilated code
--verilate-jobs Job threads for Verilation stage
+verilog1995ext+<ext> Synonym for +1364-1995ext+<ext>
+verilog2001ext+<ext> Synonym for +1364-2001ext+<ext>
--version Show program version and exits
@ -526,9 +528,9 @@ description of these arguments.
=for VL_SPHINX_EXTRACT "_build/gen/args_verilated.rst"
+verilator+coverage+file+<filename> Set coverage output filename
+verilator+debug Enable debugging
+verilator+debugi+<value> Enable debugging at a level
+verilator+coverage+file+<filename> Set coverage output filename
+verilator+error+limit+<value> Set error limit
+verilator+help Show help
+verilator+noassert Disable assert checking

View File

@ -8,17 +8,27 @@ import collections
import math
import re
import statistics
from collections import OrderedDict
# from pprint import pprint
Sections = []
Sections = OrderedDict()
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: {}),
'info': {
'numa': 'no data'
},
'stats': {}
}
ElapsedTime = None # total elapsed time
ExecGraphTime = 0 # total elapsed time excuting an exec graph
ExecGraphTime = 0 # total elapsed time executing an exec graph
WaitingTime = 0 # total elapsed time waiting for mtasks
ExecGraphIntervals = [] # list of (start, end) pairs
ThreadScheduleWaitIntervals = [] # list of (start, tick, ecpu) pairs
######################################################################
@ -27,23 +37,29 @@ 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_mtaskEnd = re.compile(r'id (\d+) predictCost (\d+)')
# The hierBlock argument is optional
re_payload_mtaskBegin = re.compile(
r'id (\d+) predictStart (\d+) cpu (\d+)(?: hierBlock)?\s*(\w+)?')
re_payload_mtaskEnd = re.compile(r'predictCost (\d+)')
re_payload_wait = re.compile(r'cpu (\d+)')
re_arg1 = re.compile(r'VLPROF arg\s+(\S+)\+([0-9.]*)\s*')
re_arg2 = re.compile(r'VLPROF arg\s+(\S+)\s+([0-9.]*)\s*$')
re_stat = re.compile(r'VLPROF stat\s+(\S+)\s+([0-9.]+)')
re_info = re.compile(r'VLPROF info\s+(\S+)\s+(.*)$')
re_stat = re.compile(r'VLPROF stat\s+(\S+)\s+(\S+)')
re_proc_cpu = re.compile(r'VLPROFPROC processor\s*:\s*(\d+)\s*$')
re_proc_dat = re.compile(r'VLPROFPROC ([a-z_ ]+)\s*:\s*(.*)$')
cpu = None
thread = 0
execGraphStart = None
global LongestVcdStrValueLength
global ExecGraphTime
global WaitingTime
ExecGraphStack = []
SectionStack = []
mTaskThread = {}
MtasksStack = []
ThreadScheduleWait = collections.defaultdict(list)
for line in fh:
recordMatch = re_record.match(line)
@ -60,44 +76,57 @@ def read_data(filename):
SectionStack.pop()
Sections[thread].append((tick, tuple(SectionStack)))
elif kind == "MTASK_BEGIN":
mtask, predict_start, ecpu = re_payload_mtaskBegin.match(payload).groups()
mtask, predict_start, ecpu, hier_block = re_payload_mtaskBegin.match(
payload).groups()
hier_block = "" if hier_block is None else hier_block
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
records.append({
'start': tick,
'mtask': mtask,
'predict_start': predict_start,
'hier_block': hier_block,
'cpu': ecpu
})
Mtasks[mtask]['begin'] = tick
Mtasks[mtask]['thread'] = thread
Mtasks[mtask]['predict_start'] = predict_start
Mtasks[(hier_block, mtask)]['begin'] = tick
Mtasks[(hier_block, mtask)]['predict_start'] = predict_start
Mtasks[(hier_block, mtask)]['thread'] = thread
MtasksStack.append((hier_block, mtask, records[-1]))
elif kind == "MTASK_END":
mtask, predict_cost = re_payload_mtaskEnd.match(payload).groups()
predict_cost, = re_payload_mtaskEnd.match(payload).groups()
mtask = int(mtask)
hier_block, mtask, record = MtasksStack.pop()
predict_cost = int(predict_cost)
begin = Mtasks[mtask]['begin']
record = Threads[mTaskThread[mtask]][-1]
begin = Mtasks[(hier_block, mtask)]['begin']
record['end'] = tick
assert record and records[-1]['start'] <= records[-1]['end'] <= tick
record['predict_cost'] = predict_cost
Mtasks[mtask]['elapsed'] += tick - begin
Mtasks[mtask]['predict_cost'] = predict_cost
Mtasks[mtask]['end'] = max(Mtasks[mtask]['end'], tick)
Mtasks[(hier_block, mtask)]['elapsed'] += tick - begin
Mtasks[(hier_block, mtask)]['predict_cost'] = predict_cost
Mtasks[(hier_block, mtask)]['end'] = max(Mtasks[(hier_block, mtask)]['end'],
tick)
elif kind == "THREAD_SCHEDULE_WAIT_BEGIN":
ecpu = int(re_payload_wait.match(payload).groups()[0])
ThreadScheduleWait[ecpu].append(tick)
elif kind == "THREAD_SCHEDULE_WAIT_END":
ecpu = int(re_payload_wait.match(payload).groups()[0])
start = ThreadScheduleWait[ecpu].pop()
WaitingTime += tick - start
ThreadScheduleWaitIntervals.append((start, tick, ecpu))
elif kind == "EXEC_GRAPH_BEGIN":
execGraphStart = tick
ExecGraphStack.append(tick)
elif kind == "EXEC_GRAPH_END":
assert ExecGraphStack, "EXEC_GRAPH_END without EXEC_GRAPH_BEGIN"
execGraphStart = ExecGraphStack.pop()
ExecGraphTime += tick - execGraphStart
ExecGraphIntervals.append((execGraphStart, tick))
execGraphStart = None
elif Args.debug:
print("-Unknown execution trace record: %s" % line)
elif re_thread.match(line):
thread = int(re_thread.match(line).group(1))
Sections.append([])
Sections[thread] = []
elif re.match(r'^VLPROF(THREAD|VERSION)', line):
pass
elif re_arg1.match(line):
@ -106,6 +135,9 @@ def read_data(filename):
elif re_arg2.match(line):
match = re_arg2.match(line)
Global['args'][match.group(1)] = match.group(2)
elif re_info.match(line):
match = re_info.match(line)
Global['info'][match.group(1)] = match.group(2)
elif re_stat.match(line):
match = re_stat.match(line)
Global['stats'][match.group(1)] = match.group(2)
@ -156,11 +188,13 @@ def report():
print("\nSummary:")
print(" Total elapsed time = {} rdtsc ticks".format(ElapsedTime))
print(" Parallelized code = {:.2%} of elapsed time".format(ExecGraphTime / ElapsedTime))
print(" Waiting time = {:.2%} of elapsed time".format(WaitingTime / ElapsedTime))
print(" Total threads = %d" % nthreads)
print(" Total CPUs used = %d" % ncpus)
print(" Total mtasks = %d" % len(Mtasks))
print(" Total yields = %d" % int(Global['stats'].get('yields', 0)))
report_numa()
report_mtasks()
report_cpus()
report_sections()
@ -181,6 +215,11 @@ def report():
print()
def report_numa():
print("\nNUMA assignment:")
print(" NUMA status = %s" % Global['info']['numa'])
def report_mtasks():
if not Mtasks:
return
@ -201,8 +240,8 @@ def report_mtasks():
long_mtask = None
predict_mtask_time = 0
predict_elapsed = 0
for mtaskId in Mtasks:
record = Mtasks[mtaskId]
for (hier_block, mtask_id) in Mtasks:
record = Mtasks[(hier_block, mtask_id)]
predict_mtask_time += record['predict_cost']
total_mtask_time += record['elapsed']
thread_mtask_time[record['thread']] += record['elapsed']
@ -210,7 +249,8 @@ def report_mtasks():
predict_elapsed = max(predict_elapsed, predict_end)
if record['elapsed'] > long_mtask_time:
long_mtask_time = record['elapsed']
long_mtask = mtaskId
long_mtask = mtask_id
long_mtask_hier_block = hier_block
Global['predict_last_end'] = predict_elapsed
serialTime = ElapsedTime - ExecGraphTime
@ -239,31 +279,52 @@ def report_mtasks():
max_p2e = -1000000
max_mtask = None
for mtask in sorted(Mtasks.keys()):
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'])
for (hier_block, mtask_id) in sorted(Mtasks.keys()):
mtask = Mtasks[(hier_block, mtask_id)]
if mtask['elapsed'] > 0:
if mtask['predict_cost'] == 0:
mtask['predict_cost'] = 1 # don't log(0) below
p2e_ratio = math.log(mtask['predict_cost'] / mtask['elapsed'])
p2e_ratios.append(p2e_ratio)
if p2e_ratio > max_p2e:
max_p2e = p2e_ratio
max_mtask = mtask
max_mtask = mtask_id
max_hier_block = hier_block
if p2e_ratio < min_p2e:
min_p2e = p2e_ratio
min_mtask = mtask
min_mtask = mtask_id
min_hier_block = hier_block
print("\nMTask statistics:")
print(" Longest mtask id = {}".format(long_mtask))
if long_mtask_hier_block:
print(" Longest mtask id = {} from hier_block '{}'".format(long_mtask,
long_mtask_hier_block))
else:
print(" Longest mtask id = {}".format(long_mtask))
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(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
if min_hier_block:
print(" from hier_block '%s' mtask %d (predict %d," %
(min_hier_block, min_mtask, Mtasks[(min_hier_block, min_mtask)]['predict_cost']),
end="")
else:
print(" from mtask %d (predict %d," %
(min_mtask, Mtasks[(min_hier_block, min_mtask)]['predict_cost']),
end="")
print(" elapsed %d)" % Mtasks[(min_hier_block, 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(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
if max_hier_block:
print(" from hier_block '%s' mtask %d (predict %d," %
(max_hier_block, max_mtask, Mtasks[(max_hier_block, max_mtask)]['predict_cost']),
end="")
else:
print(" from mtask %d (predict %d," %
(max_mtask, Mtasks[(max_hier_block, max_mtask)]['predict_cost']),
end="")
print(" elapsed %d)" % Mtasks[(max_hier_block, max_mtask)]['elapsed'])
stddev = statistics.pstdev(p2e_ratios)
mean = statistics.mean(p2e_ratios)
@ -308,7 +369,7 @@ def report_cpus():
def report_sections():
for thread, section in enumerate(Sections):
for thread, section in Sections.items():
if section:
print(f"\nSection profile for thread {thread}:")
report_section(section)
@ -403,6 +464,9 @@ def write_vcd(filename):
val = buf.ljust(LongestVcdStrValueLength * 8, "0")
values[time][code] = val
def addXValue(code, time):
values[time][code] = 'x'
# Measured graph
for thread in sorted(Threads):
mcode = getCode(32, 'measured', 't%d_mtask' % thread)
@ -427,27 +491,36 @@ def write_vcd(filename):
tStart = sorted(_['start'] for records in Threads.values() for _ in records)
tEnd = sorted(_['end'] for records in Threads.values() for _ in records)
# Measured waiting time
for (start, end, cpu) in ThreadScheduleWaitIntervals:
mcode = getCode(32, 'measured', 'cpu%d_waiting' % cpu)
addXValue(mcode, start)
addValue(mcode, end, None)
# Predicted graph
for start, end in ExecGraphIntervals:
# Find the earliest MTask start after the start point, and the
# latest MTask end before the end point, so we can scale to the
# same range
start = tStart[bisect.bisect_left(tStart, start)]
tStartIdx = bisect.bisect_left(tStart, start)
if tStartIdx >= len(tStart):
continue
start = tStart[tStartIdx]
end = tEnd[bisect.bisect_right(tEnd, end) - 1]
# Compute scale so predicted graph is of same width as interval
measured_scaling = (end - start) / Global['predict_last_end']
# 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)
for (hier_block, mtask_id) in Mtasks:
mtask = Mtasks[(hier_block, mtask_id)]
thread = mtask['thread']
pred_scaled_start = start + int(mtask['predict_start'] * measured_scaling)
pred_scaled_end = start + int(
(Mtasks[mtask]['predict_start'] + Mtasks[mtask]['predict_cost']) *
measured_scaling)
(mtask['predict_start'] + mtask['predict_cost']) * measured_scaling)
if pred_scaled_start == pred_scaled_end:
continue
mcode = getCode(32, 'predicted', 't%d_mtask' % thread)
addValue(mcode, pred_scaled_start, mtask)
addValue(mcode, pred_scaled_start, mtask_id)
addValue(mcode, pred_scaled_end, None)
parallelism['predicted'][pred_scaled_start] += 1
@ -462,7 +535,7 @@ def write_vcd(filename):
addValue(pcode, time, value)
# Section graph
for thread, section in enumerate(Sections):
for thread, section in Sections.items():
if section:
scode = getCode(LongestVcdStrValueLength * 8, "section", f"t{thread}_trace")
dcode = getCode(32, "section", f"t{thread}_depth")
@ -510,6 +583,8 @@ def write_vcd(filename):
value = values[time][code]
if value is None:
fh.write("bz v%x\n" % code)
elif value == 'x':
fh.write("bx v%x\n" % code)
elif isinstance(value, str):
fh.write("b%s v%x\n" % (value, code))
else:

View File

@ -40,7 +40,7 @@ fi
install-vcddiff() {
TMP_DIR="$(mktemp -d)"
git clone https://github.com/veripool/vcddiff "$TMP_DIR"
git -C "${TMP_DIR}" checkout e5664be5fe39d353bf3fcb50aa05214ab7ed4ac4
git -C "${TMP_DIR}" checkout dca845020668887fd13498c772939814d9264fd5
"$MAKE" -C "${TMP_DIR}"
sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin
}
@ -55,16 +55,16 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
sudo apt-get update
sudo apt-get install ccache help2man libfl-dev ||
sudo apt-get install ccache help2man libfl-dev
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ]; then
if [[ ! "$CI_RUNS_ON" =~ "ubuntu-22.04" ]]; then
# Some conflict of libunwind verison on 22.04, can live without it for now
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" ] || [ "$CI_RUNS_ON" = "ubuntu-24.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" ] || [ "$CI_RUNS_ON" = "ubuntu-24.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
@ -92,11 +92,11 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
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.py
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ] || [ "$CI_RUNS_ON" = "ubuntu-24.04" ]; then
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" ] || [ "$CI_RUNS_ON" = "ubuntu-24.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

View File

@ -87,7 +87,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
fi
# Run sanitize on Ubuntu 22.04 only
( [ "$CI_RUNS_ON" = 'ubuntu-22.04' ] || [ "$CI_RUNS_ON" = 'ubuntu-24.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
@ -98,6 +98,8 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
export VERILATOR_ROOT="$RELOC_DIR/relocated-install/share/verilator"
TEST_REGRESS="$RELOC_DIR/test_regress"
mv test_regress "$TEST_REGRESS"
NODIST="$RELOC_DIR/nodist"
mv nodist "$NODIST"
# Feeling brave?
find . -delete
ls -la .
@ -107,22 +109,25 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
ccache -z
case $TESTS in
dist-vlt-0)
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=0/4
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean $sanitize" DRIVER_HASHSET=--hashset=0/4
;;
dist-vlt-1)
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=1/4
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean $sanitize" DRIVER_HASHSET=--hashset=1/4
;;
dist-vlt-2)
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=2/4
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean $sanitize" DRIVER_HASHSET=--hashset=2/4
;;
dist-vlt-3)
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=3/4
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean $sanitize" DRIVER_HASHSET=--hashset=3/4
;;
vltmt-0)
"$MAKE" -C "$TEST_REGRESS" SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt --driver-clean" DRIVER_HASHSET=--hashset=0/3
;;
vltmt-1)
"$MAKE" -C "$TEST_REGRESS" SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt --driver-clean" DRIVER_HASHSET=--hashset=1/3
;;
vltmt-2)
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt --driver-clean" DRIVER_HASHSET=--hashset=2/3
;;
coverage-all)
nodist/code_coverage --stages 1-

View File

@ -10,7 +10,7 @@
# Then 'make maintainer-dist'
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[5.034 2025-02-24],
AC_INIT([Verilator],[5.036 2025-04-27],
[https://verilator.org],
[verilator],[https://verilator.org])
@ -432,6 +432,7 @@ AC_SUBST(HAVE_COROUTINES)
# Flags for compiling Verilator internals including parser always
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Qunused-arguments)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Xclang -fno-pch-timestamp)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-faligned-new)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-unused-parameter)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-shadow)
@ -469,6 +470,7 @@ CFG_CXX_FLAGS_CMAKE="-faligned-new"
m4_foreach([cflag],[
[-fbracket-depth=4096],
[-fcf-protection=none],
[-Xclang -fno-pch-timestamp],
[-mno-cet],
[-Qunused-arguments],
[-Wno-bool-operation],
@ -515,7 +517,7 @@ if test "$CFG_ENABLE_PARTIAL_STATIC" = "yes"; then
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libgcc)
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libstdc++)
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -Xlinker -gc-sections)
LTCMALLOC=-l:libtcmalloc_minimal.a
LTCMALLOC="-Wl,--whole-archive -l:libtcmalloc_minimal.a -Wl,--no-whole-archive"
else
LTCMALLOC=-ltcmalloc_minimal
fi

View File

@ -19,12 +19,14 @@ Andreas Kuster
Andrei Kostovski
Andrew Miloradovsky
Andrew Nolte
Andrew Voznytsa
Anthony Donlon
Anthony Moore
Arkadiusz Kozdra
Arthur Rosa
Aylon Chaim Porat
Bartłomiej Chmiel
Brian Li
Cameron Kirk
Chih-Mao Chen
Chris Bachhuber
@ -65,6 +67,7 @@ Garrett Smith
Geza Lore
Gianfranco Costamagna
Gijs Burghoorn
Gilberto Abram
Glen Gibb
Gökçe Aydos
Graham Rushton
@ -107,6 +110,7 @@ Jiuyang Liu
Joey Liu
John Coiner
John Demme
John Khoo
John Wehle
Jonathan Drolet
Jonathan Schröter
@ -132,6 +136,7 @@ Krzysztof Boronski
Krzysztof Boroński
Krzysztof Obłonczek
Krzysztof Starecki
Krzysztof Sychla
Kuba Ober
Larry Doolittle
Liam Braun
@ -148,6 +153,7 @@ Marlon James
Marshal Qiao
Martin Schmidt
Martin Stadler
Mateusz Gancarz
Matthew Ballance
Michael Bikovitsky
Michael Killough
@ -191,6 +197,7 @@ Ricardo Barbedo
Richard Myers
Risto Pejašinović
Robert Balas
Robin Heinemann
Rupert Swarbrick
Ryan Ziegler
Ryszard Rozak
@ -243,6 +250,8 @@ Yutetsu TAKATSUKASA
Yves Mathieu
Zhanglei Wang
Zhou Shen
Zhouyi Shen
Zixi Li
أحمد المحمودي
404allen404
Tobias Jensen

View File

@ -77,6 +77,7 @@ help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
clean mostlyclean distclean maintainer-clean::
rm -rf _build
rm -f $(SCRIPTS) *.tmp
rm -f *.aux *.cp *.cps *.dvi *.fn *.fns *.ky *.kys *.log
rm -f *.pg *.pgs *.toc *.tp *.tps *.vr *.vrs *.idx

View File

@ -169,15 +169,7 @@ latex_elements = {
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
# latex_documents = [
# (
# master_doc,
# "Verilog-to-Routing.tex",
# "Verilog-to-Routing Documentation",
# "VTR Developers",
# "manual",
# ),
# ]
# latex_documents = [ ... ]
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.

View File

@ -73,8 +73,8 @@ often inlined into the root scope) will need to be updated as follows:
:code:`$` character, i.e.: :code:`rootp` points to the Verilated
SystemVerilog :code:`$root` scope.
* Replace :code:`modelp->internal->member->lookup` references with
:code:`modelp->rootp->internal->member->lookup` references, which
* Replace :code:`modelp->internal->member` references with
:code:`modelp->rootp->internal->member` references, which
contain one additional indirection via the :code:`rootp` pointer.

View File

@ -72,13 +72,17 @@ 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
<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
With :vlopt:`--debug`, Verilator will write a *{prefix}*\ __inputs\ .vpp
file which has all of the individual input files combined and
pre-processed, this is often useful as the input design into `sv-bugpoint`.
Please refer to `sv-bugpoint README
<https://github.com/antmicro/sv-bugpoint/blob/main/README.md>`_ for more
information on how to use `sv-bugpoint`.
.. Contributing

View File

@ -47,6 +47,11 @@ Summary:
Display help and exit.
.. option:: +verilator+noassert
Disable assert checking per runtime argument. This is the same as
calling :code:`VerilatedContext*->assertOn(false)` in the model.
.. option:: +verilator+prof+exec+file+<filename>
When a model was Verilated using :vlopt:`--prof-exec`, sets the
@ -110,11 +115,6 @@ Summary:
simulation runtime random seed value. If zero or not specified picks a
value from the system random number generator.
.. option:: +verilator+noassert
Disable assert checking per runtime argument. This is the same as
calling :code:`VerilatedContext*->assertOn(false)` in the model.
.. option:: +verilator+V
Shows the verbose version, including configuration information.

View File

@ -1,8 +1,9 @@
.. Copyright 2003-2025 by Wilson Snyder.
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
verilator Arguments
===================
=====================
verilator Arguments
=====================
The following arguments may be passed to the "verilator" executable.
@ -11,20 +12,6 @@ Summary:
.. include:: ../_build/gen/args_verilator.rst
.. option:: <file.v>
Specifies the Verilog file containing the top module to be Verilated.
.. option:: <file.c/.cc/.cpp/.cxx>
Used with :vlopt:`--exe` to specify optional C++ files to be linked in
with the Verilog code. The file path should either be absolute, or
relative to where the make will be executed from, or add to your
makefile's VPATH the appropriate directory to find the file.
See also :vlopt:`-CFLAGS` and :vlopt:`-LDFLAGS` options, which are
useful when the C++ files need special compiler flags.
.. option:: <file.a/.o/.so>
Specifies optional object or library files to be linked with the
@ -37,6 +24,20 @@ Summary:
rule that uses these files when linking the module's executable. This
generally is only useful when used with the :vlopt:`--exe` option.
.. option:: <file.c/.cc/.cpp/.cxx>
Used with :vlopt:`--exe` to specify optional C++ files to be linked in
with the Verilog code. The file path should either be absolute, or
relative to where the make will be executed from, or add to your
makefile's VPATH the appropriate directory to find the file.
See also :vlopt:`-CFLAGS` and :vlopt:`-LDFLAGS` options, which are
useful when the C++ files need special compiler flags.
.. option:: <file.v>
Specifies the Verilog file containing the top module to be Verilated.
.. option:: +1364-1995ext+<ext>
.. option:: +1364-2001ext+<ext>
@ -146,13 +147,16 @@ Summary:
This option was named `--bin` before version 4.228.
.. option:: --build-jobs [<value>]
.. option:: --build-jobs <value>
Specify the level of parallelism for :vlopt:`--build`. If zero, uses the
number of threads in the current hardware. Otherwise, the <value> must
be a positive integer specifying the maximum number of parallel build
jobs.
If not provided, and :vlopt:`-j` is provided, the :vlopt:`-j` value is
used.
This forms the :command:`make` option ``-j`` value, unless the
:option:`MAKEFLAGS` environment variable contains ``-jobserver-auth``,
in which case Verilator assumes that make's jobserver is being used.
@ -328,11 +332,11 @@ Summary:
detailed messages. See :vlopt:`--debug` for other implications of
enabling debug.
.. option:: --decorations none
.. option:: --no-decoration
.. option:: --decorations medium
Alias for ``--decorations none``.
.. option:: --decorations node
.. option:: --decorations <level>
When creating output Verilated code, set level of comment and whitespace
decoration.
@ -359,10 +363,6 @@ Summary:
between different Verilator runs, this may harm compile caching and
should only be used for debug.
.. option:: --no-decoration
Alias for ``--decorations none``.
.. option:: --default-language <value>
Select the language used by default when first processing each
@ -399,6 +399,11 @@ Summary:
name or location of the emitted DPI header file, it is output in
:vlopt:`--Mdir` as it would be without this option.
.. option:: --dump-<srcfile>
Rarely needed - for developer use. Enable all dumping in the given
source file at level 3.
.. option:: --dump-defines
With :vlopt:`-E`, suppress normal output, and instead print a list of
@ -430,18 +435,6 @@ Summary:
:vlopt:`--debug --no-dump-tree <--dump-tree>` may be useful if the dump
files are large and not desired.
.. option:: --dump-tree-json
Rarely needed. Enable dumping Ast .json.tree debug files with dumping level 3,
which dumps the standard critical stages. For details on the format, see
the Verilator Internals manual.
.. option:: --dump-tree-dot
Rarely needed. Enable dumping Ast .tree.dot debug files in Graphviz
Dot format. This option implies :vlopt:`--dump-tree`, unless
:vlopt:`--dumpi-tree` was passed explicitly.
.. option:: --dump-tree-addrids
Rarely needed - for developer use. Replace AST node addresses with
@ -451,10 +444,24 @@ Summary:
by a newly allocated node after a node with the same address has been
dumped and then freed.
.. option:: --dump-<srcfile>
.. option:: --dump-tree-dot
Rarely needed - for developer use. Enable all dumping in the given
source file at level 3.
Rarely needed. Enable dumping Ast .tree.dot debug files in Graphviz
Dot format. This option implies :vlopt:`--dump-tree`, unless
:vlopt:`--dumpi-tree` was passed explicitly.
.. option:: --dump-tree-json
Rarely needed. Enable dumping Ast .json.tree debug files with dumping level 3,
which dumps the standard critical stages. For details on the format, see
the Verilator Internals manual.
.. option:: --dumpi-<srcfile> <level>
Rarely needed - for developer use. Set the dumping level in the
specified Verilator source file to the specified value (e.g.,
`--dumpi-V3Order 9`). Level 0 disables dumps and is equivalent to
`--no-dump-<srcfile>`. Level 9 enables the dumping of everything.
.. option:: --dumpi-dfg <level>
@ -476,13 +483,6 @@ Summary:
Rarely needed - for developer use. Set internal Ast JSON dumping level
globally to the specified value.
.. option:: --dumpi-<srcfile> <level>
Rarely needed - for developer use. Set the dumping level in the
specified Verilator source file to the specified value (e.g.,
`--dumpi-V3Order 9`). Level 0 disables dumps and is equivalent to
`--no-dump-<srcfile>`. Level 9 enables the dumping of everything.
.. option:: -E
Preprocess the source code, but do not compile, similar to C++
@ -566,7 +566,7 @@ Summary:
.. option:: -fno-const
.. options: -fno-const-before-dfg
.. option:: -fno-const-before-dfg
Do not apply any global expression folding prior to the DFG pass. This
option is solely for the purpose of DFG testing and should not be used
@ -589,14 +589,14 @@ Summary:
Disable individual DFG peephole optimizer pattern.
.. option:: -fno-dfg-pre-inline
Do not apply the DFG optimizer before inlining.
.. option:: -fno-dfg-post-inline
Do not apply the DFG optimizer after inlining.
.. option:: -fno-dfg-pre-inline
Do not apply the DFG optimizer before inlining.
.. option:: -fno-expand
.. option:: -fno-func-opt
@ -641,6 +641,11 @@ Summary:
are typically used only when recommended by a maintainer to help debug
or work around an issue.
.. option:: -fno-var-split
Do not attempt to split variables automatically. Variables explicitly
annotated with :option:`/*verilator&32;split_var*/` are still split.
.. option:: -future0 <option>
Rarely needed. Suppress an unknown Verilator option for an option that
@ -716,14 +721,6 @@ Summary:
Generate a true-random key suitable for use with :vlopt:`--protect-key`,
print it, and exit immediately.
.. option:: --getenv <variable>
If the variable is declared in the environment, print it and exit
immediately. Otherwise, if it's built into Verilator
(e.g., VERILATOR_ROOT), print that and exit immediately. Otherwise, print
a newline and exit immediately. This can be useful in makefiles. See
also :vlopt:`-V`, and the various :file:`*.mk` files.
.. option:: --get-supported <feature>
If the given feature is supported, print "1" and exit
@ -733,6 +730,14 @@ Summary:
Feature may be one of the following: COROUTINES, SYSTEMC.
.. option:: --getenv <variable>
If the variable is declared in the environment, print it and exit
immediately. Otherwise, if it's built into Verilator
(e.g., VERILATOR_ROOT), print that and exit immediately. Otherwise, print
a newline and exit immediately. This can be useful in makefiles. See
also :vlopt:`-V`, and the various :file:`*.mk` files.
.. option:: --help
Displays this message and program version and exits.
@ -788,9 +793,21 @@ Summary:
Specify the level of parallelism for :vlopt:`--build` if
:vlopt:`--build-jobs` isn't provided, and the internal compilation steps
of Verilator if :vlopt:`--verilate-jobs` isn't provided. If zero, uses
the number of threads in the current hardware. Otherwise, must be a
positive integer specifying the maximum number of parallel build jobs.
of Verilator if :vlopt:`--verilate-jobs` isn't provided. Also sets
:vlopt:`--output-groups` if isn't provided.
If zero, uses the number of threads in the current hardware. Otherwise,
must be a positive integer specifying the maximum number of parallel
build jobs.
.. option:: --no-json-edit-nums
Don't dump edit number in .tree.json files. This may make the file more
run-to-run stable for easier comparison.
.. option:: --no-json-ids
Don't use short identifiers instead of addresses/paths in .tree.json.
.. option:: --json-only
@ -815,15 +832,6 @@ Summary:
Specifies the filename for the main output file (`.tree.json`) of --json-only.
Using this option automatically sets :vlopt:`--json-only`.
.. option:: --no-json-edit-nums
Don't dump edit number in .tree.json files. This may make the file more
run-to-run stable for easier comparison.
.. option:: --no-json-ids
Don't use short identifiers instead of addresses/paths in .tree.json.
.. option:: --l2-name <value>
Instead of using the module name when showing Verilog scope, use the
@ -897,28 +905,6 @@ Summary:
Rarely needed. Set the maximum variable size in bytes for it to be
subject to localizing-to-stack optimization. Defaults to 1024.
.. option:: --make <build-tool>
Generates a script for the specified build tool.
Supported values are ``gmake`` for GNU Make and ``cmake`` for CMake.
Both can be specified together. If no build tool is specified, gmake is
assumed. The executable of gmake can be configured via the environment
variable :option:`MAKE`.
When using :vlopt:`--build`, Verilator takes over the responsibility of
building the model library/executable. For this reason :option:`--make`
cannot be specified when using :vlopt:`--build`.
.. option:: -MAKEFLAGS <string>
When using :vlopt:`--build`, add the specified argument to the invoked
make command line. For multiple flags, either pass them as a single
argument with space separators quoted in the shell (e.g. ``-MAKEFLAGS
"-a -b"``), or use multiple -MAKEFLAGS arguments
(e.g. ``-MAKEFLAGS -l -MAKEFLAGS -k``). Use of this option should not be
required for simple builds using the host toolchain.
.. option:: --main
Generates a top-level C++ main() file that supports parsing arguments,
@ -944,6 +930,30 @@ Summary:
If the string ``"-"`` is used, no top level scope is added.
.. option:: --make <build-tool>
Generates a script for the specified build tool.
Supported values are ``gmake`` for GNU Make, or ``cmake`` for CMake, or
``json`` to create a JSON file to feed other build tools.
Multiple options can be specified together. If no build tool is
specified, gmake is assumed. The executable of gmake can be configured
via the environment variable :option:`MAKE`.
When using :vlopt:`--build`, Verilator takes over the responsibility of
building the model library/executable. For this reason :option:`--make`
cannot be specified when using :vlopt:`--build`.
.. option:: -MAKEFLAGS <string>
When using :vlopt:`--build`, add the specified argument to the invoked
make command line. For multiple flags, either pass them as a single
argument with space separators quoted in the shell (e.g. ``-MAKEFLAGS
"-a -b"``), or use multiple -MAKEFLAGS arguments
(e.g. ``-MAKEFLAGS -l -MAKEFLAGS -k``). Use of this option should not be
required for simple builds using the host toolchain.
.. option:: --max-num-width <value>
Set the maximum number literal width (e.g., in 1024'd22 this
@ -978,6 +988,11 @@ Summary:
Ignored for compatibility with other simulators.
.. option:: -o <executable>
Specify the name for the final executable built if using :vlopt:`--exe`.
Defaults to the :vlopt:`--prefix` if not specified.
.. option:: -O0
Disables optimization of the model.
@ -998,11 +1013,6 @@ Summary:
is deprecated and the various `-f<optimization>` arguments should be
used instead.
.. option:: -o <executable>
Specify the name for the final executable built if using :vlopt:`--exe`.
Defaults to the :vlopt:`--prefix` if not specified.
.. option:: --no-order-clock-delay
Deprecated and has no effect (ignored).
@ -1016,18 +1026,24 @@ Summary:
.. 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.
effective output .cpp files. This minimizes the compiler startup
overhead from compiling many small files, 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.
swap thrashing with large designs, high values give no benefits.
Default is zero, which disables this feature.
Typically setting the number of files to the hardware thread count,
corresponding to number of compiler jobs that can run in parallel, will
lead to fastest build times. (e.g. for small to medium designs the value
should range from 2 to 20.)
Zero disables this feature. Negative one, the default, sets the groups
to the value from :vlopt:`--build-jobs`, or from :vlopt:`-j`, or zero in
that priority.
.. option:: --output-split <statements>
@ -1088,6 +1104,14 @@ Summary:
position to indicate the corresponding bit of the __out variable has
a value being driven from within the Verilated model.
.. option:: --pins-sc-biguint
Specifies SystemC inputs/outputs greater than 65 bits wide should use
sc_biguint between 65 and 512, and sc_bv from 513 upwards. When
combined with the :vlopt:`--pins-sc-uint` combination, it results in
sc_uint being used between 2 and 64 and sc_biguint being used between 65
and 512.
.. option:: --pins-sc-uint
Specifies SystemC inputs/outputs greater than 2 bits wide should use
@ -1099,14 +1123,6 @@ Summary:
Specifies SystemC inputs/outputs one bit wide should use sc_uint<1>.
.. option:: --pins-sc-biguint
Specifies SystemC inputs/outputs greater than 65 bits wide should use
sc_biguint between 65 and 512, and sc_bv from 513 upwards. When
combined with the :vlopt:`--pins-sc-uint` combination, it results in
sc_uint being used between 2 and 64 and sc_biguint being used between 65
and 512.
.. option:: --pins-uint8
Specifies SystemC inputs/outputs smaller than the
@ -1468,25 +1484,21 @@ Summary:
A synonym for :vlopt:`+1800-2023ext+\<ext\>`.
.. option:: --threads <threads>
With "--threads 1", the default, the generated model is single-threaded
but may run in a multithreaded environment. With "--threads N",
where N >= 2, the model is generated to run multithreaded on up to N
threads. See :ref:`Multithreading`. This option also applies to
:vlopt:`--trace` (but not :vlopt:`--trace-fst`).
.. option:: --no-threads
Deprecated and has no effect (ignored).
In versions before 5.004, created a model which was not thread-safe.
.. option:: --threads-dpi all
.. option:: --threads <threads>
.. option:: --threads-dpi none
With "--threads 1", the default, the generated model is single-threaded
but may run in a multithreaded environment. With "--threads N",
where N >= 2, the model is generated to run multithreaded on up to N
threads. See :ref:`Multithreading`. This option also applies to
:vlopt:`--trace-vcd` (but not :vlopt:`--trace-fst`).
.. option:: --threads-dpi pure
.. option:: --threads-dpi <mode>
When using :vlopt:`--threads`, controls which DPI imported tasks and
functions are considered thread-safe.
@ -1520,10 +1532,10 @@ Summary:
does not occur before a given module. Default is "1ps/1ps" (to match
SystemC). This is overridden by :vlopt:`--timescale-override`.
.. option:: --timescale-override <timeunit>/<timeprecision>
.. option:: --timescale-override /<timeprecision>
.. option:: --timescale-override <timeunit>/<timeprecision>
Overrides all "\`timescale"s in sources. The timeunit may be left empty
to specify only to override the timeprecision, e.g. "/1fs".
@ -1555,26 +1567,19 @@ Summary:
.. option:: --trace
Adds waveform tracing code to the model using VCD format. This overrides
:vlopt:`--trace-fst`.
Deprecated; use :vlopt:`--trace-fst`, :vlopt:`--trace-saif` or
:vlopt:`--trace-vcd` instead.
Verilator will generate additional :file:`<prefix>__Trace*.cpp` files
must be compiled. In addition :file:`verilated_vcd_sc.cpp`
(for SystemC traces) or :file:`verilated_vcd_c.cpp` (for both) must be
compiled and linked in. If using the Verilator-generated Makefiles,
these files will be added to the source file lists for you. If you are
not using the Verilator Makefiles, you will need to add these to your
Makefile manually.
Using :vlopt:`--trace` without :vlopt:`--trace-fst` nor
:vlopt:`--trace-fst` requests VCD traces.
Having tracing compiled in may result in small performance losses,
even when tracing is not turned on during model execution.
Using :vlopt:`--trace` :vlopt:`--trace-fst` requests FST traces.
When using :vlopt:`--threads`, VCD tracing is parallelized, using the
same number of threads as passed to :vlopt:`--threads`.
Using :vlopt:`--trace` :vlopt:`--trace-saif` requests SAIF traces.
.. option:: --trace-coverage
With :vlopt:`--trace` and ``--coverage-*``, enable tracing to include a
With `--trace-*` and ``--coverage-*``, enable tracing to include a
traced signal for every :vlopt:`--coverage-line` or
:vlopt:`--coverage-user`\ -inserted coverage point, to assist in
debugging coverage items. Note :vlopt:`--coverage-toggle` does not get
@ -1614,6 +1619,12 @@ Summary:
Disable tracing of parameters.
.. option:: --trace-saif
Enable SAIF tracing in the model. This overrides :vlopt:`--trace`.
Specification of this format can be found in `IEEE 1801-2018
<https://ieeexplore.ieee.org/document/8686430>`_ (see Annex I).
.. option:: --trace-structs
Enable tracing to show the name of packed structure, union, and packed
@ -1648,6 +1659,24 @@ Summary:
underscore. Otherwise, these signals are not output during tracing. See
also :vlopt:`--coverage-underscore` option.
.. option:: --trace-vcd
Adds waveform tracing code to the model using VCD format.
Verilator will generate additional :file:`<prefix>__Trace*.cpp` files
must be compiled. In addition :file:`verilated_vcd_sc.cpp`
(for SystemC traces) or :file:`verilated_vcd_c.cpp` (for both) must be
compiled and linked in. If using the Verilator-generated Makefiles,
these files will be added to the source file lists for you. If you are
not using the Verilator Makefiles, you will need to add these to your
Makefile manually.
Having tracing compiled in may result in small performance losses,
even when tracing is not turned on during model execution.
When using :vlopt:`--threads`, VCD tracing is parallelized, using the
same number of threads as passed to :vlopt:`--threads`.
.. option:: -U<var>
Undefines the given preprocessor symbol.
@ -1700,13 +1729,16 @@ Summary:
execute only the build. This can be useful for rebuilding the Verilated code
produced by a previous invocation of Verilator.
.. option:: --verilate-jobs [<value>]
.. option:: --verilate-jobs <value>
Specify the level of parallelism for the internal compilation steps of
Verilator. If zero, uses the number of threads in the current hardware.
Otherwise, must be a positive integer specifying the maximum number of
parallel build jobs.
If not provided, and :vlopt:`-j` is provided, the :vlopt:`-j` value is
used.
See also :vlopt:`-j`.
.. option:: +verilog1995ext+<ext>
@ -1852,33 +1884,36 @@ Summary:
``-Wwarn-UNUSEDGENVAR`` ``-Wwarn-UNUSEDLOOP`` ``-Wwarn-UNUSEDPARAM``
``-Wwarn-UNUSEDSIGNAL`` ``-Wwarn-VARHIDDEN``.
.. option:: --x-assign 0
.. option:: --x-assign 1
.. option:: --x-assign fast (default)
.. option:: --x-assign unique
.. option:: --x-assign <mode>
Controls the two-state value that is substituted when an explicit X
value is encountered in the source. "--x-assign fast", the default,
converts all Xs to whatever is best for performance. "--x-assign 0"
converts all Xs to 0s, and is also fast. "--x-assign 1" converts all Xs
to 1s, this is nearly as fast as 0, but more likely to find reset bugs
as active high logic will fire. Using "--x-assign unique" will result in
all explicit Xs being replaced by a constant value determined at
runtime. The value is determined by calling a function at initialization
time. This enables the randomization of Xs with different seeds on different
executions. This method is the slowest, but safest for finding reset
bugs.
value is encountered in the source.
If using "--x-assign unique", you may want to seed your random number
generator such that each regression run gets a different randomization
sequence. The simplest is to use the :vlopt:`+verilator+seed+\<value\>`
runtime option. Alternatively, use the system's :code:`srand48()` or for
Windows :code:`srand()` function to do this. You'll probably also want
to print any seeds selected, and code to enable rerunning with that same
seed so you can reproduce bugs.
With "--x-assign 0",
converts all Xs to 0s, and is also fast.
With "--x-assign 1",
converts all Xs to 1s, this is nearly as fast as 0, but more likely to
find reset bugs as active high logic will fire.
With "--x-assign fast", the default,
converts all Xs to whatever is best for performance.
With "--x-assign unique",
all explicit Xs being replaced by a constant value determined at
runtime. The value is determined by calling a function at
initialization time. This enables the randomization of Xs with
different seeds on different executions. This method is the slowest,
but safest for finding reset bugs.
If using `--x-assign unique`, you may want to seed your random number
generator such that each regression run gets a different randomization
sequence. The simplest is to use the
:vlopt:`+verilator+seed+\<value\>` runtime option. Alternatively, use
the system's :code:`srand48()` or for Windows :code:`srand()` function
to do this. You'll probably also want to print any seeds selected,
and code to enable rerunning with that same seed so you can reproduce
bugs.
.. note::
@ -1888,24 +1923,20 @@ Summary:
specified. Initial values of all other state holding variables are
controlled with `--x-initial`.
.. option:: --x-initial 0
.. option:: --x-initial fast
.. option:: --x-initial unique (default)
.. option:: --x-initial <mode>
Controls the two-state value used to initialize variables that
are not otherwise initialized.
"--x-initial 0",
With "--x-initial 0",
initializes all otherwise uninitialized variables to zero.
"--x-initial unique", the default,
With "--x-initial unique", the default,
initializes variables using a function, which determines the value to
use for each initialization. This gives the greatest flexibility and
allows for finding reset bugs. See :ref:`Unknown states`.
"--x-initial fast",
With "--x-initial fast",
is best for performance, and initializes all variables to a state
Verilator determines is optimal. This may allow further code
optimizations, but will likely hide any code bugs relating to missing
@ -1986,8 +2017,9 @@ Summary:
.. _Configuration Files:
Configuration Files
===================
=====================
Configuration Files
=====================
In addition to the command line, warnings and other features for the
:command:`verilator` command may be controlled with configuration files,
@ -2020,15 +2052,6 @@ The grammar of configuration commands is as follows:
Take the remaining text and treat it as Verilator configuration commands.
.. option:: coverage_on [-file "<filename>" [-lines <line> [ - <line> ]]]
.. option:: coverage_off [-file "<filename>" [-lines <line> [ - <line> ]]]
Enable/disable coverage for the specified filename (or wildcard with
'\*' or '?', or all files if omitted) and range of line numbers (or all
lines if omitted). Often used to ignore an entire module for coverage
analysis purposes.
.. option:: clock_enable -module "<modulename>" -var "<signame>"
Deprecated and has no effect (ignored).
@ -2040,30 +2063,42 @@ The grammar of configuration commands is as follows:
Same as :option:`/*verilator&32;clock_enable*/` metacomment.
.. option:: clocker -module "<modulename>" [-task "<taskname>"] -var "<signame>"
.. t_dist_docs_style ignore no_clocker
.. option:: clocker -module "<modulename>" [-function "<funcname>"] -var "<signame>"
.. option:: no_clocker -module "<modulename>" [-task "<taskname>"] -var "<signame>"
.. option:: clocker -module "<modulename>" [-task "<taskname>"] -var "<signame>"
.. option:: no_clocker -module "<modulename>" [-function "<funcname>"] -var "<signame>"
.. option:: no_clocker -module "<modulename>" [-task "<taskname>"] -var "<signame>"
Indicates whether the signal is used as clock or not. Verilator uses
this information to mark the signal and any derived signals as clocker.
See :vlopt:`--clk`.
Same as :option:`/*verilator&32;clocker*/` metacomment.
.. option:: coverage_block_off -module "<modulename>" -block "<blockname>"
.. option:: coverage_block_off -file "<filename>" -line <lineno>
.. option:: coverage_block_off -module "<modulename>" -block "<blockname>"
Specifies the entire begin/end block should be ignored for coverage
analysis purposes. It can either be specified as a named block or as a
filename and line number.
Same as :option:`/*verilator&32;coverage_block_off*/` metacomment.
.. option:: coverage_off [-file "<filename>" [-lines <line> [ - <line> ]]]
.. option:: coverage_on [-file "<filename>" [-lines <line> [ - <line> ]]]
Enable/disable coverage for the specified filename (or wildcard with
'\*' or '?', or all files if omitted) and range of line numbers (or all
lines if omitted). Often used to ignore an entire module for coverage
analysis purposes.
.. option:: forceable -module "<modulename>" -var "<signame>"
Generate public `<signame>__VforceEn` and `<signame>__VforceVal` signals
@ -2074,11 +2109,8 @@ The grammar of configuration commands is as follows:
.. option:: full_case -file "<filename>" -lines <lineno>
.. option:: parallel_case -file "<filename>" -lines <lineno>
Same as :code:`//synopsys full_case` and
:code:`//synopsys parallel_case`. When these synthesis directives are
discovered, Verilator will either formally prove the directive to be
Same as :code:`//synthesis full_case`. When these synthesis directives
are discovered, Verilator will either formally prove the directive to be
true, or, failing that, will insert the appropriate code to detect
failing cases at simulation runtime and print an "Assertion failed"
error message.
@ -2096,20 +2128,27 @@ The grammar of configuration commands is as follows:
This option should not be used directly.
See :ref:`Hierarchical Verilation`.
.. option:: hier_workers -hier-dpi "<function_name>" -workers <worker_count>
Specifies how many threads need to be used for scheduling hierarchical DPI
tasks. This data is inserted internally during :vlopt:`--hierarchical`,
based on value specified in `hier_workers -module`. This option
should not be used directly. See :ref:`Hierarchical Verilation`.
.. option:: hier_workers -module "<module_name>" -workers <worker_count>
Specifies how many threads need to be used for scheduling given module with
:option:`/*verilator&32;hier_block*/` metacomment. This number needs to be
smaller than :vlopt:`--threads` to fit in a thread schedule.
See :ref:`Hierarchical Verilation`.
.. option:: inline -module "<modulename>"
Specifies the module may be inlined into any modules that use this
module. Same as :option:`/*verilator&32;inline_module*/` metacomment.
.. option:: isolate_assignments -module "<modulename>" [-task "<taskname>"] -var "<signame>"
.. option:: isolate_assignments -module "<modulename>" [-function "<funcname>"] -var "<signame>"
.. option:: isolate_assignments -module "<modulename>" -function "<fname>"
Used to indicate that the assignments to this signal in any blocks
should be isolated into new blocks. Same as
:option:`/*verilator&32;isolate_assignments*/` metacomment.
.. t_dist_docs_style ignore no_inline
.. option:: no_inline -module "<modulename>"
@ -2117,10 +2156,10 @@ The grammar of configuration commands is as follows:
this module. Same as :option:`/*verilator&32;no_inline_module*/`
metacomment.
.. option:: no_inline [-module "<modulename>"] -task "<taskname>"
.. option:: no_inline [-module "<modulename>"] -function "<funcname>"
.. option:: no_inline [-module "<modulename>"] -task "<taskname>"
Specify the function or task should not be inlined into where it is
used. This may reduce the size of the final executable when a task is
used a very large number of times. For this flag to work, the task and
@ -2129,12 +2168,22 @@ The grammar of configuration commands is as follows:
Same as :option:`/*verilator&32;no_inline_task*/` metacomment.
.. option:: lint_on [-rule <message>] [-file "<filename>" [-lines <line> [ - <line>]]]
.. option:: isolate_assignments -module "<modulename>" -function "<fname>"
.. option:: isolate_assignments -module "<modulename>" [-function "<funcname>"] -var "<signame>"
.. option:: isolate_assignments -module "<modulename>" [-task "<taskname>"] -var "<signame>"
Used to indicate that the assignments to this signal in any blocks
should be isolated into new blocks. Same as
:option:`/*verilator&32;isolate_assignments*/` metacomment.
.. option:: lint_off [-rule <message>] [-file "<filename>" [-lines <line> [ - <line>]]]
.. option:: lint_off [-rule <message>] [-file "<filename>"] [-contents "<wildcard>"] [-match "<wildcard>"]
.. option:: lint_on [-rule <message>] [-file "<filename>" [-lines <line> [ - <line>]]]
Enable/disables the specified lint warning, in the specified filename
(or wildcard with '\*' or '?', or all files if omitted) and range of
line numbers (or all lines if omitted).
@ -2165,18 +2214,13 @@ The grammar of configuration commands is as follows:
Before version 4.026, :code:`-rule` was named :code:`-msg`, and
:code:`-msg` remained a deprecated alias until Version 5.000.
.. option:: public [-module "<modulename>"] [-task/-function "<taskname>"] -var "<signame>"
.. option:: parallel_case -file "<filename>" -lines <lineno>
.. option:: public_flat [-module "<modulename>"] [-task/-function "<taskname>"] -var "<signame>"
.. option:: public_flat_rd [-module "<modulename>"] [-task/-function "<taskname>"] -var "<signame>"
.. option:: public_flat_rw [-module "<modulename>"] [-task/-function "<taskname>"] -var "<signame>" "@(edge)"
Sets the variable to be public. Same as
:option:`/*verilator&32;public*/` or
:option:`/*verilator&32;public_flat*/`, etc., metacomments. See
also :ref:`VPI Example`.
Same as :code:`//synthesis parallel_case`. When these synthesis
directives are discovered, Verilator will either formally prove the
directive to be true, or, failing that, will insert the appropriate code
to detect failing cases at simulation runtime and print an "Assertion
failed" error message.
.. option:: profile_data -hier-dpi "<function_name>" -cost <cost_value>
@ -2191,18 +2235,31 @@ The grammar of configuration commands is as follows:
order to improve model runtime performance. This option is not expected
to be used by users directly. See :ref:`Thread PGO`.
.. option:: sc_bv -module "<modulename>" [-task "<taskname>"] -var "<signame>"
.. option:: public [-module "<modulename>"] [-task/-function "<taskname>"] -var "<signame>"
.. option:: public_flat [-module "<modulename>"] [-task/-function "<taskname>"] -var "<signame>"
.. option:: public_flat_rd [-module "<modulename>"] [-task/-function "<taskname>"] -var "<signame>"
.. option:: public_flat_rw [-module "<modulename>"] [-task/-function "<taskname>"] -var "<signame>" "@(edge)"
Sets the variable to be public. Same as
:option:`/*verilator&32;public*/` or
:option:`/*verilator&32;public_flat*/`, etc., metacomments. See
also :ref:`VPI Example`.
.. option:: sc_bv -module "<modulename>" [-function "<funcname>"] -var "<signame>"
.. option:: sc_bv -module "<modulename>" [-task "<taskname>"] -var "<signame>"
Sets the port to be of :code:`sc_bv<{width}>` type, instead of bool,
uint32_t, or uint64_t. Same as :option:`/*verilator&32;sc_bv*/`
metacomment.
.. option:: sformat [-module "<modulename>"] [-task "<taskname>"] -var "<signame>"
.. option:: sformat [-module "<modulename>"] [-function "<funcname>"] -var "<signame>"
.. option:: sformat [-module "<modulename>"] [-task "<taskname>"] -var "<signame>"
Must be applied to the final argument of type :code:`input string` of a
function or task to indicate that the function or task should pass all
remaining arguments through $sformatf. This allows the creation of DPI
@ -2211,20 +2268,20 @@ The grammar of configuration commands is as follows:
Same as :option:`/*verilator&32;sformat*/` metacomment.
.. option:: split_var [-module "<modulename>"] [-task "<taskname>"] -var "<varname>"
.. option:: split_var [-module "<modulename>"] [-function "<funcname>"] -var "<varname>"
.. option:: split_var [-module "<modulename>"] [-task "<taskname>"] -var "<varname>"
Break the variable into multiple pieces typically to resolve UNOPTFLAT
performance issues. Typically the variables to attach this to are
recommended by Verilator itself; see :option:`UNOPTFLAT`.
Same as :option:`/*verilator&32;split_var*/` metacomment.
.. option:: timing_on [-file "<filename>" [-lines <line> [ - <line>]]]
.. option:: timing_off [-file "<filename>" [-lines <line> [ - <line>]]]
.. option:: timing_on [-file "<filename>" [-lines <line> [ - <line>]]]
Enables/disables timing constructs for the specified file and lines.
When disabled, all timing control constructs in the specified source
code locations are ignored the same way as with the
@ -2234,14 +2291,17 @@ The grammar of configuration commands is as follows:
Same as :option:`/*verilator&32;timing_on*/`,
:option:`/*verilator&32;timing_off*/` metacomments.
.. option:: tracing_on [-file "<filename>" [-lines <line> [ - <line> ]]]
.. t_dist_docs_style ignore tracing_on
.. option:: tracing_off [-file "<filename>" [-lines <line> [ - <line> ]]]
.. option:: tracing_on [-scope "<scopename>" [-levels <levels> ]]
.. option:: tracing_on [-file "<filename>" [-lines <line> [ - <line> ]]]
.. option:: tracing_off [-scope "<scopename>" [-levels <levels> ]]
.. option:: tracing_on [-scope "<scopename>" [-levels <levels> ]]
Enable/disable waveform tracing for all future signals declared in
all files.

View File

@ -49,116 +49,119 @@ verilator_coverage Arguments
.. option:: <filename>
Specifies the input coverage data file. Multiple filenames may be provided
to read multiple inputs. If no data file is specified, by default,
"coverage.dat" will be read.
Specifies the input coverage data file. Multiple filenames may be
provided to read multiple inputs. If no data file is specified, by
default, "coverage.dat" will be read.
.. option:: --annotate <output_directory>
Specifies the directory name to which source files with annotated coverage
data should be written.
Specifies the directory name to which source files with annotated
coverage data should be written.
Points are children of each line coverage- branches, expressions 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.
Points are children of each line coverage- branches, expressions 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
to filter the report.
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 to filter the report.
* " " (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`.
* " " (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::
.. code-block::
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.
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
Specifies all files should be shown. By default, only those source files
with low coverage are written to the output directory.
Specifies all files should be shown. By default, only those source
files with low coverage are written to the output directory.
This option should be used together with :option:`--annotate`.
This option should be used together with :option:`--annotate`.
.. option:: --annotate-min <count>
Specifies the threshold (<count>) below which coverage point is considered
sufficient. If the threshold is not exceeded, then the annotation will begin
with a "%" symbol to indicate the coverage is insufficient.
Specifies the threshold (<count>) below which coverage point is
considered sufficient. If the threshold is not exceeded, then the
annotation will begin with a "%" symbol to indicate the coverage is
insufficient.
The <count> threshold defaults to 10.
The <count> threshold defaults to 10.
This option should be used together with :option:`--annotate`.
This option should be used together with :option:`--annotate`.
.. option:: --annotate-points
Specifies all coverage points should be shown after each line of text. By
default, only source lines are shown.
Specifies all coverage points should be shown after each line of text. By
default, only source lines are shown.
.. code-block::
.. code-block::
100000 input logic a, b, c;
+100000 point: comment=a // These lines are only shown
+200000 point: comment=b // with option --annotate-points
+300000 point: comment=c // enabled.
100000 input logic a, b, c;
+100000 point: comment=a // These lines are only shown
+200000 point: comment=b // with option --annotate-points
+300000 point: comment=c // enabled.
This option should be used together with :option:`--annotate`.
This option should be used together with :option:`--annotate`.
.. option:: --help
Displays a help summary, the program version, and exits.
Displays a help summary, the program version, and exits.
.. option:: --rank
Prints an experimental report listing the relative importance of each test
in covering all of the coverage points. The report shows "Covered" which
indicates the number of points the test covers; a test is considered to
cover a point if it has a bucket count of at least 1. The "rank" column has
a higher number t indicate the test is more critical, and rank 0 means the
test does not need to be run to cover the points. "RankPts" indicates the
number of coverage points this test will contribute to overall coverage if
all tests are run in the order of highest to the lowest rank.
Prints an experimental report listing the relative importance of each
test in covering all of the coverage points. The report shows "Covered"
which indicates the number of points the test covers; a test is
considered to cover a point if it has a bucket count of at least 1. The
"rank" column has a higher number t indicate the test is more critical,
and rank 0 means the test does not need to be run to cover the points.
"RankPts" indicates the number of coverage points this test will
contribute to overall coverage if all tests are run in the order of
highest to the lowest rank.
.. option:: --unlink
With :option:`--write`, unlink all input files after the output
has been successfully created.
With :option:`--write`, unlink all input files after the output has been
successfully created.
.. option:: --version
Displays program version and exits.
Displays program version and exits.
.. option:: --write <filename>
Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename in verilator_coverage data format.
This is useful in scripts to combine many coverage data files (likely
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 verilator_coverage data
format. This is useful in scripts to combine many coverage data files
(likely generated from random test runs) into one master coverage file.
.. option:: --write-info <filename.info>
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. 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`
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. 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

@ -51,6 +51,10 @@ predicted_parallelism
cpu#_thread
For the given CPU number, the thread number measured to be executing.
cpu#_waiting
For the given CPU number, aggregated waiting time for mtask dependencies.
Visualized as `X` values.
mtask#_cpu
For the given mtask id, the CPU it was measured to execute on.
@ -80,16 +84,16 @@ verilator_gantt Arguments
.. option:: <filename>
The filename to read data from; the default is "profile_exec.dat".
The filename to read data from; the default is "profile_exec.dat".
.. option:: --help
Displays a help summary, the program version, and exits.
Displays a help summary, the program version, and exits.
.. option:: --no-vcd
Disables creating a .vcd file.
Disables creating a .vcd file.
.. option:: --vcd <filename>
Sets the output filename for vcd dump; the default is "verilator_gantt.vcd".
Sets the output filename for vcd dump; the default is "verilator_gantt.vcd".

View File

@ -33,8 +33,8 @@ verilator_profcfunc Arguments
.. option:: <filename>
The :command:`gprof`-generated filename to read data from. Typically "gprof.out".
The :command:`gprof`-generated filename to read data from. Typically "gprof.out".
.. option:: --help
Displays a help summary, the program version, and exits.
Displays a help summary, the program version, and exits.

View File

@ -1,14 +1,19 @@
.. Copyright 2003-2025 by Wilson Snyder.
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
*******************
Language Extensions
*******************
=====================
Language Extensions
=====================
The following additional constructs are the extensions Verilator supports
on top of standard Verilog code. Using these features outside of comments
or "`ifdef`"'s may break other tools.
.. option:: """ [string] """
A triple-quoted block specifies a string that may include newlines and
single quotes. This extension was standardized in IEEE 1800-2023.
.. option:: `__FILE__
The :option:`\`__FILE__` define expands to the current filename as a
@ -21,6 +26,12 @@ or "`ifdef`"'s may break other tools.
C++'s __LINE__. This Verilator feature added in 2006 was incorporated
into IEEE 1800-2009.
.. option:: `coverage_block_off
Specifies the entire begin/end block should be ignored for coverage
analysis. Must be inside a code block, e.g., within a begin/end pair.
Same as :option:`coverage_block_off` in :ref:`Configuration Files`.
.. option:: `error [string]
This will report an error when the preprocessor emits it, similar to
@ -33,10 +44,116 @@ or "`ifdef`"'s may break other tools.
internal tests, so that debugging can leave the line numbers correctly
referring to the test file's line numbers.
.. option:: """ [string] """
.. option:: `systemc_class_name
A triple-quoted block specifies a string that may include newlines and
single quotes. This extension was standardized in IEEE 1800-2023.
Inside one of the :option:`\`systemc_... <\`systemc_header>` text
blocks, replaced with the C++ class name generated for the given
containing SystemVerilog class or module. Currently this is replaced
blindly, ignoring quoting or other escapes; this behavior may change in
the future. This attribute is indented only to be used internally in
`verilated_std.sv`.
.. option:: `systemc_ctor
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the C++ class constructor. Must be placed as a module or
class item, e.g., directly inside a module/endmodule or class/endclass
pair. Despite the name of this macro, this also works in pure C++ code.
.. option:: `systemc_dtor
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the C++ class destructor. Must be placed as a module or
class item, e.g., directly inside a module/endmodule or class/endclass
pair. Despite the name of this macro, this also works in pure C++ code.
.. option:: `systemc_header
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the output .h file's header. Must be placed as a module
or class item, e.g., directly inside a module/endmodule or
class/endclass pair. Despite the name of this macro, this also works in
pure C++ code.
.. option:: `systemc_header_post
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the output .h file's header after the class definition.
Must be placed as a module or class item, e.g., directly inside a
module/endmodule or class/endclass pair. Despite the name of this macro,
this also works in pure C++ code.
.. option:: `systemc_imp_header
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the header of all files for this C++ class implementation.
Must be placed as a module or class item, e.g., directly inside a
module/endmodule or class/endclass pair. Despite the name of this macro,
this also works in pure C++ code.
.. option:: `systemc_implementation
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into a single file of the C++ class implementation. Must be
placed as a module or class item, e.g., directly inside a
module/endmodule or class/endclass pair. Despite the name of this macro,
this also works in pure C++ code.
If you will be reading or writing any Verilog variables in the C++
functions, the Verilog signals must be declared with a
:option:`/*verilator&32;public*/` metacomment. See also the public task
feature; writing an accessor may result in cleaner code.
.. option:: `systemc_interface
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the C++ class interface. Must be placed as a module or
class item, e.g., directly inside a module/endmodule or class/endclass
pair. Despite the name of this macro, this also works in pure C++ code.
.. option:: `SYSTEMVERILOG
The SYSTEMVERILOG, SV_COV_START, and related standard predefined macros
are defined by default when :vlopt:`--language <--language>` is
"1800-\*".
.. option:: `VERILATOR
.. option:: `verilator
.. option:: `verilator3
The VERILATOR, verilator and verilator3 predefined macros are defined by
default so you may "\`ifdef" around tool specific constructs.
.. option:: `verilator_config
Take the remaining text up to the next :option:`\`verilog` mode switch and
treat it as Verilator configuration commands. See :ref:`Configuration Files`.
.. option:: `VERILATOR_TIMING
The VERILATOR_TIMING define is set when :vlopt:`--timing` is used to
allow an "\`ifdef" of code dependent on this feature. Note that this define
is not affected by the :option:`timing_off` configuration file option
nor timing metacomments.
.. option:: `verilog
Switch back to processing Verilog code after a
:option:`\`systemc_... <\`systemc_header>` mode switch. The Verilog
code returns to the last language mode specified with
"\`begin_keywords", or SystemVerilog if none was specified.
.. t_dist_docs_style restart_sort
.. option:: $c([string], ...);
@ -86,6 +203,16 @@ or "`ifdef`"'s may break other tools.
prints 5 digits per the C standard. This extension was standardized into
1800-2009.
.. option:: $stacktrace
Called as a task, print a stack trace. Called as a function, return a
string with a stack trace. This relies on the C++ system trace, which
may give less meaningful results if the model is not compiled with debug
symbols. Also, the data represents the C++ stack; the SystemVerilog
functions/tasks involved may be renamed and/or inlined before becoming
the C++ functions that may be visible in the stack trace. This
extension was standardized in IEEE 1800-2023.
.. option:: $timeprecision
Returns the timeprecision of the model as an integer. This extension is
@ -96,98 +223,6 @@ or "`ifdef`"'s may break other tools.
Returns the timeunit of the current module as an integer. This
extension is experimental and may be removed without deprecation.
.. option:: `coverage_block_off
Specifies the entire begin/end block should be ignored for coverage
analysis. Must be inside a code block, e.g., within a begin/end pair.
Same as :option:`coverage_block_off` in :ref:`Configuration Files`.
.. option:: `systemc_header
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the output .h file's header. Must be placed as a module
item, e.g., directly inside a module/endmodule pair. Despite the name of
this macro, this also works in pure C++ code.
.. option:: `systemc_ctor
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the C++ class constructor. Must be placed as a module
item, e.g., directly inside a module/endmodule pair. Despite the name of
this macro, this also works in pure C++ code.
.. option:: `systemc_dtor
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the C++ class destructor. Must be placed as a module
item, e.g., directly inside a module/endmodule pair. Despite the name of
this macro, this also works in pure C++ code.
.. option:: `systemc_interface
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the C++ class interface. Must be placed as a module item,
e.g., directly inside a module/endmodule pair. Despite the name of this
macro, this also works in pure C++ code.
.. option:: `systemc_imp_header
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the header of all files for this C++ class implementation.
Must be placed as a module item, e.g., directly inside a module/endmodule
pair. Despite the name of this macro, this also works in pure C++ code.
.. option:: `systemc_implementation
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into a single file of the C++ class implementation. Must be
placed as a module item, e.g., directly inside a module/endmodule
pair. Despite the name of this macro, this also works in pure C++ code.
If you will be reading or writing any Verilog variables in the C++
functions, the Verilog signals must be declared with a
:option:`/*verilator&32;public*/` metacomment. See also the public task
feature; writing an accessor may result in cleaner code.
.. option:: `SYSTEMVERILOG
The SYSTEMVERILOG, SV_COV_START, and related standard defines are set by
default when :vlopt:`--language <--language>` is "1800-\*".
.. option:: `VERILATOR
.. option:: `verilator
.. option:: `verilator3
The VERILATOR, verilator and verilator3 defines are set by default so
you may "\`ifdef" around tool specific constructs.
.. option:: `verilator_config
Take the remaining text up to the next :option:`\`verilog` mode switch and
treat it as Verilator configuration commands. See :ref:`Configuration Files`.
.. option:: `VERILATOR_TIMING
The VERILATOR_TIMING define is set when :vlopt:`--timing` is used to
allow an "\`ifdef" of code dependent on this feature. Note that this define
is not affected by the :option:`timing_off` configuration file option
nor timing metacomments.
.. option:: `verilog
Switch back to processing Verilog code after a
:option:`\`systemc_... <\`systemc_header>` mode switch. The Verilog
code returns to the last language mode specified with
"\`begin_keywords", or SystemVerilog if none was specified.
.. option:: /*verilator&32;clock_enable*/
Deprecated and has no effect (ignored).
@ -212,6 +247,9 @@ or "`ifdef`"'s may break other tools.
Same as :option:`clock_enable` configuration file option.
.. t_dist_docs_style ignore /*verilator&32;no_clocker*/
.. option:: /*verilator&32;clocker*/
.. option:: /*verilator&32;no_clocker*/
@ -379,29 +417,6 @@ or "`ifdef`"'s may break other tools.
parameter [2:0] PARAM /*verilator public*/ = 2'b0;
.. option:: /*verilator&32;public*/ (on typedef enum)
Used after an enum typedef declaration to indicate the emitted C code
should have the enum values visible. Due to C++ language restrictions,
this may only be used on 64-bit or narrower integral enumerations.
.. code-block:: sv
typedef enum logic [2:0] { ZERO = 3'b0 } pub_t /*verilator public*/;
.. option:: /*verilator&32;public*/ (on variable)
Used after an input, output, register, or wire declaration to indicate
the signal should be declared so that C code may read or write the value
of the signal. This will also declare this module public; otherwise, use
:code:`/*verilator&32;public_flat*/`.
Instead of using public variables, consider making a DPI or public
function that accesses the variable. This is nicer as it provides an
obvious entry point compatible across simulators.
Same as :option:`public` configuration file option.
.. option:: /*verilator&32;public*/ (on task/function)
Used inside the declaration section of a function or task declaration to
@ -426,6 +441,52 @@ or "`ifdef`"'s may break other tools.
Same as :option:`public` configuration file option.
.. option:: /*verilator&32;public*/ (on typedef enum)
Used after an enum typedef declaration to indicate the emitted C code
should have the enum values visible. Due to C++ language restrictions,
this may only be used on 64-bit or narrower integral enumerations.
.. code-block:: sv
typedef enum logic [2:0] { ZERO = 3'b0 } pub_t /*verilator public*/;
.. option:: /*verilator&32;public*/ (on variable)
Used after an input, output, register, or wire declaration to indicate
the signal should be declared so that C code may read or write the value
of the signal. This will also declare this module public; otherwise, use
:code:`/*verilator&32;public_flat*/`.
Instead of using public variables, consider making a DPI or public
function that accesses the variable. This is nicer as it provides an
obvious entry point compatible across simulators.
Same as :option:`public` configuration file option.
.. option:: /*verilator&32;public_[|flat|flat_rd|flat_rw]_on [@(<edge_list>)]*/ (as scope)
Used to wrap multiple signals and parameters with the respective public attribute.
See attribute above for their respective behavior. Cannot be nested. e.g:
.. code-block:: sv
/*verilator public_flat_rw_on*/
logic clk;
logic rst;
parameter width = 8;
/* verilator public_off*/
logic data;
Is equivalent to:
.. code-block:: sv
logic clk /*verilator public_flat_rw*/;
logic rst /*verilator public_flat_rw*/;
parameter width /*verilator public_flat_rw*/ = 8;
logic data;
.. option:: /*verilator&32;public_flat*/ (on variable)
Used after an input, output, register, or wire declaration to indicate
@ -453,33 +514,6 @@ or "`ifdef`"'s may break other tools.
Same as :option:`public_flat_rw` configuration file option.
.. option:: /*verilator&32;public_[|flat|flat_rd|flat_rw]_on [@(<edge_list>)]*/ (as scope)
Used to wrap multiple signals and parameters with the respective public attribute.
See attribute above for their respective behavior. Cannot be nested. e.g:
.. code-block:: sv
/*verilator public_flat_rw_on*/
logic clk;
logic rst;
parameter width = 8;
/* verilator public_off*/
logic data;
Is equivalent to:
.. code-block:: sv
logic clk /*verilator public_flat_rw*/;
logic rst /*verilator public_flat_rw*/;
parameter width /*verilator public_flat_rw*/ = 8;
logic data;
.. option:: /*verilator&32;public_off*/
Terminates the previous `/*verilator public*_on*/` directive; see above.
.. option:: /*verilator&32;public_module*/
Used after a module statement to indicate the module should not be
@ -490,13 +524,9 @@ or "`ifdef`"'s may break other tools.
Same as :option:`public` configuration file option.
.. option:: /*verilator&32;sc_clock*/
.. option:: /*verilator&32;public_off*/
Deprecated and ignored. Previously used after an input declaration to
indicate the signal should be declared in SystemC as a sc_clock instead
of a bool. This was needed in SystemC 1.1 and 1.2 only; versions 2.0
and later do not require clock pins to be sc_clocks, and this is no
longer needed and is ignored.
Terminates the previous `/*verilator public*_on*/` directive; see above.
.. option:: /*verilator&32;sc_bv*/
@ -509,6 +539,14 @@ or "`ifdef`"'s may break other tools.
Same as :option:`sc_bv` configuration file option.
.. option:: /*verilator&32;sc_clock*/
Deprecated and ignored. Previously used after an input declaration to
indicate the signal should be declared in SystemC as a sc_clock instead
of a bool. This was needed in SystemC 1.1 and 1.2 only; versions 2.0
and later do not require clock pins to be sc_clocks, and this is no
longer needed and is ignored.
.. option:: /*verilator&32;sformat*/
Attached to the final argument of type "input string" of a function or
@ -550,6 +588,20 @@ or "`ifdef`"'s may break other tools.
large arrays may slow down the Verilation speed, so use this only on
variables that require it.
Packed variables that are only referenced locally (without hierarchical
references) via non-overlapping, constant-indexed bit or part select
expressions are split automatically. This covers the somewhat common
usage pattern:
.. code-block:: sv
logic [1:0][31:0] tmp;
assign tmp[0] = foo + a;
assign tmp[1] = tmp[1] + b;
assign bar = tmp[1] + c;
Same as :option:`split_var` configuration file option.
.. option:: /*verilator&32;tag <text...>*/
@ -583,7 +635,7 @@ or "`ifdef`"'s may break other tools.
Attached to a DPI import to indicate that function should be called when
initializing tracing. This attribute is indented only to be used
internally in code that Verilator generates when :vlopt:`--lib-create`
or :vlopt:`--hierarchical` is used along with :vlopt:`--trace`.
or :vlopt:`--hierarchical` is used along with :vlopt:`--trace-vcd`.
.. option:: /*verilator&32;tracing_off*/
@ -613,13 +665,3 @@ or "`ifdef`"'s may break other tools.
following loop at the same statement level should always be fully
unrolled by Verilator, ignoring :vlopt:`--unroll-count`. This is
similar to clang's ``#pragma clang loop unroll(full)``.
.. option:: $stacktrace
Called as a task, print a stack trace. Called as a function, return a
string with a stack trace. This relies on the C++ system trace, which
may give less meaningful results if the model is not compiled with debug
symbols. Also, the data represents the C++ stack; the SystemVerilog
functions/tasks involved may be renamed and/or inlined before becoming
the C++ functions that may be visible in the stack trace. This
extension was standardized in IEEE 1800-2023.

View File

@ -128,7 +128,7 @@ How do I generate waveforms (traces) in C++?
See also the next question for tracing in SystemC mode.
A. Pass the :vlopt:`--trace` option to Verilator. Then you may use ``$dumpfile`` and
A. Pass the :vlopt:`--trace-vcd` option to Verilator. Then you may use ``$dumpfile`` and
``$dumpvars`` to enable traces, the same as with any Verilog simulator,
although Verilator ignores the arguments to ``$dumpvars``. See
``examples/make_tracing_c`` in the distribution.
@ -177,7 +177,7 @@ file.
How do I generate waveforms (traces) in SystemC?
""""""""""""""""""""""""""""""""""""""""""""""""
A. Pass the :vlopt:`--trace` option to Verilator, and in your top-level
A. Pass the :vlopt:`--trace-vcd` option to Verilator, and in your top-level
:code:`sc_main()`, call :code:`Verilated::traceEverOn(true)`. Then you
may use :code:`$dumpfile` and code:`$dumpvars` to enable traces, as
with any Verilog simulator; see the non-SystemC example in

View File

@ -65,9 +65,9 @@ For --cc/--sc, it creates:
* - *{prefix}*\ ___024root\ *{__DepSet_hash__n}*\ .cpp
- Infrequent cold routines (hashed to reduce build times)
* - *{prefix}*\ ___024root__Trace\ *{__n}*\ .cpp
- Wave file generation code (from --trace)
- Wave file generation code (from --trace-\*)
* - *{prefix}*\ ___024root__Trace__Slow\ *{__n}*\ .cpp
- Wave file generation code (from --trace)
- Wave file generation code (from --trace-\*)
* - *{prefix}*\ __Dpi.h
- DPI import and export declarations (from --dpi)
* - *{prefix}*\ __Dpi.cpp

View File

@ -15,9 +15,9 @@ Package Manager Quick Install
=============================
Using a distribution's package manager is the easiest way to get
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:
started. (Note distribution packages almost never have the most recent
Verilator version, so we recommend following :ref:`Git Install` below,
instead.) To install as a package:
.. code-block:: shell
@ -118,6 +118,25 @@ To build or run Verilator, you need these standard packages:
sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
sudo apt-get install zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error)
For SystemC:
.. code-block:: shell
sudo apt-get install libsystemc libsystemc-dev
For constraints:
.. code-block:: shell
sudo apt-get install z3 # Optional solver
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 or run Verilator, the following are optional but should be installed
for good performance:
@ -127,13 +146,6 @@ for good performance:
sudo apt-get install mold # If present at build, needed for run
sudo apt-get install libgoogle-perftools-dev numactl
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:
@ -146,7 +158,7 @@ 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 apt-get install python3-clang python3-distro 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
@ -155,7 +167,10 @@ Those developing Verilator itself may also want these (see internals.rst):
Install SystemC
^^^^^^^^^^^^^^^
If you will be using SystemC (vs straight C++ output), download `SystemC
SystemC code can be generated from Verilator (with :vlopt:`--sc`) if it is
installed as a package (see above).
Alternatively, from their sources, download `SystemC
<https://www.accellera.org/downloads/standards/systemc>`__. Follow their
installation instructions. You will need to set the
:option:`SYSTEMC_INCLUDE` environment variable to point to the include
@ -170,6 +185,10 @@ To make use of Verilator FST tracing you will want `GTKwave
<http://gtkwave.sourceforge.net/>`__ installed, however this is not
required at Verilator build time.
.. code-block:: shell
sudo apt-get install gtkwave # Optional Waveform viewer
Install Z3
^^^^^^^^^^

View File

@ -334,7 +334,8 @@ Gate Primitives
The 2-state gate primitives (and, buf, nand, nor, not, or, xnor, xor) are
directly converted to behavioral equivalents. The 3-state and MOS gate
primitives are not supported. Tables are not supported.
primitives are not supported. User-defined primitive (UDP) tables are
supported.
Specify blocks
@ -396,8 +397,8 @@ This section describes specific limitations for each language keyword.
\`begin_keywords, \`begin_keywords, \`begin_keywords, \`begin_keywords,
\`define, \`else, \`elsif, \`end_keywords, \`endif, \`error, \`ifdef,
\`ifndef, \`include, \`line, \`systemc_ctor, \`systemc_dtor,
\`systemc_header, \`systemc_imp_header, \`systemc_implementation,
\`systemc_interface, \`undef, \`verilog
\`systemc_header, \`systemc_header_post, \`systemc_imp_header,
\`systemc_implementation, \`systemc_interface, \`undef, \`verilog
|cmdslong1|
Fully supported.
@ -451,17 +452,17 @@ disable
force, release
Verilator supports the procedural `force` (and corresponding `release`)
statement. However, the behavior of the `force` statement does not
entirely comply with IEEE 1800. According to the standard, when a
procedural statement of the form `force a = b;` is executed, the
simulation should behave as if, from that point forwards, a continuous
assignment `assign a = b;` has been added to override the drivers of `a`.
More specifically: the value of `a` should be updated whenever the value
of `b` changes, until a `release a;` statement is executed. Verilator
instead evaluates the current value of `b` when the `force` statement is
executed, and forces `a` to that value, without updating it until a new
`force` or `release` statement is encountered that applies to `a`. This
non-standard behavior is nevertheless consistent with some other
simulators.
entirely comply with IEEE 1800-2023:
#. Using forced variable as a value to another force statement is
currently not supported. The dependent force statement is forced by an
initial constant value.
#. Force/release with procedural continuous assignment is not supported.
The assignment is treated as procedural.
#. Expressions using multiple variable references or function calls on
forced right-hand side are not sensitive to dependency changes.
inside
Inside expressions may not include unpacked array traversal or $ as an
@ -488,7 +489,7 @@ $bits, $countbits, $countones, $finish, $isunknown, $onehot, $onehot0, $signed,
$dump/$dumpports and related
$dumpfile or $dumpports will create a VCD or FST file (based on
the :vlopt:`--trace` option given when the model was Verilated). This
the :vlopt:`--trace-vcd` option given when the model was Verilated). This
will take effect starting at the next eval() call. If you have multiple
Verilated designs under the same C model, this will dump signals
only from the design containing the $dumpvars.

View File

@ -83,9 +83,10 @@ option will require a longer time to run Verilator, and
may increase the risk of reset bugs in trade for performance; see the above
documentation for these options.
If using Verilated multithreaded, use ``numactl`` to ensure you use
non-conflicting hardware resources. See :ref:`Multithreading`. Also,
consider using profile-guided optimization; see :ref:`Thread PGO`.
If using Verilated multithreaded, consider overriding Verilator's default
thread-to-processor assignment by using ``numactl``; see
:ref:`Multithreading`. Also, consider using profile-guided optimization;
see :ref:`Thread PGO`.
Minor Verilog code changes can also give big wins. You should not have any
:option:`UNOPTFLAT` warnings from Verilator. Fixing these warnings can

View File

@ -221,7 +221,7 @@ model, it may be beneficial to performance to adjust the
influences the partitioning of the model by adjusting the assumed execution
time of DPI imports.
When using :vlopt:`--trace` to perform VCD tracing, the VCD trace
When using :vlopt:`--trace-vcd` to perform VCD tracing, the VCD trace
construction is parallelized using the same number of threads as specified
with :vlopt:`--threads`, and is executed on the same thread pool as the model.
@ -243,11 +243,14 @@ trace. FST tracing can utilize up to 2 offload threads, so there is no use
of setting :vlopt:`--trace-threads` higher than 2 at the moment.
When running a multithreaded model, the default Linux task scheduler often
works against the model by assuming short-lived threads and thus
it often schedules threads using multiple hyperthreads within the same
physical core. For best performance, use the :command:`numactl` program to
(when the threading count fits) select unique physical cores on the same
socket. The same applies for :vlopt:`--trace-threads` as well.
works against the model by assuming short-lived threads and thus it often
schedules threads using multiple hyperthreads within the same physical
core. If there is no affinity already set, on Linux only, Verilator
attempts to set thread-to-processor affinity in a reasonable way.
For best performance, use the :command:`numactl` program to (when the
threading count fits) select unique physical cores on the same socket. The
same applies for :vlopt:`--trace-threads` as well.
As an example, if a model was Verilated with
:vlopt:`--threads 4 <--threads>`, we consult:
@ -290,8 +293,8 @@ and must be called only by the eval thread.
If using :vlopt:`--sc`, the SystemC kernel is not thread-safe; therefore,
the eval thread and main thread must be the same.
If using :vlopt:`--trace`, the tracing classes must be constructed and
called from the main thread.
If using :vlopt:`--trace-vcd` or other trace options, the tracing classes
must be constructed and called from the main thread.
If using :vlopt:`--vpi`, since SystemVerilog VPI was not architected by
IEEE to be multithreaded, Verilator requires all VPI calls are only made
@ -367,10 +370,11 @@ Verilate in CMake
.. code-block:: CMake
verilate(target SOURCES source ... [TOP_MODULE top] [PREFIX name]
[TRACE] [TRACE_FST] [SYSTEMC] [COVERAGE]
[COVERAGE] [SYSTEMC]
[TRACE_FST] [TRACE_SAIF] [TRACE_VCD] [TRACE_THREADS num]
[INCLUDE_DIRS dir ...] [OPT_SLOW ...] [OPT_FAST ...]
[OPT_GLOBAL ..] [DIRECTORY dir] [THREADS num]
[TRACE_THREADS num] [VERILATOR_ARGS ...])
[VERILATOR_ARGS ...])
Lowercase and ... should be replaced with arguments; the uppercase parts
delimit the arguments and can be passed in any order or left out entirely
@ -443,10 +447,6 @@ SystemC include directories and link to the SystemC libraries.
Optional. Enable a multithreaded model; see :vlopt:`--threads`.
.. describe:: TRACE_THREADS
Optional. Enable multithreaded FST trace; see :vlopt:`--trace-threads`.
.. describe:: TOP_MODULE
Optional. Sets the name of the top module. Defaults to the name of the
@ -454,14 +454,27 @@ SystemC include directories and link to the SystemC libraries.
.. describe:: TRACE
Optional. Enables VCD tracing if present, equivalent to "VERILATOR_ARGS
--trace".
Deprecated. Same as TRACE_VCD, which should be used instead.
.. describe:: TRACE_FST
Optional. Enables FST tracing if present, equivalent to "VERILATOR_ARGS
--trace-fst".
.. describe:: TRACE_SAIF
Optional. Enables SAIF tracing if present, equivalent to "VERILATOR_ARGS
--trace-saif".
.. describe:: TRACE_THREADS
Optional. Enable multithreaded FST trace; see :vlopt:`--trace-threads`.
.. describe:: TRACE_VCD
Optional. Enables VCD tracing if present, equivalent to "VERILATOR_ARGS
--trace-vcd".
.. describe:: VERILATOR_ARGS
Optional. Extra arguments to Verilator. Do not specify :vlopt:`--Mdir`

View File

@ -1,9 +1,9 @@
.. Copyright 2003-2025 by Wilson Snyder.
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
*******************
Errors and Warnings
*******************
=====================
Errors and Warnings
=====================
.. _Disabling Warnings:
@ -86,6 +86,8 @@ List Of Warnings
Limitations`.
.. t_dist_docs_style restart_sort
.. option:: ALWCOMBORDER
.. TODO better example
@ -472,6 +474,31 @@ List Of Warnings
correctly.
.. option:: DEFOVERRIDE
Warns that a macro definition within the code is being overridden by a command line directive:
For example, running Verilator with :code:`<+define+\<DUP\>=\<def2\>>` and
.. code-block:: sv
:linenos:
:emphasize-lines: 1
`define DUP def2 //<--- Warning
Results in:
.. code-block::
%Warning-DEFOVERRIDE: example.v1:20: Overriding define: 'DEF' with value: 'def2' to existing command line define value: 'def1'
... Location of previous definition, with value: '50'
While not explicitly stated in the IEEE 1800-2023 standard, this warning
tracks with the other simulators' behavior of overriding macro
definitions within code files with the definition passed in through
the command line.
.. option:: DEFPARAM
Warns that the :code:`defparam` statement was deprecated in IEEE 1364-2001,
@ -1222,13 +1249,6 @@ List Of Warnings
simulate correctly.
.. option:: NOTIMING
Error when a timing-related construct that requires :vlopt:`--timing` has
been encountered. Issued only if Verilator is run with the
:vlopt:`--no-timing` option.
.. option:: NONSTD
Warns when a non-standard language feature is used that has a standard
@ -1237,6 +1257,13 @@ List Of Warnings
:code:`$sformatf`.
.. option:: NOTIMING
Error when a timing-related construct that requires :vlopt:`--timing` has
been encountered. Issued only if Verilator is run with the
:vlopt:`--no-timing` option.
.. option:: NULLPORT
Warns that a null port was detected in the module definition port
@ -1261,6 +1288,7 @@ List Of Warnings
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
.. option:: PINCONNECTEMPTY
.. TODO better example
@ -1349,6 +1377,26 @@ List Of Warnings
This error may be disabled with a lint_off PINNOTFOUND metacomment.
.. option:: PKGNODECL
An error that a package/class appears to have been referenced that has
not yet been declared. According to IEEE 1800-2023 26.3, all packages
must be declared before being used.
Faulty example:
.. include:: ../../docs/gen/ex_PKGNODECL_faulty.rst
Results in:
.. include:: ../../docs/gen/ex_PKGNODECL_msg.rst
Often the package is declared in its own header file. In this case add
an include of that package header file to the referencing file. (And
make sure you have header guards in the package's header file to prevent
multiple declarations of the package.)
.. option:: PORTSHORT
Warns that an output port is connected to a constant.
@ -1372,26 +1420,6 @@ List Of Warnings
This error may be disabled with a lint_off PORTSHORT metacomment.
.. option:: PKGNODECL
An error that a package/class appears to have been referenced that has
not yet been declared. According to IEEE 1800-2023 26.3, all packages
must be declared before being used.
Faulty example:
.. include:: ../../docs/gen/ex_PKGNODECL_faulty.rst
Results in:
.. include:: ../../docs/gen/ex_PKGNODECL_msg.rst
Often the package is declared in its own header file. In this case add
an include of that package header file to the referencing file. (And
make sure you have header guards in the package's header file to prevent
multiple declarations of the package.)
.. option:: PREPROCZERO
Warns that a preprocessor \`ifdef/\`ifndef expression (added in IEEE
@ -2181,21 +2209,6 @@ List Of Warnings
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_fixed.rst
.. option:: WIDTHTRUNC
A more granular :option:`WIDTH` warning, for when a value is
truncated. See :option:`WIDTH`.
.. option:: WIDTHEXPAND
A more granular :option:`WIDTH` warning, for when a value is zero
expanded. See :option:`WIDTH`.
.. option:: WIDTHXZEXPAND
A more granular :option:`WIDTH` warning, for when a value is X/Z
expanded. See :option:`WIDTH`.
.. option:: WIDTHCONCAT
Warns that based on the width rules of Verilog, a concatenate, or
@ -2221,6 +2234,21 @@ List Of Warnings
width to the parameter usage (:code:`{PAR[31:0], PAR[31:0]}`).
.. option:: WIDTHEXPAND
A more granular :option:`WIDTH` warning, for when a value is zero
expanded. See :option:`WIDTH`.
.. option:: WIDTHTRUNC
A more granular :option:`WIDTH` warning, for when a value is
truncated. See :option:`WIDTH`.
.. option:: WIDTHXZEXPAND
A more granular :option:`WIDTH` warning, for when a value is X/Z
expanded. See :option:`WIDTH`.
.. option:: ZERODLY
Warns that `#0` delays do not schedule the process to be resumed in the

View File

@ -2046,6 +2046,11 @@ driver.py Non-Scenario Arguments
Same as ``verilator --debugi level``: Set Verilator internal debugging
level globally to the specified debug level (1-10).
--driver-clean
After a test passes, remove the generated objects. Reduces storage
requirements, but may result in longer runtime if the tests are run
again.
--dump-tree
Same as ``verilator --dump-tree``: Enable Verilator writing .tree debug
files with dumping level 3, which dumps the standard critical stages.
@ -2077,7 +2082,10 @@ driver.py Non-Scenario Arguments
--j #
Run number of parallel tests, or 0 to determine the count based on the
number of cores installed. Requires Perl's Parallel::Forker package.
number of cores installed.
--obj-suffix <name>
Append the argument to the name of the ``test_regress/obj_`` directories.
--quiet
Suppress all output except for failures and progress messages every 15

View File

@ -19,6 +19,7 @@ Asciidoc
Ashutosh
Ast
Atmel
Augustin
Aurelien
Badáň
Bagri
@ -109,6 +110,7 @@ Embecosm
Engstrom
Enzo
Eugen
Fabre
Fabrizio
Faucher
Faure
@ -650,6 +652,7 @@ elike
elsif
endcase
endcelldefine
endclass
endfunction
endgenerate
endian
@ -860,6 +863,7 @@ noprivate
noreturn
notif
nullptr
numactl
onehot
ooo
oprofile
@ -960,6 +964,7 @@ runtime
runtimes
rw
sVerilator
saif
sawatzke
sc
scalared
@ -1018,6 +1023,7 @@ swrite
synthesizeable
sys
systemc
tcmalloc
tenghtt
testbench
threadsafe
@ -1093,7 +1099,9 @@ verilator
verilog
verilogmod
verimake
veriuser
vl
vlSelf
vlopt
vlt
vltstd
@ -1113,6 +1121,7 @@ vpiUndefined
vpm
vpp
warmup
wavealloca
waveforms
whitespace
widthed

View File

@ -20,9 +20,11 @@
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
VERILATOR_COVERAGE = verilator_coverage
else
export VERILATOR_ROOT
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage
endif
######################################################################

View File

@ -20,9 +20,11 @@
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
VERILATOR_COVERAGE = verilator_coverage
else
export VERILATOR_ROOT
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage
endif
######################################################################

View File

@ -20,9 +20,11 @@
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
VERILATOR_COVERAGE = verilator_coverage
else
export VERILATOR_ROOT
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage
endif
######################################################################

View File

@ -36,7 +36,7 @@ add_executable(example ../make_tracing_c/sim_main.cpp)
target_compile_features(example PUBLIC cxx_std_14)
# Add the Verilated circuit to the target
verilate(example COVERAGE TRACE
verilate(example COVERAGE TRACE_VCD
INCLUDE_DIRS "../make_tracing_c"
VERILATOR_ARGS -f ../make_tracing_c/input.vc -x-assign fast
SOURCES ../make_tracing_c/top.v

View File

@ -20,9 +20,11 @@
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
VERILATOR_COVERAGE = verilator_coverage
else
export VERILATOR_ROOT
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage
endif
######################################################################
@ -59,7 +61,7 @@ run:
@echo
@echo "-- RUN ---------------------"
@mkdir -p logs
build/example +trace
build/example +trace_vcd
@echo
@echo "-- COVERAGE ----------------"

View File

@ -46,7 +46,7 @@ target_compile_features(example PUBLIC cxx_std_14)
set_property(TARGET example PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD})
# Add the Verilated circuit to the target
verilate(example SYSTEMC COVERAGE TRACE
verilate(example COVERAGE SYSTEMC TRACE_VCD
INCLUDE_DIRS "../make_tracing_sc"
VERILATOR_ARGS -f ../make_tracing_sc/input.vc -x-assign fast
SOURCES ../make_tracing_sc/top.v

View File

@ -20,9 +20,11 @@
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
VERILATOR_COVERAGE = verilator_coverage
else
export VERILATOR_ROOT
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage
endif
######################################################################
@ -77,7 +79,7 @@ run:
@echo
@echo "-- RUN ---------------------"
@mkdir -p logs
build/example +trace
build/example +trace_vcd
@echo
@echo "-- COVERAGE ----------------"

View File

@ -43,7 +43,7 @@ VERILATOR_FLAGS += -Wall
VERILATOR_FLAGS += -CFLAGS -DVL_TIME_CONTEXT
# Make waveforms
TOP_VERILATOR_FLAGS = $(VERILATOR_FLAGS) --trace
TOP_VERILATOR_FLAGS = $(VERILATOR_FLAGS) --trace-vcd
######################################################################
default: run

View File

@ -40,7 +40,7 @@ VERILATOR_FLAGS += -x-assign fast
# Warn abount lint issues; may not want this on less solid designs
VERILATOR_FLAGS += -Wall
# Make waveforms
VERILATOR_FLAGS += --trace
VERILATOR_FLAGS += --trace-vcd
# Check SystemVerilog assertions
VERILATOR_FLAGS += --assert
# Generate coverage analysis

View File

@ -41,7 +41,7 @@ VERILATOR_FLAGS += -x-assign fast
# Warn abount lint issues; may not want this on less solid designs
VERILATOR_FLAGS += -Wall
# Make waveforms
VERILATOR_FLAGS += --trace
VERILATOR_FLAGS += --trace-vcd
# Check SystemVerilog assertions
VERILATOR_FLAGS += --assert
# Generate coverage analysis

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,8 @@
#define FST_API_H
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif
#include <stdio.h>
@ -36,428 +37,508 @@ extern "C" {
#include <zlib.h>
#include <inttypes.h>
#if defined(_MSC_VER)
#include "fst_win_unistd.h"
#include "fst_win_unistd.h"
#else
#include <unistd.h>
#include <unistd.h>
#endif
#include <time.h>
#define FST_RDLOAD "FSTLOAD | "
typedef uint32_t fstHandle;
typedef uint32_t fstEnumHandle;
enum fstWriterPackType {
FST_WR_PT_ZLIB = 0,
FST_WR_PT_FASTLZ = 1,
FST_WR_PT_LZ4 = 2
enum fstWriterPackType
{
FST_WR_PT_ZLIB = 0,
FST_WR_PT_FASTLZ = 1,
FST_WR_PT_LZ4 = 2
};
enum fstFileType {
FST_FT_MIN = 0,
enum fstFileType
{
FST_FT_MIN = 0,
FST_FT_VERILOG = 0,
FST_FT_VHDL = 1,
FST_FT_VERILOG_VHDL = 2,
FST_FT_VERILOG = 0,
FST_FT_VHDL = 1,
FST_FT_VERILOG_VHDL = 2,
FST_FT_MAX = 2
FST_FT_MAX = 2
};
enum fstBlockType {
FST_BL_HDR = 0,
FST_BL_VCDATA = 1,
FST_BL_BLACKOUT = 2,
FST_BL_GEOM = 3,
FST_BL_HIER = 4,
FST_BL_VCDATA_DYN_ALIAS = 5,
FST_BL_HIER_LZ4 = 6,
FST_BL_HIER_LZ4DUO = 7,
FST_BL_VCDATA_DYN_ALIAS2 = 8,
enum fstBlockType
{
FST_BL_HDR = 0,
FST_BL_VCDATA = 1,
FST_BL_BLACKOUT = 2,
FST_BL_GEOM = 3,
FST_BL_HIER = 4,
FST_BL_VCDATA_DYN_ALIAS = 5,
FST_BL_HIER_LZ4 = 6,
FST_BL_HIER_LZ4DUO = 7,
FST_BL_VCDATA_DYN_ALIAS2 = 8,
FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
FST_BL_SKIP = 255 /* used while block is being written */
FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
FST_BL_SKIP = 255 /* used while block is being written */
};
enum fstScopeType {
FST_ST_MIN = 0,
enum fstScopeType
{
FST_ST_MIN = 0,
FST_ST_VCD_MODULE = 0,
FST_ST_VCD_TASK = 1,
FST_ST_VCD_FUNCTION = 2,
FST_ST_VCD_BEGIN = 3,
FST_ST_VCD_FORK = 4,
FST_ST_VCD_GENERATE = 5,
FST_ST_VCD_STRUCT = 6,
FST_ST_VCD_UNION = 7,
FST_ST_VCD_CLASS = 8,
FST_ST_VCD_INTERFACE = 9,
FST_ST_VCD_PACKAGE = 10,
FST_ST_VCD_PROGRAM = 11,
FST_ST_VCD_MODULE = 0,
FST_ST_VCD_TASK = 1,
FST_ST_VCD_FUNCTION = 2,
FST_ST_VCD_BEGIN = 3,
FST_ST_VCD_FORK = 4,
FST_ST_VCD_GENERATE = 5,
FST_ST_VCD_STRUCT = 6,
FST_ST_VCD_UNION = 7,
FST_ST_VCD_CLASS = 8,
FST_ST_VCD_INTERFACE = 9,
FST_ST_VCD_PACKAGE = 10,
FST_ST_VCD_PROGRAM = 11,
FST_ST_VHDL_ARCHITECTURE = 12,
FST_ST_VHDL_PROCEDURE = 13,
FST_ST_VHDL_FUNCTION = 14,
FST_ST_VHDL_RECORD = 15,
FST_ST_VHDL_PROCESS = 16,
FST_ST_VHDL_BLOCK = 17,
FST_ST_VHDL_FOR_GENERATE = 18,
FST_ST_VHDL_IF_GENERATE = 19,
FST_ST_VHDL_GENERATE = 20,
FST_ST_VHDL_PACKAGE = 21,
FST_ST_VHDL_ARCHITECTURE = 12,
FST_ST_VHDL_PROCEDURE = 13,
FST_ST_VHDL_FUNCTION = 14,
FST_ST_VHDL_RECORD = 15,
FST_ST_VHDL_PROCESS = 16,
FST_ST_VHDL_BLOCK = 17,
FST_ST_VHDL_FOR_GENERATE = 18,
FST_ST_VHDL_IF_GENERATE = 19,
FST_ST_VHDL_GENERATE = 20,
FST_ST_VHDL_PACKAGE = 21,
FST_ST_MAX = 21,
FST_ST_MAX = 21,
FST_ST_GEN_ATTRBEGIN = 252,
FST_ST_GEN_ATTREND = 253,
FST_ST_GEN_ATTRBEGIN = 252,
FST_ST_GEN_ATTREND = 253,
FST_ST_VCD_SCOPE = 254,
FST_ST_VCD_UPSCOPE = 255
FST_ST_VCD_SCOPE = 254,
FST_ST_VCD_UPSCOPE = 255
};
enum fstVarType {
FST_VT_MIN = 0, /* start of vartypes */
enum fstVarType
{
FST_VT_MIN = 0, /* start of vartypes */
FST_VT_VCD_EVENT = 0,
FST_VT_VCD_INTEGER = 1,
FST_VT_VCD_PARAMETER = 2,
FST_VT_VCD_REAL = 3,
FST_VT_VCD_REAL_PARAMETER = 4,
FST_VT_VCD_REG = 5,
FST_VT_VCD_SUPPLY0 = 6,
FST_VT_VCD_SUPPLY1 = 7,
FST_VT_VCD_TIME = 8,
FST_VT_VCD_TRI = 9,
FST_VT_VCD_TRIAND = 10,
FST_VT_VCD_TRIOR = 11,
FST_VT_VCD_TRIREG = 12,
FST_VT_VCD_TRI0 = 13,
FST_VT_VCD_TRI1 = 14,
FST_VT_VCD_WAND = 15,
FST_VT_VCD_WIRE = 16,
FST_VT_VCD_WOR = 17,
FST_VT_VCD_PORT = 18,
FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */
FST_VT_VCD_REALTIME = 20,
FST_VT_VCD_EVENT = 0,
FST_VT_VCD_INTEGER = 1,
FST_VT_VCD_PARAMETER = 2,
FST_VT_VCD_REAL = 3,
FST_VT_VCD_REAL_PARAMETER = 4,
FST_VT_VCD_REG = 5,
FST_VT_VCD_SUPPLY0 = 6,
FST_VT_VCD_SUPPLY1 = 7,
FST_VT_VCD_TIME = 8,
FST_VT_VCD_TRI = 9,
FST_VT_VCD_TRIAND = 10,
FST_VT_VCD_TRIOR = 11,
FST_VT_VCD_TRIREG = 12,
FST_VT_VCD_TRI0 = 13,
FST_VT_VCD_TRI1 = 14,
FST_VT_VCD_WAND = 15,
FST_VT_VCD_WIRE = 16,
FST_VT_VCD_WOR = 17,
FST_VT_VCD_PORT = 18,
FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */
FST_VT_VCD_REALTIME = 20,
FST_VT_GEN_STRING = 21, /* generic string type (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */
FST_VT_GEN_STRING = 21, /* generic string type (max len is defined dynamically via
fstWriterEmitVariableLengthValueChange) */
FST_VT_SV_BIT = 22,
FST_VT_SV_LOGIC = 23,
FST_VT_SV_INT = 24, /* declare as size = 32 */
FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */
FST_VT_SV_LONGINT = 26, /* declare as size = 64 */
FST_VT_SV_BYTE = 27, /* declare as size = 8 */
FST_VT_SV_ENUM = 28, /* declare as appropriate type range */
FST_VT_SV_SHORTREAL = 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */
FST_VT_SV_BIT = 22,
FST_VT_SV_LOGIC = 23,
FST_VT_SV_INT = 24, /* declare as size = 32 */
FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */
FST_VT_SV_LONGINT = 26, /* declare as size = 64 */
FST_VT_SV_BYTE = 27, /* declare as size = 8 */
FST_VT_SV_ENUM = 28, /* declare as appropriate type range */
FST_VT_SV_SHORTREAL = 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted
as double, not a float) */
FST_VT_MAX = 29 /* end of vartypes */
FST_VT_MAX = 29 /* end of vartypes */
};
enum fstVarDir {
FST_VD_MIN = 0,
enum fstVarDir
{
FST_VD_MIN = 0,
FST_VD_IMPLICIT = 0,
FST_VD_INPUT = 1,
FST_VD_OUTPUT = 2,
FST_VD_INOUT = 3,
FST_VD_BUFFER = 4,
FST_VD_LINKAGE = 5,
FST_VD_IMPLICIT = 0,
FST_VD_INPUT = 1,
FST_VD_OUTPUT = 2,
FST_VD_INOUT = 3,
FST_VD_BUFFER = 4,
FST_VD_LINKAGE = 5,
FST_VD_MAX = 5
FST_VD_MAX = 5
};
enum fstHierType {
FST_HT_MIN = 0,
enum fstHierType
{
FST_HT_MIN = 0,
FST_HT_SCOPE = 0,
FST_HT_UPSCOPE = 1,
FST_HT_VAR = 2,
FST_HT_ATTRBEGIN = 3,
FST_HT_ATTREND = 4,
FST_HT_SCOPE = 0,
FST_HT_UPSCOPE = 1,
FST_HT_VAR = 2,
FST_HT_ATTRBEGIN = 3,
FST_HT_ATTREND = 4,
/* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when fstHier bridges other formats */
FST_HT_TREEBEGIN = 5,
FST_HT_TREEEND = 6,
/* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when
fstHier bridges other formats */
FST_HT_TREEBEGIN = 5,
FST_HT_TREEEND = 6,
FST_HT_MAX = 6
FST_HT_MAX = 6
};
enum fstAttrType {
FST_AT_MIN = 0,
enum fstAttrType
{
FST_AT_MIN = 0,
FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */
FST_AT_ARRAY = 1,
FST_AT_ENUM = 2,
FST_AT_PACK = 3,
FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */
FST_AT_ARRAY = 1,
FST_AT_ENUM = 2,
FST_AT_PACK = 3,
FST_AT_MAX = 3
FST_AT_MAX = 3
};
enum fstMiscType {
FST_MT_MIN = 0,
enum fstMiscType
{
FST_MT_MIN = 0,
FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */
FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */
FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */
FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */
FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
FST_MT_UNKNOWN = 8,
FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */
FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */
FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */
FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */
FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
FST_MT_VALUELIST =
6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
FST_MT_ENUMTABLE =
7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
FST_MT_UNKNOWN = 8,
FST_MT_MAX = 8
FST_MT_MAX = 8
};
enum fstArrayType {
FST_AR_MIN = 0,
enum fstArrayType
{
FST_AR_MIN = 0,
FST_AR_NONE = 0,
FST_AR_UNPACKED = 1,
FST_AR_PACKED = 2,
FST_AR_SPARSE = 3,
FST_AR_NONE = 0,
FST_AR_UNPACKED = 1,
FST_AR_PACKED = 2,
FST_AR_SPARSE = 3,
FST_AR_MAX = 3
FST_AR_MAX = 3
};
enum fstEnumValueType {
FST_EV_SV_INTEGER = 0,
FST_EV_SV_BIT = 1,
FST_EV_SV_LOGIC = 2,
FST_EV_SV_INT = 3,
FST_EV_SV_SHORTINT = 4,
FST_EV_SV_LONGINT = 5,
FST_EV_SV_BYTE = 6,
FST_EV_SV_UNSIGNED_INTEGER = 7,
FST_EV_SV_UNSIGNED_BIT = 8,
FST_EV_SV_UNSIGNED_LOGIC = 9,
FST_EV_SV_UNSIGNED_INT = 10,
enum fstEnumValueType
{
FST_EV_SV_INTEGER = 0,
FST_EV_SV_BIT = 1,
FST_EV_SV_LOGIC = 2,
FST_EV_SV_INT = 3,
FST_EV_SV_SHORTINT = 4,
FST_EV_SV_LONGINT = 5,
FST_EV_SV_BYTE = 6,
FST_EV_SV_UNSIGNED_INTEGER = 7,
FST_EV_SV_UNSIGNED_BIT = 8,
FST_EV_SV_UNSIGNED_LOGIC = 9,
FST_EV_SV_UNSIGNED_INT = 10,
FST_EV_SV_UNSIGNED_SHORTINT = 11,
FST_EV_SV_UNSIGNED_LONGINT = 12,
FST_EV_SV_UNSIGNED_BYTE = 13,
FST_EV_SV_UNSIGNED_LONGINT = 12,
FST_EV_SV_UNSIGNED_BYTE = 13,
FST_EV_REG = 14,
FST_EV_TIME = 15,
FST_EV_REG = 14,
FST_EV_TIME = 15,
FST_EV_MAX = 15
FST_EV_MAX = 15
};
enum fstPackType {
FST_PT_NONE = 0,
FST_PT_UNPACKED = 1,
FST_PT_PACKED = 2,
enum fstPackType
{
FST_PT_NONE = 0,
FST_PT_UNPACKED = 1,
FST_PT_PACKED = 2,
FST_PT_TAGGED_PACKED = 3,
FST_PT_MAX = 3
FST_PT_MAX = 3
};
enum fstSupplementalVarType {
FST_SVT_MIN = 0,
enum fstSupplementalVarType
{
FST_SVT_MIN = 0,
FST_SVT_NONE = 0,
FST_SVT_NONE = 0,
FST_SVT_VHDL_SIGNAL = 1,
FST_SVT_VHDL_VARIABLE = 2,
FST_SVT_VHDL_CONSTANT = 3,
FST_SVT_VHDL_FILE = 4,
FST_SVT_VHDL_MEMORY = 5,
FST_SVT_VHDL_SIGNAL = 1,
FST_SVT_VHDL_VARIABLE = 2,
FST_SVT_VHDL_CONSTANT = 3,
FST_SVT_VHDL_FILE = 4,
FST_SVT_VHDL_MEMORY = 5,
FST_SVT_MAX = 5
FST_SVT_MAX = 5
};
enum fstSupplementalDataType {
FST_SDT_MIN = 0,
enum fstSupplementalDataType
{
FST_SDT_MIN = 0,
FST_SDT_NONE = 0,
FST_SDT_NONE = 0,
FST_SDT_VHDL_BOOLEAN = 1,
FST_SDT_VHDL_BIT = 2,
FST_SDT_VHDL_BIT_VECTOR = 3,
FST_SDT_VHDL_STD_ULOGIC = 4,
FST_SDT_VHDL_BOOLEAN = 1,
FST_SDT_VHDL_BIT = 2,
FST_SDT_VHDL_BIT_VECTOR = 3,
FST_SDT_VHDL_STD_ULOGIC = 4,
FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5,
FST_SDT_VHDL_STD_LOGIC = 6,
FST_SDT_VHDL_STD_LOGIC_VECTOR = 7,
FST_SDT_VHDL_UNSIGNED = 8,
FST_SDT_VHDL_SIGNED = 9,
FST_SDT_VHDL_INTEGER = 10,
FST_SDT_VHDL_REAL = 11,
FST_SDT_VHDL_NATURAL = 12,
FST_SDT_VHDL_POSITIVE = 13,
FST_SDT_VHDL_TIME = 14,
FST_SDT_VHDL_CHARACTER = 15,
FST_SDT_VHDL_STRING = 16,
FST_SDT_VHDL_STD_LOGIC = 6,
FST_SDT_VHDL_STD_LOGIC_VECTOR = 7,
FST_SDT_VHDL_UNSIGNED = 8,
FST_SDT_VHDL_SIGNED = 9,
FST_SDT_VHDL_INTEGER = 10,
FST_SDT_VHDL_REAL = 11,
FST_SDT_VHDL_NATURAL = 12,
FST_SDT_VHDL_POSITIVE = 13,
FST_SDT_VHDL_TIME = 14,
FST_SDT_VHDL_CHARACTER = 15,
FST_SDT_VHDL_STRING = 16,
FST_SDT_MAX = 16,
FST_SDT_MAX = 16,
FST_SDT_SVT_SHIFT_COUNT = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left after shifting FST_SDT_SVT_SHIFT_COUNT */
FST_SDT_ABS_MAX = ((1<<(FST_SDT_SVT_SHIFT_COUNT))-1)
FST_SDT_SVT_SHIFT_COUNT = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left
after shifting FST_SDT_SVT_SHIFT_COUNT */
FST_SDT_ABS_MAX = ((1 << (FST_SDT_SVT_SHIFT_COUNT)) - 1)
};
struct fstHier
{
unsigned char htyp;
unsigned char htyp;
union {
union
{
/* if htyp == FST_HT_SCOPE */
struct fstHierScope {
unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */
const char *name;
const char *component;
uint32_t name_length; /* strlen(u.scope.name) */
uint32_t component_length; /* strlen(u.scope.component) */
} scope;
struct fstHierScope
{
unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */
const char *name;
const char *component;
uint32_t name_length; /* strlen(u.scope.name) */
uint32_t component_length; /* strlen(u.scope.component) */
} scope;
/* if htyp == FST_HT_VAR */
struct fstHierVar {
unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */
unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */
unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */
unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */
unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */
const char *name;
uint32_t length;
fstHandle handle;
uint32_t name_length; /* strlen(u.var.name) */
unsigned is_alias : 1;
} var;
struct fstHierVar
{
unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */
unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */
unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */
unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */
unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */
const char *name;
uint32_t length;
fstHandle handle;
uint32_t name_length; /* strlen(u.var.name) */
unsigned is_alias : 1;
} var;
/* if htyp == FST_HT_ATTRBEGIN */
struct fstHierAttr {
unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */
unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
const char *name;
uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */
uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + FST_MT_SOURCESTEM) */
uint32_t name_length; /* strlen(u.attr.name) */
} attr;
} u;
struct fstHierAttr
{
unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */
unsigned char
subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
const char *name;
uint64_t arg; /* number of array elements, struct members, or some other payload
(possibly ignored) */
uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer
(FST_AT_MISC + FST_MT_SOURCESTEM) */
uint32_t name_length; /* strlen(u.attr.name) */
} attr;
} u;
};
struct fstETab
{
char *name;
uint32_t elem_count;
char **literal_arr;
char **val_arr;
char *name;
uint32_t elem_count;
char **literal_arr;
char **val_arr;
};
/*
* writer functions
*/
void fstWriterClose(void *ctx);
void * fstWriterCreate(const char *nam, int use_compressed_hier);
fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr);
/* used for Verilog/SV */
fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd,
uint32_t len, const char *nam, fstHandle aliasHandle);
/* future expansion for VHDL and other languages. The variable type, data type, etc map onto
the current Verilog/SV one. The "type" string is optional for a more verbose or custom description */
fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd,
uint32_t len, const char *nam, fstHandle aliasHandle,
const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt);
void fstWriterEmitDumpActive(void *ctx, int enable);
void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle);
void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val);
void fstWriterEmitValueChange32(void *ctx, fstHandle handle,
uint32_t bits, uint32_t val);
void fstWriterEmitValueChange64(void *ctx, fstHandle handle,
uint32_t bits, uint64_t val);
void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle,
uint32_t bits, const uint32_t *val);
void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle,
uint32_t bits, const uint64_t *val);
void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len);
void fstWriterEmitTimeChange(void *ctx, uint64_t tim);
void fstWriterFlushContext(void *ctx);
int fstWriterGetDumpSizeLimitReached(void *ctx);
int fstWriterGetFseekFailed(void *ctx);
void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype,
const char *attrname, uint64_t arg);
void fstWriterSetAttrEnd(void *ctx);
void fstWriterSetComment(void *ctx, const char *comm);
void fstWriterSetDate(void *ctx, const char *dat);
void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes);
void fstWriterSetEnvVar(void *ctx, const char *envvar);
void fstWriterSetFileType(void *ctx, enum fstFileType filetype);
void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ);
void fstWriterSetParallelMode(void *ctx, int enable);
void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */
void fstWriterSetScope(void *ctx, enum fstScopeType scopetype,
const char *scopename, const char *scopecomp);
void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath);
void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath);
void fstWriterSetTimescale(void *ctx, int ts);
void fstWriterSetTimescaleFromString(void *ctx, const char *s);
void fstWriterSetTimezero(void *ctx, int64_t tim);
void fstWriterSetUpscope(void *ctx);
void fstWriterSetValueList(void *ctx, const char *vl);
void fstWriterSetVersion(void *ctx, const char *vers);
typedef struct fstWriterContext fstWriterContext;
void fstWriterClose(fstWriterContext *ctx);
fstWriterContext *fstWriterCreate(const char *nam, int use_compressed_hier);
fstEnumHandle fstWriterCreateEnumTable(fstWriterContext *ctx,
const char *name,
uint32_t elem_count,
unsigned int min_valbits,
const char **literal_arr,
const char **val_arr);
/* used for Verilog/SV */
fstHandle fstWriterCreateVar(fstWriterContext *ctx,
enum fstVarType vt,
enum fstVarDir vd,
uint32_t len,
const char *nam,
fstHandle aliasHandle);
/* future expansion for VHDL and other languages. The variable type, data type, etc map onto
the current Verilog/SV one. The "type" string is optional for a more verbose or custom
description */
fstHandle fstWriterCreateVar2(fstWriterContext *ctx,
enum fstVarType vt,
enum fstVarDir vd,
uint32_t len,
const char *nam,
fstHandle aliasHandle,
const char *type,
enum fstSupplementalVarType svt,
enum fstSupplementalDataType sdt);
void fstWriterEmitDumpActive(fstWriterContext *ctx, int enable);
void fstWriterEmitEnumTableRef(fstWriterContext *ctx, fstEnumHandle handle);
void fstWriterEmitValueChange(fstWriterContext *ctx, fstHandle handle, const void *val);
void fstWriterEmitValueChange32(fstWriterContext *ctx,
fstHandle handle,
uint32_t bits,
uint32_t val);
void fstWriterEmitValueChange64(fstWriterContext *ctx,
fstHandle handle,
uint32_t bits,
uint64_t val);
void fstWriterEmitValueChangeVec32(fstWriterContext *ctx,
fstHandle handle,
uint32_t bits,
const uint32_t *val);
void fstWriterEmitValueChangeVec64(fstWriterContext *ctx,
fstHandle handle,
uint32_t bits,
const uint64_t *val);
void fstWriterEmitVariableLengthValueChange(fstWriterContext *ctx,
fstHandle handle,
const void *val,
uint32_t len);
void fstWriterEmitTimeChange(fstWriterContext *ctx, uint64_t tim);
void fstWriterFlushContext(fstWriterContext *ctx);
int fstWriterGetDumpSizeLimitReached(fstWriterContext *ctx);
int fstWriterGetFseekFailed(fstWriterContext *ctx);
int fstWriterGetFlushContextPending(fstWriterContext *ctx);
void fstWriterSetAttrBegin(fstWriterContext *ctx,
enum fstAttrType attrtype,
int subtype,
const char *attrname,
uint64_t arg);
void fstWriterSetAttrEnd(fstWriterContext *ctx);
void fstWriterSetComment(fstWriterContext *ctx, const char *comm);
void fstWriterSetDate(fstWriterContext *ctx, const char *dat);
void fstWriterSetDumpSizeLimit(fstWriterContext *ctx, uint64_t numbytes);
void fstWriterSetEnvVar(fstWriterContext *ctx, const char *envvar);
void fstWriterSetFileType(fstWriterContext *ctx, enum fstFileType filetype);
void fstWriterSetPackType(fstWriterContext *ctx, enum fstWriterPackType typ);
void fstWriterSetParallelMode(fstWriterContext *ctx, int enable);
void fstWriterSetRepackOnClose(fstWriterContext *ctx,
int enable); /* type = 0 (none), 1 (libz) */
void fstWriterSetScope(fstWriterContext *ctx,
enum fstScopeType scopetype,
const char *scopename,
const char *scopecomp);
void fstWriterSetSourceInstantiationStem(fstWriterContext *ctx,
const char *path,
unsigned int line,
unsigned int use_realpath);
void fstWriterSetSourceStem(fstWriterContext *ctx,
const char *path,
unsigned int line,
unsigned int use_realpath);
void fstWriterSetTimescale(fstWriterContext *ctx, int ts);
void fstWriterSetTimescaleFromString(fstWriterContext *ctx, const char *s);
void fstWriterSetTimezero(fstWriterContext *ctx, int64_t tim);
void fstWriterSetUpscope(fstWriterContext *ctx);
void fstWriterSetValueList(fstWriterContext *ctx, const char *vl);
void fstWriterSetVersion(fstWriterContext *ctx, const char *vers);
/*
* reader functions
*/
void fstReaderClose(void *ctx);
void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx);
void fstReaderClrFacProcessMaskAll(void *ctx);
uint64_t fstReaderGetAliasCount(void *ctx);
const char * fstReaderGetCurrentFlatScope(void *ctx);
void * fstReaderGetCurrentScopeUserInfo(void *ctx);
int fstReaderGetCurrentScopeLen(void *ctx);
const char * fstReaderGetDateString(void *ctx);
int fstReaderGetDoubleEndianMatchState(void *ctx);
uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx);
unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx);
uint64_t fstReaderGetEndTime(void *ctx);
int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx);
int fstReaderGetFileType(void *ctx);
int fstReaderGetFseekFailed(void *ctx);
fstHandle fstReaderGetMaxHandle(void *ctx);
uint64_t fstReaderGetMemoryUsedByWriter(void *ctx);
uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx);
uint64_t fstReaderGetScopeCount(void *ctx);
uint64_t fstReaderGetStartTime(void *ctx);
signed char fstReaderGetTimescale(void *ctx);
int64_t fstReaderGetTimezero(void *ctx);
uint64_t fstReaderGetValueChangeSectionCount(void *ctx);
char * fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf);
uint64_t fstReaderGetVarCount(void *ctx);
const char * fstReaderGetVersionString(void *ctx);
struct fstHier *fstReaderIterateHier(void *ctx);
int fstReaderIterateHierRewind(void *ctx);
int fstReaderIterBlocks(void *ctx,
void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
void *user_callback_data_pointer, FILE *vcdhandle);
int fstReaderIterBlocks2(void *ctx,
void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len),
void *user_callback_data_pointer, FILE *vcdhandle);
void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable);
void * fstReaderOpen(const char *nam);
void * fstReaderOpenForUtilitiesOnly(void);
const char * fstReaderPopScope(void *ctx);
int fstReaderProcessHier(void *ctx, FILE *vcdhandle);
const char * fstReaderPushScope(void *ctx, const char *nam, void *user_info);
void fstReaderResetScope(void *ctx);
void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx);
void fstReaderSetFacProcessMaskAll(void *ctx);
void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time);
void fstReaderSetUnlimitedTimeRange(void *ctx);
void fstReaderSetVcdExtensions(void *ctx, int enable);
typedef struct fstReaderContext fstReaderContext;
void fstReaderClose(fstReaderContext *ctx);
void fstReaderClrFacProcessMask(fstReaderContext *ctx, fstHandle facidx);
void fstReaderClrFacProcessMaskAll(fstReaderContext *ctx);
uint64_t fstReaderGetAliasCount(fstReaderContext *ctx);
const char *fstReaderGetCurrentFlatScope(fstReaderContext *ctx);
void *fstReaderGetCurrentScopeUserInfo(fstReaderContext *ctx);
int fstReaderGetCurrentScopeLen(fstReaderContext *ctx);
const char *fstReaderGetDateString(fstReaderContext *ctx);
int fstReaderGetDoubleEndianMatchState(fstReaderContext *ctx);
uint64_t fstReaderGetDumpActivityChangeTime(fstReaderContext *ctx, uint32_t idx);
unsigned char fstReaderGetDumpActivityChangeValue(fstReaderContext *ctx, uint32_t idx);
uint64_t fstReaderGetEndTime(fstReaderContext *ctx);
int fstReaderGetFacProcessMask(fstReaderContext *ctx, fstHandle facidx);
int fstReaderGetFileType(fstReaderContext *ctx);
int fstReaderGetFseekFailed(fstReaderContext *ctx);
fstHandle fstReaderGetMaxHandle(fstReaderContext *ctx);
uint64_t fstReaderGetMemoryUsedByWriter(fstReaderContext *ctx);
uint32_t fstReaderGetNumberDumpActivityChanges(fstReaderContext *ctx);
uint64_t fstReaderGetScopeCount(fstReaderContext *ctx);
uint64_t fstReaderGetStartTime(fstReaderContext *ctx);
signed char fstReaderGetTimescale(fstReaderContext *ctx);
int64_t fstReaderGetTimezero(fstReaderContext *ctx);
uint64_t fstReaderGetValueChangeSectionCount(fstReaderContext *ctx);
char *fstReaderGetValueFromHandleAtTime(fstReaderContext *ctx,
uint64_t tim,
fstHandle facidx,
char *buf);
uint64_t fstReaderGetVarCount(fstReaderContext *ctx);
const char *fstReaderGetVersionString(fstReaderContext *ctx);
struct fstHier *fstReaderIterateHier(fstReaderContext *ctx);
int fstReaderIterateHierRewind(fstReaderContext *ctx);
int fstReaderIterBlocks(fstReaderContext *ctx,
void (*value_change_callback)(void *user_callback_data_pointer,
uint64_t time,
fstHandle facidx,
const unsigned char *value),
void *user_callback_data_pointer,
FILE *vcdhandle);
int fstReaderIterBlocks2(fstReaderContext *ctx,
void (*value_change_callback)(void *user_callback_data_pointer,
uint64_t time,
fstHandle facidx,
const unsigned char *value),
void (*value_change_callback_varlen)(void *user_callback_data_pointer,
uint64_t time,
fstHandle facidx,
const unsigned char *value,
uint32_t len),
void *user_callback_data_pointer,
FILE *vcdhandle);
void fstReaderIterBlocksSetNativeDoublesOnCallback(fstReaderContext *ctx, int enable);
fstReaderContext *fstReaderOpen(const char *nam);
fstReaderContext *fstReaderOpenForUtilitiesOnly(void);
const char *fstReaderPopScope(fstReaderContext *ctx);
int fstReaderProcessHier(fstReaderContext *ctx, FILE *vcdhandle);
const char *fstReaderPushScope(fstReaderContext *ctx, const char *nam, void *user_info);
void fstReaderResetScope(fstReaderContext *ctx);
void fstReaderSetFacProcessMask(fstReaderContext *ctx, fstHandle facidx);
void fstReaderSetFacProcessMaskAll(fstReaderContext *ctx);
void fstReaderSetLimitTimeRange(fstReaderContext *ctx, uint64_t start_time, uint64_t end_time);
void fstReaderSetUnlimitedTimeRange(fstReaderContext *ctx);
void fstReaderSetVcdExtensions(fstReaderContext *ctx, int enable);
/*
* utility functions
*/
int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */
int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len);
int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */
int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len);
int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
struct fstETab *fstUtilityExtractEnumTableFromString(const char *s);
void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */
void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */
#ifdef __cplusplus
}

View File

@ -1,41 +0,0 @@
/*
* Copyright (c) 1999 Tony Bybell.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
*/
#ifndef WAVE_ALLOCA_H
#define WAVE_ALLOCA_H
#include <stdlib.h>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#elif defined(__GNUC__)
#ifndef __MINGW32__
#ifndef alloca
#define alloca __builtin_alloca
#endif
#else
#include <malloc.h>
#endif
#endif
#define wave_alloca alloca
#endif

View File

@ -56,6 +56,7 @@
#include <cctype>
#include <cerrno>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <list>
#include <sstream>
@ -916,6 +917,21 @@ void _vl_vsformat(std::string& output, const std::string& format, va_list ap) VL
}
break;
}
case 'p': { // 'x' but parameter is string
const int lbits = va_arg(ap, int);
(void)lbits;
const std::string* const cstr = va_arg(ap, const std::string*);
std::ostringstream oss;
for (unsigned char c : *cstr) oss << std::hex << static_cast<int>(c);
std::string hex_str = oss.str();
if (width > 0 && widthSet) {
hex_str = hex_str.size() > width
? hex_str.substr(0, width)
: std::string(width - hex_str.size(), '0') + hex_str;
output += hex_str;
}
break;
}
default: {
// Deal with all read-and-print somethings
const int lbits = va_arg(ap, int);
@ -1234,9 +1250,9 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
bool inPct = false;
bool inIgnore = false;
std::string::const_iterator pos = format.cbegin();
for (; pos != format.cend() && !_vl_vsss_eof(fp, floc); ++pos) {
// VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc,
// fromp, fstr)<<"'\n");
for (; pos != format.cend(); ++pos) {
// VL_DBG_MSGF("_vlscan fmt='%c' floc=%d file='%c'\n", pos[0], floc,
// _vl_vsss_peek(fp, floc, fromp, fstr));
if (!inPct && pos[0] == '%') {
inPct = true;
inIgnore = false;
@ -1420,7 +1436,12 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
} // switch
}
}
// Processed all arguments
return got;
done:
// Scan stopped early, return parsed or EOF
if (_vl_vsss_eof(fp, floc)) return -1;
return got;
}
@ -3017,7 +3038,7 @@ void VerilatedContext::trace(VerilatedTraceBaseC* tfp, int levels, int options)
if (m_ns.m_traceBaseModelCbs.empty())
VL_FATAL_MT("", 0, "",
"Testbench C call to 'VerilatedContext::trace()' requires model(s) Verilated"
" with --trace or --trace-vcd option");
" with --trace-fst or --trace-vcd option");
for (auto& cbr : m_ns.m_traceBaseModelCbs) cbr(tfp, levels, options);
}
void VerilatedContext::traceBaseModelCbAdd(traceBaseModelCb_t cb) VL_MT_SAFE {
@ -3455,7 +3476,7 @@ void VerilatedHierarchy::remove(VerilatedScope* fromp, VerilatedScope* top) {
void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE {
VL_FATAL_MT(__FILE__, __LINE__, "",
"Routine called that is single threaded, but called from"
" a different thread then the expected constructing thread");
" a different thread than the expected constructing thread");
}
#endif

View File

@ -175,9 +175,14 @@ enum class VerilatedAssertDirectiveType : uint8_t {
using VerilatedAssertType_t = std::underlying_type<VerilatedAssertType>::type;
using VerilatedAssertDirectiveType_t = std::underlying_type<VerilatedAssertDirectiveType>::type;
// Type trait for custom struct
// Type trait: whether T is a user-defined custom struct
template <typename>
struct VlIsCustomStruct : public std::false_type {};
// Type trait: used to detect if array element is a custom struct (e.g. for struct arrays)
template <typename T>
struct VlContainsCustomStruct : VlIsCustomStruct<T> {};
//=============================================================================
// Utility functions

View File

@ -90,6 +90,7 @@ VK_CPPFLAGS_ALWAYS += \
-DVM_TRACE=$(VM_TRACE) \
-DVM_TRACE_FST=$(VM_TRACE_FST) \
-DVM_TRACE_VCD=$(VM_TRACE_VCD) \
-DVM_TRACE_SAIF=$(VM_TRACE_SAIF) \
$(CFG_CXXFLAGS_NO_UNUSED) \
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users

View File

@ -101,6 +101,7 @@ void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
void VerilatedFst::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
const VerilatedLockGuard lock{m_mutex};
Super::closeBase();
emitTimeChangeMaybe();
fstWriterClose(m_fst);
m_fst = nullptr;
}
@ -108,10 +109,22 @@ void VerilatedFst::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
void VerilatedFst::flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
const VerilatedLockGuard lock{m_mutex};
Super::flushBase();
emitTimeChangeMaybe();
fstWriterFlushContext(m_fst);
}
void VerilatedFst::emitTimeChange(uint64_t timeui) { fstWriterEmitTimeChange(m_fst, timeui); }
void VerilatedFst::emitTimeChange(uint64_t timeui) {
if (!timeui) fstWriterEmitTimeChange(m_fst, timeui);
m_timeui = timeui;
}
VL_ATTR_ALWINLINE
void VerilatedFst::emitTimeChangeMaybe() {
if (VL_UNLIKELY(m_timeui)) {
fstWriterEmitTimeChange(m_fst, m_timeui);
m_timeui = 0;
}
}
//=============================================================================
// Decl
@ -311,12 +324,14 @@ void VerilatedFst::configure(const VerilatedTraceConfig& config) {
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitEvent(uint32_t code) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
}
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitBit(uint32_t code, CData newval) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0");
}
@ -325,6 +340,7 @@ void VerilatedFstBuffer::emitCData(uint32_t code, CData newval, int bits) {
char buf[VL_BYTESIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtCDataToStr(buf, newval << (VL_BYTESIZE - bits));
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
}
@ -333,6 +349,7 @@ void VerilatedFstBuffer::emitSData(uint32_t code, SData newval, int bits) {
char buf[VL_SHORTSIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtSDataToStr(buf, newval << (VL_SHORTSIZE - bits));
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
}
@ -341,6 +358,7 @@ void VerilatedFstBuffer::emitIData(uint32_t code, IData newval, int bits) {
char buf[VL_IDATASIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtIDataToStr(buf, newval << (VL_IDATASIZE - bits));
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
}
@ -349,6 +367,7 @@ void VerilatedFstBuffer::emitQData(uint32_t code, QData newval, int bits) {
char buf[VL_QUADSIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtQDataToStr(buf, newval << (VL_QUADSIZE - bits));
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
}
@ -365,10 +384,12 @@ void VerilatedFstBuffer::emitWData(uint32_t code, const WData* newvalp, int bits
cvtEDataToStr(wp, newvalp[--words]);
wp += VL_EDATASIZE;
}
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbufp);
}
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitDouble(uint32_t code, double newval) {
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
}

View File

@ -34,6 +34,8 @@ typedef uint32_t vlFstEnumHandle;
class VerilatedFstBuffer;
struct fstWriterContext;
//=============================================================================
// VerilatedFst
// Base class to create a Verilator FST dump
@ -49,11 +51,12 @@ private:
//=========================================================================
// FST-specific internals
void* m_fst = nullptr;
fstWriterContext* m_fst = nullptr;
std::map<uint32_t, vlFstHandle> m_code2symbol;
std::map<int, vlFstEnumHandle> m_local2fstdtype;
vlFstHandle* m_symbolp = nullptr; // same as m_code2symbol, but as an array
char* m_strbufp = nullptr; // String buffer long enough to hold maxBits() chars
uint64_t m_timeui = 0; // Time to emit, 0 = not needed
bool m_useFstWriterThread = false; // Whether to use the separate FST writer thread
@ -73,6 +76,7 @@ protected:
// Called when the trace moves forward to a new time point
void emitTimeChange(uint64_t timeui) override;
void emitTimeChangeMaybe();
// Hooks called from VerilatedTrace
bool preFullDump() override { return isOpen(); }
@ -161,7 +165,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
VerilatedFst& m_owner; // Trace file owning this buffer. Required by subclasses.
// The FST file handle
void* const m_fst = m_owner.m_fst;
fstWriterContext* const m_fst = m_owner.m_fst;
// code to fstHande map, as an array
const vlFstHandle* const m_symbolp = m_owner.m_symbolp;
// String buffer long enough to hold maxBits() chars

View File

@ -233,6 +233,14 @@ static inline std::string VL_CVT_N_CSTR(const char* lhsp) VL_PURE {
return lhsp ? std::string{lhsp} : ""s;
}
// Return queue from an unpacked array
template <typename T, std::size_t N_Depth>
static inline VlQueue<T> VL_CVT_UNPACK_TO_Q(const VlUnpacked<T, N_Depth>& q) VL_PURE {
VlQueue<T> ret;
for (size_t i = 0; i < N_Depth; ++i) ret.push_back(q[i]);
return ret;
}
// Return double from lhs (numeric) unsigned
double VL_ITOR_D_W(int lbits, WDataInP const lwp) VL_PURE;
static inline double VL_ITOR_D_I(int, IData lhs) VL_PURE {

View File

@ -34,28 +34,6 @@ thread_local VlExecutionProfiler::ExecutionTrace VlExecutionProfiler::t_trace;
constexpr const char* const VlExecutionRecord::s_ascii[];
//=============================================================================
// VlPgoProfiler implementation
uint16_t VlExecutionRecord::getcpu() {
#if defined(__linux)
return sched_getcpu(); // TODO: this is a system call. Not exactly cheap.
#elif defined(__APPLE__) && !defined(__arm64__)
uint32_t info[4];
__cpuid_count(1, 0, info[0], info[1], info[2], info[3]);
// info[1] is EBX, bits 24-31 are APIC ID
if ((info[3] & (1 << 9)) == 0) {
return -1; // no APIC on chip
} else {
return (unsigned)info[1] >> 24;
}
#elif defined(_WIN32)
return GetCurrentProcessorNumber();
#else
return 0;
#endif
}
//=============================================================================
// VlExecutionProfiler implementation
@ -157,15 +135,21 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
VL_DEBUG_IF(VL_DBG_MSGF("+prof+exec writing to '%s'\n", filenamep););
FILE* const fp = std::fopen(filenamep, "w");
if (VL_UNLIKELY(!fp)) { VL_FATAL_MT(filenamep, 0, "", "+prof+exec+file file not writable"); }
if (VL_UNLIKELY(!fp)) VL_FATAL_MT(filenamep, 0, "", "+prof+exec+file file not writable");
// TODO Perhaps merge with verilated_coverage output format, so can
// have a common merging and reporting tool, etc.
fprintf(fp, "VLPROFVERSION 2.1 # Verilator execution profile version 2.1\n");
fprintf(fp, "VLPROFVERSION 2.2 # Verilator execution profile version 2.2\n");
fprintf(fp, "VLPROF arg +verilator+prof+exec+start+%" PRIu64 "\n",
Verilated::threadContextp()->profExecStart());
fprintf(fp, "VLPROF arg +verilator+prof+exec+window+%u\n",
Verilated::threadContextp()->profExecWindow());
std::string numa = "no threads";
if (VlThreadPool* const threadPoolp
= static_cast<VlThreadPool*>(Verilated::threadContextp()->threadPoolp())) {
numa = threadPoolp->numaStatus();
}
fprintf(fp, "VLPROF info numa %s\n", numa.c_str());
// Note that VerilatedContext will by default create as many threads as there are hardware
// processors, but not all of them might be utilized. Report the actual number that has trace
// entries to avoid over-counting.
@ -206,13 +190,24 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
break;
case VlExecutionRecord::Type::MTASK_BEGIN: {
const auto& payload = er.m_payload.mtaskBegin;
fprintf(fp, " id %u predictStart %u cpu %u\n", payload.m_id,
payload.m_predictStart, payload.m_cpu);
if (payload.m_hierBlock[0] != '\0') {
fprintf(fp, " id %u predictStart %u cpu %u hierBlock %s\n", payload.m_id,
payload.m_predictStart, payload.m_cpu, payload.m_hierBlock);
} else {
fprintf(fp, " id %u predictStart %u cpu %u\n", payload.m_id,
payload.m_predictStart, payload.m_cpu);
}
break;
}
case VlExecutionRecord::Type::MTASK_END: {
const auto& payload = er.m_payload.mtaskEnd;
fprintf(fp, " id %u predictCost %u\n", payload.m_id, payload.m_predictCost);
fprintf(fp, " predictCost %u\n", payload.m_predictCost);
break;
}
case VlExecutionRecord::Type::THREAD_SCHEDULE_WAIT_BEGIN:
case VlExecutionRecord::Type::THREAD_SCHEDULE_WAIT_END: {
const auto& payload = er.m_payload.threadScheduleWait;
fprintf(fp, " cpu %u\n", payload.m_cpu);
break;
}
case VlExecutionRecord::Type::SECTION_PUSH: {

View File

@ -62,6 +62,8 @@ VL_ATTR_ALWINLINE QData VL_CPU_TICK() {
_VL_FOREACH_APPLY(macro, SECTION_POP) \
_VL_FOREACH_APPLY(macro, MTASK_BEGIN) \
_VL_FOREACH_APPLY(macro, MTASK_END) \
_VL_FOREACH_APPLY(macro, THREAD_SCHEDULE_WAIT_BEGIN) \
_VL_FOREACH_APPLY(macro, THREAD_SCHEDULE_WAIT_END) \
_VL_FOREACH_APPLY(macro, EXEC_GRAPH_BEGIN) \
_VL_FOREACH_APPLY(macro, EXEC_GRAPH_END)
// clang-format on
@ -90,11 +92,14 @@ class VlExecutionRecord final {
uint32_t m_id; // MTask id
uint32_t m_predictStart; // Time scheduler predicted would start
uint32_t m_cpu; // Executing CPU id
const char* m_hierBlock; // Name of a hier block with this mtask
} mtaskBegin;
struct {
uint32_t m_id; // MTask id
uint32_t m_predictCost; // How long scheduler predicted would take
} mtaskEnd;
struct {
uint32_t m_cpu; // Executing CPU id
} threadScheduleWait;
};
// STATE
@ -105,8 +110,6 @@ class VlExecutionRecord final {
static_assert(alignof(uint64_t) >= alignof(Payload), "Padding not allowed");
static_assert(alignof(Payload) >= alignof(Type), "Padding not allowed");
static uint16_t getcpu(); // Return currently executing CPU id
public:
// CONSTRUCTOR
VlExecutionRecord() = default;
@ -117,17 +120,25 @@ public:
m_type = Type::SECTION_PUSH;
}
void sectionPop() { m_type = Type::SECTION_POP; }
void mtaskBegin(uint32_t id, uint32_t predictStart) {
void mtaskBegin(uint32_t id, uint32_t predictStart, const char* hierBlock = "") {
m_payload.mtaskBegin.m_id = id;
m_payload.mtaskBegin.m_predictStart = predictStart;
m_payload.mtaskBegin.m_cpu = getcpu();
m_payload.mtaskBegin.m_cpu = VlOs::getcpu();
m_payload.mtaskBegin.m_hierBlock = hierBlock;
m_type = Type::MTASK_BEGIN;
}
void mtaskEnd(uint32_t id, uint32_t predictCost) {
m_payload.mtaskEnd.m_id = id;
void mtaskEnd(uint32_t predictCost) {
m_payload.mtaskEnd.m_predictCost = predictCost;
m_type = Type::MTASK_END;
}
void threadScheduleWaitBegin() {
m_payload.threadScheduleWait.m_cpu = VlOs::getcpu();
m_type = Type::THREAD_SCHEDULE_WAIT_BEGIN;
}
void threadScheduleWaitEnd() {
m_payload.threadScheduleWait.m_cpu = VlOs::getcpu();
m_type = Type::THREAD_SCHEDULE_WAIT_END;
}
void execGraphBegin() { m_type = Type::EXEC_GRAPH_BEGIN; }
void execGraphEnd() { m_type = Type::EXEC_GRAPH_END; }
};
@ -214,7 +225,7 @@ public:
// METHODS
VlPgoProfiler() = default;
~VlPgoProfiler() = default;
void write(const char* modelp, const std::string& filename) VL_MT_SAFE;
void write(const char* modelp, const std::string& filename, bool firstHierCall) VL_MT_SAFE;
void addCounter(size_t counter, const std::string& name) {
VL_DEBUG_IF(assert(counter < N_Entries););
m_records.emplace_back(Record{name, counter});
@ -228,7 +239,8 @@ public:
};
template <std::size_t N_Entries>
void VlPgoProfiler<N_Entries>::write(const char* modelp, const std::string& filename) VL_MT_SAFE {
void VlPgoProfiler<N_Entries>::write(const char* modelp, const std::string& filename,
bool firstHierCall) VL_MT_SAFE {
static VerilatedMutex s_mutex;
const VerilatedLockGuard lock{s_mutex};
@ -238,7 +250,7 @@ void VlPgoProfiler<N_Entries>::write(const char* modelp, const std::string& file
// each will collect is own data correctly. However when each is
// destroyed we need to get all the data, not keep overwriting and only
// get the last model's data.
static bool s_firstCall = true;
static bool s_firstCall = firstHierCall;
VL_DEBUG_IF(VL_DBG_MSGF("+prof+vlt+file writing to '%s'\n", filename.c_str()););
@ -246,12 +258,14 @@ void VlPgoProfiler<N_Entries>::write(const char* modelp, const std::string& file
if (VL_UNLIKELY(!fp)) {
VL_FATAL_MT(filename.c_str(), 0, "", "+prof+vlt+file file not writable");
}
s_firstCall = false;
if (s_firstCall) {
// TODO Perhaps merge with verilated_coverage output format, so can
// have a common merging and reporting tool, etc.
fprintf(fp, "// Verilated model profile-guided optimization data dump file\n");
fprintf(fp, "`verilator_config\n");
}
// TODO Perhaps merge with verilated_coverage output format, so can
// have a common merging and reporting tool, etc.
fprintf(fp, "// Verilated model profile-guided optimization data dump file\n");
fprintf(fp, "`verilator_config\n");
s_firstCall = false;
for (const Record& rec : m_records) {
fprintf(fp, "profile_data -model \"%s\" -mtask \"%s\" -cost 64'd%" PRIu64 "\n", modelp,

View File

@ -166,7 +166,7 @@ public:
s << "(Array (_ BitVec " << idxWidths[i] << ") ";
}
s << "(_ BitVec " << width() << ")";
for (int i = 0; i < dimension(); ++i) { s << ")"; }
for (int i = 0; i < dimension(); ++i) s << ")";
}
} else {
VL_FATAL_MT(__FILE__, __LINE__, "randomize", "indexed_name not found in m_arr_vars");
@ -200,8 +200,8 @@ class VlRandomizer final {
std::map<std::string, std::shared_ptr<const VlRandomVar>> m_vars; // Solver-dependent
// variables
ArrayInfoMap m_arr_vars; // Tracks each element in array structures for iteration
std::map<size_t, std::string> seen_values; // Record String Index to avoid conflicts
const VlQueue<CData>* m_randmode; // rand_mode state;
int m_index = 0; // Internal counter for key generation
// PRIVATE METHODS
void randomConstraint(std::ostream& os, VlRNG& rngr, int bits);
@ -216,6 +216,11 @@ public:
// Finds the next solution satisfying the constraints
bool next(VlRNG& rngr);
// -----------------------------------------------
// --- Process the key for associative array ---
// -----------------------------------------------
// process_key: Handle integral keys (<= 32-bit)
template <typename T_Key>
typename std::enable_if<std::is_integral<T_Key>::value && (sizeof(T_Key) <= 4)>::type
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
@ -225,6 +230,8 @@ public:
= base_name + "[" + std::to_string(integral_index[integral_index.size() - 1]) + "]";
idx_width = sizeof(T_Key) * 8;
}
// process_key: Handle integral keys (> 32-bit), split into 2 x 32-bit segments
template <typename T_Key>
typename std::enable_if<std::is_integral<T_Key>::value && (sizeof(T_Key) > 4)>::type
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
@ -244,6 +251,8 @@ public:
idx_width = sizeof(T_Key) * 8;
}
// process_key: Handle wide keys (VlWide-like), segment is 32-bit per element
template <typename T_Key>
typename std::enable_if<VlIsVlWide<T_Key>::value>::type
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
@ -261,6 +270,8 @@ public:
indexed_name = base_name + "[" + index_string + "]";
idx_width = key.size() * 32;
}
// process_key: Handle string key, encoded as 128-bit hex
template <typename T_Key>
typename std::enable_if<std::is_same<T_Key, std::string>::value>::type
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
@ -289,6 +300,8 @@ public:
idx_width = 128;
}
// process_key: Unsupported key type fallback
template <typename T_Key>
typename std::enable_if<!std::is_integral<T_Key>::value
&& !std::is_same<T_Key, std::string>::value
@ -300,8 +313,13 @@ public:
"supported currently.");
}
// -----------------------------------------
// --- write_var to register variables ---
// -----------------------------------------
// Register scalar variable (non-struct, basic type)
template <typename T>
typename std::enable_if<!VlIsCustomStruct<T>::value, void>::type
typename std::enable_if<!VlContainsCustomStruct<T>::value, void>::type
write_var(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;
@ -309,28 +327,60 @@ public:
m_vars[name]
= std::make_shared<const VlRandomVar>(name, width, &var, dimension, randmodeIdx);
}
// Register user-defined struct variable by recursively writing members
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()) {
typename std::enable_if<VlIsCustomStruct<T>::value, void>::type
write_var(T& var, int width, const char* name, int dimension,
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
modifyMembers(var, var.memberIndices(), name);
}
// Register queue of non-struct types
template <typename T>
typename std::enable_if<!VlContainsCustomStruct<T>::value, void>::type
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 VlRandomArrayVarTemplate<VlQueue<T>>>(
name, width, &var, dimension, randmodeIdx);
if (dimension > 0) {
idx = 0;
m_index = 0;
record_arr_table(var, name, dimension, {}, {});
}
}
// Register queue of structs
template <typename T>
typename std::enable_if<VlContainsCustomStruct<T>::value, void>::type
write_var(VlQueue<T>& var, int width, const char* name, int dimension,
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
if (dimension > 0) record_struct_arr(var, name, dimension, {}, {});
}
// Register unpacked array of non-struct types
template <typename T, std::size_t N_Depth>
void write_var(VlUnpacked<T, N_Depth>& var, int width, const char* name, int dimension,
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
typename std::enable_if<!VlContainsCustomStruct<T>::value, void>::type
write_var(VlUnpacked<T, N_Depth>& 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 VlRandomArrayVarTemplate<VlUnpacked<T, N_Depth>>>(
name, width, &var, dimension, randmodeIdx);
if (dimension > 0) {
idx = 0;
m_index = 0;
record_arr_table(var, name, dimension, {}, {});
}
}
// Register unpacked array of structs
template <typename T, std::size_t N_Depth>
typename std::enable_if<VlContainsCustomStruct<T>::value, void>::type
write_var(VlUnpacked<T, N_Depth>& var, int width, const char* name, int dimension,
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
if (dimension > 0) record_struct_arr(var, name, dimension, {}, {});
}
// Register associative array of non-struct types
template <typename T_Key, typename T_Value>
void write_var(VlAssocArray<T_Key, T_Value>& var, int width, const char* name, int dimension,
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
@ -339,59 +389,28 @@ public:
= std::make_shared<const VlRandomArrayVarTemplate<VlAssocArray<T_Key, T_Value>>>(
name, width, &var, dimension, randmodeIdx);
if (dimension > 0) {
idx = 0;
m_index = 0;
record_arr_table(var, name, dimension, {}, {});
}
}
template <typename T, std::size_t... I>
void modifyMembers(T& obj, std::index_sequence<I...>, std::string baseName) {
// Use the indices to access each member via std::get
(void)std::initializer_list<int>{
(write_var(std::get<I>(obj.getMembers(obj)), obj.memberWidth()[I],
(baseName + "." + obj.memberNames()[I]).c_str(), obj.memberDimension()[I]),
0)...};
}
template <typename T>
typename std::enable_if<VlIsCustomStruct<T>::value, void>::type
write_var(T& var, int width, const char* name, int dimension,
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
modifyMembers(var, var.memberIndices(), name);
}
// TODO: Register associative array of structs
int idx;
std::string generateKey(const std::string& name, int idx) {
if (!name.empty() && name[0] == '\\') {
const size_t space_pos = name.find(' ');
return (space_pos != std::string::npos ? name.substr(0, space_pos) : name)
+ std::to_string(idx);
}
const size_t bracket_pos = name.find('[');
return (bracket_pos != std::string::npos ? name.substr(0, bracket_pos) : name)
+ std::to_string(idx);
}
// ----------------------------------------
// --- Record Arrays: flat and struct ---
// ----------------------------------------
// Record a flat (non-class) element into the array variable table
template <typename T>
typename std::enable_if<!std::is_class<T>::value, void>::type
record_arr_table(T& var, const std::string name, int dimension, std::vector<IData> indices,
std::vector<size_t> idxWidths) {
const std::string key = generateKey(name, idx);
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices, idxWidths);
++idx;
}
template <typename T>
void record_arr_table(VlQueue<T>& var, const std::string name, int dimension,
std::vector<IData> indices, std::vector<size_t> idxWidths) {
if ((dimension > 0) && (var.size() != 0)) {
idxWidths.push_back(32);
for (size_t i = 0; i < var.size(); ++i) {
const std::string indexed_name = name + "[" + std::to_string(i) + "]";
indices.push_back(i);
record_arr_table(var.atWrite(i), indexed_name, dimension - 1, indices, idxWidths);
indices.pop_back();
}
}
const std::string key = generateKey(name, m_index);
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, m_index, indices, idxWidths);
++m_index;
}
// Recursively record all elements in an unpacked array
template <typename T, std::size_t N_Depth>
void record_arr_table(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension,
std::vector<IData> indices, std::vector<size_t> idxWidths) {
@ -406,6 +425,23 @@ public:
}
}
}
// Recursively record all elements in a queue
template <typename T>
void record_arr_table(VlQueue<T>& var, const std::string name, int dimension,
std::vector<IData> indices, std::vector<size_t> idxWidths) {
if ((dimension > 0) && (var.size() != 0)) {
idxWidths.push_back(32);
for (size_t i = 0; i < var.size(); ++i) {
const std::string indexed_name = name + "[" + std::to_string(i) + "]";
indices.push_back(i);
record_arr_table(var.atWrite(i), indexed_name, dimension - 1, indices, idxWidths);
indices.pop_back();
}
}
}
// Recursively record all elements in an associative array
template <typename T_Key, typename T_Value>
void record_arr_table(VlAssocArray<T_Key, T_Value>& var, const std::string name, int dimension,
std::vector<IData> indices, std::vector<size_t> idxWidths) {
@ -433,6 +469,76 @@ public:
}
}
// Register a single structArray element via write_var
template <typename T>
typename std::enable_if<VlContainsCustomStruct<T>::value, void>::type
record_struct_arr(T& var, const std::string name, int dimension, std::vector<IData> indices,
std::vector<size_t> idxWidths) {
std::ostringstream oss;
for (size_t i = 0; i < indices.size(); ++i) {
oss << std::hex << static_cast<int>(indices[i]);
if (i < indices.size() - 1) oss << ".";
}
write_var(var, 1ULL, (name + "." + oss.str()).c_str(), 1ULL);
}
// Recursively process VlUnpacked of structs
template <typename T, std::size_t N_Depth>
void record_struct_arr(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension,
std::vector<IData> indices, std::vector<size_t> idxWidths) {
if (dimension > 0 && N_Depth != 0) {
idxWidths.push_back(32);
for (size_t i = 0; i < N_Depth; ++i) {
indices.push_back(i);
record_struct_arr(var.operator[](i), name, dimension - 1, indices, idxWidths);
indices.pop_back();
}
}
}
// Recursively process VlQueue of structs
template <typename T>
void record_struct_arr(VlQueue<T>& var, const std::string name, int dimension,
std::vector<IData> indices, std::vector<size_t> idxWidths) {
if ((dimension > 0) && (var.size() != 0)) {
idxWidths.push_back(32);
for (size_t i = 0; i < var.size(); ++i) {
indices.push_back(i);
record_struct_arr(var.atWrite(i), name, dimension - 1, indices, idxWidths);
indices.pop_back();
}
}
}
// TODO: Add support for associative arrays of structs
// Recursively process associative arrays of structs
// --------------------------
// --- Helper functions ---
// --------------------------
// Helper: Register all members of a user-defined struct
template <typename T, std::size_t... I>
void modifyMembers(T& obj, std::index_sequence<I...>, std::string baseName) {
// Use the indices to access each member via std::get
(void)std::initializer_list<int>{
(write_var(std::get<I>(obj.getMembers(obj)), obj.memberWidth()[I],
(baseName + "." + obj.memberNames()[I]).c_str(), obj.memberDimension()[I]),
0)...};
}
// Helper: Generate unique variable key from name and index
std::string generateKey(const std::string& name, int idx) {
if (!name.empty() && name[0] == '\\') {
const size_t space_pos = name.find(' ');
return (space_pos != std::string::npos ? name.substr(0, space_pos) : name)
+ std::to_string(idx);
}
const size_t bracket_pos = name.find('[');
return (bracket_pos != std::string::npos ? name.substr(0, bracket_pos) : name)
+ std::to_string(idx);
}
void hard(std::string&& constraint);
void clear();
void set_randmode(const VlQueue<CData>& randmode) { m_randmode = &randmode; }

View File

@ -0,0 +1,662 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// Code available from: https://verilator.org
//
// Copyright 2001-2025 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
//
//=============================================================================
///
/// \file
/// \brief Verilated C++ tracing in SAIF format implementation code
///
/// This file must be compiled and linked against all Verilated objects
/// that use --trace-saif.
///
/// Use "verilator --trace-saif" to add this to the Makefile for the linker.
///
//=============================================================================
// clang-format off
#include "verilatedos.h"
#include "verilated.h"
#include "verilated_saif_c.h"
#include <algorithm>
#include <cerrno>
#include <fcntl.h>
#include <string>
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h>
#else
# include <unistd.h>
#endif
#ifndef O_LARGEFILE // WIN32 headers omit this
# define O_LARGEFILE 0
#endif
#ifndef O_NONBLOCK // WIN32 headers omit this
# define O_NONBLOCK 0
#endif
#ifndef O_CLOEXEC // WIN32 headers omit this
# define O_CLOEXEC 0
#endif
// clang-format on
//=============================================================================
// Specialization of the generics for this trace format
#define VL_SUB_T VerilatedSaif
#define VL_BUF_T VerilatedSaifBuffer
#include "verilated_trace_imp.h"
#undef VL_SUB_T
#undef VL_BUF_T
//=============================================================================
// VerilatedSaifActivityBit
class VerilatedSaifActivityBit final {
// MEMBERS
bool m_lastVal = false; // Last emitted activity bit value
uint64_t m_highTime = 0; // Total time when bit was high
size_t m_transitions = 0; // Total number of bit transitions
public:
// METHODS
VL_ATTR_ALWINLINE
void aggregateVal(uint64_t dt, bool newVal) {
m_transitions += newVal != m_lastVal ? 1 : 0;
m_highTime += m_lastVal ? dt : 0;
m_lastVal = newVal;
}
// ACCESSORS
VL_ATTR_ALWINLINE bool bitValue() const { return m_lastVal; }
VL_ATTR_ALWINLINE uint64_t highTime() const { return m_highTime; }
VL_ATTR_ALWINLINE uint64_t toggleCount() const { return m_transitions; }
};
//=============================================================================
// VerilatedSaifActivityVar
class VerilatedSaifActivityVar final {
// MEMBERS
uint64_t m_lastTime = 0; // Last time when variable value was updated
VerilatedSaifActivityBit* m_bits; // Pointer to variable bits objects
uint32_t m_width; // Width of variable (in bits)
public:
// CONSTRUCTORS
VerilatedSaifActivityVar(uint32_t width, VerilatedSaifActivityBit* bits)
: m_bits{bits}
, m_width{width} {}
VerilatedSaifActivityVar(VerilatedSaifActivityVar&&) = default;
VerilatedSaifActivityVar& operator=(VerilatedSaifActivityVar&&) = default;
// METHODS
VL_ATTR_ALWINLINE void emitBit(uint64_t time, CData newval);
template <typename DataType>
VL_ATTR_ALWINLINE void emitData(uint64_t time, DataType newval, uint32_t bits) {
static_assert(std::is_integral<DataType>::value,
"The emitted value must be of integral type");
const uint64_t dt = time - m_lastTime;
for (size_t i = 0; i < std::min(m_width, bits); i++) {
m_bits[i].aggregateVal(dt, (newval >> i) & 1);
}
updateLastTime(time);
}
VL_ATTR_ALWINLINE void emitWData(uint64_t time, const WData* newvalp, uint32_t bits);
VL_ATTR_ALWINLINE void updateLastTime(uint64_t val) { m_lastTime = val; }
// ACCESSORS
VL_ATTR_ALWINLINE uint32_t width() const { return m_width; }
VL_ATTR_ALWINLINE VerilatedSaifActivityBit& bit(std::size_t index);
VL_ATTR_ALWINLINE uint64_t lastUpdateTime() const { return m_lastTime; }
private:
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedSaifActivityVar);
};
//=============================================================================
// VerilatedSaifActivityScope
class VerilatedSaifActivityScope final {
// MEMBERS
// Absolute path to the scope
std::string m_scopePath;
// Name of the activity scope
std::string m_scopeName;
// Array indices of child scopes
std::vector<std::unique_ptr<VerilatedSaifActivityScope>> m_childScopes{};
// Children signals codes mapped to their names in the current scope
std::vector<std::pair<uint32_t, std::string>> m_childActivities{};
// Parent scope pointer
VerilatedSaifActivityScope* m_parentScope = nullptr;
public:
// CONSTRUCTORS
VerilatedSaifActivityScope(std::string scopePath, std::string name,
VerilatedSaifActivityScope* parentScope = nullptr)
: m_scopePath{std::move(scopePath)}
, m_scopeName{std::move(name)}
, m_parentScope{parentScope} {}
VerilatedSaifActivityScope(VerilatedSaifActivityScope&&) = default;
VerilatedSaifActivityScope& operator=(VerilatedSaifActivityScope&&) = default;
// METHODS
VL_ATTR_ALWINLINE void addChildScope(std::unique_ptr<VerilatedSaifActivityScope> childScope) {
m_childScopes.emplace_back(std::move(childScope));
}
VL_ATTR_ALWINLINE void addActivityVar(uint32_t code, std::string name) {
m_childActivities.emplace_back(code, std::move(name));
}
VL_ATTR_ALWINLINE bool hasParent() const { return m_parentScope; }
// ACCESSORS
VL_ATTR_ALWINLINE const std::string& path() const { return m_scopePath; }
VL_ATTR_ALWINLINE const std::string& name() const { return m_scopeName; }
VL_ATTR_ALWINLINE const std::vector<std::unique_ptr<VerilatedSaifActivityScope>>&
childScopes() const {
return m_childScopes;
}
VL_ATTR_ALWINLINE
const std::vector<std::pair<uint32_t, std::string>>& childActivities() const {
return m_childActivities;
}
VL_ATTR_ALWINLINE VerilatedSaifActivityScope* parentScope() const { return m_parentScope; }
private:
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedSaifActivityScope);
};
//=============================================================================
// VerilatedSaifActivityAccumulator
class VerilatedSaifActivityAccumulator final {
// Give access to the private activities
friend class VerilatedSaifBuffer;
friend class VerilatedSaif;
// MEMBERS
// Map of scopes paths to codes of activities inside
std::unordered_map<std::string, std::vector<std::pair<uint32_t, std::string>>>
m_scopeToActivities;
// Map of variables codes mapped to their activity objects
std::unordered_map<uint32_t, VerilatedSaifActivityVar> m_activity;
// Memory pool for signals bits objects
std::vector<std::vector<VerilatedSaifActivityBit>> m_activityArena;
public:
// METHODS
void declare(uint32_t code, const std::string& absoluteScopePath, std::string variableName,
int bits, bool array, int arraynum);
// CONSTRUCTORS
VerilatedSaifActivityAccumulator() = default;
VerilatedSaifActivityAccumulator(VerilatedSaifActivityAccumulator&&) = default;
VerilatedSaifActivityAccumulator& operator=(VerilatedSaifActivityAccumulator&&) = default;
private:
VL_UNCOPYABLE(VerilatedSaifActivityAccumulator);
};
//=============================================================================
//=============================================================================
//=============================================================================
// VerilatedSaifActivityVar implementation
VL_ATTR_ALWINLINE
void VerilatedSaifActivityVar::emitBit(const uint64_t time, const CData newval) {
assert(m_lastTime <= time);
m_bits[0].aggregateVal(time - m_lastTime, newval);
updateLastTime(time);
}
VL_ATTR_ALWINLINE
void VerilatedSaifActivityVar::emitWData(const uint64_t time, const WData* newvalp,
const uint32_t bits) {
assert(m_lastTime <= time);
const uint64_t dt = time - m_lastTime;
for (std::size_t i = 0; i < std::min(m_width, bits); ++i) {
const size_t wordIndex = i / VL_EDATASIZE;
m_bits[i].aggregateVal(dt, (newvalp[wordIndex] >> VL_BITBIT_E(i)) & 1);
}
updateLastTime(time);
}
VerilatedSaifActivityBit& VerilatedSaifActivityVar::bit(const std::size_t index) {
assert(index < m_width);
return m_bits[index];
}
//=============================================================================
//=============================================================================
//=============================================================================
// VerilatedSaifActivityAccumulator implementation
void VerilatedSaifActivityAccumulator::declare(uint32_t code, const std::string& absoluteScopePath,
std::string variableName, int bits, bool array,
int arraynum) {
const size_t block_size = 1024;
if (m_activityArena.empty()
|| m_activityArena.back().size() + bits > m_activityArena.back().capacity()) {
m_activityArena.emplace_back();
m_activityArena.back().reserve(block_size);
}
const size_t bitsIdx = m_activityArena.back().size();
m_activityArena.back().resize(m_activityArena.back().size() + bits);
if (array) {
variableName += '[';
variableName += std::to_string(arraynum);
variableName += ']';
}
m_scopeToActivities[absoluteScopePath].emplace_back(code, variableName);
m_activity.emplace(code, VerilatedSaifActivityVar{static_cast<uint32_t>(bits),
m_activityArena.back().data() + bitsIdx});
}
//=============================================================================
//=============================================================================
//=============================================================================
// VerilatedSaif implementation
VerilatedSaif::VerilatedSaif(void* filep) {
m_activityAccumulators.emplace_back(std::make_unique<VerilatedSaifActivityAccumulator>());
}
void VerilatedSaif::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
const VerilatedLockGuard lock{m_mutex};
if (isOpen()) return;
m_filename = filename; // "" is ok, as someone may overload open
m_filep = ::open(m_filename.c_str(),
O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666);
m_isOpen = true;
initializeSaifFileContents();
Super::traceInit();
}
void VerilatedSaif::initializeSaifFileContents() {
printStr("// Generated by verilated_saif\n");
printStr("(SAIFILE\n");
printStr("(SAIFVERSION \"2.0\")\n");
printStr("(DIRECTION \"backward\")\n");
printStr("(PROGRAM_NAME \"Verilator\")\n");
printStr("(DIVIDER / )\n");
printStr("(TIMESCALE ");
printStr(timeResStr());
printStr(")\n");
}
void VerilatedSaif::emitTimeChange(uint64_t timeui) { m_time = timeui; }
VerilatedSaif::~VerilatedSaif() { close(); }
void VerilatedSaif::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
// This function is on the flush() call path
const VerilatedLockGuard lock{m_mutex};
if (!isOpen()) return;
finalizeSaifFileContents();
clearCurrentlyCollectedData();
writeBuffered(true);
::close(m_filep);
m_isOpen = false;
Super::closeBase();
}
void VerilatedSaif::finalizeSaifFileContents() {
printStr("(DURATION ");
printStr(std::to_string(currentTime()));
printStr(")\n");
incrementIndent();
for (const auto& topScope : m_scopes) recursivelyPrintScopes(*topScope);
decrementIndent();
printStr(")\n"); // SAIFILE
}
void VerilatedSaif::recursivelyPrintScopes(const VerilatedSaifActivityScope& scope) {
openInstanceScope(scope.name());
printScopeActivities(scope);
for (const auto& childScope : scope.childScopes()) recursivelyPrintScopes(*childScope);
closeInstanceScope();
}
void VerilatedSaif::openInstanceScope(const std::string& instanceName) {
printIndent();
printStr("(INSTANCE ");
printStr(instanceName);
printStr("\n");
incrementIndent();
}
void VerilatedSaif::closeInstanceScope() {
decrementIndent();
printIndent();
printStr(")\n"); // INSTANCE
}
void VerilatedSaif::printScopeActivities(const VerilatedSaifActivityScope& scope) {
bool anyNetWritten = false;
for (auto& accumulator : m_activityAccumulators) {
anyNetWritten |= printScopeActivitiesFromAccumulatorIfPresent(scope.path(), *accumulator,
anyNetWritten);
}
if (anyNetWritten) closeNetScope();
}
bool VerilatedSaif::printScopeActivitiesFromAccumulatorIfPresent(
const std::string& absoluteScopePath, VerilatedSaifActivityAccumulator& accumulator,
bool anyNetWritten) {
if (accumulator.m_scopeToActivities.count(absoluteScopePath) == 0) return false;
for (const auto& childSignal : accumulator.m_scopeToActivities.at(absoluteScopePath)) {
VerilatedSaifActivityVar& activityVariable = accumulator.m_activity.at(childSignal.first);
anyNetWritten
= printActivityStats(activityVariable, childSignal.second.c_str(), anyNetWritten);
}
return anyNetWritten;
}
void VerilatedSaif::openNetScope() {
printIndent();
printStr("(NET\n");
incrementIndent();
}
void VerilatedSaif::closeNetScope() {
decrementIndent();
printIndent();
printStr(")\n"); // NET
}
bool VerilatedSaif::printActivityStats(VerilatedSaifActivityVar& activity,
const std::string& activityName, bool anyNetWritten) {
for (size_t i = 0; i < activity.width(); ++i) {
VerilatedSaifActivityBit& bit = activity.bit(i);
bit.aggregateVal(currentTime() - activity.lastUpdateTime(), bit.bitValue());
if (!anyNetWritten) {
openNetScope();
anyNetWritten = true;
}
printIndent();
printStr("(");
printStr(activityName);
if (activity.width() > 1) {
printStr("\\[");
printStr(std::to_string(i));
printStr("\\]");
}
// We only have two-value logic so TZ, TX and TB will always be 0
printStr(" (T0 ");
printStr(std::to_string(currentTime() - bit.highTime()));
printStr(") (T1 ");
printStr(std::to_string(bit.highTime()));
printStr(") (TZ 0) (TX 0) (TB 0) (TC ");
printStr(std::to_string(bit.toggleCount()));
printStr("))\n");
}
activity.updateLastTime(currentTime());
return anyNetWritten;
}
void VerilatedSaif::clearCurrentlyCollectedData() {
m_currentScope = nullptr;
m_scopes.clear();
m_activityAccumulators.clear();
}
void VerilatedSaif::printStr(const char* str) {
m_buffer.append(str);
writeBuffered(false);
}
void VerilatedSaif::printStr(const std::string& str) {
m_buffer.append(str);
writeBuffered(false);
}
void VerilatedSaif::writeBuffered(bool force) {
if (VL_UNLIKELY(m_buffer.size() >= WRITE_BUFFER_SIZE || force)) {
if (VL_UNLIKELY(!m_buffer.empty())) {
::write(m_filep, m_buffer.data(), m_buffer.size());
m_buffer = "";
m_buffer.reserve(WRITE_BUFFER_SIZE * 2);
}
}
}
//=============================================================================
// Definitions
void VerilatedSaif::flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
const VerilatedLockGuard lock{m_mutex};
Super::flushBase();
}
void VerilatedSaif::incrementIndent() { m_indent += 1; }
void VerilatedSaif::decrementIndent() { m_indent -= 1; }
void VerilatedSaif::printIndent() {
printStr(std::string(m_indent, ' ')); // Must use () constructor
}
void VerilatedSaif::pushPrefix(const std::string& name, VerilatedTracePrefixType type) {
std::string pname = name;
if (m_prefixStack.back().second == VerilatedTracePrefixType::ROOTIO_MODULE) popPrefix();
if (pname.empty()) {
pname = "$rootio";
type = VerilatedTracePrefixType::ROOTIO_MODULE;
}
if (type != VerilatedTracePrefixType::ARRAY_UNPACKED
&& type != VerilatedTracePrefixType::ARRAY_PACKED) {
std::string scopePath = m_prefixStack.back().first + pname;
std::string scopeName = lastWord(scopePath);
auto newScope = std::make_unique<VerilatedSaifActivityScope>(
std::move(scopePath), std::move(scopeName), m_currentScope);
VerilatedSaifActivityScope* newScopePtr = newScope.get();
if (m_currentScope) {
m_currentScope->addChildScope(std::move(newScope));
} else {
m_scopes.emplace_back(std::move(newScope));
}
m_currentScope = newScopePtr;
}
std::string newPrefix = m_prefixStack.back().first + pname;
if (type != VerilatedTracePrefixType::ARRAY_UNPACKED
&& type != VerilatedTracePrefixType::ARRAY_PACKED) {
newPrefix += ' ';
}
m_prefixStack.emplace_back(newPrefix, type);
}
void VerilatedSaif::popPrefix() {
if (m_prefixStack.back().second != VerilatedTracePrefixType::ARRAY_UNPACKED
&& m_prefixStack.back().second != VerilatedTracePrefixType::ARRAY_PACKED
&& m_currentScope != nullptr) {
m_currentScope = m_currentScope->parentScope();
}
m_prefixStack.pop_back();
}
void VerilatedSaif::declare(const uint32_t code, uint32_t fidx, const char* name,
const char* wirep, const bool array, const int arraynum,
const bool bussed, const int msb, const int lsb) {
assert(m_activityAccumulators.size() > fidx);
VerilatedSaifActivityAccumulator& accumulator = *m_activityAccumulators.at(fidx);
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
const std::string hierarchicalName = m_prefixStack.back().first + name;
if (!Super::declCode(code, hierarchicalName, bits)) return;
std::string variableName = lastWord(hierarchicalName);
m_currentScope->addActivityVar(code, variableName);
accumulator.declare(code, m_currentScope->path(), std::move(variableName), bits, array,
arraynum);
}
void VerilatedSaif::declEvent(const uint32_t code, const uint32_t fidx, const char* name,
const int dtypenum, const VerilatedTraceSigDirection,
const VerilatedTraceSigKind, const VerilatedTraceSigType,
const bool array, const int arraynum) {
declare(code, fidx, name, "event", array, arraynum, false, 0, 0);
}
void VerilatedSaif::declBit(const uint32_t code, const uint32_t fidx, const char* name,
const int dtypenum, const VerilatedTraceSigDirection,
const VerilatedTraceSigKind, const VerilatedTraceSigType,
const bool array, const int arraynum) {
declare(code, fidx, name, "wire", array, arraynum, false, 0, 0);
}
void VerilatedSaif::declBus(const uint32_t code, const uint32_t fidx, const char* name,
const int dtypenum, const VerilatedTraceSigDirection,
const VerilatedTraceSigKind, const VerilatedTraceSigType,
const bool array, const int arraynum, const int msb, const int lsb) {
declare(code, fidx, name, "wire", array, arraynum, true, msb, lsb);
}
void VerilatedSaif::declQuad(const uint32_t code, const uint32_t fidx, const char* name,
const int dtypenum, const VerilatedTraceSigDirection,
const VerilatedTraceSigKind, const VerilatedTraceSigType,
const bool array, const int arraynum, const int msb, const int lsb) {
declare(code, fidx, name, "wire", array, arraynum, true, msb, lsb);
}
void VerilatedSaif::declArray(const uint32_t code, const uint32_t fidx, const char* name,
const int dtypenum, const VerilatedTraceSigDirection,
const VerilatedTraceSigKind, const VerilatedTraceSigType,
const bool array, const int arraynum, const int msb, const int lsb) {
declare(code, fidx, name, "wire", array, arraynum, true, msb, lsb);
}
void VerilatedSaif::declDouble(const uint32_t code, const uint32_t fidx, const char* name,
const int dtypenum, const VerilatedTraceSigDirection,
const VerilatedTraceSigKind, const VerilatedTraceSigType,
const bool array, const int arraynum) {
declare(code, fidx, name, "real", array, arraynum, false, 63, 0);
}
//=============================================================================
// Get/commit trace buffer
VerilatedSaif::Buffer* VerilatedSaif::getTraceBuffer(uint32_t fidx) { return new Buffer{*this}; }
void VerilatedSaif::commitTraceBuffer(VerilatedSaif::Buffer* bufp) { delete bufp; }
//=============================================================================
//=============================================================================
//=============================================================================
// VerilatedSaifBuffer implementation
//=============================================================================
// emit* trace routines
// Note: emit* are only ever called from one place (full* in
// verilated_trace_imp.h, which is included in this file at the top),
// so always inline them.
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitEvent(const uint32_t code) {
// NOP
}
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitBit(const uint32_t code, const CData newval) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
&& "Activity must be declared earlier");
VerilatedSaifActivityVar& activity
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
activity.emitBit(m_owner.currentTime(), newval);
}
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitCData(const uint32_t code, const CData newval, const int bits) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
&& "Activity must be declared earlier");
VerilatedSaifActivityVar& activity
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
activity.emitData<CData>(m_owner.currentTime(), newval, bits);
}
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitSData(const uint32_t code, const SData newval, const int bits) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
&& "Activity must be declared earlier");
VerilatedSaifActivityVar& activity
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
activity.emitData<SData>(m_owner.currentTime(), newval, bits);
}
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitIData(const uint32_t code, const IData newval, const int bits) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
&& "Activity must be declared earlier");
VerilatedSaifActivityVar& activity
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
activity.emitData<IData>(m_owner.currentTime(), newval, bits);
}
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitQData(const uint32_t code, const QData newval, const int bits) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
&& "Activity must be declared earlier");
VerilatedSaifActivityVar& activity
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
activity.emitData<QData>(m_owner.currentTime(), newval, bits);
}
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitWData(const uint32_t code, const WData* newvalp, const int bits) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
&& "Activity must be declared earlier");
VerilatedSaifActivityVar& activity
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
activity.emitWData(m_owner.currentTime(), newvalp, bits);
}
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitDouble(const uint32_t code, const double newval) {
// NOP
}

292
include/verilated_saif_c.h Normal file
View File

@ -0,0 +1,292 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// Code available from: https://verilator.org
//
// Copyright 2001-2025 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
//
//=============================================================================
///
/// \file
/// \brief Verilated tracing in SAIF format header
///
/// User wrapper code should use this header when creating SAIF traces.
///
//=============================================================================
#ifndef VERILATOR_VERILATED_SAIF_C_H_
#define VERILATOR_VERILATED_SAIF_C_H_
#include "verilated.h"
#include "verilated_trace.h"
#include <string>
#include <unordered_map>
#include <vector>
class VerilatedSaifBuffer;
class VerilatedSaifActivityAccumulator;
class VerilatedSaifActivityScope;
class VerilatedSaifActivityVar;
class VerilatedSaifActivityBit;
//=============================================================================
// VerilatedSaif
// Base class to create a Verilator SAIF dump
// This is an internally used class - see VerilatedSaifC for what to call from applications
class VerilatedSaif VL_NOT_FINAL : public VerilatedTrace<VerilatedSaif, VerilatedSaifBuffer> {
public:
using Super = VerilatedTrace<VerilatedSaif, VerilatedSaifBuffer>;
private:
friend VerilatedSaifBuffer; // Give the buffer access to the private bits
//=========================================================================
// SAIF-specific internals
int m_filep = 0; // File we're writing to
bool m_isOpen = false; // True indicates open file
std::string m_filename; // Filename we're writing to (if open)
std::string m_buffer; // Write data buffer
int m_indent = 0; // Indentation size in spaces
static constexpr size_t WRITE_BUFFER_SIZE = 256 * 1024; // Bytes between write calls
// Currently active scope
VerilatedSaifActivityScope* m_currentScope = nullptr;
// Array of declared scopes
std::vector<std::unique_ptr<VerilatedSaifActivityScope>> m_scopes{};
// Activity accumulators used to store variables statistics over simulation time
std::vector<std::unique_ptr<VerilatedSaifActivityAccumulator>> m_activityAccumulators{};
// Total time of the currently traced simulation
uint64_t m_time = 0;
// Stack of declared scopes combined names
std::vector<std::pair<std::string, VerilatedTracePrefixType>> m_prefixStack{
{"", VerilatedTracePrefixType::SCOPE_MODULE}};
// METHODS
VL_ATTR_ALWINLINE uint64_t currentTime() const { return m_time; }
void initializeSaifFileContents();
void finalizeSaifFileContents();
void recursivelyPrintScopes(const VerilatedSaifActivityScope& scope);
void openInstanceScope(const std::string& instanceName);
void closeInstanceScope();
void printScopeActivities(const VerilatedSaifActivityScope& scope);
bool
printScopeActivitiesFromAccumulatorIfPresent(const std::string& absoluteScopePath,
VerilatedSaifActivityAccumulator& accumulator,
bool anyNetWritten);
void openNetScope();
void closeNetScope();
bool printActivityStats(VerilatedSaifActivityVar& activity, const std::string& activityName,
bool anyNetWritten);
void incrementIndent();
void decrementIndent();
void printIndent();
void printStr(const char* str);
void printStr(const std::string& str);
void writeBuffered(bool force);
void clearCurrentlyCollectedData();
void declare(uint32_t code, uint32_t fidx, const char* name, const char* wirep, bool array,
int arraynum, bool bussed, int msb, int lsb);
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedSaif);
protected:
//=========================================================================
// Implementation of VerilatedTrace interface
// Called when the trace moves forward to a new time point
void emitTimeChange(uint64_t timeui) override;
// Hooks called from VerilatedTrace
bool preFullDump() override { return isOpen(); }
bool preChangeDump() override { return isOpen(); }
// Trace buffer management
Buffer* getTraceBuffer(uint32_t fidx) override;
void commitTraceBuffer(Buffer*) override;
// Configure sub-class
void configure(const VerilatedTraceConfig&) override {}
public:
//=========================================================================
// External interface to client code
// CONSTRUCTOR
explicit VerilatedSaif(void* filep = nullptr);
~VerilatedSaif();
// METHODS - All must be thread safe
// Open the file; call isOpen() to see if errors
void open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex);
// Close the file
void close() VL_MT_SAFE_EXCLUDES(m_mutex);
// Flush any remaining data to this file
void flush() VL_MT_SAFE_EXCLUDES(m_mutex);
// Return if file is open
bool isOpen() const VL_MT_SAFE { return m_isOpen; }
//=========================================================================
// Internal interface to Verilator generated code
void pushPrefix(const std::string&, VerilatedTracePrefixType);
void popPrefix();
void declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum);
void declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum);
void declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum, int msb, int lsb);
void declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum, int msb, int lsb);
void declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum, int msb, int lsb);
void declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
bool array, int arraynum);
};
#ifndef DOXYGEN
// Declare specialization here as it's used in VerilatedSaifC just below
template <>
void VerilatedSaif::Super::dump(uint64_t time);
template <>
void VerilatedSaif::Super::set_time_unit(const char* unitp);
template <>
void VerilatedSaif::Super::set_time_unit(const std::string& unit);
template <>
void VerilatedSaif::Super::set_time_resolution(const char* unitp);
template <>
void VerilatedSaif::Super::set_time_resolution(const std::string& unit);
template <>
void VerilatedSaif::Super::dumpvars(int level, const std::string& hier);
#endif // DOXYGEN
//=============================================================================
// VerilatedSaifBuffer
class VerilatedSaifBuffer VL_NOT_FINAL {
// Give the trace file and sub-classes access to the private bits
friend VerilatedSaif;
friend VerilatedSaif::Super;
friend VerilatedSaif::Buffer;
friend VerilatedSaif::OffloadBuffer;
VerilatedSaif& m_owner; // Trace file owning this buffer. Required by subclasses.
uint32_t m_fidx; // Index of target activity accumulator
// CONSTRUCTORS
explicit VerilatedSaifBuffer(VerilatedSaif& owner)
: m_owner{owner}
, m_fidx{0} {}
explicit VerilatedSaifBuffer(VerilatedSaif& owner, uint32_t fidx)
: m_owner{owner}
, m_fidx{fidx} {}
virtual ~VerilatedSaifBuffer() = default;
//=========================================================================
// 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);
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);
VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int bits);
VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int bits);
VL_ATTR_ALWINLINE void emitWData(uint32_t code, const WData* newvalp, int bits);
VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval);
};
//=============================================================================
// VerilatedSaifC
// Class representing a SAIF dump file in C standalone (no SystemC)
// simulations. Also derived for use in SystemC simulations.
class VerilatedSaifC VL_NOT_FINAL : public VerilatedTraceBaseC {
VerilatedSaif m_sptrace; // Trace file being created
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedSaifC);
public:
// Construct the dump. Optional argument is ignored
explicit VerilatedSaifC(void* filep = nullptr)
: m_sptrace{filep} {}
// Destruct, flush, and close the dump
virtual ~VerilatedSaifC() { close(); }
// METHODS - User called
// Return if file is open
bool isOpen() const override VL_MT_SAFE { return m_sptrace.isOpen(); }
// Open a new SAIF file
// This includes a complete header dump each time it is called,
// just as if this object was deleted and reconstructed.
virtual void open(const char* filename) VL_MT_SAFE { m_sptrace.open(filename); }
void rolloverSize(size_t size) VL_MT_SAFE {} // NOP
// Close dump
void close() VL_MT_SAFE {
m_sptrace.close();
modelConnected(false);
}
// Flush dump
void flush() VL_MT_SAFE { m_sptrace.flush(); }
// Write one cycle of dump data
// Call with the current context's time just after eval'ed,
// e.g. ->dump(contextp->time())
void dump(uint64_t timeui) VL_MT_SAFE { m_sptrace.dump(timeui); }
// Write one cycle of dump data - backward compatible and to reduce
// conversion warnings. It's better to use a uint64_t time instead.
void dump(double timestamp) { dump(static_cast<uint64_t>(timestamp)); }
void dump(uint32_t timestamp) { dump(static_cast<uint64_t>(timestamp)); }
void dump(int timestamp) { dump(static_cast<uint64_t>(timestamp)); }
// METHODS - Internal/backward compatible
// \protectedsection
// Set time units (s/ms, defaults to ns)
// Users should not need to call this, as for Verilated models, these
// propagate from the Verilated default timeunit
void set_time_unit(const char* unit) VL_MT_SAFE { m_sptrace.set_time_unit(unit); }
void set_time_unit(const std::string& unit) VL_MT_SAFE { m_sptrace.set_time_unit(unit); }
// Set time resolution (s/ms, defaults to ns)
// Users should not need to call this, as for Verilated models, these
// propagate from the Verilated default timeprecision
void set_time_resolution(const char* unit) VL_MT_SAFE { m_sptrace.set_time_resolution(unit); }
void set_time_resolution(const std::string& unit) VL_MT_SAFE {
m_sptrace.set_time_resolution(unit);
}
// Set variables to dump, using $dumpvars format
// If level = 0, dump everything and hier is then ignored
void dumpvars(int level, const std::string& hier) VL_MT_SAFE {
m_sptrace.dumpvars(level, hier);
}
// Internal class access
VerilatedSaif* spTrace() { return &m_sptrace; }
};
#endif // guard

View File

@ -0,0 +1,56 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// Copyright 2001-2025 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
//
//=============================================================================
///
/// \file
/// \brief Verilated tracing in SAIF format for SystemC header
///
/// User wrapper code should use this header when creating SAIF SystemC traces.
///
/// This class is not threadsafe, as the SystemC kernel is not threadsafe.
///
//=============================================================================
#ifndef VERILATOR_VERILATED_SAIF_SC_H_
#define VERILATOR_VERILATED_SAIF_SC_H_
#include "verilatedos.h"
#include "verilated_saif_c.h"
#include "verilated_sc_trace.h"
//=============================================================================
// VerilatedSaifSc
/// Trace file used to create SAIF dump for SystemC version of Verilated models. It's very similar
/// to its C version (see the class VerilatedSaifC)
class VerilatedSaifSc final : VerilatedScTraceBase, public VerilatedSaifC {
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedSaifSc);
public:
VerilatedSaifSc() {
spTrace()->set_time_unit(VerilatedScTraceBase::getScTimeUnit());
spTrace()->set_time_resolution(VerilatedScTraceBase::getScTimeResolution());
}
// METHODS
// Override VerilatedSaifC. Must be called after starting simulation.
void open(const char* filename) override VL_MT_SAFE {
VerilatedScTraceBase::checkScElaborationDone();
VerilatedSaifC::open(filename);
}
// METHODS - for SC kernel
// Called from SystemC kernel
void cycle() override { VerilatedSaifC::dump(sc_core::sc_time_stamp().to_double()); }
};
#endif // Guard

View File

@ -175,6 +175,32 @@ package std;
`endif
endtask
// Two process references are equal if the different classes' containing
// m_process are equal. Can't yet use <=> as the base class template
// comparisons doesn't define <=> as they don't yet require --timing and C++20.
`ifdef VERILATOR_TIMING
`systemc_header_post
template<> template<>
inline bool VlClassRef<`systemc_class_name>::operator==(const VlClassRef<`systemc_class_name>& rhs) const {
if (!m_objp && !rhs.m_objp) return true;
if (!m_objp || !rhs.m_objp) return false;
return m_objp->__PVT__m_process == rhs.m_objp->__PVT__m_process;
};
template<> template<>
inline bool VlClassRef<`systemc_class_name>::operator!=(const VlClassRef<`systemc_class_name>& rhs) const {
if (!m_objp && !rhs.m_objp) return false;
if (!m_objp || !rhs.m_objp) return true;
return m_objp->__PVT__m_process != rhs.m_objp->__PVT__m_process;
};
template<> template<>
inline bool VlClassRef<`systemc_class_name>::operator<(const VlClassRef<`systemc_class_name>& rhs) const {
if (!m_objp && !rhs.m_objp) return false;
if (!m_objp || !rhs.m_objp) return false;
return m_objp->__PVT__m_process < rhs.m_objp->__PVT__m_process;
};
`verilog
`endif
// When really implemented, srandom must operate on the process, but for
// now rely on the srandom() that is automatically generated for all
// classes.

View File

@ -26,6 +26,8 @@
#include "verilated_threads.h"
#include <cstdio>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
@ -100,10 +102,153 @@ void VlWorkerThread::startWorker(VlWorkerThread* workerp, VerilatedContext* cont
// VlThreadPool
VlThreadPool::VlThreadPool(VerilatedContext* contextp, unsigned nThreads) {
for (unsigned i = 0; i < nThreads; ++i) m_workers.push_back(new VlWorkerThread{contextp});
for (unsigned i = 0; i < nThreads; ++i) {
m_workers.push_back(new VlWorkerThread{contextp});
m_unassignedWorkers.push(i);
}
m_numaStatus = numaAssign();
}
VlThreadPool::~VlThreadPool() {
// Each ~WorkerThread will wait for its thread to exit.
for (auto& i : m_workers) delete i;
}
bool VlThreadPool::isNumactlRunning() {
// We assume if current thread is CPU-masked, then under numactl, otherwise not.
// This shows that numactl is visible through the affinity mask
#if defined(__linux) || defined(CPU_ZERO) // Linux-like; assume we have pthreads etc
const unsigned num_cpus = std::thread::hardware_concurrency();
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
const int rc = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (rc != 0) return true; // Error; assuming returning true is the least-damage option
for (unsigned c = 0; c < std::min(num_cpus, static_cast<unsigned>(CPU_SETSIZE)); ++c) {
if (!CPU_ISSET(c, &cpuset)) return true;
}
#endif
return false;
}
std::string VlThreadPool::numaAssign() {
#if defined(__linux) || defined(CPU_ZERO) // Linux-like; assume we have pthreads etc
// If not under numactl, make a reasonable processor affinity selection
if (isNumactlRunning()) return "running under numactl"; // User presumably set affinity
const int num_threads = static_cast<int>(m_workers.size());
const int num_proc = static_cast<int>(std::thread::hardware_concurrency());
if (num_threads < 2) return "too few threads";
if (num_threads > num_proc) return "too many threads";
// Read CPU info.
// Uncertain if any modern system has gaps in the processor id (Solaris
// did), but just in case use vectors instead of processor number math.
//
// Currently ignoring socket number "physical id".
// If processor numbers are sequential on sockets, algorithm works out ok.
// If processor numbers are strided on sockets, algorithm also works out ok.
std::ifstream is{"/proc/cpuinfo"};
if (VL_UNLIKELY(!is)) return "%Warning: no /proc/cpuinfo";
std::vector<int> unassigned_processors; // Processors to assign in sorted order
std::map<int, int> processor_core;
std::multimap<int, int> core_processors;
std::set<int> cores;
int processor = -1;
int core = -1;
while (!is.eof()) {
std::string line;
std::getline(is, line);
static std::string::size_type pos = line.find(":");
int number = -1;
if (pos != std::string::npos) number = atoi(line.c_str() + pos + 1);
if (line.compare(0, std::strlen("processor"), "processor") == 0) {
processor = number;
core = -1;
} else if (line.compare(0, std::strlen("core id"), "core id") == 0) {
core = number;
// std::cout << "p" << processor << " socket " << socket << " c" << core << std::endl;
cores.emplace(core);
processor_core[processor] = core;
core_processors.emplace(core, processor);
unassigned_processors.push_back(processor);
}
}
// Start scheduling on the current CPU + 1.
// This will help to land on the same socket as current CPU, and also
// help make sure that different processes have different masks (when
// num_threads is not a common-factor of the processor count).
std::sort(unassigned_processors.begin(), unassigned_processors.end());
{
const int on_cpu = sched_getcpu(); // TODO: this is a system call. Not exactly cheap.
bool hit = false;
std::vector<int> new_front;
std::vector<int> new_back;
for (const int processor : unassigned_processors) {
if (hit) {
new_front.push_back(processor);
} else {
new_back.push_back(processor);
}
if (processor == on_cpu) hit = true;
}
unassigned_processors = new_front;
unassigned_processors.insert(unassigned_processors.end(), new_back.begin(),
new_back.end());
}
// If less threads than cores, we can schedule per-core
const bool core_per_thread = num_threads <= cores.size();
// Compute core mapping
std::multimap<int, int> thread_processors;
{
std::set<int> assigned_processors;
int thread = 0;
for (const int processor : unassigned_processors) {
// Find free processor, the current thread can use that
if (assigned_processors.find(processor) != assigned_processors.end()) continue;
assigned_processors.emplace(processor);
thread_processors.emplace(thread, processor);
if (core_per_thread) {
// Also include all other processors same core,
// so that another thread doesn't land on different processor in same core
const int core = processor_core[processor];
const auto bounds = core_processors.equal_range(core);
for (auto it{bounds.first}; it != bounds.second; ++it) {
if (assigned_processors.find(it->second) != assigned_processors.end())
continue;
if (it->second == processor) continue;
thread_processors.emplace(thread, it->second);
assigned_processors.emplace(it->second);
}
}
// Prepare for next loop
thread = (thread + 1) % num_threads;
}
}
// Set affinity
std::string status = "assigned ";
for (int thread = 0; thread < num_threads; ++thread) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
const auto bounds = thread_processors.equal_range(thread);
for (auto it{bounds.first}; it != bounds.second; ++it) {
if (it != bounds.first) status += ',';
status += std::to_string(it->second);
CPU_SET(it->second, &cpuset);
}
status += ";";
const int rc = pthread_setaffinity_np(m_workers[thread]->m_cthread.native_handle(),
sizeof(cpu_set_t), &cpuset);
if (rc != 0) return "%Warning: pthread_setaffinity_np failed";
}
// std::cout << "Status: " << status << std::endl;
return status;
#else
return "non-supported host OS";
#endif
}

View File

@ -30,18 +30,10 @@
#include <atomic>
#include <condition_variable>
#include <set>
#include <stack>
#include <thread>
#include <vector>
// clang-format off
#if defined(__linux)
# include <sched.h> // For sched_getcpu()
#endif
#if defined(__APPLE__) && !defined(__arm64__)
# include <cpuid.h> // For __cpuid_count()
#endif
// clang-format on
class VlExecutionProfiler;
class VlThreadPool;
@ -155,6 +147,10 @@ private:
VL_UNCOPYABLE(VlWorkerThread);
protected:
friend class VlThreadPool;
const std::thread& cthread() const { return m_cthread; }
public:
// CONSTRUCTORS
explicit VlWorkerThread(VerilatedContext* contextp);
@ -205,6 +201,13 @@ class VlThreadPool final : public VerilatedVirtualBase {
// MEMBERS
std::vector<VlWorkerThread*> m_workers; // our workers
mutable VerilatedMutex m_mutex; // Guards indexes of unassigned workers
// Indexes of unassigned workers
std::stack<size_t> m_unassignedWorkers VL_GUARDED_BY(m_mutex);
// For sequentially generating task IDs to avoid shadowing
std::atomic<unsigned> m_assignedTasks{0};
std::string m_numaStatus; // Status of NUMA assignment
public:
// CONSTRUCTORS
// Construct a thread pool with 'nThreads' dedicated threads. The thread
@ -214,7 +217,21 @@ public:
~VlThreadPool() override;
// METHODS
size_t assignWorkerIndex() {
const VerilatedLockGuard lock{m_mutex};
assert(!m_unassignedWorkers.empty());
const size_t index = m_unassignedWorkers.top();
m_unassignedWorkers.pop();
return index;
}
void freeWorkerIndexes(std::vector<size_t>& indexes) {
const VerilatedLockGuard lock{m_mutex};
for (size_t index : indexes) m_unassignedWorkers.push(index);
indexes.clear();
}
unsigned assignTaskIndex() { return m_assignedTasks++; }
int numThreads() const { return static_cast<int>(m_workers.size()); }
std::string numaStatus() const { return m_numaStatus; }
VlWorkerThread* workerp(int index) {
assert(index >= 0);
assert(index < static_cast<int>(m_workers.size()));
@ -223,6 +240,9 @@ public:
private:
VL_UNCOPYABLE(VlThreadPool);
static bool isNumactlRunning();
std::string numaAssign();
};
#endif

View File

@ -184,8 +184,11 @@ public:
// Word at given 'wordIndex'
uint64_t word(size_t wordIndex) const { return m_flags[wordIndex]; }
// Set specified flag to given value
void set(size_t index, bool value) {
// Set specified word to given value
void setWord(size_t wordIndex, uint64_t value) { m_flags[wordIndex] = value; }
// Set specified bit to given value
void setBit(size_t index, bool value) {
uint64_t& w = m_flags[index / 64];
const size_t bitIndex = index % 64;
w &= ~(1ULL << bitIndex);
@ -618,11 +621,13 @@ public:
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())) {
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
if (index == m_deque.size()) {
push_back(atDefault());
return m_deque[index];
}
t_throwAway = atDefault();
return t_throwAway;
} else if (VL_UNLIKELY(index == m_deque.size())) {
push_back(atDefault());
}
return m_deque[index];
}
@ -921,6 +926,9 @@ std::string VL_TO_STRING(const VlQueue<T_Value, N_MaxSize>& obj) {
return obj.to_string();
}
template <typename T_Value, size_t N_MaxSize>
struct VlContainsCustomStruct<VlQueue<T_Value, N_MaxSize>> : VlContainsCustomStruct<T_Value> {};
//===================================================================
// Verilog associative array container
// There are no multithreaded locks on this; the base variable must
@ -1256,6 +1264,9 @@ std::string VL_TO_STRING(const VlAssocArray<T_Key, T_Value>& obj) {
return obj.to_string();
}
template <typename T_Key, typename T_Value>
struct VlContainsCustomStruct<VlAssocArray<T_Key, T_Value>> : VlContainsCustomStruct<T_Key> {};
template <typename T_Key, typename T_Value>
void VL_READMEM_N(bool hex, int bits, const std::string& filename,
VlAssocArray<T_Key, T_Value>& obj, QData start, QData end) VL_MT_SAFE {
@ -1586,6 +1597,9 @@ std::string VL_TO_STRING(const VlUnpacked<T_Value, N_Depth>& obj) {
return obj.to_string();
}
template <typename T, int N>
struct VlContainsCustomStruct<VlUnpacked<T, N>> : VlContainsCustomStruct<T> {};
//===================================================================
// Helper to apply the given indices to a target expression

View File

@ -15,9 +15,9 @@
/// \brief Verilated C++ tracing in VCD format implementation code
///
/// This file must be compiled and linked against all Verilated objects
/// that use --trace.
/// that use --trace-vcd.
///
/// Use "verilator --trace" to add this to the Makefile for the linker.
/// Use "verilator --trace-vcd" to add this to the Makefile for the linker.
///
//=============================================================================
@ -100,6 +100,8 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) {
m_wrBufp = new char[m_wrChunkSize * 8];
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
m_writep = m_wrBufp;
m_wrTimeBeginp = nullptr;
m_wrTimeEndp = nullptr;
}
void VerilatedVcd::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
@ -187,10 +189,19 @@ bool VerilatedVcd::preChangeDump() {
}
void VerilatedVcd::emitTimeChange(uint64_t timeui) {
printStr("#");
const std::string str = std::to_string(timeui);
printStr(str.c_str());
printStr("\n");
// Remember pointers when last emitted time stamp; if last output was
// timestamp backup and overwrite it.
// This is faster then checking on every signal change if time needs to
// be emitted. Note buffer flushes may still emit a rare duplicate.
if (m_wrTimeEndp == m_writep) m_writep = m_wrTimeBeginp;
m_wrTimeBeginp = m_writep;
{
printStr("#");
const std::string str = std::to_string(timeui);
printStr(str.c_str());
printStr("\n");
}
m_wrTimeEndp = m_writep;
}
VerilatedVcd::~VerilatedVcd() {
@ -257,6 +268,10 @@ void VerilatedVcd::bufferResize(size_t minsize) {
m_wrBufp = new char[m_wrChunkSize * 8];
std::memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
m_writep = m_wrBufp + (m_writep - oldbufp);
if (m_wrTimeBeginp) {
m_wrTimeBeginp = m_wrBufp + (m_wrTimeBeginp - oldbufp);
m_wrTimeEndp = m_wrBufp + (m_wrTimeEndp - oldbufp);
}
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
VL_DO_CLEAR(delete[] oldbufp, oldbufp = nullptr);
}
@ -293,6 +308,8 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
// Reset buffer
m_writep = m_wrBufp;
m_wrTimeBeginp = nullptr;
m_wrTimeEndp = nullptr;
}
//=============================================================================

View File

@ -55,6 +55,8 @@ private:
char* m_wrBufp; // Output buffer
char* m_wrFlushp; // Output buffer flush trigger location
char* m_writep; // Write pointer into output buffer
char* m_wrTimeBeginp = nullptr; // Write pointer for last time dump
char* m_wrTimeEndp = nullptr; // Write pointer for last time dump
size_t m_wrChunkSize; // Output buffer size
size_t m_maxSignalBytes = 0; // Upper bound on number of bytes a single signal can generate
uint64_t m_wroteBytes = 0; // Number of bytes written to this file

View File

@ -85,7 +85,7 @@ public:
// To simplify our free list, we use a size large enough for all derived types
// We reserve word zero for the next pointer, as that's safer in case a
// dangling reference to the original remains around.
static constexpr size_t CHUNK_SIZE = 128;
static constexpr size_t CHUNK_SIZE = 256;
if (VL_UNCOVERABLE(size > CHUNK_SIZE))
VL_FATAL_MT(__FILE__, __LINE__, "", "increase CHUNK_SIZE");
if (VL_LIKELY(t_freeHeadp)) {
@ -421,7 +421,7 @@ public:
const char* fullname() const override {
static thread_local std::string t_out;
t_out = std::string{scopep()->name()} + "." + name();
for (auto idx : index()) { t_out += "[" + std::to_string(idx) + "]"; }
for (auto idx : index()) t_out += "[" + std::to_string(idx) + "]";
return t_out.c_str();
}
void* prevDatap() const { return m_prevDatap; }
@ -873,6 +873,7 @@ class VerilatedVpiImp final {
// All only medium-speed, so use singleton function
// Callbacks that are past or at current timestamp
std::array<VpioCbList, CB_ENUM_MAX_VALUE> m_cbCurrentLists;
VpioCbList m_cbCallList; // List of callbacks currently being called by callCbs
VpioFutureCbs m_futureCbs; // Time based callbacks for future timestamps
VpioFutureCbs m_nextCbs; // cbNextSimTime callbacks
std::list<VerilatedVpiPutHolder> m_inertialPuts; // Pending vpi puts due to vpiInertialDelay
@ -925,7 +926,13 @@ public:
for (auto& ir : s().m_cbCurrentLists[reason]) {
if (ir.id() == id) {
ir.invalidate();
return; // Once found, it won't also be in m_futureCbs
return; // Once found, it won't also be in m_cbCallList, m_futureCbs, or m_nextCbs
}
}
for (auto& ir : s().m_cbCallList) {
if (ir.id() == id) {
ir.invalidate();
return; // Once found, it won't also be in m_futureCbs or m_nextCbs
}
}
{ // Remove from cbFuture queue
@ -985,10 +992,9 @@ public:
moveFutureCbs();
if (s().m_cbCurrentLists[reason].empty()) return false;
// Iterate on old list, making new list empty, to prevent looping over newly added elements
VpioCbList cbObjList;
std::swap(s().m_cbCurrentLists[reason], cbObjList);
std::swap(s().m_cbCurrentLists[reason], s().m_cbCallList);
bool called = false;
for (VerilatedVpiCbHolder& ihor : cbObjList) {
for (VerilatedVpiCbHolder& ihor : s().m_cbCallList) {
// cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
if (VL_LIKELY(!ihor.invalid())) { // Not deleted earlier
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: reason_callback reason=%d id=%" PRId64 "\n",
@ -998,6 +1004,7 @@ public:
called = true;
}
}
s().m_cbCallList.clear();
return called;
}
static bool callValueCbs() VL_MT_UNSAFE_ONE {
@ -2567,8 +2574,8 @@ void vl_vpi_put_word(const VerilatedVpioVar* vop, QData word, size_t bitCount, s
}
void vl_vpi_get_value(const VerilatedVpioVarBase* vop, p_vpi_value valuep) {
const VerilatedVar* varp = vop->varp();
void* varDatap = vop->varDatap();
const VerilatedVar* const varp = vop->varp();
void* const varDatap = vop->varDatap();
const char* fullname = vop->fullname();
if (!vl_check_format(varp, valuep, fullname, true)) return;
@ -2781,8 +2788,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
} else if (valuep->format == vpiOctStrVal) {
const int len = std::strlen(valuep->value.str);
for (int i = 0; i < len; ++i) {
char digit = valuep->value.str[len - i - 1] - '0';
if (digit < 0 || digit > 7) {
unsigned char digit = valuep->value.str[len - i - 1] - '0';
if (digit > 7) { // If str was < '0', then as unsigned, digit > 7
VL_VPI_WARNING_(__FILE__, __LINE__,
"%s: Non octal character '%c' in '%s' as value %s for %s",
__func__, digit + '0', valuep->value.str,
@ -2973,7 +2980,6 @@ void vl_get_value_array_vectors(unsigned index, const unsigned num, const unsign
"type T is not unsigned"); // ensure logical right shift
const unsigned element_size_bytes = VL_BYTES_I(packedSize);
const unsigned element_size_words = VL_WORDS_I(packedSize);
const unsigned element_size_repr = (element_size_bytes + sizeof(T) - 1) / sizeof(T);
if (sizeof(T) == sizeof(QData)) {
for (unsigned i = 0; i < num; i++) {
dst[i * 2].aval = static_cast<QData>(src[index]);
@ -3095,7 +3101,7 @@ void vl_put_value_array_rawvals(unsigned index, const unsigned num, const unsign
}
}
void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_INT32* index_p,
void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, const PLI_INT32* index_p,
PLI_UINT32 num) {
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
if (!vl_check_array_format(vop->varp(), arrayvalue_p, vop->fullname())) return;
@ -3112,7 +3118,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_INT
}
const bool leftIsLow = vop->rangep()->left() == vop->rangep()->low();
int index
const int index
= leftIsLow ? index_p[0] - vop->rangep()->left() : vop->rangep()->left() - index_p[0];
if (arrayvalue_p->format == vpiShortIntVal) {
@ -3303,9 +3309,8 @@ void vpi_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_IN
return;
}
int lowRange = vop->rangep()->low();
int highRange = vop->rangep()->high();
const int lowRange = vop->rangep()->low();
const int highRange = vop->rangep()->high();
if ((index_p[0] > highRange) || (index_p[0] < lowRange)) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: index %u for object %s is out of bounds [%u,%u]",
__func__, index_p[0], vop->fullname(), lowRange, highRange);
@ -3321,14 +3326,14 @@ void vpi_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_IN
vl_get_value_array(object, arrayvalue_p, index_p, num);
}
void vl_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_INT32* index_p,
void vl_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, const PLI_INT32* index_p,
PLI_UINT32 num) {
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
if (!vl_check_array_format(vop->varp(), arrayvalue_p, vop->fullname())) return;
const VerilatedVar* const varp = vop->varp();
int size = vop->size();
const int size = vop->size();
if (VL_UNCOVERABLE(num > size)) {
VL_VPI_ERROR_(__FILE__, __LINE__,
"%s: requested elements to set (%u) exceed array size (%u)", __func__, num,
@ -3337,7 +3342,7 @@ void vl_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_INT
}
const bool leftIsLow = vop->rangep()->left() == vop->rangep()->low();
int index
const int index
= leftIsLow ? index_p[0] - vop->rangep()->left() : vop->rangep()->left() - index_p[0];
if (arrayvalue_p->format == vpiShortIntVal) {
@ -3485,11 +3490,8 @@ void vpi_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_IN
return;
}
const VerilatedVar* const varp = vop->varp();
int lowRange = vop->rangep()->low();
int highRange = vop->rangep()->high();
const int lowRange = vop->rangep()->low();
const int highRange = vop->rangep()->high();
if ((index_p[0] > highRange) || (index_p[0] < lowRange)) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: index %u for object %s is out of bounds [%u,%u]",
__func__, index_p[0], vop->fullname(), lowRange, highRange);

View File

@ -632,7 +632,12 @@ namespace VlOs {
/// Get environment variable
extern std::string getenvStr(const std::string& envvar,
const std::string& defaultValue) VL_MT_SAFE;
extern uint64_t memUsageBytes() VL_MT_SAFE; ///< Return memory usage in bytes, or 0 if unknown
/// Return currently executing processor number; may do an OS call underneath so slow
extern uint16_t getcpu() VL_MT_SAFE;
/// Return memory usage in bytes, or 0 if unknown
extern uint64_t memUsageBytes() VL_MT_SAFE;
// Internal: Record CPU time, starting point on construction, and current delta from that
class DeltaCpuTime final {

View File

@ -31,6 +31,13 @@
# include <processthreadsapi.h> // GetProcessTimes
# include <psapi.h> // GetProcessMemoryInfo
#endif
#if defined(__linux)
# include <sched.h> // For sched_getcpu()
#endif
#if defined(__APPLE__) && !defined(__arm64__)
# include <cpuid.h> // For __cpuid_count()
#endif
// clang-format on
namespace VlOs {
@ -72,6 +79,28 @@ double DeltaWallTime::gettime() VL_MT_SAFE {
#endif
}
//=============================================================================
// Vlos::getcpu implementation
uint16_t getcpu() VL_MT_SAFE {
#if defined(__linux)
return sched_getcpu(); // TODO: this is a system call. Not exactly cheap.
#elif defined(__APPLE__) && !defined(__arm64__)
uint32_t info[4];
__cpuid_count(1, 0, info[0], info[1], info[2], info[3]);
// info[1] is EBX, bits 24-31 are APIC ID
if ((info[3] & (1 << 9)) == 0) {
return 0; // no APIC on chip
} else {
return (unsigned)info[1] >> 24;
}
#elif defined(_WIN32)
return GetCurrentProcessorNumber();
#else
return 0;
#endif
}
//=========================================================================
// VlOs::memUsageBytes implementation

31
include/vltstd/veriuser.h Normal file
View File

@ -0,0 +1,31 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Code available from: https://verilator.org
//
// Copyright 2009-2025 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
//
//=========================================================================
///
/// \file
/// \brief Verilated user tf_routines
///
/// This file contains routines to interface user VPI/PLI C++ code with
/// Verilator. Traditionally the veriuser.h code has been used for only
/// tf_ routines, which verilator does not implement, so this file is
/// empty.
///
/// User code relying on tf_ routines should migrate to VPI (vpi_user.h) or
/// DPI (svdpi.h) routines.
///
/// This file is only provided for backwards compatibility for applications
/// which include veriuser.h even though they use only vpi_ or dpi_
/// routines.
///
//=========================================================================
// Intentionally empty, see above.

View File

@ -90,7 +90,7 @@ def process():
print()
print("You may now want to clean up spelling, and commit:")
print(" (cd docs ; make spelling)")
print(" (cd docs ; make spelling | grep -vi 'writing output')")
print(" git ci -am 'Commentary: Changes update'")
print()

241
nodist/verilator_saif_diff Executable file
View File

@ -0,0 +1,241 @@
#!/usr/bin/env python3
# pylint: disable=C0114,C0115,C0116,R0902,R0903,R0912,R0915,W0719,W0718
######################################################################
#
# Copyright 2025 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
import argparse
import re
SUCCESS_CODE = 0
FAILURE_CODE = 1
INSTANCE_TYPE = "INSTANCE"
NET_LIST_TYPE = "NET"
SIGNAL_TYPE = "SIGNAL"
EOF_ERROR = "Unexpected EOF"
def saif_assert(expression, message):
if not expression:
raise Exception(message)
def saif_error(message):
raise Exception(message)
class SAIFSignalBit:
name: str
high_time: int
low_time: int
transitions: int
def __init__(self, name):
self.name = name
self.high_time = 0
self.low_time = 0
self.transitions = 0
class SAIFInstance:
def __init__(self, scope_name):
self.scope_name = scope_name
self.parent_instance = None
self.nets = {}
self.child_instances = {}
class SAIFToken:
def __init__(self, token):
self.token = token
self.type = ''
self.value = ''
class SAIFParser:
def __init__(self):
self.token_stack = []
# For parsing simplicity
self.token_stack.append(SAIFToken('saif_root'))
self.current_instance = None
self.has_saifile_header = False
self.direction = ''
self.saif_version = ''
self.top_instances = {}
self.duration = 0
self.divider = ''
self.timescale = ''
def parse(self, saif_filename):
file_contents = ''
with open(saif_filename, 'r', encoding="utf8") as saif_file:
content = saif_file.readlines()
filtered_lines = [line for line in content if not line.strip().startswith('//')]
file_contents = ''.join(filtered_lines)
tokens = file_contents.replace('(', ' ( ').replace(')', ' ) ').split()
num_of_tokens = len(tokens)
index = 0
while index < num_of_tokens:
token = tokens[index]
index += 1
if token == '(':
self.token_stack.append(SAIFToken(token))
self.token_stack[-1].type = self.token_stack[-2].type
self.token_stack[-1].value = self.token_stack[-2].value
continue
if token == ')':
if self.token_stack[-1].type == INSTANCE_TYPE:
self.current_instance = self.current_instance.parent_instance
self.token_stack.pop()
continue
if re.match(r'SAIFILE', token):
self.has_saifile_header = True
continue
if re.match(r'DIRECTION', token):
saif_assert(index < num_of_tokens, EOF_ERROR)
self.direction = tokens[index].replace('\"', '')
index += 1
continue
if re.match(r'SAIFVERSION', token):
saif_assert(index < num_of_tokens, EOF_ERROR)
self.saif_version = tokens[index].replace('\"', '')
index += 1
continue
if re.match(r'DESIGN|DATE|VENDOR|PROGRAM_NAME|VERSION', token):
# NOP, only skip value
saif_assert(index < num_of_tokens, EOF_ERROR)
index += 1
continue
if re.match(r'DIVIDER', token):
saif_assert(index < num_of_tokens, EOF_ERROR)
self.divider = tokens[index]
index += 1
continue
if re.match(r'TIMESCALE', token):
saif_assert(index < num_of_tokens, EOF_ERROR)
self.timescale = tokens[index]
index += 1
continue
if re.match(r'DURATION', token):
saif_assert(index < num_of_tokens, EOF_ERROR)
self.duration = tokens[index]
index += 1
continue
if re.match(r'INSTANCE', token):
saif_assert(index < num_of_tokens, EOF_ERROR)
instance_name = tokens[index]
index += 1
self.token_stack[-1].type = INSTANCE_TYPE
self.token_stack[-1].value = instance_name
instance = SAIFInstance(instance_name)
if self.current_instance is None:
self.top_instances[instance_name] = instance
else:
self.current_instance.child_instances[instance_name] = instance
instance.parent_instance = self.current_instance
self.current_instance = instance
continue
if re.match(r'NET', token):
self.token_stack[-1].type = NET_LIST_TYPE
continue
if re.match(r'T1', token):
net_name = self.token_stack[-1].value
saif_assert(index < num_of_tokens, EOF_ERROR)
self.current_instance.nets[net_name].high_time = tokens[index]
index += 1
continue
if re.match(r'T0', token):
net_name = self.token_stack[-1].value
saif_assert(index < num_of_tokens, EOF_ERROR)
self.current_instance.nets[net_name].low_time = tokens[index]
index += 1
continue
if re.match(r'TC', token):
net_name = self.token_stack[-1].value
saif_assert(index < num_of_tokens, EOF_ERROR)
self.current_instance.nets[net_name].transitions = tokens[index]
index += 1
continue
if re.match(r'TZ|TX|TB|TG|IG|IK', token):
# NOP, only skip value
index += 1
continue
if self.token_stack[-2].type == NET_LIST_TYPE:
self.token_stack[-1].type = SIGNAL_TYPE
self.token_stack[-1].value = token
self.current_instance.nets[token] = SAIFSignalBit(token)
saif_assert(self.has_saifile_header, "SAIF file doesn't contain a SAIFILE keyword")
saif_assert(self.direction == "backward",
f"SAIF file doesn't have a valid/compatible direction: {self.direction}")
saif_assert(self.saif_version == "2.0",
f"SAIF file doesn't have a valid/compatible version: {self.saif_version}")
# Only 'saif_root' token should be left
saif_assert(len(self.token_stack) == 1, "Incorrect nesting of scopes")
def compare_saif_instances(first: SAIFInstance, second: SAIFInstance):
if len(first.nets) != len(second.nets):
saif_error(f"Number of nets doesn't match in {first.scope_name}: "
f"{len(first.nets)} != {len(second.nets)}")
for signal_name, saif_signal in first.nets.items():
if signal_name not in second.nets:
saif_error(f"Signal {signal_name} doesn't exist in the second object\n")
other_signal = second.nets[signal_name]
if (saif_signal.high_time != other_signal.high_time
or saif_signal.low_time != other_signal.low_time
or saif_signal.transitions != other_signal.transitions):
saif_error("Incompatible signal bit parameters in "
f"{signal_name}\n")
if len(first.child_instances) != len(second.child_instances):
saif_error(f"Number of child instances doesn't match in {first.scope_name}: "
f"{len(first.child_instances)} != {len(second.child_instances)}")
for instance_name, instance in first.child_instances.items():
if instance_name not in second.child_instances:
saif_error(f"Instance {instance_name} doesn't exist in the second object\n")
compare_saif_instances(instance, second.child_instances[instance_name])
def compare_saif_contents(first_file: str, second_file: str):
"""Test if second SAIF file has the same values as the first"""
first_saif = SAIFParser()
first_saif.parse(first_file)
second_saif = SAIFParser()
second_saif.parse(second_file)
if first_saif.duration != second_saif.duration:
saif_error("Duration of trace doesn't match: "
f"{first_saif.duration} != {second_saif.duration}")
if first_saif.divider != second_saif.divider:
saif_error(f"Dividers don't match: {first_saif.divider} != {second_saif.divider}")
if first_saif.timescale != second_saif.timescale:
saif_error(f"Timescale doesn't match: {first_saif.timescale} != {second_saif.timescale}")
if len(first_saif.top_instances) != len(second_saif.top_instances):
saif_error("Number of top instances doesn't match: "
f"{len(first_saif.top_instances)} != {len(second_saif.top_instances)}")
for top_instance_name, top_instance in first_saif.top_instances.items():
if top_instance_name not in second_saif.top_instances:
saif_error(f"Top instance {top_instance_name} missing in other SAIF")
compare_saif_instances(top_instance, second_saif.top_instances[top_instance_name])
return SUCCESS_CODE
parser = argparse.ArgumentParser(allow_abbrev=False,
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""verilator_saif_diff checks if two SAIF files are logically-identical. It returns first encountered difference as output.
Run as:
cd $VERILATOR_ROOT
nodist/code_coverage --first example.saif --second other.saif""")
parser.add_argument('--first', action='store', help='First SAIF file')
parser.add_argument('--second', action='store', help='Second SAIF file')
parser.set_defaults(stop=True)
args = parser.parse_args()
try:
compare_saif_contents(args.first, args.second)
except Exception as error:
print(error)

View File

@ -85,6 +85,7 @@ set(HEADERS
V3EmitCMain.h
V3EmitCMake.h
V3EmitMk.h
V3EmitMkJson.h
V3EmitV.h
V3EmitXml.h
V3Error.h
@ -177,6 +178,7 @@ set(HEADERS
V3Trace.h
V3TraceDecl.h
V3Tristate.h
V3Udp.h
V3Undriven.h
V3UniqueNames.h
V3Unknown.h
@ -246,6 +248,7 @@ set(COMMON_SOURCES
V3EmitCPch.cpp
V3EmitCSyms.cpp
V3EmitMk.cpp
V3EmitMkJson.cpp
V3EmitV.cpp
V3EmitXml.cpp
V3Error.cpp
@ -324,6 +327,7 @@ set(COMMON_SOURCES
V3TraceDecl.cpp
V3Tristate.cpp
V3TSP.cpp
V3Udp.cpp
V3Undriven.cpp
V3Unknown.cpp
V3Unroll.cpp

View File

@ -253,6 +253,7 @@ RAW_OBJS_PCH_ASTNOMT = \
V3EmitCModel.o \
V3EmitCSyms.o \
V3EmitMk.o \
V3EmitMkJson.o \
V3EmitXml.o \
V3ExecGraph.o \
V3Expand.o \
@ -310,6 +311,7 @@ RAW_OBJS_PCH_ASTNOMT = \
V3Trace.o \
V3TraceDecl.o \
V3Tristate.o \
V3Udp.o \
V3Undriven.o \
V3Unknown.o \
V3Unroll.o \

View File

@ -239,7 +239,7 @@ public:
// Make a new AstActive sensitive to the given sentree and return it
AstActive* makeActive(FileLine* const fl, AstSenTree* const senTreep) {
auto* const activep = new AstActive{fl, "", senTreep};
AstActive* const activep = new AstActive{fl, "", senTreep};
activep->sensesStorep(activep->sensesp());
addActive(activep);
return activep;
@ -314,7 +314,7 @@ class ActiveLatchCheckVisitor final : public VNVisitorConst {
void visit(AstVarRef* nodep) override {
const AstVar* const varp = nodep->varp();
if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()
&& !varp->isFuncLocalSticky()) {
&& !varp->isFuncLocalSticky() && !varp->lifetime().isAutomatic()) {
m_graph.addAssignment(nodep);
}
}
@ -572,8 +572,8 @@ class ActiveVisitor final : public VNVisitor {
m_clockedProcess = true;
if (nodep->edgeType() != VEdgeType::ET_CHANGED) m_allChanged = false;
if (const auto* const dtypep = nodep->sensp()->dtypep()) {
if (const auto* const basicp = dtypep->basicp()) {
if (const AstNodeDType* const dtypep = nodep->sensp()->dtypep()) {
if (const AstBasicDType* const basicp = dtypep->basicp()) {
if (basicp->isEvent()) nodep->edgeType(VEdgeType::ET_EVENT);
}
}

View File

@ -143,7 +143,7 @@ class AssertVisitor final : public VNVisitor {
}
}
AstSampled* newSampledExpr(AstNodeExpr* nodep) {
const auto sampledp = new AstSampled{nodep->fileline(), nodep};
AstSampled* const sampledp = new AstSampled{nodep->fileline(), nodep};
sampledp->dtypeFrom(nodep);
return sampledp;
}
@ -153,7 +153,7 @@ class AssertVisitor final : public VNVisitor {
nodep->findUInt64DType()};
v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(m_monitorNumVarp);
}
const auto varrefp = new AstVarRef{nodep->fileline(), m_monitorNumVarp, access};
AstVarRef* const varrefp = new AstVarRef{nodep->fileline(), m_monitorNumVarp, access};
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
return varrefp;
}
@ -163,7 +163,7 @@ class AssertVisitor final : public VNVisitor {
nodep->findBitDType()};
v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(m_monitorOffVarp);
}
const auto varrefp = new AstVarRef{nodep->fileline(), m_monitorOffVarp, access};
AstVarRef* const varrefp = new AstVarRef{nodep->fileline(), m_monitorOffVarp, access};
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
return varrefp;
}
@ -528,7 +528,7 @@ class AssertVisitor final : public VNVisitor {
replaceDisplay(nodep, "%%Fatal");
} else if (nodep->displayType() == VDisplayType::DT_MONITOR) {
nodep->displayType(VDisplayType::DT_DISPLAY);
const auto fl = nodep->fileline();
FileLine* const fl = nodep->fileline();
AstNode* monExprsp = nodep->fmtp()->exprsp();
AstSenItem* monSenItemsp = nullptr;
while (monExprsp) {
@ -548,8 +548,8 @@ class AssertVisitor final : public VNVisitor {
AstSenTree* const monSenTree = new AstSenTree{fl, monSenItemsp};
const auto monNum = ++m_monitorNum;
// Where $monitor was we do "__VmonitorNum = N;"
const auto newsetp = new AstAssign{fl, newMonitorNumVarRefp(nodep, VAccess::WRITE),
new AstConst{fl, monNum}};
AstAssign* const newsetp = new AstAssign{
fl, newMonitorNumVarRefp(nodep, VAccess::WRITE), new AstConst{fl, monNum}};
nodep->replaceWith(newsetp);
// Add "always_comb if (__VmonitorOn && __VmonitorNum==N) $display(...);"
AstNode* const stmtsp = nodep;
@ -566,14 +566,14 @@ class AssertVisitor final : public VNVisitor {
} else if (nodep->displayType() == VDisplayType::DT_STROBE) {
nodep->displayType(VDisplayType::DT_DISPLAY);
// Need one-shot
const auto fl = nodep->fileline();
const auto varp
FileLine* const fl = nodep->fileline();
AstVar* const varp
= new AstVar{fl, VVarType::MODULETEMP, "__Vstrobe" + cvtToStr(m_modStrobeNum++),
nodep->findBitDType()};
m_modp->addStmtsp(varp);
// Where $strobe was we do "__Vstrobe = '1;"
const auto newsetp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitTrue{}}};
AstAssign* const newsetp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitTrue{}}};
nodep->replaceWith(newsetp);
// Add "always_comb if (__Vstrobe) begin $display(...); __Vstrobe = '0; end"
AstNode* const stmtsp = nodep;
@ -587,7 +587,7 @@ class AssertVisitor final : public VNVisitor {
}
}
void visit(AstMonitorOff* nodep) override {
const auto newp
AstAssign* const newp
= new AstAssign{nodep->fileline(), newMonitorOffVarRefp(nodep, VAccess::WRITE),
new AstConst{nodep->fileline(), AstConst::BitTrue{}, nodep->off()}};
nodep->replaceWith(newp);

View File

@ -95,10 +95,10 @@ private:
if (const AstVarRef* varrefp = VN_CAST(nodep, VarRef)) {
if (varp == varrefp->varp()) nodep->replaceWith(exprp->cloneTree(false));
}
replaceVarRefsWithExprRecurse(nodep->op1p(), varp, exprp);
replaceVarRefsWithExprRecurse(nodep->op2p(), varp, exprp);
replaceVarRefsWithExprRecurse(nodep->op3p(), varp, exprp);
replaceVarRefsWithExprRecurse(nodep->op4p(), varp, exprp);
if (AstNode* const refp = nodep->op1p()) replaceVarRefsWithExprRecurse(refp, varp, exprp);
if (AstNode* const refp = nodep->op2p()) replaceVarRefsWithExprRecurse(refp, varp, exprp);
if (AstNode* const refp = nodep->op3p()) replaceVarRefsWithExprRecurse(refp, varp, exprp);
if (AstNode* const refp = nodep->op4p()) replaceVarRefsWithExprRecurse(refp, varp, exprp);
}
AstPropSpec* substitutePropertyCall(AstPropSpec* nodep) {
if (AstFuncRef* const funcrefp = VN_CAST(nodep->propp(), FuncRef)) {
@ -295,7 +295,7 @@ private:
popp->makeStmt()});
}
} else {
nodep->v3fatal("Invalid direction");
nodep->v3fatalSrc("Invalid direction");
}
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
}

View File

@ -64,10 +64,12 @@ std::ostream& operator<<(std::ostream& os, VNType rhs);
const std::shared_ptr<const string> VSelfPointerText::s_emptyp = std::make_shared<string>("");
const std::shared_ptr<const string> VSelfPointerText::s_thisp = std::make_shared<string>("this");
string VSelfPointerText::replaceThis(bool useSelfForThis, const string& text) {
return useSelfForThis ? VString::replaceWord(text, "this", "vlSelf") : text;
}
string VSelfPointerText::protect(bool useSelfForThis, bool protect) const {
const string& sp
= useSelfForThis ? VString::replaceWord(asString(), "this", "vlSelf") : asString();
return VIdProtect::protectWordsIf(sp, protect);
return VIdProtect::protectWordsIf(replaceThis(useSelfForThis, asString()), protect);
}
//######################################################################
@ -228,7 +230,7 @@ string AstNode::vpiName(const string& namein) {
// we change that identifier to an escaped identifier, wrapping it with '\' and ' '
// as specified in LRM 23.6
string name = namein;
if (0 == namein.substr(0, 7).compare("__SYM__")) { name = namein.substr(7); }
if (0 == namein.substr(0, 7).compare("__SYM__")) name = namein.substr(7);
string pretty;
pretty.reserve(name.length());
bool inEscapedIdent = false;
@ -1340,7 +1342,7 @@ void AstNode::dumpTreeFile(const string& filename, bool doDump) {
{ // Write log & close
UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> logsp{V3File::new_ofstream(filename)};
if (logsp->fail()) v3fatal("Can't write " << filename);
if (logsp->fail()) v3fatal("Can't write file: " << filename);
*logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
*logsp << "> to <e" << std::dec << editCountGbl() << ">\n";
if (editCountGbl() == editCountLast() && ::dumpTreeLevel() < 9) {
@ -1385,7 +1387,7 @@ void AstNode::dumpTreeJsonFile(const string& filename, bool doDump) {
if (!doDump) return;
UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> treejsonp{V3File::new_ofstream(filename)};
if (treejsonp->fail()) v3fatal("Can't write " << filename);
if (treejsonp->fail()) v3fatal("Can't write file: " << filename);
dumpTreeJson(*treejsonp);
*treejsonp << '\n';
}
@ -1394,7 +1396,7 @@ void AstNode::dumpJsonMetaFileGdb(const char* filename) { dumpJsonMetaFile(filen
void AstNode::dumpJsonMetaFile(const string& filename) {
UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> treejsonp{V3File::new_ofstream(filename)};
if (treejsonp->fail()) v3fatalStatic("Can't write " << filename);
if (treejsonp->fail()) v3fatalStatic("Can't write file: " << filename);
*treejsonp << '{';
FileLine::fileNameNumMapDumpJson(*treejsonp);
*treejsonp << ',';
@ -1408,7 +1410,7 @@ void AstNode::dumpTreeDotFile(const string& filename, bool doDump) {
if (doDump) {
UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> treedotp{V3File::new_ofstream(filename)};
if (treedotp->fail()) v3fatal("Can't write " << filename);
if (treedotp->fail()) v3fatal("Can't write file: " << filename);
*treedotp << "digraph vTree{\n";
*treedotp << "\tgraph\t[label=\"" << filename + ".dot"
<< "\",\n";

View File

@ -1686,6 +1686,7 @@ public:
bool isVlSym() const { return m_strp->find("vlSymsp") != string::npos; }
bool hasThis() const { return m_strp == s_thisp || VString::startsWith(*m_strp, "this"); }
string protect(bool useSelfForThis, bool protect) const;
static string replaceThis(bool useSelfForThis, const string& text);
const std::string& asString() const { return *m_strp; }
bool operator==(const VSelfPointerText& other) const { return *m_strp == *other.m_strp; }
};
@ -2359,6 +2360,7 @@ public:
AstNodeDType* findBitDType() const { return findBasicDType(VBasicDTypeKwd::LOGIC); }
AstNodeDType* findDoubleDType() const { return findBasicDType(VBasicDTypeKwd::DOUBLE); }
AstNodeDType* findStringDType() const { return findBasicDType(VBasicDTypeKwd::STRING); }
AstNodeDType* findSigned8DType() const { return findBasicDType(VBasicDTypeKwd::BYTE); }
AstNodeDType* findSigned32DType() const { return findBasicDType(VBasicDTypeKwd::INTEGER); }
AstNodeDType* findUInt32DType() const { return findBasicDType(VBasicDTypeKwd::UINT32); }
AstNodeDType* findUInt64DType() const { return findBasicDType(VBasicDTypeKwd::UINT64); }
@ -2485,6 +2487,8 @@ public:
virtual bool isGateOptimizable() const { return !isTimingControl(); }
// GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
virtual bool isGateDedupable() const { return isGateOptimizable(); }
// Whether the node can be used in expression coverage
virtual bool isExprCoverageEligible() const { return isGateDedupable(); }
// Else creates output or exits, etc, not unconsumed
virtual bool isOutputter() { return false; }
// Else a AstTime etc which output can't be predicted from input

View File

@ -189,8 +189,8 @@ bool AstVarRef::sameNode(const AstVarRef* samep) const {
return (varScopep() == samep->varScopep() && access() == samep->access());
} else {
return (selfPointer() == samep->selfPointer()
&& classOrPackagep() == samep->classOrPackagep()
&& varp()->name() == samep->varp()->name() && access() == samep->access());
&& classOrPackagep() == samep->classOrPackagep() && access() == samep->access()
&& (varp() && samep->varp() && varp()->name() == samep->varp()->name()));
}
}
bool AstVarRef::sameNoLvalue(AstVarRef* samep) const {

View File

@ -50,7 +50,8 @@ protected:
private:
// METHODS
const AstNodeDType* skipRefIterp(bool skipConst, bool skipEnum) const VL_MT_STABLE;
const AstNodeDType* skipRefIterp(bool skipConst, bool skipEnum,
bool assertOn = true) const VL_MT_STABLE;
protected:
// METHODS
@ -78,6 +79,15 @@ public:
return const_cast<AstNodeDType*>(
static_cast<const AstNodeDType*>(this)->skipRefIterp(true, true));
}
// (Slow) Recurse over MemberDType|ParamTypeDType|RefDType|ConstDType|EnumDType to other type,
// Returns null if not resolved
const AstNodeDType* skipRefOrNullp() const VL_MT_STABLE {
return skipRefIterp(true, true, false);
}
AstNodeDType* skipRefOrNullp() VL_MT_STABLE {
return const_cast<AstNodeDType*>(
static_cast<const AstNodeDType*>(this)->skipRefIterp(true, true, false));
}
// (Slow) Recurse over MemberDType|ParamTypeDType|RefDType|EnumDType to ConstDType
const AstNodeDType* skipRefToConstp() const { return skipRefIterp(false, true); }
AstNodeDType* skipRefToConstp() {
@ -110,15 +120,7 @@ public:
// Iff has second dtype, set as generic node function
virtual void virtRefDType2p(AstNodeDType* nodep) {}
// Assignable equivalence. Calls skipRefToNonRefp() during comparisons.
bool similarDType(const AstNodeDType* samep) const {
const AstNodeDType* nodep = this;
nodep = nodep->skipRefToNonRefp();
samep = samep->skipRefToNonRefp();
if (nodep == samep) return true;
if (nodep->type() != samep->type()) return false;
return nodep->similarDTypeNode(samep);
}
bool similarDType(const AstNodeDType* samep) const;
// Iff has a non-null subDTypep(), as generic node function
virtual AstNodeDType* subDTypep() const VL_MT_STABLE { return nullptr; }
virtual bool isFourstate() const;
@ -155,7 +157,7 @@ public:
bool generic() const VL_MT_SAFE { return m_generic; }
void generic(bool flag) { m_generic = flag; }
std::pair<uint32_t, uint32_t> dimensions(bool includeBasic);
uint32_t arrayUnpackedElements(); // 1, or total multiplication of all dimensions
uint32_t arrayUnpackedElements() const; // 1, or total multiplication of all dimensions
static int uniqueNumInc() { return ++s_uniqueNum; }
const char* charIQWN() const {
return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I");
@ -522,7 +524,7 @@ public:
AstCDType(FileLine* fl, const string& name)
: ASTGEN_SUPER_CDType(fl)
, m_name{name} {
this->dtypep(this);
dtypep(this);
}
public:
@ -562,8 +564,8 @@ public:
AstClassRefDType(FileLine* fl, AstClass* classp, AstPin* paramsp)
: ASTGEN_SUPER_ClassRefDType(fl)
, m_classp{classp} {
this->dtypep(this);
this->addParamsp(paramsp);
dtypep(this);
addParamsp(paramsp);
}
ASTGEN_MEMBERS_AstClassRefDType;
// METHODS
@ -571,7 +573,11 @@ public:
const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType);
return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep);
}
bool similarDTypeNode(const AstNodeDType* samep) const override { return sameNode(samep); }
bool similarDTypeNode(const AstNodeDType* samep) const override {
// Doesn't need to compare m_classOrPackagep
const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType);
return m_classp == asamep->m_classp;
}
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
@ -1065,7 +1071,7 @@ class AstQueueDType final : public AstNodeDType {
public:
AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNodeExpr* boundp)
: ASTGEN_SUPER_QueueDType(fl) {
this->childDTypep(dtp);
childDTypep(dtp);
this->boundp(boundp);
refDTypep(nullptr);
dtypep(nullptr); // V3Width will resolve
@ -1125,7 +1131,7 @@ public:
AstRefDType(FileLine* fl, const string& name, AstNodeExpr* classOrPackagep, AstPin* paramsp)
: ASTGEN_SUPER_RefDType(fl)
, m_name{name} {
this->classOrPackageOpp(classOrPackagep);
classOrPackageOpp(classOrPackagep);
addParamsp(paramsp);
}
class FlagTypeOfExpr {}; // type(expr) for parser only
@ -1342,7 +1348,7 @@ class AstUnpackArrayDType final : public AstNodeArrayDType {
public:
AstUnpackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep)
: ASTGEN_SUPER_UnpackArrayDType(fl) {
this->childDTypep(dtp); // Only for parser
childDTypep(dtp); // Only for parser
this->rangep(rangep);
refDTypep(nullptr);
dtypep(nullptr); // V3Width will resolve
@ -1382,13 +1388,20 @@ public:
string verilogKwd() const override { return "struct"; }
};
class AstUnionDType final : public AstNodeUOrStructDType {
bool m_isSoft; // Is a "union soft"
public:
// UNSUP: bool isTagged;
// VSigning below is mispurposed to indicate if packed or not
AstUnionDType(FileLine* fl, VSigning numericUnpack)
: ASTGEN_SUPER_UnionDType(fl, numericUnpack) {}
// isSoft implies packed
AstUnionDType(FileLine* fl, bool isSoft, VSigning numericUnpack)
: ASTGEN_SUPER_UnionDType(fl, numericUnpack)
, m_isSoft(isSoft) {
packed(packed() | m_isSoft);
}
ASTGEN_MEMBERS_AstUnionDType;
string verilogKwd() const override { return "union"; }
bool isSoft() const { return m_isSoft; }
};
#endif // Guard

View File

@ -243,12 +243,12 @@ protected:
AstNodeFTaskRef(VNType t, FileLine* fl, AstNode* namep, AstNodeExpr* pinsp)
: AstNodeExpr{t, fl} {
this->namep(namep);
this->addPinsp(pinsp);
addPinsp(pinsp);
}
AstNodeFTaskRef(VNType t, FileLine* fl, const string& name, AstNodeExpr* pinsp)
: AstNodeExpr{t, fl}
, m_name{name} {
this->addPinsp(pinsp);
addPinsp(pinsp);
}
public:
@ -542,6 +542,7 @@ public:
// Know no children, and hot function, so skip iterator for speed
// cppcheck-suppress functionConst
void iterateChildren(VNVisitorConst& v) {}
static AstNodeVarRef* varRefLValueRecurse(AstNode* nodep);
};
// === Concrete node types =====================================================
@ -647,7 +648,7 @@ public:
: ASTGEN_SUPER_CMethodHard(fl)
, m_name{name} {
this->fromp(fromp);
this->addPinsp(pinsp);
addPinsp(pinsp);
setPurity();
}
ASTGEN_MEMBERS_AstCMethodHard;
@ -674,7 +675,7 @@ public:
AstCast(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, AstNodeDType* dtp)
: ASTGEN_SUPER_Cast(fl) {
this->fromp(fromp);
this->childDTypep(dtp);
childDTypep(dtp);
dtypeFrom(dtp);
}
AstCast(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
@ -728,7 +729,7 @@ public:
AstCellArrayRef(FileLine* fl, const string& name, AstNodeExpr* selp)
: ASTGEN_SUPER_CellArrayRef(fl)
, m_name{name} {
this->addSelp(selp);
addSelp(selp);
}
ASTGEN_MEMBERS_AstCellArrayRef;
// ACCESSORS
@ -769,7 +770,7 @@ public:
: ASTGEN_SUPER_ClassOrPackageRef(fl)
, m_name{name}
, m_classOrPackageNodep{classOrPackageNodep} {
this->addParamsp(paramsp);
addParamsp(paramsp);
}
ASTGEN_MEMBERS_AstClassOrPackageRef;
// METHODS
@ -876,7 +877,7 @@ public:
AstConsPackMember* membersp = nullptr)
: ASTGEN_SUPER_ConsPackUOrStruct(fl) {
this->dtypep(dtypep);
this->addMembersp(membersp);
addMembersp(membersp);
}
ASTGEN_MEMBERS_AstConsPackUOrStruct;
const char* broken() const override {
@ -1155,6 +1156,20 @@ public:
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstCvtUnpackedToQueue final : public AstNodeExpr {
// Cast from unpacked array to dynamic/unpacked queue data type
// @astgen op1 := fromp : AstNodeExpr
public:
AstCvtUnpackedToQueue(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_CvtUnpackedToQueue(fl) {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCvtUnpackedToQueue;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { return "VL_CVT_UNPACK_TO_Q(%P, %li)"; }
bool cleanOut() const override { return true; }
};
class AstDist final : public AstNodeExpr {
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := itemsp : List[AstDistItem]
@ -1162,7 +1177,7 @@ public:
AstDist(FileLine* fl, AstNodeExpr* exprp, AstDistItem* itemsp)
: ASTGEN_SUPER_Inside(fl) {
this->exprp(exprp);
this->addItemsp(itemsp);
addItemsp(itemsp);
dtypeSetBit();
}
ASTGEN_MEMBERS_AstDist;
@ -1552,7 +1567,7 @@ public:
AstInside(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* itemsp)
: ASTGEN_SUPER_Inside(fl) {
this->exprp(exprp);
this->addItemsp(itemsp);
addItemsp(itemsp);
dtypeSetBit();
}
ASTGEN_MEMBERS_AstInside;
@ -1599,6 +1614,7 @@ public:
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void name(const string& name) override { m_name = name; }
bool index() const { return m_index; }
bool isExprCoverageEligible() const override { return false; }
};
class AstMemberSel final : public AstNodeExpr {
// @astgen op1 := fromp : AstNodeExpr
@ -1744,7 +1760,7 @@ class AstPatMember final : public AstNodeExpr {
public:
AstPatMember(FileLine* fl, AstNodeExpr* lhssp, AstNode* keyp, AstNodeExpr* repp)
: ASTGEN_SUPER_PatMember(fl) {
this->addLhssp(lhssp);
addLhssp(lhssp);
this->keyp(keyp);
this->repp(repp);
}
@ -1911,6 +1927,7 @@ public:
}
ASTGEN_MEMBERS_AstSFormatF;
string name() const override VL_MT_STABLE { return m_text; }
void name(const string& name) override { m_text = name; }
int instrCount() const override { return INSTR_COUNT_PLI; }
bool sameNode(const AstNode* samep) const override {
return text() == VN_DBG_AS(samep, SFormatF)->text();
@ -1941,7 +1958,7 @@ public:
AstSScanF(FileLine* fl, const string& text, AstNode* fromp, AstNode* exprsp)
: ASTGEN_SUPER_SScanF(fl)
, m_text{text} {
this->addExprsp(exprsp);
addExprsp(exprsp);
this->fromp(fromp);
}
ASTGEN_MEMBERS_AstSScanF;
@ -2029,7 +2046,7 @@ public:
AstSelLoopVars(FileLine* fl, AstNodeExpr* fromp, AstNode* elementsp)
: ASTGEN_SUPER_SelLoopVars(fl) {
this->fromp(fromp);
this->addElementsp(elementsp);
addElementsp(elementsp);
}
ASTGEN_MEMBERS_AstSelLoopVars;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
@ -2150,7 +2167,7 @@ class AstSysIgnore final : public AstNodeExpr {
public:
AstSysIgnore(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_SysIgnore(fl) {
this->addExprsp(exprsp);
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstSysIgnore;
string verilogKwd() const override { return "$ignored"; }
@ -2261,7 +2278,7 @@ class AstUCFunc final : public AstNodeExpr {
public:
AstUCFunc(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_UCFunc(fl) {
this->addExprsp(exprsp);
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstUCFunc;
bool cleanOut() const override { return false; }
@ -2343,7 +2360,7 @@ public:
: ASTGEN_SUPER_With(fl) {
this->indexArgRefp(indexArgRefp);
this->valueArgRefp(valueArgRefp);
this->addExprp(exprp);
addExprp(exprp);
}
ASTGEN_MEMBERS_AstWith;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
@ -2368,7 +2385,7 @@ public:
AstWithParse(FileLine* fl, AstNodeExpr* funcrefp, AstNode* exprsp)
: ASTGEN_SUPER_WithParse(fl) {
this->funcrefp(funcrefp);
this->addExprsp(exprsp);
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstWithParse;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
@ -4405,12 +4422,15 @@ public:
class AstNew final : public AstNodeFTaskRef {
// New as constructor
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
bool m_isImplicit = false; // Implicitly generated from extends args
public:
AstNew(FileLine* fl, AstNodeExpr* pinsp)
: ASTGEN_SUPER_New(fl, "new", pinsp) {}
ASTGEN_MEMBERS_AstNew;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool isImplicit() const { return m_isImplicit; }
void isImplicit(bool flag) { m_isImplicit = flag; }
};
class AstTaskRef final : public AstNodeFTaskRef {
// A reference to a task
@ -5740,6 +5760,7 @@ class AstVarXRef final : public AstNodeVarRef {
string m_name;
string m_dotted; // Dotted part of scope the name()'ed reference is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
bool m_containsGenBlock = false; // Contains gen block reference
public:
AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access)
: ASTGEN_SUPER_VarXRef(fl, nullptr, access)
@ -5755,6 +5776,8 @@ public:
void dotted(const string& dotted) { m_dotted = dotted; }
string inlinedDots() const { return m_inlinedDots; }
void inlinedDots(const string& flag) { m_inlinedDots = flag; }
bool containsGenBlock() const { return m_containsGenBlock; }
void containsGenBlock(const bool flag) { m_containsGenBlock = flag; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }

View File

@ -388,7 +388,7 @@ protected:
AstNodeCase(VNType t, FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp)
: AstNodeStmt{t, fl} {
this->exprp(exprp);
this->addItemsp(itemsp);
addItemsp(itemsp);
}
public:
@ -414,7 +414,7 @@ public:
, m_type{type}
, m_directive{directive} {
this->propp(propp);
this->addPasssp(passsp);
addPasssp(passsp);
}
ASTGEN_MEMBERS_AstNodeCoverOrAssert;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
@ -440,10 +440,10 @@ protected:
AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp,
AstNode* stmtsp)
: AstNodeStmt{t, fl} {
this->addInitsp(initsp);
addInitsp(initsp);
this->condp(condp);
this->addIncsp(incsp);
this->addStmtsp(stmtsp);
addIncsp(incsp);
addStmtsp(stmtsp);
}
public:
@ -459,7 +459,7 @@ public:
AstNodeForeach(VNType t, FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
: AstNodeStmt(t, fl) {
this->arrayp(arrayp);
this->addStmtsp(stmtsp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstNodeForeach;
bool isGateOptimizable() const override { return false; }
@ -477,8 +477,8 @@ protected:
AstNodeIf(VNType t, FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
: AstNodeStmt{t, fl} {
this->condp(condp);
this->addThensp(thensp);
this->addElsesp(elsesp);
addThensp(thensp);
addElsesp(elsesp);
isBoundsCheck(false);
}
@ -598,7 +598,7 @@ public:
: ASTGEN_SUPER_Bind(fl)
, m_name{name} {
UASSERT_OBJ(VN_IS(cellsp, Cell), cellsp, "Only instances allowed to be bound");
this->addCellsp(cellsp);
addCellsp(cellsp);
}
ASTGEN_MEMBERS_AstBind;
// ACCESSORS
@ -631,8 +631,10 @@ class AstCFunc final : public AstNode {
bool m_isConstructor : 1; // Is C class constructor
bool m_isDestructor : 1; // Is C class destructor
bool m_isMethod : 1; // Is inside a class definition
bool m_isLoose : 1; // Semantically this is a method, but is implemented as a function
// with an explicitly passed 'self' pointer as the first argument
bool m_isLoose : 1; // Semantically this is a method, but is implemented as a function with
// an explicitly passed 'self' pointer as the first argument. This can
// be slightly faster due to __restrict, and we do not declare in header
// so adding/removing loose functions doesn't recompile everything.
bool m_isInline : 1; // Inline function
bool m_isVirtual : 1; // Virtual function
bool m_entryPoint : 1; // User may call into this top level function
@ -762,7 +764,7 @@ class AstCLocalScope final : public AstNode {
public:
AstCLocalScope(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_CLocalScope(fl) {
this->addStmtsp(stmtsp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstCLocalScope;
};
@ -790,8 +792,8 @@ class AstCaseItem final : public AstNode {
public:
AstCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* stmtsp)
: ASTGEN_SUPER_CaseItem(fl) {
this->addCondsp(condsp);
this->addStmtsp(stmtsp);
addCondsp(condsp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstCaseItem;
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
@ -824,8 +826,8 @@ public:
, m_hasIfaceVar{false}
, m_recursive{false}
, m_trace{true} {
this->addPinsp(pinsp);
this->addParamsp(paramsp);
addPinsp(pinsp);
addParamsp(paramsp);
this->rangep(rangep);
}
ASTGEN_MEMBERS_AstCell;
@ -915,6 +917,7 @@ class AstClassExtends final : public AstNode {
// during early parse, then moves to dtype
// @astgen op1 := childDTypep : Optional[AstNodeDType]
// @astgen op2 := classOrPkgsp : Optional[AstNode]
// @astgen op3 := argsp : List[AstNodeExpr]
const bool m_isImplements = false; // class implements
bool m_parameterized = false; // has parameters in its statement
@ -1037,7 +1040,7 @@ public:
AstConstraint(FileLine* fl, const string& name, AstNode* itemsp)
: ASTGEN_SUPER_Constraint(fl)
, m_name(name) {
this->addItemsp(itemsp);
addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstConstraint;
void dump(std::ostream& str) const override;
@ -1067,8 +1070,8 @@ class AstConstraintBefore final : public AstNode {
public:
AstConstraintBefore(FileLine* fl, AstNodeExpr* lhssp, AstNodeExpr* rhssp)
: ASTGEN_SUPER_ConstraintBefore(fl) {
this->addLhssp(lhssp);
this->addRhssp(rhssp);
addLhssp(lhssp);
addRhssp(rhssp);
}
ASTGEN_MEMBERS_AstConstraintBefore;
bool isGateOptimizable() const override { return false; }
@ -1187,7 +1190,7 @@ class AstImplicit final : public AstNode {
public:
AstImplicit(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_Implicit(fl) {
this->addExprsp(exprsp);
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstImplicit;
};
@ -1250,7 +1253,7 @@ public:
AstModport(FileLine* fl, const string& name, AstNode* varsp)
: ASTGEN_SUPER_Modport(fl)
, m_name{name} {
this->addVarsp(varsp);
addVarsp(varsp);
}
string verilogKwd() const override { return "modport"; }
string name() const override VL_MT_STABLE { return m_name; }
@ -1645,7 +1648,7 @@ class AstSenTree final : public AstNode {
public:
AstSenTree(FileLine* fl, AstSenItem* sensesp)
: ASTGEN_SUPER_SenTree(fl) {
this->addSensesp(sensesp);
addSensesp(sensesp);
}
ASTGEN_MEMBERS_AstSenTree;
void dump(std::ostream& str) const override;
@ -1798,18 +1801,47 @@ public:
AstUdpTable(FileLine* fl, AstUdpTableLine* linesp)
: ASTGEN_SUPER_UdpTable(fl) {
this->addLinesp(linesp);
if (!v3Global.hasTable()) v3Global.setHasTable();
}
ASTGEN_MEMBERS_AstUdpTable;
};
class AstUdpTableLine final : public AstNode {
string m_text;
// @astgen op1 := iFieldsp : List[AstUdpTableLineVal] // Input fields
// @astgen op2 := oFieldsp : List[AstUdpTableLineVal] // Output fields
private:
const bool m_udpIsCombo; // Combinational or sequential UDP
public:
AstUdpTableLine(FileLine* fl, const string& text)
class UdpCombo {};
AstUdpTableLine(UdpCombo, FileLine* fl, AstUdpTableLineVal* iFieldsp,
AstUdpTableLineVal* oFieldsp)
: ASTGEN_SUPER_UdpTableLine(fl)
, m_text{text} {}
, m_udpIsCombo{true} {
addIFieldsp(iFieldsp);
addOFieldsp(oFieldsp);
}
class UdpSequential {};
AstUdpTableLine(UdpSequential, FileLine* fl, AstUdpTableLineVal* iFieldsp,
AstUdpTableLineVal* oFieldsp1, AstUdpTableLineVal* oFieldsp2)
: ASTGEN_SUPER_UdpTableLine(fl)
, m_udpIsCombo{false} {
addIFieldsp(iFieldsp);
addOFieldsp(oFieldsp1);
addOFieldsp(oFieldsp2);
}
ASTGEN_MEMBERS_AstUdpTableLine;
int udpIsCombo() const { return m_udpIsCombo; }
};
class AstUdpTableLineVal final : public AstNode {
string m_text; // Value character
public:
AstUdpTableLineVal(FileLine* fl, const string& text)
: ASTGEN_SUPER_UdpTableLineVal(fl)
, m_text{text} {}
ASTGEN_MEMBERS_AstUdpTableLineVal;
string name() const override VL_MT_STABLE { return m_text; }
void name(std::string const& text) override VL_MT_STABLE { m_text = text; }
string text() const VL_MT_SAFE { return m_text; }
};
class AstVar final : public AstNode {
@ -1878,6 +1910,7 @@ class AstVar final : public AstNode {
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
bool m_ignoreSchedWrite : 1; // Ignore writes in scheduling (for coverage increments)
void init() {
m_ansi = false;
@ -1923,6 +1956,7 @@ class AstVar final : public AstNode {
m_isWrittenByDpi = false;
m_isWrittenBySuspendable = false;
m_ignorePostWrite = false;
m_ignoreSchedWrite = false;
m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN;
}
@ -2080,6 +2114,8 @@ public:
void setWrittenBySuspendable() { m_isWrittenBySuspendable = true; }
bool ignorePostWrite() const { return m_ignorePostWrite; }
void setIgnorePostWrite() { m_ignorePostWrite = true; }
bool ignoreSchedWrite() const { return m_ignoreSchedWrite; }
void setIgnoreSchedWrite() { m_ignoreSchedWrite = true; }
// METHODS
void name(const string& name) override { m_name = name; }
@ -2165,6 +2201,8 @@ public:
string verilogKwd() const override;
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
VLifetime lifetime() const { return m_lifetime; }
void pinNum(int id) { m_pinNum = id; }
int pinNum() const { return m_pinNum; }
void propagateAttrFrom(const AstVar* fromp) {
// This is getting connected to fromp; keep attributes
// Note the method below too
@ -2197,9 +2235,11 @@ public:
m_direction = VDirection::NONE;
m_name = name;
}
bool needsCReset() const {
return !isIfaceParent() && !isIfaceRef() && !noReset() && !isParam() && !isStatementTemp()
&& !(basicp() && (basicp()->isEvent() || basicp()->isTriggerVec()));
}
static AstVar* scVarRecurse(AstNode* nodep);
void pinNum(int id) { m_pinNum = id; }
int pinNum() const { return m_pinNum; }
};
class AstVarScope final : public AstNode {
// A particular scoped usage of a variable
@ -2302,7 +2342,7 @@ public:
class AstLet final : public AstNodeFTask {
// Verilog "let" statement
// Parents: MODULE
// stmtp is always a StmtExpr as Let always returns AstNodeExpr
// stmtp list first item is returned StmtExpr, as Let always returns AstNodeExpr
public:
AstLet(FileLine* fl, const string& name)
: ASTGEN_SUPER_Let(fl, name, nullptr) {}
@ -2382,7 +2422,6 @@ class AstClass final : public AstNodeModule {
bool m_extended = false; // Is extension or extended by other classes
bool m_interfaceClass = false; // Interface class
bool m_needRNG = false; // Need RNG, uses srandom/randomize
bool m_parameterized = false; // Parameterized class
bool m_useVirtualPublic = false; // Subclasses need virtual public as uses interface class
bool m_virtual = false; // Virtual class
@ -2403,8 +2442,6 @@ public:
void isExtended(bool flag) { m_extended = flag; }
bool isInterfaceClass() const { return m_interfaceClass; }
void isInterfaceClass(bool flag) { m_interfaceClass = flag; }
bool isParameterized() const { return m_parameterized; }
void isParameterized(bool flag) { m_parameterized = flag; }
bool isVirtual() const { return m_virtual; }
void isVirtual(bool flag) { m_virtual = flag; }
bool needRNG() const { return m_needRNG; }
@ -2484,14 +2521,28 @@ public:
};
class AstModule final : public AstNodeModule {
// A module declaration
const bool m_isProgram; // Module represents a program
const bool m_isChecker = false; // Module represents a checker
const bool m_isProgram = false; // Module represents a program
public:
AstModule(FileLine* fl, const string& name, bool program = false)
class Checker {}; // for constructor type-overload selection
class Program {}; // for constructor type-overload selection
AstModule(FileLine* fl, const string& name)
: ASTGEN_SUPER_Module(fl, name) {}
AstModule(FileLine* fl, const string& name, Checker)
: ASTGEN_SUPER_Module(fl, name)
, m_isProgram{program} {}
, m_isChecker{true} {}
AstModule(FileLine* fl, const string& name, Program)
: ASTGEN_SUPER_Module(fl, name)
, m_isProgram{true} {}
ASTGEN_MEMBERS_AstModule;
string verilogKwd() const override { return m_isProgram ? "program" : "module"; }
string verilogKwd() const override {
return m_isChecker ? "checker" : m_isProgram ? "program" : "module";
}
bool timescaleMatters() const override { return true; }
bool isChecker() const { return m_isChecker; }
bool isProgram() const { return m_isProgram; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
};
class AstNotFoundModule final : public AstNodeModule {
// A missing module declaration
@ -2740,15 +2791,22 @@ public:
class AstCReset final : public AstNodeStmt {
// Reset variable at startup
// @astgen op1 := varrefp : AstVarRef
const bool m_constructing; // Previously cleared by constructor
public:
AstCReset(FileLine* fl, AstVarRef* varrefp)
: ASTGEN_SUPER_CReset(fl) {
AstCReset(FileLine* fl, AstVarRef* varrefp, bool constructing)
: ASTGEN_SUPER_CReset(fl)
, m_constructing(constructing) {
this->varrefp(varrefp);
}
ASTGEN_MEMBERS_AstCReset;
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 sameNode(const AstNode* /*samep*/) const override { return true; }
bool sameNode(const AstNode* samep) const override {
return constructing() == VN_DBG_AS(samep, CReset)->constructing();
}
bool constructing() const { return m_constructing; }
};
class AstCReturn final : public AstNodeStmt {
// C++ return from a function
@ -2768,7 +2826,7 @@ class AstCStmt final : public AstNodeStmt {
public:
AstCStmt(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_CStmt(fl) {
this->addExprsp(exprsp);
addExprsp(exprsp);
}
inline AstCStmt(FileLine* fl, const string& textStmt);
ASTGEN_MEMBERS_AstCStmt;
@ -2817,7 +2875,7 @@ class AstConstraintUnique final : public AstNodeStmt {
public:
AstConstraintUnique(FileLine* fl, AstNode* rangesp)
: ASTGEN_SUPER_ConstraintUnique(fl) {
this->addRangesp(rangesp);
addRangesp(rangesp);
}
ASTGEN_MEMBERS_AstConstraintUnique;
bool isGateOptimizable() const override { return false; }
@ -2983,14 +3041,14 @@ public:
AstNodeExpr* exprsp, char missingArgChar = 'd')
: ASTGEN_SUPER_Display(fl)
, m_displayType{dispType} {
this->fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
this->filep(filep);
}
AstDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* filep, AstNodeExpr* exprsp,
char missingArgChar = 'd')
: ASTGEN_SUPER_Display(fl)
, m_displayType{dispType} {
this->fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar});
fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar});
this->filep(filep);
}
ASTGEN_MEMBERS_AstDisplay;
@ -3063,7 +3121,7 @@ public:
AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp)
: ASTGEN_SUPER_EventControl(fl) {
this->sensesp(sensesp);
this->addStmtsp(stmtsp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstEventControl;
string verilogKwd() const override { return "@(%l) %r"; }
@ -3144,7 +3202,7 @@ public:
// After construction must call ->labelp to associate with appropriate label
AstJumpBlock(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_JumpBlock(fl) {
this->addStmtsp(stmtsp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstJumpBlock;
const char* broken() const override;
@ -3276,7 +3334,7 @@ public:
AstRepeat(FileLine* fl, AstNodeExpr* countp, AstNode* stmtsp)
: ASTGEN_SUPER_Repeat(fl) {
this->countp(countp);
this->addStmtsp(stmtsp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstRepeat;
bool isGateOptimizable() const override { return false; } // Not relevant - converted to FOR
@ -3305,12 +3363,12 @@ public:
AstSFormat(FileLine* fl, AstNodeExpr* lhsp, const string& text, AstNodeExpr* exprsp,
char missingArgChar = 'd')
: ASTGEN_SUPER_SFormat(fl) {
this->fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
this->lhsp(lhsp);
}
AstSFormat(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* exprsp, char missingArgChar = 'd')
: ASTGEN_SUPER_SFormat(fl) {
this->fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar});
fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar});
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstSFormat;
@ -3327,6 +3385,24 @@ public:
int instrCount() const override { return INSTR_COUNT_PLI; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstSetuphold final : public AstNodeStmt {
// Verilog $setuphold
// @astgen op1 := refevp : AstNodeExpr
// @astgen op2 := dataevp : AstNodeExpr
// @astgen op3 := delrefp : Optional[AstNodeExpr]
// @astgen op4 := deldatap : Optional[AstNodeExpr]
public:
AstSetuphold(FileLine* fl, AstNodeExpr* refevp, AstNodeExpr* dataevp,
AstNodeExpr* delrefp = nullptr, AstNodeExpr* deldatap = nullptr)
: ASTGEN_SUPER_Setuphold(fl) {
this->refevp(refevp);
this->dataevp(dataevp);
this->delrefp(delrefp);
this->deldatap(deldatap);
}
ASTGEN_MEMBERS_AstSetuphold;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstStackTraceT final : public AstNodeStmt {
// $stacktrace used as task
public:
@ -3540,7 +3616,7 @@ class AstUCStmt final : public AstNodeStmt {
public:
AstUCStmt(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_UCStmt(fl) {
this->addExprsp(exprsp);
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstUCStmt;
bool isGateOptimizable() const override { return false; }
@ -3556,7 +3632,7 @@ public:
AstWait(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp)
: ASTGEN_SUPER_Wait(fl) {
this->condp(condp);
this->addStmtsp(stmtsp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstWait;
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
@ -3580,8 +3656,8 @@ public:
AstWhile(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp = nullptr, AstNode* incsp = nullptr)
: ASTGEN_SUPER_While(fl) {
this->condp(condp);
this->addStmtsp(stmtsp);
this->addIncsp(incsp);
addStmtsp(stmtsp);
addIncsp(incsp);
}
ASTGEN_MEMBERS_AstWhile;
void dump(std::ostream& str) const override;
@ -3756,7 +3832,7 @@ public:
AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, VAssertType type,
VAssertDirectiveType directive, const string& name = "")
: ASTGEN_SUPER_Assert(fl, propp, passsp, type, directive, name) {
this->addFailsp(failsp);
addFailsp(failsp);
}
};
class AstAssertIntrinsic final : public AstNodeCoverOrAssert {
@ -3769,7 +3845,7 @@ public:
// Intrinsic asserts are always enabled thus 'type' field is set to INTERNAL.
: ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, VAssertType::INTERNAL,
VAssertDirectiveType::INTRINSIC, name) {
this->addFailsp(failsp);
addFailsp(failsp);
}
};
class AstCover final : public AstNodeCoverOrAssert {
@ -3886,6 +3962,14 @@ public:
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScHdrPost final : public AstNodeText {
public:
AstScHdrPost(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScHdrPost(fl, textp) {}
ASTGEN_MEMBERS_AstScHdrPost;
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScImp final : public AstNodeText {
public:
AstScImp(FileLine* fl, const string& textp)

View File

@ -327,6 +327,15 @@ AstNodeExpr* AstInsideRange::newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* l
return new AstLogAnd{fileline(), ap, bp};
}
void AstCReset::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (constructing()) str << " [CONS]";
}
void AstCReset::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, constructing);
dumpJsonGen(str);
}
AstVar* AstClocking::ensureEventp(bool childDType) {
if (!eventp()) {
AstVar* const evp
@ -815,12 +824,12 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
}
} else if (AstArraySel* const arraySelp = VN_CAST(nodep, ArraySel)) {
if (AstVar* const p = scVarRecurse(arraySelp->fromp())) return p;
if (AstVar* const p = scVarRecurse(arraySelp->bitp())) return p;
}
return nullptr;
}
const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum) const VL_MT_STABLE {
const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum,
bool assertOn) const VL_MT_STABLE {
const AstNodeDType* nodep = this;
while (true) {
if (VL_UNLIKELY(VN_IS(nodep, MemberDType) || VN_IS(nodep, ParamTypeDType)
@ -831,7 +840,7 @@ const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum) co
nodep = subp;
continue;
} else {
nodep->v3fatalSrc(nodep->prettyTypeName() << " not linked to type");
if (assertOn) nodep->v3fatalSrc(nodep->prettyTypeName() << " not linked to type");
return nullptr;
}
}
@ -839,6 +848,15 @@ const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum) co
}
}
bool AstNodeDType::similarDType(const AstNodeDType* samep) const {
const AstNodeDType* nodep = this;
nodep = nodep->skipRefToNonRefp();
samep = samep->skipRefToNonRefp();
if (nodep == samep) return true;
if (nodep->type() != samep->type()) return false;
return nodep->similarDTypeNode(samep);
}
bool AstNodeDType::isFourstate() const { return basicp() && basicp()->isFourstate(); }
class AstNodeDType::CTypeRecursed final {
@ -998,11 +1016,11 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packe
return info;
}
uint32_t AstNodeDType::arrayUnpackedElements() {
uint32_t AstNodeDType::arrayUnpackedElements() const {
uint32_t entries = 1;
for (AstNodeDType* dtypep = this; dtypep;) {
for (const AstNodeDType* dtypep = this; dtypep;) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
entries *= adtypep->elementsConst();
dtypep = adtypep->subDTypep();
} else {
@ -1986,8 +2004,8 @@ AstMemberSel::AstMemberSel(FileLine* fl, AstNodeExpr* fromp, AstVar* varp)
}
bool AstMemberSel::sameNode(const AstNode* samep) const {
const AstMemberSel* const sp = VN_DBG_AS(samep, MemberSel);
return sp != nullptr && access() == sp->access() && fromp()->isSame(sp->fromp())
&& name() == sp->name() && varp()->sameNode(sp->varp());
return sp && access() == sp->access() && fromp()->isSame(sp->fromp()) && name() == sp->name()
&& (varp() && sp->varp() && varp()->sameNode(sp->varp()));
}
void AstMemberSel::dump(std::ostream& str) const {
@ -2030,6 +2048,16 @@ void AstModportVarRef::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "direction", direction().ascii());
dumpJsonGen(str);
}
void AstModule::dump(std::ostream& str) const {
this->AstNodeModule::dump(str);
if (isChecker()) str << " [CHECKER]";
if (isProgram()) str << " [PROGRAM]";
}
void AstModule::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isChecker);
dumpJsonBoolFunc(str, isProgram);
dumpJsonGen(str);
}
void AstPin::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (modVarp()) {
@ -2474,8 +2502,24 @@ void AstNodeVarRef::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "access", access().ascii());
dumpJsonGen(str);
}
AstNodeVarRef* AstNodeVarRef::varRefLValueRecurse(AstNode* nodep) {
// Given a (possible) lvalue expression, recurse to find the being-set NodeVarRef, else nullptr
if (AstNodeVarRef* const anodep = VN_CAST(nodep, NodeVarRef)) return anodep;
if (AstNodeSel* const anodep = VN_CAST(nodep, NodeSel))
return varRefLValueRecurse(anodep->fromp());
if (AstSel* const anodep = VN_CAST(nodep, Sel)) return varRefLValueRecurse(anodep->fromp());
if (AstArraySel* const anodep = VN_CAST(nodep, ArraySel))
return varRefLValueRecurse(anodep->fromp());
if (AstMemberSel* const anodep = VN_CAST(nodep, MemberSel))
return varRefLValueRecurse(anodep->fromp());
if (AstStructSel* const anodep = VN_CAST(nodep, StructSel))
return varRefLValueRecurse(anodep->fromp());
return nullptr;
}
void AstVarXRef::dump(std::ostream& str) const {
this->AstNodeVarRef::dump(str);
if (containsGenBlock()) str << " [GENBLK]";
str << ".=" << dotted() << " ";
if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - ";
if (varScopep()) {
@ -2487,6 +2531,7 @@ void AstVarXRef::dump(std::ostream& str) const {
}
}
void AstVarXRef::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, containsGenBlock);
dumpJsonStrFunc(str, dotted);
dumpJsonStrFunc(str, inlinedDots);
dumpJsonGen(str);
@ -2538,6 +2583,8 @@ void AstVar::dump(std::ostream& str) const {
str << " [FUNC]";
}
if (isDpiOpenArray()) str << " [DPIOPENA]";
if (ignorePostWrite()) str << " [IGNPWR]";
if (ignoreSchedWrite()) str << " [IGNWR]";
if (!attrClocker().unknown()) str << " [" << attrClocker().ascii() << "] ";
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
str << " " << varType();
@ -2570,6 +2617,8 @@ void AstVar::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isParam);
dumpJsonBoolFunc(str, attrScBv);
dumpJsonBoolFunc(str, attrSFormat);
dumpJsonBoolFunc(str, ignorePostWrite);
dumpJsonBoolFunc(str, ignoreSchedWrite);
dumpJsonGen(str);
}
bool AstVar::sameNode(const AstNode* samep) const {
@ -2656,7 +2705,9 @@ AstNodeModule* AstClassOrPackageRef::classOrPackageSkipp() const {
AstNode* lastp = nullptr;
while (foundp != lastp) {
lastp = foundp;
if (AstNodeDType* const anodep = VN_CAST(foundp, NodeDType)) foundp = anodep->skipRefp();
if (AstNodeDType* const anodep = VN_CAST(foundp, NodeDType)) {
foundp = anodep->skipRefOrNullp();
}
if (AstTypedef* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
if (AstClassRefDType* const anodep = VN_CAST(foundp, ClassRefDType))
foundp = anodep->classp();
@ -2988,7 +3039,8 @@ void AstCMethodHard::setPurity() {
{"resume", false},
{"reverse", false},
{"rsort", false},
{"set", false},
{"setBit", false},
{"setWord", false},
{"set_randmode", false},
{"shuffle", false},
{"size", true},
@ -3055,7 +3107,7 @@ AstAlways* AstAssignW::convertToAlways() {
if (hasTimingControl) {
// If there's a timing control, put the assignment in a fork..join_none. This process won't
// get marked as suspendable and thus will be scheduled normally
auto* forkp = new AstFork{flp, "", bodysp};
AstFork* forkp = new AstFork{flp, "", bodysp};
forkp->joinType(VJoinType::JOIN_NONE);
bodysp = forkp;
}

View File

@ -99,7 +99,7 @@ public:
}
// Get a pointer to the user data if exists, otherwise nullptr
T_Data* tryGet(const T_Node* nodep) { return getUserp(nodep); }
T_Data* tryGet(const T_Node* nodep) const { return getUserp(nodep); }
void clear() { m_allocated.clear(); }
};

View File

@ -377,7 +377,7 @@ void V3Begin::debeginAll(AstNetlist* nodep) {
{
BeginState state;
{ BeginVisitor{nodep, &state}; }
if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; }
if (state.anyFuncInBegin()) BeginRelinkVisitor{nodep, &state};
} // Destruct before checking
V3Global::dumpCheckGlobalTree("begin", 0, dumpTreeEitherLevel() >= 3);
}
@ -506,8 +506,9 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
AstNode* const first_clearp
= new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitFalse{}}};
auto* const orp = new AstLogOr{fl, new AstVarRef{fl, first_varp, VAccess::READ},
new AstNeq{fl, new AstConst{fl, 0}, nextp}};
AstLogOr* const orp
= new AstLogOr{fl, new AstVarRef{fl, first_varp, VAccess::READ},
new AstNeq{fl, new AstConst{fl, 0}, nextp}};
AstNode* const whilep = new AstWhile{fl, orp, first_clearp};
first_clearp->addNext(bodyPointp);
AstNode* const ifbodyp

View File

@ -114,7 +114,7 @@ public:
callp->argTypes("vlSymsp");
} else {
if (m_type.isCoverage()) callp->argTypes("first");
callp->selfPointer(VSelfPointerText{VSelfPointerText::This()});
callp->selfPointer(VSelfPointerText{VSelfPointerText::This{}});
}
rootFuncp->addStmtsp(callp->makeStmt());
}
@ -137,7 +137,17 @@ class CCtorsVisitor final : public VNVisitor {
AstCFunc* m_cfuncp = nullptr; // Current function
V3CCtorsBuilder* m_varResetp = nullptr; // Builder of _ctor_var_reset
// VISITs
// METHODS
static void insertSc(AstCFunc* cfuncp, const AstNodeModule* modp, VNType type) {
auto textAndFileline = EmitCBaseVisitorConst::textSection(modp, type);
if (!textAndFileline.first.empty()) {
AstTextBlock* const newp
= new AstTextBlock{textAndFileline.second, textAndFileline.first, false, false};
cfuncp->addStmtsp(newp);
}
}
// VISITORS
void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
VL_RESTORER(m_varResetp);
@ -167,6 +177,7 @@ class CCtorsVisitor final : public VNVisitor {
// If can be referred to by base pointer, need virtual delete
funcp->isVirtual(classp->isExtended());
funcp->slow(false);
insertSc(funcp, classp, VNType::atScDtor);
classp->addStmtsp(funcp);
}
}
@ -177,18 +188,16 @@ class CCtorsVisitor final : public VNVisitor {
m_varResetp = nullptr;
m_cfuncp = nodep;
iterateChildren(nodep);
if (nodep->name() == "new") insertSc(nodep, m_modp, VNType::atScCtor);
}
void visit(AstVar* nodep) override {
if (!nodep->isIfaceParent() && !nodep->isIfaceRef() && !nodep->noReset()
&& !nodep->isParam() && !nodep->isStatementTemp()
&& !(nodep->basicp()
&& (nodep->basicp()->isEvent() || nodep->basicp()->isTriggerVec()))) {
if (nodep->needsCReset()) {
if (m_varResetp) {
const auto vrefp = new AstVarRef{nodep->fileline(), nodep, VAccess::WRITE};
m_varResetp->add(new AstCReset{nodep->fileline(), vrefp});
AstVarRef* const vrefp = new AstVarRef{nodep->fileline(), nodep, VAccess::WRITE};
m_varResetp->add(new AstCReset{nodep->fileline(), vrefp, true});
} else if (m_cfuncp) {
const auto vrefp = new AstVarRef{nodep->fileline(), nodep, VAccess::WRITE};
nodep->addNextHere(new AstCReset{nodep->fileline(), vrefp});
AstVarRef* const vrefp = new AstVarRef{nodep->fileline(), nodep, VAccess::WRITE};
nodep->addNextHere(new AstCReset{nodep->fileline(), vrefp, true});
}
}
}
@ -226,7 +235,7 @@ void V3CCtors::evalAsserts() {
// if (signal & CONST(upper_non_clean_mask)) { fail; }
AstVarRef* const vrefp
= new AstVarRef{varp->fileline(), varp, VAccess::READ};
vrefp->selfPointer(VSelfPointerText{VSelfPointerText::This()});
vrefp->selfPointer(VSelfPointerText{VSelfPointerText::This{}});
AstNodeExpr* newp = vrefp;
if (varp->isWide()) {
newp = new AstWordSel{

View File

@ -72,13 +72,13 @@ class CaseLintVisitor final : public VNVisitorConst {
// Check for X/Z in non-casex statements
{
VL_RESTORER(m_caseExprp);
m_caseExprp = nodep;
iterateConst(nodep->exprp());
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), CaseItem)) {
iterateAndNextConstNull(itemp->condsp());
}
m_caseExprp = nullptr;
}
}
void visit(AstConst* nodep) override {
@ -578,7 +578,7 @@ class CaseVisitor final : public VNVisitor {
}
//--------------------
void visit(AstAlways* nodep) override {
VL_RESTORER(m_alwaysp)
VL_RESTORER(m_alwaysp);
m_alwaysp = nodep;
iterateChildren(nodep);
}

View File

@ -188,9 +188,9 @@ class CombineVisitor final : VNVisitor {
}
void visit(AstNodeModule* nodep) override {
UASSERT_OBJ(!m_modp, nodep, "Should not nest");
VL_RESTORER(m_modp);
m_modp = nodep;
iterateChildrenConst(nodep);
m_modp = nullptr;
}
void visit(AstCFunc* nodep) override {
iterateChildrenConst(nodep);

View File

@ -540,6 +540,8 @@ class V3ConfigResolver final {
std::unordered_map<string, std::unordered_map<string, uint64_t>>
m_profileData; // Access to profile_data records
uint8_t m_mode = NONE;
std::unordered_map<string, int> m_hierWorkers;
FileLine* m_hierWorkersFileLine = nullptr;
FileLine* m_profileFileLine = nullptr;
V3ConfigResolver() = default;
@ -570,6 +572,16 @@ public:
// Empty key for hierarchical DPI wrapper costs.
return getProfileData(hierDpi, "");
}
void addHierWorkers(FileLine* fl, const string& model, int workers) {
if (!m_hierWorkersFileLine) m_hierWorkersFileLine = fl;
m_hierWorkers[model] = workers;
}
int getHierWorkers(const string& model) const {
const auto mit = m_hierWorkers.find(model);
// Assign a single worker if no specified.
return mit != m_hierWorkers.cend() ? mit->second : 0;
}
FileLine* getHierWorkersFileLine() const { return m_hierWorkersFileLine; }
uint64_t getProfileData(const string& model, const string& key) const {
const auto mit = m_profileData.find(model);
if (mit == m_profileData.cend()) return 0;
@ -602,6 +614,10 @@ void V3Config::addCoverageBlockOff(const string& module, const string& blockname
V3ConfigResolver::s().modules().at(module).addCoverageBlockOff(blockname);
}
void V3Config::addHierWorkers(FileLine* fl, const string& model, int workers) {
V3ConfigResolver::s().addHierWorkers(fl, model, workers);
}
void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max) {
if (filename == "*") {
FileLine::globalWarnOff(code, !on);
@ -741,6 +757,12 @@ void V3Config::applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar
if (vp) vp->apply(varp);
}
int V3Config::getHierWorkers(const string& model) {
return V3ConfigResolver::s().getHierWorkers(model);
}
FileLine* V3Config::getHierWorkersFileLine() {
return V3ConfigResolver::s().getHierWorkersFileLine();
}
uint64_t V3Config::getProfileData(const string& hierDpi) {
return V3ConfigResolver::s().getProfileData(hierDpi);
}

View File

@ -33,6 +33,7 @@ public:
static void addCaseParallel(const string& file, int lineno);
static void addCoverageBlockOff(const string& file, int lineno);
static void addCoverageBlockOff(const string& module, const string& blockname);
static void addHierWorkers(FileLine* fl, const string& model, int workers);
static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max);
static void addIgnoreMatch(V3ErrorCode code, const string& filename, const string& contents,
const string& match);
@ -52,6 +53,8 @@ public:
static void applyModule(AstNodeModule* modulep);
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
static int getHierWorkers(const string& model);
static FileLine* getHierWorkersFileLine();
static uint64_t getProfileData(const string& hierDpi);
static uint64_t getProfileData(const string& model, const string& key);
static FileLine* getProfileDataFileLine();

View File

@ -2169,7 +2169,7 @@ class ConstVisitor final : public VNVisitor {
// Add a cast if needed.
AstStreamR* const streamp = VN_AS(nodep->rhsp(), StreamR)->unlinkFrBack();
AstNodeExpr* srcp = streamp->lhsp()->unlinkFrBack();
AstNodeDType* const srcDTypep = srcp->dtypep();
AstNodeDType* const srcDTypep = srcp->dtypep()->skipRefp();
if (VN_IS(srcDTypep, QueueDType) || VN_IS(srcDTypep, DynArrayDType)) {
srcp = new AstCvtArrayToPacked{srcp->fileline(), srcp, nodep->dtypep()};
} else if (VN_IS(srcDTypep, UnpackArrayDType)) {
@ -2191,30 +2191,32 @@ class ConstVisitor final : public VNVisitor {
// Push the stream operator to the rhs of the assignment statement
AstNodeExpr* streamp = nodep->lhsp()->unlinkFrBack();
AstNodeExpr* const dstp = VN_AS(streamp, StreamL)->lhsp()->unlinkFrBack();
AstNodeDType* const dstDTypep = dstp->dtypep()->skipRefp();
AstNodeExpr* const srcp = nodep->rhsp()->unlinkFrBack();
AstNodeDType* const srcDTypep = srcp->dtypep()->skipRefp();
const int sWidth = srcp->width();
const int dWidth = dstp->width();
// Connect the rhs to the stream operator and update its width
VN_AS(streamp, StreamL)->lhsp(srcp);
if (VN_IS(srcp->dtypep(), DynArrayDType) || VN_IS(srcp->dtypep(), QueueDType)
|| VN_IS(srcp->dtypep(), UnpackArrayDType)) {
if (VN_IS(srcDTypep, DynArrayDType) || VN_IS(srcDTypep, QueueDType)
|| VN_IS(srcDTypep, UnpackArrayDType)) {
streamp->dtypeSetStream();
} else {
streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), VSigning::UNSIGNED);
}
if (VN_IS(dstp->dtypep(), UnpackArrayDType)) {
streamp = new AstCvtPackedToArray{nodep->fileline(), streamp, dstp->dtypep()};
if (VN_IS(dstDTypep, UnpackArrayDType)) {
streamp = new AstCvtPackedToArray{nodep->fileline(), streamp, dstDTypep};
} else {
UASSERT(sWidth >= dWidth, "sWidth >= dWidth should have caused an error earlier");
if (dWidth == 0) {
streamp = new AstCvtPackedToArray{nodep->fileline(), streamp, dstp->dtypep()};
streamp = new AstCvtPackedToArray{nodep->fileline(), streamp, dstDTypep};
} else if (sWidth >= dWidth) {
streamp = new AstSel{streamp->fileline(), streamp, sWidth - dWidth, dWidth};
}
}
nodep->lhsp(dstp);
nodep->rhsp(streamp);
nodep->dtypep(dstp->dtypep());
nodep->dtypep(dstDTypep);
return true;
} else if (m_doV && VN_IS(nodep->lhsp(), StreamR)) {
// The right stream operator on lhs of assignment statement does
@ -2222,12 +2224,13 @@ class ConstVisitor final : public VNVisitor {
// then we select bits from the left-most, not the right-most.
AstNodeExpr* const streamp = nodep->lhsp()->unlinkFrBack();
AstNodeExpr* const dstp = VN_AS(streamp, StreamR)->lhsp()->unlinkFrBack();
AstNodeDType* const dstDTypep = dstp->dtypep()->skipRefp();
AstNodeExpr* srcp = nodep->rhsp()->unlinkFrBack();
const int sWidth = srcp->width();
const int dWidth = dstp->width();
if (VN_IS(dstp->dtypep(), UnpackArrayDType)) {
if (VN_IS(dstDTypep, UnpackArrayDType)) {
const int dstBitWidth
= dWidth * VN_AS(dstp->dtypep(), UnpackArrayDType)->arrayUnpackedElements();
= dWidth * VN_AS(dstDTypep, UnpackArrayDType)->arrayUnpackedElements();
// Handling the case where rhs is wider than lhs. StreamL does not require this
// since the combination of the left streaming operation and the implicit
// truncation in VL_ASSIGN_UNPACK automatically selects the left-most bits.
@ -2235,30 +2238,30 @@ class ConstVisitor final : public VNVisitor {
srcp
= new AstSel{streamp->fileline(), srcp, sWidth - dstBitWidth, dstBitWidth};
}
srcp = new AstCvtPackedToArray{nodep->fileline(), srcp, dstp->dtypep()};
srcp = new AstCvtPackedToArray{nodep->fileline(), srcp, dstDTypep};
} else {
UASSERT(sWidth >= dWidth, "sWidth >= dWidth should have caused an error earlier");
if (dWidth == 0) {
srcp = new AstCvtPackedToArray{nodep->fileline(), srcp, dstp->dtypep()};
srcp = new AstCvtPackedToArray{nodep->fileline(), srcp, dstDTypep};
} else if (sWidth >= dWidth) {
srcp = new AstSel{streamp->fileline(), srcp, sWidth - dWidth, dWidth};
}
}
nodep->lhsp(dstp);
nodep->rhsp(srcp);
nodep->dtypep(dstp->dtypep());
nodep->dtypep(dstDTypep);
VL_DO_DANGLING(pushDeletep(streamp), streamp);
// Further reduce, any of the nodes may have more reductions.
return true;
} else if (m_doV && VN_IS(nodep->rhsp(), StreamL)) {
AstNodeDType* const lhsDtypep = nodep->lhsp()->dtypep();
AstNodeDType* const lhsDtypep = nodep->lhsp()->dtypep()->skipRefp();
AstStreamL* streamp = VN_AS(nodep->rhsp(), StreamL);
AstNodeExpr* const srcp = streamp->lhsp();
const AstNodeDType* const srcDTypep = srcp->dtypep();
const AstNodeDType* const srcDTypep = srcp->dtypep()->skipRefp();
if (VN_IS(srcDTypep, QueueDType) || VN_IS(srcDTypep, DynArrayDType)
|| VN_IS(srcDTypep, UnpackArrayDType)) {
streamp->lhsp(new AstCvtArrayToPacked{srcp->fileline(), srcp->unlinkFrBack(),
nodep->dtypep()});
streamp->lhsp(
new AstCvtArrayToPacked{srcp->fileline(), srcp->unlinkFrBack(), lhsDtypep});
streamp->dtypeFrom(lhsDtypep);
}
} else if (m_doV && replaceAssignMultiSel(nodep)) {
@ -2896,8 +2899,8 @@ class ConstVisitor final : public VNVisitor {
if (const AstConst* const aConstp = VN_CAST(ap, Const)) {
const AstConst* const bConstp = VN_AS(bp, Const);
if (aConstp->toUQuad() < bConstp->toUQuad()) return -1;
if (aConstp->toUQuad() > bConstp->toUQuad()) return 1;
if (aConstp->num().isLtXZ(bConstp->num())) return -1;
if (bConstp->num().isLtXZ(aConstp->num())) return 1;
return 0;
}
@ -3249,7 +3252,7 @@ class ConstVisitor final : public VNVisitor {
}
}
if (m_doNConst && anyconst) {
// UINFO(9," Display in "<<nodep->text()<<endl);
// UINFO(9, " Display in " << nodep->text() << endl);
string newFormat;
string fmt;
bool inPct = false;
@ -3265,9 +3268,9 @@ class ConstVisitor final : public VNVisitor {
inPct = false;
fmt += ch;
switch (std::tolower(ch)) {
case '%': break; // %% - just output a %
case 'm': break; // %m - auto insert "name"
case 'l': break; // %l - auto insert "library"
case '%': break; // %% - still %%
case 'm': break; // %m - still %m - auto insert "name"
case 'l': break; // %l - still %l - auto insert "library"
case 't': // FALLTHRU
case '^': // %t/%^ - don't know $timeformat so can't constify
if (argp) argp = argp->nextp();
@ -3871,7 +3874,7 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
} else {
nodep = visitor.mainAcceptEdit(nodep);
}
// Because we do edits, nodep links may get trashed and core dump this.
// Because we do edits, nodep links may get trashed and core dump if have next line
// if (debug() > 0) nodep->dumpTree("- forceConDONE: ");
return nodep;
}

View File

@ -35,6 +35,40 @@
VL_DEFINE_DEBUG_FUNCTIONS;
class ExprCoverageEligibleVisitor final : public VNVisitor {
// STATE
bool m_eligible = true;
void visit(AstNodeVarRef* nodep) override {
AstNodeDType* dtypep = nodep->varp()->dtypep();
// Class objecs and references not supported for expression coverage
// because the object may not persist until the point at which
// coverage data is gathered
// This could be resolved in the future by protecting against dereferrencing
// null pointers when cloning the expression for expression coverage
if (VN_CAST(dtypep, ClassRefDType)) {
m_eligible = false;
} else {
iterateChildren(nodep);
}
}
void visit(AstNode* nodep) override {
if (!nodep->isExprCoverageEligible()) {
m_eligible = false;
} else {
iterateChildren(nodep);
}
}
public:
// CONSTRUCTORS
explicit ExprCoverageEligibleVisitor(AstNode* nodep) { iterateChildren(nodep); }
~ExprCoverageEligibleVisitor() override = default;
bool eligible() { return m_eligible; }
};
//######################################################################
// Coverage state, as a visitor of each AstNode
@ -159,6 +193,7 @@ class CoverageVisitor final : public VNVisitor {
fl_nowarn->modifyWarnOff(V3ErrorCode::UNUSEDSIGNAL, true);
AstVar* const varp = new AstVar{fl_nowarn, VVarType::MODULETEMP, trace_var_name,
incp->findUInt32DType()};
varp->setIgnoreSchedWrite(); // Ignore the increment output, so no UNOPTFLAT
varp->trace(true);
m_modp->addStmtsp(varp);
UINFO(5, "New coverage trace: " << varp << endl);
@ -668,6 +703,7 @@ class CoverageVisitor final : public VNVisitor {
m_objective = true;
iterate(nodep);
if (checkMaxExprs(falseExprs.size())) return;
if (m_seeking == ABORTED) return;
addExprCoverInc(nodep);
const int start = m_exprs.size();
@ -871,26 +907,30 @@ class CoverageVisitor final : public VNVisitor {
lineTrack(nodep);
}
// Lambdas not supported for expression coverage
void visit(AstWith* nodep) override {
VL_RESTORER(m_seeking);
if (m_seeking == SEEKING) abortExprCoverage();
m_seeking = ABORTED;
iterateChildren(nodep);
lineTrack(nodep);
void visit(AstFuncRef* nodep) override {
if (nodep->taskp()->lifetime().isAutomatic()) {
visit(static_cast<AstNodeExpr*>(nodep));
} else {
exprUnsupported(nodep, "non-automatic function");
}
}
void visit(AstNodeExpr* nodep) override {
if (m_seeking != SEEKING) {
iterateChildren(nodep);
} else {
std::stringstream emitV;
V3EmitV::verilogForTree(nodep, emitV);
// Add new expression with a single term
CoverExpr expr;
expr.emplace_back(nodep, m_objective, emitV.str());
m_exprs.push_back(std::move(expr));
checkMaxExprs();
ExprCoverageEligibleVisitor elgibleVisitor(nodep);
if (elgibleVisitor.eligible()) {
std::stringstream emitV;
V3EmitV::verilogForTree(nodep, emitV);
// Add new expression with a single term
CoverExpr expr;
expr.emplace_back(nodep, m_objective, emitV.str());
m_exprs.push_back(std::move(expr));
checkMaxExprs();
} else {
exprUnsupported(nodep, "not coverage eligible");
}
}
lineTrack(nodep);
}
@ -901,6 +941,17 @@ class CoverageVisitor final : public VNVisitor {
lineTrack(nodep);
}
void exprUnsupported(AstNode* nodep, const string& why) {
UINFO(9, "unsupported: " << why << " " << nodep << endl);
bool wasSeeking = m_seeking == SEEKING;
Objective oldSeeking = m_seeking;
if (wasSeeking) abortExprCoverage();
m_seeking = ABORTED;
iterateChildren(nodep);
lineTrack(nodep);
if (!wasSeeking) m_seeking = oldSeeking;
}
public:
// CONSTRUCTORS
explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); }

View File

@ -155,6 +155,7 @@ class DelayedVisitor final : public VNVisitor {
struct { // Stuff needed for Scheme::FlagShared
AstActive* activep; // The active block for the Pre/Post logic
AstAlwaysPost* postp; // The post block for commiting results
AstVarScope* commitFlagp; // The commit flag variable, for reuse
AstIf* commitIfp; // The previous if statement for committing, for reuse
} m_flagSharedKit;
struct { // Stuff needed for Scheme::FlagUnique
@ -346,8 +347,8 @@ class DelayedVisitor final : public VNVisitor {
arrSelp->bitp(captureVal(scopep, insertp, arrSelp->bitp()->unlinkFrBack(), tmpName));
nodep = arrSelp->fromp();
}
// What remains must be an AstVarRef
UASSERT_OBJ(VN_IS(nodep, VarRef), lhsp, "Malformed LHS in NBA");
// What remains must be an AstVarRef, or some sort of select, we assume can reuse it.
UASSERT_OBJ(nodep->isPure(), lhsp, "Malformed LHS in NBA");
// Now have been converted to use the captured values
return lhsp;
}
@ -421,6 +422,9 @@ class DelayedVisitor final : public VNVisitor {
AstAlwaysPost* const postp = new AstAlwaysPost{flp};
activep->addStmtsp(postp);
vscpInfo.flagSharedKit().postp = postp;
// Initialize
vscpInfo.flagSharedKit().commitFlagp = nullptr;
vscpInfo.flagSharedKit().commitIfp = nullptr;
}
void convertSchemeFlagShared(AstAssignDly* nodep, AstVarScope* vscp, VarScopeInfo& vscpInfo) {
UASSERT_OBJ(vscpInfo.m_scheme == Scheme::FlagShared, vscp, "Inconsistent NBA scheme");
@ -443,14 +447,16 @@ class DelayedVisitor final : public VNVisitor {
const bool consecutive = nodep == m_nextDlyp;
m_nextDlyp = VN_CAST(nodep->nextp(), AssignDly);
VarScopeInfo* const prevVscpInfop = consecutive ? &m_vscpInfo(m_prevVscp) : nullptr;
// We can reuse the flag of the previous assignment if:
const bool reuseTheFlag =
// Consecutive NBAs
consecutive
// ... that use the same scheme
&& m_vscpInfo(m_prevVscp).m_scheme == Scheme::FlagShared
&& prevVscpInfop->m_scheme == Scheme::FlagShared
// ... and share the same overall update domain
&& m_vscpInfo(m_prevVscp).senTreep()->sameTree(vscpInfo.senTreep());
&& prevVscpInfop->senTreep()->sameTree(vscpInfo.senTreep());
if (!reuseTheFlag) {
// Create new flag
@ -466,10 +472,25 @@ class DelayedVisitor final : public VNVisitor {
// Add the 'Post' scheduled commit
AstIf* const ifp = new AstIf{flp, new AstVarRef{flp, flagVscp, VAccess::READ}};
vscpInfo.flagSharedKit().postp->addStmtsp(ifp);
vscpInfo.flagSharedKit().commitFlagp = flagVscp;
vscpInfo.flagSharedKit().commitIfp = ifp;
} else {
// Reuse the commit block of the previous assignment
vscpInfo.flagSharedKit().commitIfp = m_vscpInfo(m_prevVscp).flagSharedKit().commitIfp;
if (vscp != m_prevVscp) {
// Different variable, ensure the commit block exists for this variable,
// can reuse existing one with the same flag, otherwise create a new one.
AstVarScope* const flagVscp = prevVscpInfop->flagSharedKit().commitFlagp;
UASSERT_OBJ(flagVscp, nodep, "Commit flag of previous assignment should exist");
if (vscpInfo.flagSharedKit().commitFlagp != flagVscp) {
AstIf* const ifp = new AstIf{flp, new AstVarRef{flp, flagVscp, VAccess::READ}};
vscpInfo.flagSharedKit().postp->addStmtsp(ifp);
vscpInfo.flagSharedKit().commitFlagp = flagVscp;
vscpInfo.flagSharedKit().commitIfp = ifp;
}
} else {
// Same variable, reuse the commit block of the previous assignment
vscpInfo.flagSharedKit().commitFlagp = prevVscpInfop->flagSharedKit().commitFlagp;
vscpInfo.flagSharedKit().commitIfp = prevVscpInfop->flagSharedKit().commitIfp;
}
++m_nSharedSetFlags;
}
// Commit the captured value to the captured destination

View File

@ -74,7 +74,7 @@ class DescopeVisitor final : public VNVisitor {
string name = scopep->name();
string::size_type pos;
if ((pos = name.rfind('.')) != string::npos) name.erase(0, pos + 1);
ret.thisPtr = VSelfPointerText{VSelfPointerText::This(), name};
ret.thisPtr = VSelfPointerText{VSelfPointerText::This{}, name};
}
return ret.thisPtr;
}
@ -104,9 +104,9 @@ class DescopeVisitor final : public VNVisitor {
if (VN_IS(scopep->modp(), Class)) {
// Direct reference to class members are from within the class itself, references from
// outside the class must go via AstMemberSel
return VSelfPointerText{VSelfPointerText::This()};
return VSelfPointerText{VSelfPointerText::This{}};
} else if (relativeRefOk && scopep == m_scopep) {
return VSelfPointerText{VSelfPointerText::This()};
return VSelfPointerText{VSelfPointerText::This{}};
} else if (relativeRefOk && !m_modSingleton && scopep->aboveScopep() == m_scopep
&& VN_IS(scopep->modp(), Module)) {
// Reference to scope of instance directly under this module, can just "this->cell",
@ -215,9 +215,9 @@ class DescopeVisitor final : public VNVisitor {
makePublicFuncWrappers();
}
void visit(AstScope* nodep) override {
VL_RESTORER(m_scopep);
m_scopep = nodep;
iterateChildren(nodep);
m_scopep = nullptr;
}
void visit(AstVarScope* nodep) override {
// Delete the varscope when we're finished

View File

@ -193,7 +193,7 @@ void DfgGraph::dumpDotFile(const string& filename, const string& label) const {
// This generates a file used by graphviz, https://www.graphviz.org
// "hardcoded" parameters:
const std::unique_ptr<std::ofstream> os{V3File::new_ofstream(filename)};
if (os->fail()) v3fatal("Cannot write to file: " << filename);
if (os->fail()) v3fatal("Can't write file: " << filename);
dumpDot(*os.get(), label);
os->close();
}
@ -244,7 +244,7 @@ void DfgGraph::dumpDotUpstreamCone(const string& fileName, const DfgVertex& vtx,
const string& name) const {
// Open output file
const std::unique_ptr<std::ofstream> os{V3File::new_ofstream(fileName)};
if (os->fail()) v3fatal("Cannot write to file: " << fileName);
if (os->fail()) v3fatal("Can't write file: " << fileName);
// Header
*os << "digraph dfg {\n";
@ -278,7 +278,7 @@ void DfgGraph::dumpDotAllVarConesPrefixed(const string& label) const {
const string coneName{prefix + sinkp->varp()->name()};
const string fileName{v3Global.debugFilename(coneName) + ".dot"};
const std::unique_ptr<std::ofstream> os{V3File::new_ofstream(fileName)};
if (os->fail()) v3fatal("Cannot write to file: " << fileName);
if (os->fail()) v3fatal("Can't write file: " << fileName);
// Header
*os << "digraph dfg {\n";

View File

@ -199,7 +199,7 @@ class DfgToAstVisitor final : DfgVisitor {
// VISITORS
void visit(DfgVertex* vtxp) override { // LCOV_EXCL_START
vtxp->v3fatal("Unhandled DfgVertex: " << vtxp->typeName());
vtxp->v3fatalSrc("Unhandled DfgVertex: " << vtxp->typeName());
} // LCOV_EXCL_STOP
void visit(DfgVarPacked* vtxp) override {

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