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. 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? 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? 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? May we assist you in trying to fix this in Verilator yourself?

View File

@ -12,15 +12,6 @@ on:
schedule: schedule:
- cron: '0 0 * * 0' # weekly - 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: defaults:
run: run:
shell: bash shell: bash
@ -32,134 +23,155 @@ concurrency:
jobs: jobs:
build: build-2404-gcc:
name: Build
uses: ./.github/workflows/reusable-build.yml
with:
os: ${{ matrix.os }}
cc: ${{ matrix.cc }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-24.04, ubuntu-22.04, ubuntu-20.04]
compiler:
- {cc: clang, cxx: clang++}
- {cc: gcc, cxx: g++}
include: include:
# Build GCC 10 on ubuntu-20.04 - {os: ubuntu-24.04, cc: gcc}
- 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:
- name: Checkout build-2404-clang:
uses: actions/checkout@v4 name: Build
with: uses: ./.github/workflows/reusable-build.yml
path: repo with:
os: ${{ matrix.os }}
- name: Cache $CCACHE_DIR cc: ${{ matrix.cc }}
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
strategy: strategy:
fail-fast: false fail-fast: false
matrix: 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: include:
# Test with GCC 10 on ubuntu-20.04, also test relocation - {os: ubuntu-24.04, cc: clang}
- {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:
- name: Download tar archive build-2204-gcc:
uses: actions/download-artifact@v4 name: Build
with: uses: ./.github/workflows/reusable-build.yml
name: ${{ env.VERILATOR_ARCHIVE }} with:
path: ${{ github.workspace }} os: ${{ matrix.os }}
cc: ${{ matrix.cc }}
strategy:
fail-fast: false
matrix:
include:
- {os: ubuntu-22.04, cc: gcc}
- name: Unpack tar archive build-2204-clang:
working-directory: ${{ github.workspace }} name: Build
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }} 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 test-2404-gcc:
uses: actions/cache@v4 name: Test | ${{ matrix.os }} | ${{ matrix.cc }}
env: needs: build-2404-gcc
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2 uses: ./.github/workflows/reusable-test.yml
with: with:
path: ${{ env.CCACHE_DIR }} os: ${{ matrix.os }}
key: ${{ env.CACHE_KEY }}-${{ github.sha }} cc: ${{ matrix.cc }}
restore-keys: | reloc: ${{ matrix.reloc }}
${{ env.CACHE_KEY }}- 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 test-2404-clang:
run: ./ci/ci-install.bash 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 test-2204-gcc:
env: name: Test | ${{ matrix.os }} | ${{ matrix.cc }}
TESTS: ${{ matrix.suite }} needs: build-2204-gcc
run: ./ci/ci-script.bash 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: lint-py:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
name: Lint Python name: Lint Python
env: env:
CI_OS_NAME: linux
CI_COMMIT: ${{ github.sha }}
CI_BUILD_STAGE_NAME: build CI_BUILD_STAGE_NAME: build
CI_RUNS_ON: ubuntu-22.04 CI_RUNS_ON: ubuntu-22.04
CCACHE_COMPRESS: 1
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_LIMIT_MULTIPLE: 0.95
strategy:
fail-fast: false
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4

View File

@ -76,11 +76,11 @@ jobs:
- name: Build and Push to Docker - name: Build and Push to Docker
uses: docker/build-push-action@v4 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: with:
context: ${{ env.build_context }} context: ${{ env.build_context }}
build-args: SOURCE_COMMIT=${{ env.git_tag }} build-args: SOURCE_COMMIT=${{ env.git_tag }}
platforms: linux/arm64,linux/amd64 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 }} tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }} 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 cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
project( project(
Verilator Verilator
VERSION 5.034 VERSION 5.036
HOMEPAGE_URL https://verilator.org HOMEPAGE_URL https://verilator.org
LANGUAGES CXX LANGUAGES CXX
) )
@ -134,10 +134,7 @@ configure_package_config_file(
INSTALL_DESTINATION . INSTALL_DESTINATION .
) )
install( install(FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config.cmake DESTINATION .)
FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config.cmake
DESTINATION .
)
configure_package_config_file( configure_package_config_file(
verilator-config-version.cmake.in 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! 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 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 with associative array access (#5484). [Ethan Sifferman]
* Fix short-circuiting on method calls (#5486). [Ethan Sifferman] * Fix short-circuiting on method calls (#5486). [Ethan Sifferman]
* Fix exponential concatenate performance (#5488). [Arkadiusz Kozdra, Antmicro Ltd.] * 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 randomize with foreach constraints (#5492). [Arkadiusz Kozdra, Antmicro Ltd.]
* Fix explicit CMAKE_INSTALL_PREFIX usages (#5500). [Fabian Keßler] * Fix explicit CMAKE_INSTALL_PREFIX usages (#5500). [Fabian Keßler]
* Fix configure inserting absolute paths for Python and Perl (#5504) (#5505). [Nathan Graybeal] * 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 parsing but otherwise ignore std::randomize (#5354). [Arkadiusz Kozdra, Antmicro Ltd.]
* Add Verilated cc define when `--timing` used (#5383). [Kaleb Barrett] * Add Verilated cc define when `--timing` used (#5383). [Kaleb Barrett]
* Improve emitted code to use a reference for VlSelf (#5254). [Yangyu Chen] * 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 fusing macro arguments to not ignore whitespace (#5061). [Tudor Timi]
* Fix optimized-out sensitivity trees with `--timing` (#5080) (#5349). [Krzysztof Bieganski, Antmicro Ltd.] * Fix optimized-out sensitivity trees with `--timing` (#5080) (#5349). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix classes/modules of case-similar names (#5109). [Arkadiusz Kozdra] * 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 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 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 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 make flows to pass PYTHON3 (like PERL) (#5307) (#5308). [Markus Krause]
* Fix assert on wide expression (#5319) (#5324). [Varun Koyyalagunta] * Fix assert on wide expression (#5319) (#5324). [Varun Koyyalagunta]
* Fix output clock variable overwriting signal (#5320) (#5347). [Krzysztof Bieganski, Antmicro Ltd.] * 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_get()` and `vpi_get64()` to return vpiUndefined on errors (#4795). [Marlon James]
* Fix VPI parameter iteration (#4798). [Marlon James] * Fix VPI parameter iteration (#4798). [Marlon James]
* Fix delays using wrong timeunit when modules inlined (#4806). [Paul Wright] * 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 null pointer dereference (#4810) (#4825). [Adrian Sampson]
* Fix compilation error on multi-inherited interface class usage (#4819). * Fix compilation error on multi-inherited interface class usage (#4819).
* Fix maybe-uninitialized compiler warning (#4820) (#4822). [Larry Doolittle] * 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 conflicted namespace for coroutines (#4701) (#4707). [Jinyan Xu]
* Fix compilers seeing empty input due to file system races (#4708). [Flavien Solt] * Fix compilers seeing empty input due to file system races (#4708). [Flavien Solt]
* Fix shift of > 32-bit number (#4719). [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 power operator with wide numbers and constants (#4721) (#4763). [Flavien Solt]
* Fix parameter passing to ports (#4723). [Ryszard Rozak, Antmicro Ltd.] * Fix parameter passing to ports (#4723). [Ryszard Rozak, Antmicro Ltd.]
* Fix block names of nested do..while loops (#4728). [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 $finish twice to no longer exit (#4757). [Tim Hutt]
* Fix dynamic NBA conditions (#4773). [Krzysztof Bieganski, Antmicro Ltd.] * 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 `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] * Fix select value too wide (#5148) (#5153). [Dercury]
@ -1211,7 +1292,7 @@ Verilator 4.218 2022-01-17
* Support class static members (#2233). * Support class static members (#2233).
* Support force/release (#2431) (#2593). [Shunyao CAD] * 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 lower dimension looping in foreach loops (#3172). [Ehab Ibrahim]
* Support up to 64 bit enums for .next/.prev/.name (#3244). [Alexander Grobman] * Support up to 64 bit enums for .next/.prev/.name (#3244). [Alexander Grobman]
* Reduce .rodata footprint of trace initialization (#3250). [Geza Lore, Shunyao CAD] * Reduce .rodata footprint of trace initialization (#3250). [Geza Lore, Shunyao CAD]
@ -1435,7 +1516,7 @@ Verilator 4.200 2021-03-12
**Major:** **Major:**
* Add simulation context (VerilatedContext) to allow multiple fully independent * 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. * Add context->time() and context->timeInc() API calls, to set simulation time.
These now are recommended in place of the legacy sc_time_stamp(). 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 slice-assign overflow (#2803) (#2811). [David Turner]
* Fix interface array connection ordering broken in v4.110 (#2827). [Don Owen] * 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 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 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 vpiLeftRange on little-endian memories (#2696). [Marlon James]
* Fix VPI module tree (#2704). [Todd Strader] * Fix VPI module tree (#2704). [Todd Strader]
* Fix vpi_release_handle to be called implicitly per IEEE (#2706). * 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 $urandom_range maximum value (#2723). [Nandu Raj]
* Fix tracing empty sc module (#2729). * Fix tracing empty sc module (#2729).
* Fix generate for unrolling to be signed (#2730). [yanx21] * Fix generate for unrolling to be signed (#2730). [yanx21]
@ -1607,11 +1688,11 @@ Verilator 4.040 2020-08-15
**Minor:** **Minor:**
* Fix arrayed interfaces, broke in 4.038 (#2468). [Josh Redford] * 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] * Support simple function localparams (#2461). [James Hanlon]
* Miscellaneous parsing error changes towards UVM support. * Miscellaneous parsing error changes towards UVM support.
* Fix arrayed interfaces (#2469). [Josh Redford] * 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 combining different-width parameters (#2484). [abirkmanis]
* Fix protect-lib without sequential logic (#2492). [Yutetsu TAKATSUKASA] * Fix protect-lib without sequential logic (#2492). [Yutetsu TAKATSUKASA]
* Fix V3Unknown from running with flat XML output (#2494). [James Hanlon] * 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. waivers to the warnings emitted during a Verilator run.
* Support verilator_coverage --write-info for lcov HTML reports. * Support verilator_coverage --write-info for lcov HTML reports.
* Line Coverage now tracks all statement lines, not just branch lines. * 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 multi channel descriptor I/O (#2190) [Stephen Henry]
* Support $countbits. (#2287) [Yossi Nivin] * Support $countbits (#2287). [Yossi Nivin]
* Support $isunbounded and parameter $. (#2104) * Support $isunbounded and parameter $ (#2104).
* Support unpacked array .sum and .product. * 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 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 $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 Verilator 4.034 2020-05-03

View File

@ -528,6 +528,8 @@ GERSEMI_FLAGS = -i
format-cmake: format-cmake:
$(GERSEMI) $(GERSEMI_FLAGS) $(CMAKE_FILES) $(GERSEMI) $(GERSEMI_FLAGS) $(CMAKE_FILES)
format-yaml: yamlfix
PYLINT = pylint PYLINT = pylint
PYLINT_FLAGS = --recursive=n --score=n --disable=R0801 PYLINT_FLAGS = --recursive=n --score=n --disable=R0801
PYLINT_TEST_FLAGS = $(PYLINT_FLAGS) --disable=C0103,C0114,C0116,C0209,C0411,C0413,C0301,R0801,R0912,R0915,R0916,R1702,W0511,W0621 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 -f *.tex
rm -rf examples/*/obj_dir* examples/*/logs rm -rf examples/*/obj_dir* examples/*/logs
rm -rf test_*/obj_dir 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/fuzzer/dictionary
rm -rf nodist/obj_dir rm -rf nodist/obj_dir
rm -rf verilator.txt rm -rf verilator.txt

View File

@ -1,7 +1,7 @@
.. Github doesn't render images unless absolute URL .. Github doesn't render images unless absolute URL
.. Do not know of a conditional tag, "only: github" nor "github display" works .. 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 .. |badge1| image:: https://img.shields.io/badge/Website-Verilator.org-181717.svg
:target: https://verilator.org :target: https://verilator.org
@ -13,8 +13,6 @@
:target: https://repology.org/project/verilator/versions :target: https://repology.org/project/verilator/versions
.. |badge5| image:: https://img.shields.io/docker/pulls/verilator/verilator .. |badge5| image:: https://img.shields.io/docker/pulls/verilator/verilator
:target: https://hub.docker.com/r/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 .. |badge7| image:: https://github.com/verilator/verilator/workflows/build/badge.svg
:target: https://github.com/verilator/verilator/actions?query=workflow%3Abuild :target: https://github.com/verilator/verilator/actions?query=workflow%3Abuild
@ -134,7 +132,7 @@ Related Projects
- `GTKwave <http://gtkwave.sourceforge.net/>`_ - Waveform viewer for - `GTKwave <http://gtkwave.sourceforge.net/>`_ - Waveform viewer for
Verilator traces. 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. 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. # This is similar to quotemeta() but less aggressive.
# There's no need to escape hyphens, periods, or forward slashes # There's no need to escape hyphens, periods, or forward slashes
# for the shell as these have no special meaning to the shell. # 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; return $arg;
} }
@ -341,11 +341,12 @@ detailed descriptions of these arguments.
--no-debug-leak Disable leaking memory in --debug mode --no-debug-leak Disable leaking memory in --debug mode
--debugi <level> Enable debugging at a specified level --debugi <level> Enable debugging at a specified level
--debugi-<srcfile> <level> Enable debugging a source file at a 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 --no-decoration Disable comments and lower spacing level
--decorations <level> Set output comment and spacing level
--default-language <lang> Default language to parse --default-language <lang> Default language to parse
+define+<var>=<value> Set preprocessor define +define+<var>=<value> Set preprocessor define
--dpi-hdr-only Only produce the DPI header file --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-defines Show preprocessor defines with -E
--dump-dfg Enable dumping DfgGraphs to .dot files --dump-dfg Enable dumping DfgGraphs to .dot files
--dump-graph Enable dumping V3Graphs 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-addrids Use short identifiers instead of addresses
--dump-tree-dot Enable dumping Ast .tree.dot debug files --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-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-dfg <level> Enable dumping DfgGraphs to .dot files at level
--dumpi-graph <level> Enable dumping V3Graphs 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 <level> Enable dumping Ast .tree files at level
--dumpi-tree-json <level> Enable dumping Ast .tree.json 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 -E Preprocess, but do not compile
--emit-accessors Emit getter and setter methods for model top class --emit-accessors Emit getter and setter methods for model top class
--error-limit <value> Abort after this number of errors --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-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 --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 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-meta-output .tree.meta.json output filename
--json-only-output .tree.json output filename
--l2-name <value> Verilog scope name of the top module --l2-name <value> Verilog scope name of the top module
--language <lang> Default language standard to parse --language <lang> Default language standard to parse
-LDFLAGS <flags> Linker pre-object arguments for makefile -LDFLAGS <flags> Linker pre-object arguments for makefile
@ -399,20 +399,20 @@ detailed descriptions of these arguments.
+libext+<ext>+[ext]... Extensions for finding modules +libext+<ext>+[ext]... Extensions for finding modules
--lint-only Lint, but do not make output --lint-only Lint, but do not make output
--localize-max-size <value> Tune localize optimization variable size --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 Generate C++ main() file
--main-top-name Specify top name passed to Verilated model in generated C++ main --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) --max-num-width <value> Maximum number width (default: 64K)
--Mdir <directory> Name of output object directory --Mdir <directory> Name of output object directory
--MMD Create .d dependency files --MMD Create .d dependency files
--mod-prefix <topname> Name to prepend to lower classes --mod-prefix <topname> Name to prepend to lower classes
--MP Create phony dependency targets --MP Create phony dependency targets
+notimingchecks Ignored +notimingchecks Ignored
-o <executable> Name of final executable
-O0 Disable optimizations -O0 Disable optimizations
-O3 High-performance optimizations -O3 High-performance optimizations
-O<optimization-letter> Selectable optimizations -O<optimization-letter> Selectable optimizations
-o <executable> Name of final executable
--output-groups <numfiles> Group .cpp files into larger ones --output-groups <numfiles> Group .cpp files into larger ones
--output-split <statements> Split .cpp files into pieces --output-split <statements> Split .cpp files into pieces
--output-split-cfuncs <statements> Split model functions --output-split-cfuncs <statements> Split model functions
@ -467,23 +467,25 @@ detailed descriptions of these arguments.
--threads <threads> Enable multithreading --threads <threads> Enable multithreading
--threads-dpi <mode> Enable multithreaded DPI --threads-dpi <mode> Enable multithreaded DPI
--threads-max-mtasks <mtasks> Tune maximum mtask partitioning --threads-max-mtasks <mtasks> Tune maximum mtask partitioning
--timing Enable timing support
--no-timing Disable timing support
--timescale <timescale> Sets default timescale --timescale <timescale> Sets default timescale
--timescale-override <timescale> Overrides all timescales --timescale-override <timescale> Overrides all timescales
--timing Enable timing support
--no-timing Disable timing support
--top <topname> Alias of --top-module --top <topname> Alias of --top-module
--top-module <topname> Name of top-level input 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-coverage Enable tracing of coverage
--trace-depth <levels> Depth of tracing --trace-depth <levels> Depth of tracing
--trace-fst Enable FST waveform creation --trace-fst Enable FST waveform creation
--trace-max-array <depth> Maximum array depth for tracing --trace-max-array <depth> Maximum array depth for tracing
--trace-max-width <width> Maximum bit width for tracing --trace-max-width <width> Maximum bit width for tracing
--trace-params Enable tracing of parameters --trace-params Enable tracing of parameters
--trace-saif Enable SAIF file creation
--trace-structs Enable tracing structure names --trace-structs Enable tracing structure names
--trace-threads <threads> Enable FST waveform creation on separate threads --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 --no-trace-top Do not emit traces for signals in the top module generated by verilator
--trace-underscore Enable tracing of _signals --trace-underscore Enable tracing of _signals
--trace-vcd Enable VCD waveform creation
-U<var> Undefine preprocessor define -U<var> Undefine preprocessor define
--no-unlimited-stack Don't disable stack size limit --no-unlimited-stack Don't disable stack size limit
--unroll-count <loops> Tune maximum loop iterations --unroll-count <loops> Tune maximum loop iterations
@ -492,8 +494,8 @@ detailed descriptions of these arguments.
-V Verbose version and config -V Verbose version and config
-v <filename> Verilog library -v <filename> Verilog library
--valgrind Run Verilator under valgrind --valgrind Run Verilator under valgrind
--verilate-jobs Job threads for Verilation stage
--no-verilate Skip Verilation and just compile previously Verilated code --no-verilate Skip Verilation and just compile previously Verilated code
--verilate-jobs Job threads for Verilation stage
+verilog1995ext+<ext> Synonym for +1364-1995ext+<ext> +verilog1995ext+<ext> Synonym for +1364-1995ext+<ext>
+verilog2001ext+<ext> Synonym for +1364-2001ext+<ext> +verilog2001ext+<ext> Synonym for +1364-2001ext+<ext>
--version Show program version and exits --version Show program version and exits
@ -526,9 +528,9 @@ description of these arguments.
=for VL_SPHINX_EXTRACT "_build/gen/args_verilated.rst" =for VL_SPHINX_EXTRACT "_build/gen/args_verilated.rst"
+verilator+coverage+file+<filename> Set coverage output filename
+verilator+debug Enable debugging +verilator+debug Enable debugging
+verilator+debugi+<value> Enable debugging at a level +verilator+debugi+<value> Enable debugging at a level
+verilator+coverage+file+<filename> Set coverage output filename
+verilator+error+limit+<value> Set error limit +verilator+error+limit+<value> Set error limit
+verilator+help Show help +verilator+help Show help
+verilator+noassert Disable assert checking +verilator+noassert Disable assert checking

View File

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

View File

@ -40,7 +40,7 @@ fi
install-vcddiff() { install-vcddiff() {
TMP_DIR="$(mktemp -d)" TMP_DIR="$(mktemp -d)"
git clone https://github.com/veripool/vcddiff "$TMP_DIR" 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}" "$MAKE" -C "${TMP_DIR}"
sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin 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 update
sudo apt-get install ccache help2man libfl-dev || sudo apt-get install ccache help2man libfl-dev ||
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 # 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 ||
sudo apt-get install libgoogle-perftools-dev sudo apt-get install libgoogle-perftools-dev
fi 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 ||
sudo apt-get install libsystemc libsystemc-dev sudo apt-get install libsystemc libsystemc-dev
fi 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 ||
sudo apt-get install bear mold sudo apt-get install bear mold
fi 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 ||
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 # 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 ||
sudo apt-get install python3-clang mold sudo apt-get install python3-clang mold
fi 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 ||
sudo apt-get install libsystemc-dev sudo apt-get install libsystemc-dev
fi fi

View File

@ -87,7 +87,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
fi fi
# Run sanitize on Ubuntu 22.04 only # 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 TEST_REGRESS=test_regress
if [ "$CI_RELOC" == 1 ]; then 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" export VERILATOR_ROOT="$RELOC_DIR/relocated-install/share/verilator"
TEST_REGRESS="$RELOC_DIR/test_regress" TEST_REGRESS="$RELOC_DIR/test_regress"
mv test_regress "$TEST_REGRESS" mv test_regress "$TEST_REGRESS"
NODIST="$RELOC_DIR/nodist"
mv nodist "$NODIST"
# Feeling brave? # Feeling brave?
find . -delete find . -delete
ls -la . ls -la .
@ -107,22 +109,25 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
ccache -z ccache -z
case $TESTS in case $TESTS in
dist-vlt-0) 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) 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) 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) 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) 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) 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) coverage-all)
nodist/code_coverage --stages 1- nodist/code_coverage --stages 1-

View File

@ -10,7 +10,7 @@
# Then 'make maintainer-dist' # Then 'make maintainer-dist'
#AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel]) #AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[5.034 2025-02-24], AC_INIT([Verilator],[5.036 2025-04-27],
[https://verilator.org], [https://verilator.org],
[verilator],[https://verilator.org]) [verilator],[https://verilator.org])
@ -432,6 +432,7 @@ AC_SUBST(HAVE_COROUTINES)
# Flags for compiling Verilator internals including parser always # Flags for compiling Verilator internals including parser always
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Qunused-arguments) _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,-faligned-new)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-unused-parameter) _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-unused-parameter)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-shadow) _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-shadow)
@ -469,6 +470,7 @@ CFG_CXX_FLAGS_CMAKE="-faligned-new"
m4_foreach([cflag],[ m4_foreach([cflag],[
[-fbracket-depth=4096], [-fbracket-depth=4096],
[-fcf-protection=none], [-fcf-protection=none],
[-Xclang -fno-pch-timestamp],
[-mno-cet], [-mno-cet],
[-Qunused-arguments], [-Qunused-arguments],
[-Wno-bool-operation], [-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-libgcc)
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libstdc++) _MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libstdc++)
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -Xlinker -gc-sections) _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 else
LTCMALLOC=-ltcmalloc_minimal LTCMALLOC=-ltcmalloc_minimal
fi fi

View File

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

View File

@ -77,6 +77,7 @@ help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
clean mostlyclean distclean maintainer-clean:: clean mostlyclean distclean maintainer-clean::
rm -rf _build
rm -f $(SCRIPTS) *.tmp rm -f $(SCRIPTS) *.tmp
rm -f *.aux *.cp *.cps *.dvi *.fn *.fns *.ky *.kys *.log rm -f *.aux *.cp *.cps *.dvi *.fn *.fns *.ky *.kys *.log
rm -f *.pg *.pgs *.toc *.tp *.tps *.vr *.vrs *.idx 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 # Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, # (source start file, target name, title,
# author, documentclass [howto, manual, or own class]). # author, documentclass [howto, manual, or own class]).
# latex_documents = [ # latex_documents = [ ... ]
# (
# master_doc,
# "Verilog-to-Routing.tex",
# "Verilog-to-Routing Documentation",
# "VTR Developers",
# "manual",
# ),
# ]
# For "manual" documents, if this is true, then toplevel headings are parts, # For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters. # 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 :code:`$` character, i.e.: :code:`rootp` points to the Verilated
SystemVerilog :code:`$root` scope. SystemVerilog :code:`$root` scope.
* Replace :code:`modelp->internal->member->lookup` references with * Replace :code:`modelp->internal->member` references with
:code:`modelp->rootp->internal->member->lookup` references, which :code:`modelp->rootp->internal->member` references, which
contain one additional indirection via the :code:`rootp` pointer. 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 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 clear which parts are necessary to reproduce the bug. In these cases, an
Open Source tool called `sv-bugpoint 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. reduce a SystemVerilog design to the smallest possible reproducer.
It can be used to automatically reduce a design with hundreds of thousands of 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. lines to a minimal test case while preserving the bug-inducing behavior.
Please refer to the `README With :vlopt:`--debug`, Verilator will write a *{prefix}*\ __inputs\ .vpp
<https://github.com/antmicro/sv-bugpoint/blob/main/README.md>`_ file for more 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`. information on how to use `sv-bugpoint`.
.. Contributing .. Contributing

View File

@ -47,6 +47,11 @@ Summary:
Display help and exit. 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> .. option:: +verilator+prof+exec+file+<filename>
When a model was Verilated using :vlopt:`--prof-exec`, sets the 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 simulation runtime random seed value. If zero or not specified picks a
value from the system random number generator. 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 .. option:: +verilator+V
Shows the verbose version, including configuration information. Shows the verbose version, including configuration information.

View File

@ -1,8 +1,9 @@
.. Copyright 2003-2025 by Wilson Snyder. .. Copyright 2003-2025 by Wilson Snyder.
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 .. 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. The following arguments may be passed to the "verilator" executable.
@ -11,20 +12,6 @@ Summary:
.. include:: ../_build/gen/args_verilator.rst .. 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> .. option:: <file.a/.o/.so>
Specifies optional object or library files to be linked with the 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 rule that uses these files when linking the module's executable. This
generally is only useful when used with the :vlopt:`--exe` option. 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-1995ext+<ext>
.. option:: +1364-2001ext+<ext> .. option:: +1364-2001ext+<ext>
@ -146,13 +147,16 @@ Summary:
This option was named `--bin` before version 4.228. 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 Specify the level of parallelism for :vlopt:`--build`. If zero, uses the
number of threads in the current hardware. Otherwise, the <value> must number of threads in the current hardware. Otherwise, the <value> must
be a positive integer specifying the maximum number of parallel build be a positive integer specifying the maximum number of parallel build
jobs. 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 This forms the :command:`make` option ``-j`` value, unless the
:option:`MAKEFLAGS` environment variable contains ``-jobserver-auth``, :option:`MAKEFLAGS` environment variable contains ``-jobserver-auth``,
in which case Verilator assumes that make's jobserver is being used. 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 detailed messages. See :vlopt:`--debug` for other implications of
enabling debug. 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 When creating output Verilated code, set level of comment and whitespace
decoration. decoration.
@ -359,10 +363,6 @@ Summary:
between different Verilator runs, this may harm compile caching and between different Verilator runs, this may harm compile caching and
should only be used for debug. should only be used for debug.
.. option:: --no-decoration
Alias for ``--decorations none``.
.. option:: --default-language <value> .. option:: --default-language <value>
Select the language used by default when first processing each 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 name or location of the emitted DPI header file, it is output in
:vlopt:`--Mdir` as it would be without this option. :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 .. option:: --dump-defines
With :vlopt:`-E`, suppress normal output, and instead print a list of 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 :vlopt:`--debug --no-dump-tree <--dump-tree>` may be useful if the dump
files are large and not desired. 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 .. option:: --dump-tree-addrids
Rarely needed - for developer use. Replace AST node addresses with 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 by a newly allocated node after a node with the same address has been
dumped and then freed. dumped and then freed.
.. option:: --dump-<srcfile> .. option:: --dump-tree-dot
Rarely needed - for developer use. Enable all dumping in the given Rarely needed. Enable dumping Ast .tree.dot debug files in Graphviz
source file at level 3. 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> .. option:: --dumpi-dfg <level>
@ -476,13 +483,6 @@ Summary:
Rarely needed - for developer use. Set internal Ast JSON dumping level Rarely needed - for developer use. Set internal Ast JSON dumping level
globally to the specified value. 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 .. option:: -E
Preprocess the source code, but do not compile, similar to C++ Preprocess the source code, but do not compile, similar to C++
@ -566,7 +566,7 @@ Summary:
.. option:: -fno-const .. 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 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 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. Disable individual DFG peephole optimizer pattern.
.. option:: -fno-dfg-pre-inline
Do not apply the DFG optimizer before inlining.
.. option:: -fno-dfg-post-inline .. option:: -fno-dfg-post-inline
Do not apply the DFG optimizer after inlining. 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-expand
.. option:: -fno-func-opt .. option:: -fno-func-opt
@ -641,6 +641,11 @@ Summary:
are typically used only when recommended by a maintainer to help debug are typically used only when recommended by a maintainer to help debug
or work around an issue. 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> .. option:: -future0 <option>
Rarely needed. Suppress an unknown Verilator option for an option that 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`, Generate a true-random key suitable for use with :vlopt:`--protect-key`,
print it, and exit immediately. 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> .. option:: --get-supported <feature>
If the given feature is supported, print "1" and exit If the given feature is supported, print "1" and exit
@ -733,6 +730,14 @@ Summary:
Feature may be one of the following: COROUTINES, SYSTEMC. 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 .. option:: --help
Displays this message and program version and exits. Displays this message and program version and exits.
@ -788,9 +793,21 @@ Summary:
Specify the level of parallelism for :vlopt:`--build` if Specify the level of parallelism for :vlopt:`--build` if
:vlopt:`--build-jobs` isn't provided, and the internal compilation steps :vlopt:`--build-jobs` isn't provided, and the internal compilation steps
of Verilator if :vlopt:`--verilate-jobs` isn't provided. If zero, uses of Verilator if :vlopt:`--verilate-jobs` isn't provided. Also sets
the number of threads in the current hardware. Otherwise, must be a :vlopt:`--output-groups` if isn't provided.
positive integer specifying the maximum number of parallel build jobs.
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 .. option:: --json-only
@ -815,15 +832,6 @@ Summary:
Specifies the filename for the main output file (`.tree.json`) of --json-only. Specifies the filename for the main output file (`.tree.json`) of --json-only.
Using this option automatically sets :vlopt:`--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> .. option:: --l2-name <value>
Instead of using the module name when showing Verilog scope, use the 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 Rarely needed. Set the maximum variable size in bytes for it to be
subject to localizing-to-stack optimization. Defaults to 1024. 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 .. option:: --main
Generates a top-level C++ main() file that supports parsing arguments, 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. 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> .. option:: --max-num-width <value>
Set the maximum number literal width (e.g., in 1024'd22 this Set the maximum number literal width (e.g., in 1024'd22 this
@ -978,6 +988,11 @@ Summary:
Ignored for compatibility with other simulators. 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 .. option:: -O0
Disables optimization of the model. Disables optimization of the model.
@ -998,11 +1013,6 @@ Summary:
is deprecated and the various `-f<optimization>` arguments should be is deprecated and the various `-f<optimization>` arguments should be
used instead. 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 .. option:: --no-order-clock-delay
Deprecated and has no effect (ignored). Deprecated and has no effect (ignored).
@ -1016,18 +1026,24 @@ Summary:
.. option:: --output-groups <numfiles> .. option:: --output-groups <numfiles>
Enables concatenating the output .cpp files into the given number of Enables concatenating the output .cpp files into the given number of
effective output .cpp files. This is useful if the compiler startup effective output .cpp files. This minimizes the compiler startup
overhead from compiling many small files becomes unacceptable, overhead from compiling many small files, which can happen in designs
which can happen in designs making extensive use of SystemVerilog classes, making extensive use of SystemVerilog classes, templates or generate
templates or generate blocks. blocks.
Using :vlopt:`--output-groups` can adversely impact caching and stability Using :vlopt:`--output-groups` can adversely impact caching and stability
(as in reproducibility) of compiled code. Compilation of larger .cpp (as in reproducibility) of compiled code. Compilation of larger .cpp
files also has higher memory requirements. Too low values might result in files also has higher memory requirements. Too low values might result in
swap thrashing with large designs, high values give no benefits. The swap thrashing with large designs, high values give no benefits.
value should range from 2 to 20 for small to medium designs.
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> .. option:: --output-split <statements>
@ -1088,6 +1104,14 @@ Summary:
position to indicate the corresponding bit of the __out variable has position to indicate the corresponding bit of the __out variable has
a value being driven from within the Verilated model. 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 .. option:: --pins-sc-uint
Specifies SystemC inputs/outputs greater than 2 bits wide should use 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>. 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 .. option:: --pins-uint8
Specifies SystemC inputs/outputs smaller than the Specifies SystemC inputs/outputs smaller than the
@ -1468,25 +1484,21 @@ Summary:
A synonym for :vlopt:`+1800-2023ext+\<ext\>`. 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 .. option:: --no-threads
Deprecated and has no effect (ignored). Deprecated and has no effect (ignored).
In versions before 5.004, created a model which was not thread-safe. 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 When using :vlopt:`--threads`, controls which DPI imported tasks and
functions are considered thread-safe. functions are considered thread-safe.
@ -1520,10 +1532,10 @@ Summary:
does not occur before a given module. Default is "1ps/1ps" (to match does not occur before a given module. Default is "1ps/1ps" (to match
SystemC). This is overridden by :vlopt:`--timescale-override`. SystemC). This is overridden by :vlopt:`--timescale-override`.
.. option:: --timescale-override <timeunit>/<timeprecision>
.. option:: --timescale-override /<timeprecision> .. option:: --timescale-override /<timeprecision>
.. option:: --timescale-override <timeunit>/<timeprecision>
Overrides all "\`timescale"s in sources. The timeunit may be left empty Overrides all "\`timescale"s in sources. The timeunit may be left empty
to specify only to override the timeprecision, e.g. "/1fs". to specify only to override the timeprecision, e.g. "/1fs".
@ -1555,26 +1567,19 @@ Summary:
.. option:: --trace .. option:: --trace
Adds waveform tracing code to the model using VCD format. This overrides Deprecated; use :vlopt:`--trace-fst`, :vlopt:`--trace-saif` or
:vlopt:`--trace-fst`. :vlopt:`--trace-vcd` instead.
Verilator will generate additional :file:`<prefix>__Trace*.cpp` files Using :vlopt:`--trace` without :vlopt:`--trace-fst` nor
must be compiled. In addition :file:`verilated_vcd_sc.cpp` :vlopt:`--trace-fst` requests VCD traces.
(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, Using :vlopt:`--trace` :vlopt:`--trace-fst` requests FST traces.
even when tracing is not turned on during model execution.
When using :vlopt:`--threads`, VCD tracing is parallelized, using the Using :vlopt:`--trace` :vlopt:`--trace-saif` requests SAIF traces.
same number of threads as passed to :vlopt:`--threads`.
.. option:: --trace-coverage .. 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 traced signal for every :vlopt:`--coverage-line` or
:vlopt:`--coverage-user`\ -inserted coverage point, to assist in :vlopt:`--coverage-user`\ -inserted coverage point, to assist in
debugging coverage items. Note :vlopt:`--coverage-toggle` does not get debugging coverage items. Note :vlopt:`--coverage-toggle` does not get
@ -1614,6 +1619,12 @@ Summary:
Disable tracing of parameters. 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 .. option:: --trace-structs
Enable tracing to show the name of packed structure, union, and packed 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 underscore. Otherwise, these signals are not output during tracing. See
also :vlopt:`--coverage-underscore` option. 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> .. option:: -U<var>
Undefines the given preprocessor symbol. Undefines the given preprocessor symbol.
@ -1700,13 +1729,16 @@ Summary:
execute only the build. This can be useful for rebuilding the Verilated code execute only the build. This can be useful for rebuilding the Verilated code
produced by a previous invocation of Verilator. 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 Specify the level of parallelism for the internal compilation steps of
Verilator. If zero, uses the number of threads in the current hardware. Verilator. If zero, uses the number of threads in the current hardware.
Otherwise, must be a positive integer specifying the maximum number of Otherwise, must be a positive integer specifying the maximum number of
parallel build jobs. parallel build jobs.
If not provided, and :vlopt:`-j` is provided, the :vlopt:`-j` value is
used.
See also :vlopt:`-j`. See also :vlopt:`-j`.
.. option:: +verilog1995ext+<ext> .. option:: +verilog1995ext+<ext>
@ -1852,33 +1884,36 @@ Summary:
``-Wwarn-UNUSEDGENVAR`` ``-Wwarn-UNUSEDLOOP`` ``-Wwarn-UNUSEDPARAM`` ``-Wwarn-UNUSEDGENVAR`` ``-Wwarn-UNUSEDLOOP`` ``-Wwarn-UNUSEDPARAM``
``-Wwarn-UNUSEDSIGNAL`` ``-Wwarn-VARHIDDEN``. ``-Wwarn-UNUSEDSIGNAL`` ``-Wwarn-VARHIDDEN``.
.. option:: --x-assign 0 .. option:: --x-assign <mode>
.. option:: --x-assign 1
.. option:: --x-assign fast (default)
.. option:: --x-assign unique
Controls the two-state value that is substituted when an explicit X Controls the two-state value that is substituted when an explicit X
value is encountered in the source. "--x-assign fast", the default, value is encountered in the source.
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.
If using "--x-assign unique", you may want to seed your random number With "--x-assign 0",
generator such that each regression run gets a different randomization converts all Xs to 0s, and is also fast.
sequence. The simplest is to use the :vlopt:`+verilator+seed+\<value\>`
runtime option. Alternatively, use the system's :code:`srand48()` or for With "--x-assign 1",
Windows :code:`srand()` function to do this. You'll probably also want converts all Xs to 1s, this is nearly as fast as 0, but more likely to
to print any seeds selected, and code to enable rerunning with that same find reset bugs as active high logic will fire.
seed so you can reproduce bugs.
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:: .. note::
@ -1888,24 +1923,20 @@ Summary:
specified. Initial values of all other state holding variables are specified. Initial values of all other state holding variables are
controlled with `--x-initial`. controlled with `--x-initial`.
.. option:: --x-initial 0 .. option:: --x-initial <mode>
.. option:: --x-initial fast
.. option:: --x-initial unique (default)
Controls the two-state value used to initialize variables that Controls the two-state value used to initialize variables that
are not otherwise initialized. are not otherwise initialized.
"--x-initial 0", With "--x-initial 0",
initializes all otherwise uninitialized variables to zero. 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 initializes variables using a function, which determines the value to
use for each initialization. This gives the greatest flexibility and use for each initialization. This gives the greatest flexibility and
allows for finding reset bugs. See :ref:`Unknown states`. 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 is best for performance, and initializes all variables to a state
Verilator determines is optimal. This may allow further code Verilator determines is optimal. This may allow further code
optimizations, but will likely hide any code bugs relating to missing optimizations, but will likely hide any code bugs relating to missing
@ -1986,8 +2017,9 @@ Summary:
.. _Configuration Files: .. _Configuration Files:
Configuration Files =====================
=================== Configuration Files
=====================
In addition to the command line, warnings and other features for the In addition to the command line, warnings and other features for the
:command:`verilator` command may be controlled with configuration files, :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. 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>" .. option:: clock_enable -module "<modulename>" -var "<signame>"
Deprecated and has no effect (ignored). 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. 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:: 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>" [-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 Indicates whether the signal is used as clock or not. Verilator uses
this information to mark the signal and any derived signals as clocker. this information to mark the signal and any derived signals as clocker.
See :vlopt:`--clk`. See :vlopt:`--clk`.
Same as :option:`/*verilator&32;clocker*/` metacomment. 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 -file "<filename>" -line <lineno>
.. option:: coverage_block_off -module "<modulename>" -block "<blockname>"
Specifies the entire begin/end block should be ignored for coverage 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 analysis purposes. It can either be specified as a named block or as a
filename and line number. filename and line number.
Same as :option:`/*verilator&32;coverage_block_off*/` metacomment. 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>" .. option:: forceable -module "<modulename>" -var "<signame>"
Generate public `<signame>__VforceEn` and `<signame>__VforceVal` signals 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:: full_case -file "<filename>" -lines <lineno>
.. option:: parallel_case -file "<filename>" -lines <lineno> Same as :code:`//synthesis full_case`. When these synthesis directives
are discovered, Verilator will either formally prove the directive to be
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
true, or, failing that, will insert the appropriate code to detect true, or, failing that, will insert the appropriate code to detect
failing cases at simulation runtime and print an "Assertion failed" failing cases at simulation runtime and print an "Assertion failed"
error message. error message.
@ -2096,20 +2128,27 @@ The grammar of configuration commands is as follows:
This option should not be used directly. This option should not be used directly.
See :ref:`Hierarchical Verilation`. 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>" .. option:: inline -module "<modulename>"
Specifies the module may be inlined into any modules that use this Specifies the module may be inlined into any modules that use this
module. Same as :option:`/*verilator&32;inline_module*/` metacomment. 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>" .. t_dist_docs_style ignore no_inline
.. 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.
.. option:: no_inline -module "<modulename>" .. 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*/` this module. Same as :option:`/*verilator&32;no_inline_module*/`
metacomment. metacomment.
.. option:: no_inline [-module "<modulename>"] -task "<taskname>"
.. option:: no_inline [-module "<modulename>"] -function "<funcname>" .. 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 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. 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 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. 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>" [-lines <line> [ - <line>]]]
.. option:: lint_off [-rule <message>] [-file "<filename>"] [-contents "<wildcard>"] [-match "<wildcard>"] .. 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 Enable/disables the specified lint warning, in the specified filename
(or wildcard with '\*' or '?', or all files if omitted) and range of (or wildcard with '\*' or '?', or all files if omitted) and range of
line numbers (or all lines if omitted). 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 Before version 4.026, :code:`-rule` was named :code:`-msg`, and
:code:`-msg` remained a deprecated alias until Version 5.000. :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>" Same as :code:`//synthesis parallel_case`. When these synthesis
directives are discovered, Verilator will either formally prove the
.. option:: public_flat_rd [-module "<modulename>"] [-task/-function "<taskname>"] -var "<signame>" directive to be true, or, failing that, will insert the appropriate code
to detect failing cases at simulation runtime and print an "Assertion
.. option:: public_flat_rw [-module "<modulename>"] [-task/-function "<taskname>"] -var "<signame>" "@(edge)" failed" error message.
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:: profile_data -hier-dpi "<function_name>" -cost <cost_value> .. 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 order to improve model runtime performance. This option is not expected
to be used by users directly. See :ref:`Thread PGO`. 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>" [-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, 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*/` uint32_t, or uint64_t. Same as :option:`/*verilator&32;sc_bv*/`
metacomment. metacomment.
.. option:: sformat [-module "<modulename>"] [-task "<taskname>"] -var "<signame>"
.. option:: sformat [-module "<modulename>"] [-function "<funcname>"] -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 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 function or task to indicate that the function or task should pass all
remaining arguments through $sformatf. This allows the creation of DPI 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. 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>"] [-function "<funcname>"] -var "<varname>"
.. option:: split_var [-module "<modulename>"] [-task "<taskname>"] -var "<varname>"
Break the variable into multiple pieces typically to resolve UNOPTFLAT Break the variable into multiple pieces typically to resolve UNOPTFLAT
performance issues. Typically the variables to attach this to are performance issues. Typically the variables to attach this to are
recommended by Verilator itself; see :option:`UNOPTFLAT`. recommended by Verilator itself; see :option:`UNOPTFLAT`.
Same as :option:`/*verilator&32;split_var*/` metacomment. 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_off [-file "<filename>" [-lines <line> [ - <line>]]]
.. option:: timing_on [-file "<filename>" [-lines <line> [ - <line>]]]
Enables/disables timing constructs for the specified file and lines. Enables/disables timing constructs for the specified file and lines.
When disabled, all timing control constructs in the specified source When disabled, all timing control constructs in the specified source
code locations are ignored the same way as with the 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*/`, Same as :option:`/*verilator&32;timing_on*/`,
:option:`/*verilator&32;timing_off*/` metacomments. :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_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_off [-scope "<scopename>" [-levels <levels> ]]
.. option:: tracing_on [-scope "<scopename>" [-levels <levels> ]]
Enable/disable waveform tracing for all future signals declared in Enable/disable waveform tracing for all future signals declared in
all files. all files.

View File

@ -49,116 +49,119 @@ verilator_coverage Arguments
.. option:: <filename> .. option:: <filename>
Specifies the input coverage data file. Multiple filenames may be provided Specifies the input coverage data file. Multiple filenames may be
to read multiple inputs. If no data file is specified, by default, provided to read multiple inputs. If no data file is specified, by
"coverage.dat" will be read. default, "coverage.dat" will be read.
.. option:: --annotate <output_directory> .. option:: --annotate <output_directory>
Specifies the directory name to which source files with annotated coverage Specifies the directory name to which source files with annotated
data should be written. coverage data should be written.
Points are children of each line coverage- branches, expressions or toggle points. Points are children of each line coverage- branches, expressions or
When point counts are aggregated into a line, the minimum and maximum counts toggle points. When point counts are aggregated into a line, the
are used to determine the status of the line (complete, partial, failing) minimum and maximum counts are used to determine the status of the line
The count is equal to the maximum of the points. (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 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 as a special character followed by the number of coverage hits. The
characters " ,%,~,+,-" indicate summary of the coverage, and allow use of grep special characters " ,%,~,+,-" indicate summary of the coverage, and
to filter the report. allow use of grep to filter the report.
* " " (whitespace) indicates that all points on the line are above the coverage min. * " " (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 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. * "~" 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 at or above the min. Only used with :option:`--annotate-points`.
* "-" coverage point was below 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 100000 input logic a; // Begins with whitespace, because
// number of hits (100000) is above the min. // number of hits (100000) is above the min.
+100000 point: comment=a // Begins with +, because +100000 point: comment=a // Begins with +, because
// number of hits (100000) is above the min. // number of hits (100000) is above the min.
%000000 input logic b; // Begins with %, because %000000 input logic b; // Begins with %, because
// number of hits (0) is below the min. // number of hits (0) is below the min.
-000000 point: comment=b // Begins with -, because -000000 point: comment=b // Begins with -, because
// number of hits (0) is below the min. // number of hits (0) is below the min.
~000010 if (cyc!=0) begin // Begins with ~, because ~000010 if (cyc!=0) begin // Begins with ~, because
// branches are below and above the min. // branches are below and above the min.
+000010 point: comment=if // The if branch is 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. -000000 point: comment=else // The else branch is below the min.
.. option:: --annotate-all .. option:: --annotate-all
Specifies all files should be shown. By default, only those source files Specifies all files should be shown. By default, only those source
with low coverage are written to the output directory. 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> .. option:: --annotate-min <count>
Specifies the threshold (<count>) below which coverage point is considered Specifies the threshold (<count>) below which coverage point is
sufficient. If the threshold is not exceeded, then the annotation will begin considered sufficient. If the threshold is not exceeded, then the
with a "%" symbol to indicate the coverage is insufficient. 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 .. option:: --annotate-points
Specifies all coverage points should be shown after each line of text. By Specifies all coverage points should be shown after each line of text. By
default, only source lines are shown. default, only source lines are shown.
.. code-block:: .. code-block::
100000 input logic a, b, c; 100000 input logic a, b, c;
+100000 point: comment=a // These lines are only shown +100000 point: comment=a // These lines are only shown
+200000 point: comment=b // with option --annotate-points +200000 point: comment=b // with option --annotate-points
+300000 point: comment=c // enabled. +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 .. option:: --help
Displays a help summary, the program version, and exits. Displays a help summary, the program version, and exits.
.. option:: --rank .. option:: --rank
Prints an experimental report listing the relative importance of each test Prints an experimental report listing the relative importance of each
in covering all of the coverage points. The report shows "Covered" which test in covering all of the coverage points. The report shows "Covered"
indicates the number of points the test covers; a test is considered to which indicates the number of points the test covers; a test is
cover a point if it has a bucket count of at least 1. The "rank" column has considered to cover a point if it has a bucket count of at least 1. The
a higher number t indicate the test is more critical, and rank 0 means the "rank" column has a higher number t indicate the test is more critical,
test does not need to be run to cover the points. "RankPts" indicates the and rank 0 means the test does not need to be run to cover the points.
number of coverage points this test will contribute to overall coverage if "RankPts" indicates the number of coverage points this test will
all tests are run in the order of highest to the lowest rank. contribute to overall coverage if all tests are run in the order of
highest to the lowest rank.
.. option:: --unlink .. option:: --unlink
With :option:`--write`, unlink all input files after the output With :option:`--write`, unlink all input files after the output has been
has been successfully created. successfully created.
.. option:: --version .. option:: --version
Displays program version and exits. Displays program version and exits.
.. option:: --write <filename> .. option:: --write <filename>
Specifies the aggregate coverage results, summed across all the files, Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename in verilator_coverage data format. should be written to the given filename in verilator_coverage data
This is useful in scripts to combine many coverage data files (likely format. This is useful in scripts to combine many coverage data files
generated from random test runs) into one master coverage file. (likely generated from random test runs) into one master coverage file.
.. option:: --write-info <filename.info> .. option:: --write-info <filename.info>
Specifies the aggregate coverage results, summed across all the files, Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename in :command:`lcov` .info format. 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 This may be used to feed into :command:`lcov` to aggregate or generate
reports. This format lacks the comments for cover points that the reports. This format lacks the comments for cover points that the
verilator_coverage format has. It can be used with :command:`genhtml` verilator_coverage format has. It can be used with :command:`genhtml` to
to generate an HTML report. :command:`genhtml --branch-coverage` will generate an HTML report. :command:`genhtml --branch-coverage` will also
also display the branch coverage, analogous to :option:`--annotate-points` display the branch coverage, analogous to :option:`--annotate-points`.

View File

@ -51,6 +51,10 @@ predicted_parallelism
cpu#_thread cpu#_thread
For the given CPU number, the thread number measured to be executing. 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 mtask#_cpu
For the given mtask id, the CPU it was measured to execute on. For the given mtask id, the CPU it was measured to execute on.
@ -80,16 +84,16 @@ verilator_gantt Arguments
.. option:: <filename> .. 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 .. option:: --help
Displays a help summary, the program version, and exits. Displays a help summary, the program version, and exits.
.. option:: --no-vcd .. option:: --no-vcd
Disables creating a .vcd file. Disables creating a .vcd file.
.. option:: --vcd <filename> .. 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> .. 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 .. 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. .. Copyright 2003-2025 by Wilson Snyder.
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 .. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
******************* =====================
Language Extensions Language Extensions
******************* =====================
The following additional constructs are the extensions Verilator supports The following additional constructs are the extensions Verilator supports
on top of standard Verilog code. Using these features outside of comments on top of standard Verilog code. Using these features outside of comments
or "`ifdef`"'s may break other tools. 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__ .. option:: `__FILE__
The :option:`\`__FILE__` define expands to the current filename as a 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 C++'s __LINE__. This Verilator feature added in 2006 was incorporated
into IEEE 1800-2009. 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] .. option:: `error [string]
This will report an error when the preprocessor emits it, similar to 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 internal tests, so that debugging can leave the line numbers correctly
referring to the test file's line numbers. 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 Inside one of the :option:`\`systemc_... <\`systemc_header>` text
single quotes. This extension was standardized in IEEE 1800-2023. 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], ...); .. 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 prints 5 digits per the C standard. This extension was standardized into
1800-2009. 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 .. option:: $timeprecision
Returns the timeprecision of the model as an integer. This extension is 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 Returns the timeunit of the current module as an integer. This
extension is experimental and may be removed without deprecation. 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*/ .. option:: /*verilator&32;clock_enable*/
Deprecated and has no effect (ignored). 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. Same as :option:`clock_enable` configuration file option.
.. t_dist_docs_style ignore /*verilator&32;no_clocker*/
.. option:: /*verilator&32;clocker*/ .. option:: /*verilator&32;clocker*/
.. option:: /*verilator&32;no_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; 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) .. option:: /*verilator&32;public*/ (on task/function)
Used inside the declaration section of a function or task declaration to 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. 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) .. option:: /*verilator&32;public_flat*/ (on variable)
Used after an input, output, register, or wire declaration to indicate 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. 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*/ .. option:: /*verilator&32;public_module*/
Used after a module statement to indicate the module should not be 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. 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 Terminates the previous `/*verilator public*_on*/` directive; see above.
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;sc_bv*/ .. option:: /*verilator&32;sc_bv*/
@ -509,6 +539,14 @@ or "`ifdef`"'s may break other tools.
Same as :option:`sc_bv` configuration file option. 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*/ .. option:: /*verilator&32;sformat*/
Attached to the final argument of type "input string" of a function or 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 large arrays may slow down the Verilation speed, so use this only on
variables that require it. 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. Same as :option:`split_var` configuration file option.
.. option:: /*verilator&32;tag <text...>*/ .. 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 Attached to a DPI import to indicate that function should be called when
initializing tracing. This attribute is indented only to be used initializing tracing. This attribute is indented only to be used
internally in code that Verilator generates when :vlopt:`--lib-create` 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*/ .. 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 following loop at the same statement level should always be fully
unrolled by Verilator, ignoring :vlopt:`--unroll-count`. This is unrolled by Verilator, ignoring :vlopt:`--unroll-count`. This is
similar to clang's ``#pragma clang loop unroll(full)``. 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. 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, ``$dumpvars`` to enable traces, the same as with any Verilog simulator,
although Verilator ignores the arguments to ``$dumpvars``. See although Verilator ignores the arguments to ``$dumpvars``. See
``examples/make_tracing_c`` in the distribution. ``examples/make_tracing_c`` in the distribution.
@ -177,7 +177,7 @@ file.
How do I generate waveforms (traces) in SystemC? 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 :code:`sc_main()`, call :code:`Verilated::traceEverOn(true)`. Then you
may use :code:`$dumpfile` and code:`$dumpvars` to enable traces, as may use :code:`$dumpfile` and code:`$dumpvars` to enable traces, as
with any Verilog simulator; see the non-SystemC example in 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 * - *{prefix}*\ ___024root\ *{__DepSet_hash__n}*\ .cpp
- Infrequent cold routines (hashed to reduce build times) - Infrequent cold routines (hashed to reduce build times)
* - *{prefix}*\ ___024root__Trace\ *{__n}*\ .cpp * - *{prefix}*\ ___024root__Trace\ *{__n}*\ .cpp
- Wave file generation code (from --trace) - Wave file generation code (from --trace-\*)
* - *{prefix}*\ ___024root__Trace__Slow\ *{__n}*\ .cpp * - *{prefix}*\ ___024root__Trace__Slow\ *{__n}*\ .cpp
- Wave file generation code (from --trace) - Wave file generation code (from --trace-\*)
* - *{prefix}*\ __Dpi.h * - *{prefix}*\ __Dpi.h
- DPI import and export declarations (from --dpi) - DPI import and export declarations (from --dpi)
* - *{prefix}*\ __Dpi.cpp * - *{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 Using a distribution's package manager is the easiest way to get
started. (Note packages are unlikely to have the most recent version, so started. (Note distribution packages almost never have the most recent
:ref:`Git Install` might be a better alternative.) To install as a Verilator version, so we recommend following :ref:`Git Install` below,
package: instead.) To install as a package:
.. code-block:: shell .. 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 libfl-dev # Ubuntu only (ignore if gives error)
sudo apt-get install zlibc zlib1g zlib1g-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 To build or run Verilator, the following are optional but should be installed
for good performance: 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 mold # If present at build, needed for run
sudo apt-get install libgoogle-perftools-dev numactl 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 To build Verilator you will need to install these packages; these do not
need to be present to run Verilator: 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 .. code-block:: shell
sudo apt-get install clang clang-format-14 cmake gdb gprof graphviz lcov 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 sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
sudo pip3 install git+https://github.com/antmicro/astsee.git sudo pip3 install git+https://github.com/antmicro/astsee.git
cpan install Pod::Perldoc cpan install Pod::Perldoc
@ -155,7 +167,10 @@ Those developing Verilator itself may also want these (see internals.rst):
Install SystemC 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 <https://www.accellera.org/downloads/standards/systemc>`__. Follow their
installation instructions. You will need to set the installation instructions. You will need to set the
:option:`SYSTEMC_INCLUDE` environment variable to point to the include :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 <http://gtkwave.sourceforge.net/>`__ installed, however this is not
required at Verilator build time. required at Verilator build time.
.. code-block:: shell
sudo apt-get install gtkwave # Optional Waveform viewer
Install Z3 Install Z3
^^^^^^^^^^ ^^^^^^^^^^

View File

@ -334,7 +334,8 @@ Gate Primitives
The 2-state gate primitives (and, buf, nand, nor, not, or, xnor, xor) are 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 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 Specify blocks
@ -396,8 +397,8 @@ This section describes specific limitations for each language keyword.
\`begin_keywords, \`begin_keywords, \`begin_keywords, \`begin_keywords, \`begin_keywords, \`begin_keywords, \`begin_keywords, \`begin_keywords,
\`define, \`else, \`elsif, \`end_keywords, \`endif, \`error, \`ifdef, \`define, \`else, \`elsif, \`end_keywords, \`endif, \`error, \`ifdef,
\`ifndef, \`include, \`line, \`systemc_ctor, \`systemc_dtor, \`ifndef, \`include, \`line, \`systemc_ctor, \`systemc_dtor,
\`systemc_header, \`systemc_imp_header, \`systemc_implementation, \`systemc_header, \`systemc_header_post, \`systemc_imp_header,
\`systemc_interface, \`undef, \`verilog \`systemc_implementation, \`systemc_interface, \`undef, \`verilog
|cmdslong1| |cmdslong1|
Fully supported. Fully supported.
@ -451,17 +452,17 @@ disable
force, release force, release
Verilator supports the procedural `force` (and corresponding `release`) Verilator supports the procedural `force` (and corresponding `release`)
statement. However, the behavior of the `force` statement does not statement. However, the behavior of the `force` statement does not
entirely comply with IEEE 1800. According to the standard, when a entirely comply with IEEE 1800-2023:
procedural statement of the form `force a = b;` is executed, the
simulation should behave as if, from that point forwards, a continuous #. Using forced variable as a value to another force statement is
assignment `assign a = b;` has been added to override the drivers of `a`. currently not supported. The dependent force statement is forced by an
More specifically: the value of `a` should be updated whenever the value initial constant value.
of `b` changes, until a `release a;` statement is executed. Verilator
instead evaluates the current value of `b` when the `force` statement is #. Force/release with procedural continuous assignment is not supported.
executed, and forces `a` to that value, without updating it until a new The assignment is treated as procedural.
`force` or `release` statement is encountered that applies to `a`. This
non-standard behavior is nevertheless consistent with some other #. Expressions using multiple variable references or function calls on
simulators. forced right-hand side are not sensitive to dependency changes.
inside inside
Inside expressions may not include unpacked array traversal or $ as an 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 $dump/$dumpports and related
$dumpfile or $dumpports will create a VCD or FST file (based on $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 will take effect starting at the next eval() call. If you have multiple
Verilated designs under the same C model, this will dump signals Verilated designs under the same C model, this will dump signals
only from the design containing the $dumpvars. 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 may increase the risk of reset bugs in trade for performance; see the above
documentation for these options. documentation for these options.
If using Verilated multithreaded, use ``numactl`` to ensure you use If using Verilated multithreaded, consider overriding Verilator's default
non-conflicting hardware resources. See :ref:`Multithreading`. Also, thread-to-processor assignment by using ``numactl``; see
consider using profile-guided optimization; see :ref:`Thread PGO`. :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 Minor Verilog code changes can also give big wins. You should not have any
:option:`UNOPTFLAT` warnings from Verilator. Fixing these warnings can :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 influences the partitioning of the model by adjusting the assumed execution
time of DPI imports. 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 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. 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. of setting :vlopt:`--trace-threads` higher than 2 at the moment.
When running a multithreaded model, the default Linux task scheduler often When running a multithreaded model, the default Linux task scheduler often
works against the model by assuming short-lived threads and thus works against the model by assuming short-lived threads and thus it often
it often schedules threads using multiple hyperthreads within the same schedules threads using multiple hyperthreads within the same physical
physical core. For best performance, use the :command:`numactl` program to core. If there is no affinity already set, on Linux only, Verilator
(when the threading count fits) select unique physical cores on the same attempts to set thread-to-processor affinity in a reasonable way.
socket. The same applies for :vlopt:`--trace-threads` as well.
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 As an example, if a model was Verilated with
:vlopt:`--threads 4 <--threads>`, we consult: :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, If using :vlopt:`--sc`, the SystemC kernel is not thread-safe; therefore,
the eval thread and main thread must be the same. the eval thread and main thread must be the same.
If using :vlopt:`--trace`, the tracing classes must be constructed and If using :vlopt:`--trace-vcd` or other trace options, the tracing classes
called from the main thread. must be constructed and called from the main thread.
If using :vlopt:`--vpi`, since SystemVerilog VPI was not architected by If using :vlopt:`--vpi`, since SystemVerilog VPI was not architected by
IEEE to be multithreaded, Verilator requires all VPI calls are only made IEEE to be multithreaded, Verilator requires all VPI calls are only made
@ -367,10 +370,11 @@ Verilate in CMake
.. code-block:: CMake .. code-block:: CMake
verilate(target SOURCES source ... [TOP_MODULE top] [PREFIX name] 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 ...] [INCLUDE_DIRS dir ...] [OPT_SLOW ...] [OPT_FAST ...]
[OPT_GLOBAL ..] [DIRECTORY dir] [THREADS num] [OPT_GLOBAL ..] [DIRECTORY dir] [THREADS num]
[TRACE_THREADS num] [VERILATOR_ARGS ...]) [VERILATOR_ARGS ...])
Lowercase and ... should be replaced with arguments; the uppercase parts Lowercase and ... should be replaced with arguments; the uppercase parts
delimit the arguments and can be passed in any order or left out entirely 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`. Optional. Enable a multithreaded model; see :vlopt:`--threads`.
.. describe:: TRACE_THREADS
Optional. Enable multithreaded FST trace; see :vlopt:`--trace-threads`.
.. describe:: TOP_MODULE .. describe:: TOP_MODULE
Optional. Sets the name of the top module. Defaults to the name of the 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 .. describe:: TRACE
Optional. Enables VCD tracing if present, equivalent to "VERILATOR_ARGS Deprecated. Same as TRACE_VCD, which should be used instead.
--trace".
.. describe:: TRACE_FST .. describe:: TRACE_FST
Optional. Enables FST tracing if present, equivalent to "VERILATOR_ARGS Optional. Enables FST tracing if present, equivalent to "VERILATOR_ARGS
--trace-fst". --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 .. describe:: VERILATOR_ARGS
Optional. Extra arguments to Verilator. Do not specify :vlopt:`--Mdir` Optional. Extra arguments to Verilator. Do not specify :vlopt:`--Mdir`

View File

@ -1,9 +1,9 @@
.. Copyright 2003-2025 by Wilson Snyder. .. Copyright 2003-2025 by Wilson Snyder.
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 .. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
******************* =====================
Errors and Warnings Errors and Warnings
******************* =====================
.. _Disabling Warnings: .. _Disabling Warnings:
@ -86,6 +86,8 @@ List Of Warnings
Limitations`. Limitations`.
.. t_dist_docs_style restart_sort
.. option:: ALWCOMBORDER .. option:: ALWCOMBORDER
.. TODO better example .. TODO better example
@ -472,6 +474,31 @@ List Of Warnings
correctly. 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 .. option:: DEFPARAM
Warns that the :code:`defparam` statement was deprecated in IEEE 1364-2001, Warns that the :code:`defparam` statement was deprecated in IEEE 1364-2001,
@ -1222,13 +1249,6 @@ List Of Warnings
simulate correctly. 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 .. option:: NONSTD
Warns when a non-standard language feature is used that has a standard Warns when a non-standard language feature is used that has a standard
@ -1237,6 +1257,13 @@ List Of Warnings
:code:`$sformatf`. :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 .. option:: NULLPORT
Warns that a null port was detected in the module definition port 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 Ignoring this warning will only suppress the lint check; it will
simulate correctly. simulate correctly.
.. option:: PINCONNECTEMPTY .. option:: PINCONNECTEMPTY
.. TODO better example .. TODO better example
@ -1349,6 +1377,26 @@ List Of Warnings
This error may be disabled with a lint_off PINNOTFOUND metacomment. 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 .. option:: PORTSHORT
Warns that an output port is connected to a constant. 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. 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 .. option:: PREPROCZERO
Warns that a preprocessor \`ifdef/\`ifndef expression (added in IEEE 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 .. 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 .. option:: WIDTHCONCAT
Warns that based on the width rules of Verilog, a concatenate, or 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]}`). 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 .. option:: ZERODLY
Warns that `#0` delays do not schedule the process to be resumed in the 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 Same as ``verilator --debugi level``: Set Verilator internal debugging
level globally to the specified debug level (1-10). 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 --dump-tree
Same as ``verilator --dump-tree``: Enable Verilator writing .tree debug Same as ``verilator --dump-tree``: Enable Verilator writing .tree debug
files with dumping level 3, which dumps the standard critical stages. files with dumping level 3, which dumps the standard critical stages.
@ -2077,7 +2082,10 @@ driver.py Non-Scenario Arguments
--j # --j #
Run number of parallel tests, or 0 to determine the count based on the 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 --quiet
Suppress all output except for failures and progress messages every 15 Suppress all output except for failures and progress messages every 15

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -20,9 +20,11 @@
# binary relative to $VERILATOR_ROOT (such as when inside the git sources). # binary relative to $VERILATOR_ROOT (such as when inside the git sources).
ifeq ($(VERILATOR_ROOT),) ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
VERILATOR_COVERAGE = verilator_coverage VERILATOR_COVERAGE = verilator_coverage
else else
export VERILATOR_ROOT export VERILATOR_ROOT
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage
endif endif
###################################################################### ######################################################################
@ -59,7 +61,7 @@ run:
@echo @echo
@echo "-- RUN ---------------------" @echo "-- RUN ---------------------"
@mkdir -p logs @mkdir -p logs
build/example +trace build/example +trace_vcd
@echo @echo
@echo "-- COVERAGE ----------------" @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}) set_property(TARGET example PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD})
# Add the Verilated circuit to the target # Add the Verilated circuit to the target
verilate(example SYSTEMC COVERAGE TRACE verilate(example COVERAGE SYSTEMC TRACE_VCD
INCLUDE_DIRS "../make_tracing_sc" INCLUDE_DIRS "../make_tracing_sc"
VERILATOR_ARGS -f ../make_tracing_sc/input.vc -x-assign fast VERILATOR_ARGS -f ../make_tracing_sc/input.vc -x-assign fast
SOURCES ../make_tracing_sc/top.v SOURCES ../make_tracing_sc/top.v

View File

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

View File

@ -43,7 +43,7 @@ VERILATOR_FLAGS += -Wall
VERILATOR_FLAGS += -CFLAGS -DVL_TIME_CONTEXT VERILATOR_FLAGS += -CFLAGS -DVL_TIME_CONTEXT
# Make waveforms # Make waveforms
TOP_VERILATOR_FLAGS = $(VERILATOR_FLAGS) --trace TOP_VERILATOR_FLAGS = $(VERILATOR_FLAGS) --trace-vcd
###################################################################### ######################################################################
default: run 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 # Warn abount lint issues; may not want this on less solid designs
VERILATOR_FLAGS += -Wall VERILATOR_FLAGS += -Wall
# Make waveforms # Make waveforms
VERILATOR_FLAGS += --trace VERILATOR_FLAGS += --trace-vcd
# Check SystemVerilog assertions # Check SystemVerilog assertions
VERILATOR_FLAGS += --assert VERILATOR_FLAGS += --assert
# Generate coverage analysis # 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 # Warn abount lint issues; may not want this on less solid designs
VERILATOR_FLAGS += -Wall VERILATOR_FLAGS += -Wall
# Make waveforms # Make waveforms
VERILATOR_FLAGS += --trace VERILATOR_FLAGS += --trace-vcd
# Check SystemVerilog assertions # Check SystemVerilog assertions
VERILATOR_FLAGS += --assert VERILATOR_FLAGS += --assert
# Generate coverage analysis # Generate coverage analysis

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,8 @@
#define FST_API_H #define FST_API_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
#include <stdio.h> #include <stdio.h>
@ -36,428 +37,508 @@ extern "C" {
#include <zlib.h> #include <zlib.h>
#include <inttypes.h> #include <inttypes.h>
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include "fst_win_unistd.h" #include "fst_win_unistd.h"
#else #else
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <time.h> #include <time.h>
#define FST_RDLOAD "FSTLOAD | "
typedef uint32_t fstHandle; typedef uint32_t fstHandle;
typedef uint32_t fstEnumHandle; typedef uint32_t fstEnumHandle;
enum fstWriterPackType { enum fstWriterPackType
FST_WR_PT_ZLIB = 0, {
FST_WR_PT_FASTLZ = 1, FST_WR_PT_ZLIB = 0,
FST_WR_PT_LZ4 = 2 FST_WR_PT_FASTLZ = 1,
FST_WR_PT_LZ4 = 2
}; };
enum fstFileType { enum fstFileType
FST_FT_MIN = 0, {
FST_FT_MIN = 0,
FST_FT_VERILOG = 0, FST_FT_VERILOG = 0,
FST_FT_VHDL = 1, FST_FT_VHDL = 1,
FST_FT_VERILOG_VHDL = 2, FST_FT_VERILOG_VHDL = 2,
FST_FT_MAX = 2 FST_FT_MAX = 2
}; };
enum fstBlockType { enum fstBlockType
FST_BL_HDR = 0, {
FST_BL_VCDATA = 1, FST_BL_HDR = 0,
FST_BL_BLACKOUT = 2, FST_BL_VCDATA = 1,
FST_BL_GEOM = 3, FST_BL_BLACKOUT = 2,
FST_BL_HIER = 4, FST_BL_GEOM = 3,
FST_BL_VCDATA_DYN_ALIAS = 5, FST_BL_HIER = 4,
FST_BL_HIER_LZ4 = 6, FST_BL_VCDATA_DYN_ALIAS = 5,
FST_BL_HIER_LZ4DUO = 7, FST_BL_HIER_LZ4 = 6,
FST_BL_VCDATA_DYN_ALIAS2 = 8, FST_BL_HIER_LZ4DUO = 7,
FST_BL_VCDATA_DYN_ALIAS2 = 8,
FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */ FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
FST_BL_SKIP = 255 /* used while block is being written */ FST_BL_SKIP = 255 /* used while block is being written */
}; };
enum fstScopeType { enum fstScopeType
FST_ST_MIN = 0, {
FST_ST_MIN = 0,
FST_ST_VCD_MODULE = 0, FST_ST_VCD_MODULE = 0,
FST_ST_VCD_TASK = 1, FST_ST_VCD_TASK = 1,
FST_ST_VCD_FUNCTION = 2, FST_ST_VCD_FUNCTION = 2,
FST_ST_VCD_BEGIN = 3, FST_ST_VCD_BEGIN = 3,
FST_ST_VCD_FORK = 4, FST_ST_VCD_FORK = 4,
FST_ST_VCD_GENERATE = 5, FST_ST_VCD_GENERATE = 5,
FST_ST_VCD_STRUCT = 6, FST_ST_VCD_STRUCT = 6,
FST_ST_VCD_UNION = 7, FST_ST_VCD_UNION = 7,
FST_ST_VCD_CLASS = 8, FST_ST_VCD_CLASS = 8,
FST_ST_VCD_INTERFACE = 9, FST_ST_VCD_INTERFACE = 9,
FST_ST_VCD_PACKAGE = 10, FST_ST_VCD_PACKAGE = 10,
FST_ST_VCD_PROGRAM = 11, FST_ST_VCD_PROGRAM = 11,
FST_ST_VHDL_ARCHITECTURE = 12, FST_ST_VHDL_ARCHITECTURE = 12,
FST_ST_VHDL_PROCEDURE = 13, FST_ST_VHDL_PROCEDURE = 13,
FST_ST_VHDL_FUNCTION = 14, FST_ST_VHDL_FUNCTION = 14,
FST_ST_VHDL_RECORD = 15, FST_ST_VHDL_RECORD = 15,
FST_ST_VHDL_PROCESS = 16, FST_ST_VHDL_PROCESS = 16,
FST_ST_VHDL_BLOCK = 17, FST_ST_VHDL_BLOCK = 17,
FST_ST_VHDL_FOR_GENERATE = 18, FST_ST_VHDL_FOR_GENERATE = 18,
FST_ST_VHDL_IF_GENERATE = 19, FST_ST_VHDL_IF_GENERATE = 19,
FST_ST_VHDL_GENERATE = 20, FST_ST_VHDL_GENERATE = 20,
FST_ST_VHDL_PACKAGE = 21, FST_ST_VHDL_PACKAGE = 21,
FST_ST_MAX = 21, FST_ST_MAX = 21,
FST_ST_GEN_ATTRBEGIN = 252, FST_ST_GEN_ATTRBEGIN = 252,
FST_ST_GEN_ATTREND = 253, FST_ST_GEN_ATTREND = 253,
FST_ST_VCD_SCOPE = 254, FST_ST_VCD_SCOPE = 254,
FST_ST_VCD_UPSCOPE = 255 FST_ST_VCD_UPSCOPE = 255
}; };
enum fstVarType { enum fstVarType
FST_VT_MIN = 0, /* start of vartypes */ {
FST_VT_MIN = 0, /* start of vartypes */
FST_VT_VCD_EVENT = 0, FST_VT_VCD_EVENT = 0,
FST_VT_VCD_INTEGER = 1, FST_VT_VCD_INTEGER = 1,
FST_VT_VCD_PARAMETER = 2, FST_VT_VCD_PARAMETER = 2,
FST_VT_VCD_REAL = 3, FST_VT_VCD_REAL = 3,
FST_VT_VCD_REAL_PARAMETER = 4, FST_VT_VCD_REAL_PARAMETER = 4,
FST_VT_VCD_REG = 5, FST_VT_VCD_REG = 5,
FST_VT_VCD_SUPPLY0 = 6, FST_VT_VCD_SUPPLY0 = 6,
FST_VT_VCD_SUPPLY1 = 7, FST_VT_VCD_SUPPLY1 = 7,
FST_VT_VCD_TIME = 8, FST_VT_VCD_TIME = 8,
FST_VT_VCD_TRI = 9, FST_VT_VCD_TRI = 9,
FST_VT_VCD_TRIAND = 10, FST_VT_VCD_TRIAND = 10,
FST_VT_VCD_TRIOR = 11, FST_VT_VCD_TRIOR = 11,
FST_VT_VCD_TRIREG = 12, FST_VT_VCD_TRIREG = 12,
FST_VT_VCD_TRI0 = 13, FST_VT_VCD_TRI0 = 13,
FST_VT_VCD_TRI1 = 14, FST_VT_VCD_TRI1 = 14,
FST_VT_VCD_WAND = 15, FST_VT_VCD_WAND = 15,
FST_VT_VCD_WIRE = 16, FST_VT_VCD_WIRE = 16,
FST_VT_VCD_WOR = 17, FST_VT_VCD_WOR = 17,
FST_VT_VCD_PORT = 18, FST_VT_VCD_PORT = 18,
FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */ FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */
FST_VT_VCD_REALTIME = 20, 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_BIT = 22,
FST_VT_SV_LOGIC = 23, FST_VT_SV_LOGIC = 23,
FST_VT_SV_INT = 24, /* declare as size = 32 */ FST_VT_SV_INT = 24, /* declare as size = 32 */
FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */ FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */
FST_VT_SV_LONGINT = 26, /* declare as size = 64 */ FST_VT_SV_LONGINT = 26, /* declare as size = 64 */
FST_VT_SV_BYTE = 27, /* declare as size = 8 */ FST_VT_SV_BYTE = 27, /* declare as size = 8 */
FST_VT_SV_ENUM = 28, /* declare as appropriate type range */ 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_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 { enum fstVarDir
FST_VD_MIN = 0, {
FST_VD_MIN = 0,
FST_VD_IMPLICIT = 0, FST_VD_IMPLICIT = 0,
FST_VD_INPUT = 1, FST_VD_INPUT = 1,
FST_VD_OUTPUT = 2, FST_VD_OUTPUT = 2,
FST_VD_INOUT = 3, FST_VD_INOUT = 3,
FST_VD_BUFFER = 4, FST_VD_BUFFER = 4,
FST_VD_LINKAGE = 5, FST_VD_LINKAGE = 5,
FST_VD_MAX = 5 FST_VD_MAX = 5
}; };
enum fstHierType { enum fstHierType
FST_HT_MIN = 0, {
FST_HT_MIN = 0,
FST_HT_SCOPE = 0, FST_HT_SCOPE = 0,
FST_HT_UPSCOPE = 1, FST_HT_UPSCOPE = 1,
FST_HT_VAR = 2, FST_HT_VAR = 2,
FST_HT_ATTRBEGIN = 3, FST_HT_ATTRBEGIN = 3,
FST_HT_ATTREND = 4, 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 and FST_HT_TREEEND are not yet used by FST but are currently used when
FST_HT_TREEBEGIN = 5, fstHier bridges other formats */
FST_HT_TREEEND = 6, FST_HT_TREEBEGIN = 5,
FST_HT_TREEEND = 6,
FST_HT_MAX = 6 FST_HT_MAX = 6
}; };
enum fstAttrType { enum fstAttrType
FST_AT_MIN = 0, {
FST_AT_MIN = 0,
FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */ FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */
FST_AT_ARRAY = 1, FST_AT_ARRAY = 1,
FST_AT_ENUM = 2, FST_AT_ENUM = 2,
FST_AT_PACK = 3, FST_AT_PACK = 3,
FST_AT_MAX = 3 FST_AT_MAX = 3
}; };
enum fstMiscType { enum fstMiscType
FST_MT_MIN = 0, {
FST_MT_MIN = 0,
FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */ FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */
FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */ FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */
FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */ FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */
FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */ FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */
FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */ FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */ FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */ FST_MT_VALUELIST =
FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */ 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
FST_MT_UNKNOWN = 8, FST_MT_ENUMTABLE =
7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
FST_MT_UNKNOWN = 8,
FST_MT_MAX = 8 FST_MT_MAX = 8
}; };
enum fstArrayType { enum fstArrayType
FST_AR_MIN = 0, {
FST_AR_MIN = 0,
FST_AR_NONE = 0, FST_AR_NONE = 0,
FST_AR_UNPACKED = 1, FST_AR_UNPACKED = 1,
FST_AR_PACKED = 2, FST_AR_PACKED = 2,
FST_AR_SPARSE = 3, FST_AR_SPARSE = 3,
FST_AR_MAX = 3 FST_AR_MAX = 3
}; };
enum fstEnumValueType { enum fstEnumValueType
FST_EV_SV_INTEGER = 0, {
FST_EV_SV_BIT = 1, FST_EV_SV_INTEGER = 0,
FST_EV_SV_LOGIC = 2, FST_EV_SV_BIT = 1,
FST_EV_SV_INT = 3, FST_EV_SV_LOGIC = 2,
FST_EV_SV_SHORTINT = 4, FST_EV_SV_INT = 3,
FST_EV_SV_LONGINT = 5, FST_EV_SV_SHORTINT = 4,
FST_EV_SV_BYTE = 6, FST_EV_SV_LONGINT = 5,
FST_EV_SV_UNSIGNED_INTEGER = 7, FST_EV_SV_BYTE = 6,
FST_EV_SV_UNSIGNED_BIT = 8, FST_EV_SV_UNSIGNED_INTEGER = 7,
FST_EV_SV_UNSIGNED_LOGIC = 9, FST_EV_SV_UNSIGNED_BIT = 8,
FST_EV_SV_UNSIGNED_INT = 10, FST_EV_SV_UNSIGNED_LOGIC = 9,
FST_EV_SV_UNSIGNED_INT = 10,
FST_EV_SV_UNSIGNED_SHORTINT = 11, FST_EV_SV_UNSIGNED_SHORTINT = 11,
FST_EV_SV_UNSIGNED_LONGINT = 12, FST_EV_SV_UNSIGNED_LONGINT = 12,
FST_EV_SV_UNSIGNED_BYTE = 13, FST_EV_SV_UNSIGNED_BYTE = 13,
FST_EV_REG = 14, FST_EV_REG = 14,
FST_EV_TIME = 15, FST_EV_TIME = 15,
FST_EV_MAX = 15 FST_EV_MAX = 15
}; };
enum fstPackType { enum fstPackType
FST_PT_NONE = 0, {
FST_PT_UNPACKED = 1, FST_PT_NONE = 0,
FST_PT_PACKED = 2, FST_PT_UNPACKED = 1,
FST_PT_PACKED = 2,
FST_PT_TAGGED_PACKED = 3, FST_PT_TAGGED_PACKED = 3,
FST_PT_MAX = 3 FST_PT_MAX = 3
}; };
enum fstSupplementalVarType { enum fstSupplementalVarType
FST_SVT_MIN = 0, {
FST_SVT_MIN = 0,
FST_SVT_NONE = 0, FST_SVT_NONE = 0,
FST_SVT_VHDL_SIGNAL = 1, FST_SVT_VHDL_SIGNAL = 1,
FST_SVT_VHDL_VARIABLE = 2, FST_SVT_VHDL_VARIABLE = 2,
FST_SVT_VHDL_CONSTANT = 3, FST_SVT_VHDL_CONSTANT = 3,
FST_SVT_VHDL_FILE = 4, FST_SVT_VHDL_FILE = 4,
FST_SVT_VHDL_MEMORY = 5, FST_SVT_VHDL_MEMORY = 5,
FST_SVT_MAX = 5 FST_SVT_MAX = 5
}; };
enum fstSupplementalDataType { enum fstSupplementalDataType
FST_SDT_MIN = 0, {
FST_SDT_MIN = 0,
FST_SDT_NONE = 0, FST_SDT_NONE = 0,
FST_SDT_VHDL_BOOLEAN = 1, FST_SDT_VHDL_BOOLEAN = 1,
FST_SDT_VHDL_BIT = 2, FST_SDT_VHDL_BIT = 2,
FST_SDT_VHDL_BIT_VECTOR = 3, FST_SDT_VHDL_BIT_VECTOR = 3,
FST_SDT_VHDL_STD_ULOGIC = 4, FST_SDT_VHDL_STD_ULOGIC = 4,
FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5, FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5,
FST_SDT_VHDL_STD_LOGIC = 6, FST_SDT_VHDL_STD_LOGIC = 6,
FST_SDT_VHDL_STD_LOGIC_VECTOR = 7, FST_SDT_VHDL_STD_LOGIC_VECTOR = 7,
FST_SDT_VHDL_UNSIGNED = 8, FST_SDT_VHDL_UNSIGNED = 8,
FST_SDT_VHDL_SIGNED = 9, FST_SDT_VHDL_SIGNED = 9,
FST_SDT_VHDL_INTEGER = 10, FST_SDT_VHDL_INTEGER = 10,
FST_SDT_VHDL_REAL = 11, FST_SDT_VHDL_REAL = 11,
FST_SDT_VHDL_NATURAL = 12, FST_SDT_VHDL_NATURAL = 12,
FST_SDT_VHDL_POSITIVE = 13, FST_SDT_VHDL_POSITIVE = 13,
FST_SDT_VHDL_TIME = 14, FST_SDT_VHDL_TIME = 14,
FST_SDT_VHDL_CHARACTER = 15, FST_SDT_VHDL_CHARACTER = 15,
FST_SDT_VHDL_STRING = 16, 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_SVT_SHIFT_COUNT = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left
FST_SDT_ABS_MAX = ((1<<(FST_SDT_SVT_SHIFT_COUNT))-1) after shifting FST_SDT_SVT_SHIFT_COUNT */
FST_SDT_ABS_MAX = ((1 << (FST_SDT_SVT_SHIFT_COUNT)) - 1)
}; };
struct fstHier struct fstHier
{ {
unsigned char htyp; unsigned char htyp;
union { union
{
/* if htyp == FST_HT_SCOPE */ /* if htyp == FST_HT_SCOPE */
struct fstHierScope { struct fstHierScope
unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */ {
const char *name; unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */
const char *component; const char *name;
uint32_t name_length; /* strlen(u.scope.name) */ const char *component;
uint32_t component_length; /* strlen(u.scope.component) */ uint32_t name_length; /* strlen(u.scope.name) */
} scope; uint32_t component_length; /* strlen(u.scope.component) */
} scope;
/* if htyp == FST_HT_VAR */ /* if htyp == FST_HT_VAR */
struct fstHierVar { struct fstHierVar
unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */ {
unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */ unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */
unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */ unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */
unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */ unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */
unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */ unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */
const char *name; unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */
uint32_t length; const char *name;
fstHandle handle; uint32_t length;
uint32_t name_length; /* strlen(u.var.name) */ fstHandle handle;
unsigned is_alias : 1; uint32_t name_length; /* strlen(u.var.name) */
} var; unsigned is_alias : 1;
} var;
/* if htyp == FST_HT_ATTRBEGIN */ /* if htyp == FST_HT_ATTRBEGIN */
struct fstHierAttr { struct fstHierAttr
unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */ {
unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */ unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */
const char *name; unsigned char
uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */ subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + FST_MT_SOURCESTEM) */ const char *name;
uint32_t name_length; /* strlen(u.attr.name) */ uint64_t arg; /* number of array elements, struct members, or some other payload
} attr; (possibly ignored) */
} u; 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 struct fstETab
{ {
char *name; char *name;
uint32_t elem_count; uint32_t elem_count;
char **literal_arr; char **literal_arr;
char **val_arr; char **val_arr;
}; };
/* /*
* writer functions * 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 * 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 * utility functions
*/ */
int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */ 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 fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len);
int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len); int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
struct fstETab *fstUtilityExtractEnumTableFromString(const char *s); 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 #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 <cctype>
#include <cerrno> #include <cerrno>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <limits> #include <limits>
#include <list> #include <list>
#include <sstream> #include <sstream>
@ -916,6 +917,21 @@ void _vl_vsformat(std::string& output, const std::string& format, va_list ap) VL
} }
break; 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: { default: {
// Deal with all read-and-print somethings // Deal with all read-and-print somethings
const int lbits = va_arg(ap, int); const int lbits = va_arg(ap, int);
@ -1234,9 +1250,9 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
bool inPct = false; bool inPct = false;
bool inIgnore = false; bool inIgnore = false;
std::string::const_iterator pos = format.cbegin(); std::string::const_iterator pos = format.cbegin();
for (; pos != format.cend() && !_vl_vsss_eof(fp, floc); ++pos) { for (; pos != format.cend(); ++pos) {
// VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc, // VL_DBG_MSGF("_vlscan fmt='%c' floc=%d file='%c'\n", pos[0], floc,
// fromp, fstr)<<"'\n"); // _vl_vsss_peek(fp, floc, fromp, fstr));
if (!inPct && pos[0] == '%') { if (!inPct && pos[0] == '%') {
inPct = true; inPct = true;
inIgnore = false; inIgnore = false;
@ -1420,7 +1436,12 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
} // switch } // switch
} }
} }
// Processed all arguments
return got;
done: done:
// Scan stopped early, return parsed or EOF
if (_vl_vsss_eof(fp, floc)) return -1;
return got; return got;
} }
@ -3017,7 +3038,7 @@ void VerilatedContext::trace(VerilatedTraceBaseC* tfp, int levels, int options)
if (m_ns.m_traceBaseModelCbs.empty()) if (m_ns.m_traceBaseModelCbs.empty())
VL_FATAL_MT("", 0, "", VL_FATAL_MT("", 0, "",
"Testbench C call to 'VerilatedContext::trace()' requires model(s) Verilated" "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); for (auto& cbr : m_ns.m_traceBaseModelCbs) cbr(tfp, levels, options);
} }
void VerilatedContext::traceBaseModelCbAdd(traceBaseModelCb_t cb) VL_MT_SAFE { 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 { void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE {
VL_FATAL_MT(__FILE__, __LINE__, "", VL_FATAL_MT(__FILE__, __LINE__, "",
"Routine called that is single threaded, but called from" "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 #endif

View File

@ -175,9 +175,14 @@ enum class VerilatedAssertDirectiveType : uint8_t {
using VerilatedAssertType_t = std::underlying_type<VerilatedAssertType>::type; using VerilatedAssertType_t = std::underlying_type<VerilatedAssertType>::type;
using VerilatedAssertDirectiveType_t = std::underlying_type<VerilatedAssertDirectiveType>::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> template <typename>
struct VlIsCustomStruct : public std::false_type {}; 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 // Utility functions

View File

@ -90,6 +90,7 @@ VK_CPPFLAGS_ALWAYS += \
-DVM_TRACE=$(VM_TRACE) \ -DVM_TRACE=$(VM_TRACE) \
-DVM_TRACE_FST=$(VM_TRACE_FST) \ -DVM_TRACE_FST=$(VM_TRACE_FST) \
-DVM_TRACE_VCD=$(VM_TRACE_VCD) \ -DVM_TRACE_VCD=$(VM_TRACE_VCD) \
-DVM_TRACE_SAIF=$(VM_TRACE_SAIF) \
$(CFG_CXXFLAGS_NO_UNUSED) \ $(CFG_CXXFLAGS_NO_UNUSED) \
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users 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) { void VerilatedFst::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
const VerilatedLockGuard lock{m_mutex}; const VerilatedLockGuard lock{m_mutex};
Super::closeBase(); Super::closeBase();
emitTimeChangeMaybe();
fstWriterClose(m_fst); fstWriterClose(m_fst);
m_fst = nullptr; 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) { void VerilatedFst::flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
const VerilatedLockGuard lock{m_mutex}; const VerilatedLockGuard lock{m_mutex};
Super::flushBase(); Super::flushBase();
emitTimeChangeMaybe();
fstWriterFlushContext(m_fst); 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 // Decl
@ -311,12 +324,14 @@ void VerilatedFst::configure(const VerilatedTraceConfig& config) {
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitEvent(uint32_t code) { void VerilatedFstBuffer::emitEvent(uint32_t code) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); VL_DEBUG_IFDEF(assert(m_symbolp[code]););
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1"); fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
} }
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitBit(uint32_t code, CData newval) { void VerilatedFstBuffer::emitBit(uint32_t code, CData newval) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); VL_DEBUG_IFDEF(assert(m_symbolp[code]););
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0"); 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]; char buf[VL_BYTESIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtCDataToStr(buf, newval << (VL_BYTESIZE - bits)); cvtCDataToStr(buf, newval << (VL_BYTESIZE - bits));
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf); 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]; char buf[VL_SHORTSIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtSDataToStr(buf, newval << (VL_SHORTSIZE - bits)); cvtSDataToStr(buf, newval << (VL_SHORTSIZE - bits));
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf); 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]; char buf[VL_IDATASIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtIDataToStr(buf, newval << (VL_IDATASIZE - bits)); cvtIDataToStr(buf, newval << (VL_IDATASIZE - bits));
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf); 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]; char buf[VL_QUADSIZE];
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); VL_DEBUG_IFDEF(assert(m_symbolp[code]););
cvtQDataToStr(buf, newval << (VL_QUADSIZE - bits)); cvtQDataToStr(buf, newval << (VL_QUADSIZE - bits));
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf); 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]); cvtEDataToStr(wp, newvalp[--words]);
wp += VL_EDATASIZE; wp += VL_EDATASIZE;
} }
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbufp); fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbufp);
} }
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitDouble(uint32_t code, double newval) { void VerilatedFstBuffer::emitDouble(uint32_t code, double newval) {
m_owner.emitTimeChangeMaybe();
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval); fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
} }

View File

@ -34,6 +34,8 @@ typedef uint32_t vlFstEnumHandle;
class VerilatedFstBuffer; class VerilatedFstBuffer;
struct fstWriterContext;
//============================================================================= //=============================================================================
// VerilatedFst // VerilatedFst
// Base class to create a Verilator FST dump // Base class to create a Verilator FST dump
@ -49,11 +51,12 @@ private:
//========================================================================= //=========================================================================
// FST-specific internals // FST-specific internals
void* m_fst = nullptr; fstWriterContext* m_fst = nullptr;
std::map<uint32_t, vlFstHandle> m_code2symbol; std::map<uint32_t, vlFstHandle> m_code2symbol;
std::map<int, vlFstEnumHandle> m_local2fstdtype; std::map<int, vlFstEnumHandle> m_local2fstdtype;
vlFstHandle* m_symbolp = nullptr; // same as m_code2symbol, but as an array vlFstHandle* m_symbolp = nullptr; // same as m_code2symbol, but as an array
char* m_strbufp = nullptr; // String buffer long enough to hold maxBits() chars 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 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 // Called when the trace moves forward to a new time point
void emitTimeChange(uint64_t timeui) override; void emitTimeChange(uint64_t timeui) override;
void emitTimeChangeMaybe();
// Hooks called from VerilatedTrace // Hooks called from VerilatedTrace
bool preFullDump() override { return isOpen(); } 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. VerilatedFst& m_owner; // Trace file owning this buffer. Required by subclasses.
// The FST file handle // 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 // code to fstHande map, as an array
const vlFstHandle* const m_symbolp = m_owner.m_symbolp; const vlFstHandle* const m_symbolp = m_owner.m_symbolp;
// String buffer long enough to hold maxBits() chars // 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 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 // Return double from lhs (numeric) unsigned
double VL_ITOR_D_W(int lbits, WDataInP const lwp) VL_PURE; double VL_ITOR_D_W(int lbits, WDataInP const lwp) VL_PURE;
static inline double VL_ITOR_D_I(int, IData lhs) 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[]; 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 // 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);); VL_DEBUG_IF(VL_DBG_MSGF("+prof+exec writing to '%s'\n", filenamep););
FILE* const fp = std::fopen(filenamep, "w"); 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 // TODO Perhaps merge with verilated_coverage output format, so can
// have a common merging and reporting tool, etc. // 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", fprintf(fp, "VLPROF arg +verilator+prof+exec+start+%" PRIu64 "\n",
Verilated::threadContextp()->profExecStart()); Verilated::threadContextp()->profExecStart());
fprintf(fp, "VLPROF arg +verilator+prof+exec+window+%u\n", fprintf(fp, "VLPROF arg +verilator+prof+exec+window+%u\n",
Verilated::threadContextp()->profExecWindow()); 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 // 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 // processors, but not all of them might be utilized. Report the actual number that has trace
// entries to avoid over-counting. // entries to avoid over-counting.
@ -206,13 +190,24 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
break; break;
case VlExecutionRecord::Type::MTASK_BEGIN: { case VlExecutionRecord::Type::MTASK_BEGIN: {
const auto& payload = er.m_payload.mtaskBegin; const auto& payload = er.m_payload.mtaskBegin;
fprintf(fp, " id %u predictStart %u cpu %u\n", payload.m_id, if (payload.m_hierBlock[0] != '\0') {
payload.m_predictStart, payload.m_cpu); 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; break;
} }
case VlExecutionRecord::Type::MTASK_END: { case VlExecutionRecord::Type::MTASK_END: {
const auto& payload = er.m_payload.mtaskEnd; 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; break;
} }
case VlExecutionRecord::Type::SECTION_PUSH: { 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, SECTION_POP) \
_VL_FOREACH_APPLY(macro, MTASK_BEGIN) \ _VL_FOREACH_APPLY(macro, MTASK_BEGIN) \
_VL_FOREACH_APPLY(macro, MTASK_END) \ _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_BEGIN) \
_VL_FOREACH_APPLY(macro, EXEC_GRAPH_END) _VL_FOREACH_APPLY(macro, EXEC_GRAPH_END)
// clang-format on // clang-format on
@ -90,11 +92,14 @@ class VlExecutionRecord final {
uint32_t m_id; // MTask id uint32_t m_id; // MTask id
uint32_t m_predictStart; // Time scheduler predicted would start uint32_t m_predictStart; // Time scheduler predicted would start
uint32_t m_cpu; // Executing CPU id uint32_t m_cpu; // Executing CPU id
const char* m_hierBlock; // Name of a hier block with this mtask
} mtaskBegin; } mtaskBegin;
struct { struct {
uint32_t m_id; // MTask id
uint32_t m_predictCost; // How long scheduler predicted would take uint32_t m_predictCost; // How long scheduler predicted would take
} mtaskEnd; } mtaskEnd;
struct {
uint32_t m_cpu; // Executing CPU id
} threadScheduleWait;
}; };
// STATE // STATE
@ -105,8 +110,6 @@ class VlExecutionRecord final {
static_assert(alignof(uint64_t) >= alignof(Payload), "Padding not allowed"); static_assert(alignof(uint64_t) >= alignof(Payload), "Padding not allowed");
static_assert(alignof(Payload) >= alignof(Type), "Padding not allowed"); static_assert(alignof(Payload) >= alignof(Type), "Padding not allowed");
static uint16_t getcpu(); // Return currently executing CPU id
public: public:
// CONSTRUCTOR // CONSTRUCTOR
VlExecutionRecord() = default; VlExecutionRecord() = default;
@ -117,17 +120,25 @@ public:
m_type = Type::SECTION_PUSH; m_type = Type::SECTION_PUSH;
} }
void sectionPop() { m_type = Type::SECTION_POP; } 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_id = id;
m_payload.mtaskBegin.m_predictStart = predictStart; 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; m_type = Type::MTASK_BEGIN;
} }
void mtaskEnd(uint32_t id, uint32_t predictCost) { void mtaskEnd(uint32_t predictCost) {
m_payload.mtaskEnd.m_id = id;
m_payload.mtaskEnd.m_predictCost = predictCost; m_payload.mtaskEnd.m_predictCost = predictCost;
m_type = Type::MTASK_END; 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 execGraphBegin() { m_type = Type::EXEC_GRAPH_BEGIN; }
void execGraphEnd() { m_type = Type::EXEC_GRAPH_END; } void execGraphEnd() { m_type = Type::EXEC_GRAPH_END; }
}; };
@ -214,7 +225,7 @@ public:
// METHODS // METHODS
VlPgoProfiler() = default; VlPgoProfiler() = default;
~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) { void addCounter(size_t counter, const std::string& name) {
VL_DEBUG_IF(assert(counter < N_Entries);); VL_DEBUG_IF(assert(counter < N_Entries););
m_records.emplace_back(Record{name, counter}); m_records.emplace_back(Record{name, counter});
@ -228,7 +239,8 @@ public:
}; };
template <std::size_t N_Entries> 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; static VerilatedMutex s_mutex;
const VerilatedLockGuard lock{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 // each will collect is own data correctly. However when each is
// destroyed we need to get all the data, not keep overwriting and only // destroyed we need to get all the data, not keep overwriting and only
// get the last model's data. // 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());); 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)) { if (VL_UNLIKELY(!fp)) {
VL_FATAL_MT(filename.c_str(), 0, "", "+prof+vlt+file file not writable"); 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 s_firstCall = false;
// have a common merging and reporting tool, etc.
fprintf(fp, "// Verilated model profile-guided optimization data dump file\n");
fprintf(fp, "`verilator_config\n");
for (const Record& rec : m_records) { for (const Record& rec : m_records) {
fprintf(fp, "profile_data -model \"%s\" -mtask \"%s\" -cost 64'd%" PRIu64 "\n", modelp, 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 << "(Array (_ BitVec " << idxWidths[i] << ") ";
} }
s << "(_ BitVec " << width() << ")"; s << "(_ BitVec " << width() << ")";
for (int i = 0; i < dimension(); ++i) { s << ")"; } for (int i = 0; i < dimension(); ++i) s << ")";
} }
} else { } else {
VL_FATAL_MT(__FILE__, __LINE__, "randomize", "indexed_name not found in m_arr_vars"); 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 std::map<std::string, std::shared_ptr<const VlRandomVar>> m_vars; // Solver-dependent
// variables // variables
ArrayInfoMap m_arr_vars; // Tracks each element in array structures for iteration 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; const VlQueue<CData>* m_randmode; // rand_mode state;
int m_index = 0; // Internal counter for key generation
// PRIVATE METHODS // PRIVATE METHODS
void randomConstraint(std::ostream& os, VlRNG& rngr, int bits); void randomConstraint(std::ostream& os, VlRNG& rngr, int bits);
@ -216,6 +216,11 @@ public:
// Finds the next solution satisfying the constraints // Finds the next solution satisfying the constraints
bool next(VlRNG& rngr); bool next(VlRNG& rngr);
// -----------------------------------------------
// --- Process the key for associative array ---
// -----------------------------------------------
// process_key: Handle integral keys (<= 32-bit)
template <typename T_Key> template <typename T_Key>
typename std::enable_if<std::is_integral<T_Key>::value && (sizeof(T_Key) <= 4)>::type 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, 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]) + "]"; = base_name + "[" + std::to_string(integral_index[integral_index.size() - 1]) + "]";
idx_width = sizeof(T_Key) * 8; idx_width = sizeof(T_Key) * 8;
} }
// process_key: Handle integral keys (> 32-bit), split into 2 x 32-bit segments
template <typename T_Key> template <typename T_Key>
typename std::enable_if<std::is_integral<T_Key>::value && (sizeof(T_Key) > 4)>::type 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, 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; idx_width = sizeof(T_Key) * 8;
} }
// process_key: Handle wide keys (VlWide-like), segment is 32-bit per element
template <typename T_Key> template <typename T_Key>
typename std::enable_if<VlIsVlWide<T_Key>::value>::type 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, 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 + "]"; indexed_name = base_name + "[" + index_string + "]";
idx_width = key.size() * 32; idx_width = key.size() * 32;
} }
// process_key: Handle string key, encoded as 128-bit hex
template <typename T_Key> template <typename T_Key>
typename std::enable_if<std::is_same<T_Key, std::string>::value>::type 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, process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
@ -289,6 +300,8 @@ public:
idx_width = 128; idx_width = 128;
} }
// process_key: Unsupported key type fallback
template <typename T_Key> template <typename T_Key>
typename std::enable_if<!std::is_integral<T_Key>::value typename std::enable_if<!std::is_integral<T_Key>::value
&& !std::is_same<T_Key, std::string>::value && !std::is_same<T_Key, std::string>::value
@ -300,8 +313,13 @@ public:
"supported currently."); "supported currently.");
} }
// -----------------------------------------
// --- write_var to register variables ---
// -----------------------------------------
// Register scalar variable (non-struct, basic type)
template <typename T> 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, write_var(T& var, int width, const char* name, int dimension,
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) { std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
if (m_vars.find(name) != m_vars.end()) return; if (m_vars.find(name) != m_vars.end()) return;
@ -309,28 +327,60 @@ public:
m_vars[name] m_vars[name]
= std::make_shared<const VlRandomVar>(name, width, &var, dimension, randmodeIdx); = std::make_shared<const VlRandomVar>(name, width, &var, dimension, randmodeIdx);
} }
// Register user-defined struct variable by recursively writing members
template <typename T> template <typename T>
void write_var(VlQueue<T>& var, int width, const char* name, int dimension, typename std::enable_if<VlIsCustomStruct<T>::value, void>::type
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) { 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; if (m_vars.find(name) != m_vars.end()) return;
m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlQueue<T>>>( m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlQueue<T>>>(
name, width, &var, dimension, randmodeIdx); name, width, &var, dimension, randmodeIdx);
if (dimension > 0) { if (dimension > 0) {
idx = 0; m_index = 0;
record_arr_table(var, name, dimension, {}, {}); 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> template <typename T, std::size_t N_Depth>
void write_var(VlUnpacked<T, N_Depth>& var, int width, const char* name, int dimension, typename std::enable_if<!VlContainsCustomStruct<T>::value, void>::type
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) { 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; if (m_vars.find(name) != m_vars.end()) return;
m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlUnpacked<T, N_Depth>>>( m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlUnpacked<T, N_Depth>>>(
name, width, &var, dimension, randmodeIdx); name, width, &var, dimension, randmodeIdx);
if (dimension > 0) { if (dimension > 0) {
idx = 0; m_index = 0;
record_arr_table(var, name, dimension, {}, {}); 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> template <typename T_Key, typename T_Value>
void write_var(VlAssocArray<T_Key, T_Value>& var, int width, const char* name, int dimension, 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()) { 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>>>( = std::make_shared<const VlRandomArrayVarTemplate<VlAssocArray<T_Key, T_Value>>>(
name, width, &var, dimension, randmodeIdx); name, width, &var, dimension, randmodeIdx);
if (dimension > 0) { if (dimension > 0) {
idx = 0; m_index = 0;
record_arr_table(var, name, dimension, {}, {}); 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> // TODO: Register associative array of structs
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);
}
int idx; // ----------------------------------------
std::string generateKey(const std::string& name, int idx) { // --- Record Arrays: flat and struct ---
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 a flat (non-class) element into the array variable table
template <typename T> template <typename T>
typename std::enable_if<!std::is_class<T>::value, void>::type 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, record_arr_table(T& var, const std::string name, int dimension, std::vector<IData> indices,
std::vector<size_t> idxWidths) { std::vector<size_t> idxWidths) {
const std::string key = generateKey(name, idx); const std::string key = generateKey(name, m_index);
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices, idxWidths); m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, m_index, indices, idxWidths);
++idx; ++m_index;
}
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 unpacked array
template <typename T, std::size_t N_Depth> template <typename T, std::size_t N_Depth>
void record_arr_table(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension, void record_arr_table(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension,
std::vector<IData> indices, std::vector<size_t> idxWidths) { 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> template <typename T_Key, typename T_Value>
void record_arr_table(VlAssocArray<T_Key, T_Value>& var, const std::string name, int dimension, 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) { 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 hard(std::string&& constraint);
void clear(); void clear();
void set_randmode(const VlQueue<CData>& randmode) { m_randmode = &randmode; } 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 `endif
endtask 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 // When really implemented, srandom must operate on the process, but for
// now rely on the srandom() that is automatically generated for all // now rely on the srandom() that is automatically generated for all
// classes. // classes.

View File

@ -26,6 +26,8 @@
#include "verilated_threads.h" #include "verilated_threads.h"
#include <cstdio> #include <cstdio>
#include <fstream>
#include <iostream>
#include <memory> #include <memory>
#include <string> #include <string>
@ -100,10 +102,153 @@ void VlWorkerThread::startWorker(VlWorkerThread* workerp, VerilatedContext* cont
// VlThreadPool // VlThreadPool
VlThreadPool::VlThreadPool(VerilatedContext* contextp, unsigned nThreads) { 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() { VlThreadPool::~VlThreadPool() {
// Each ~WorkerThread will wait for its thread to exit. // Each ~WorkerThread will wait for its thread to exit.
for (auto& i : m_workers) delete i; 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 <atomic>
#include <condition_variable> #include <condition_variable>
#include <set> #include <set>
#include <stack>
#include <thread> #include <thread>
#include <vector> #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 VlExecutionProfiler;
class VlThreadPool; class VlThreadPool;
@ -155,6 +147,10 @@ private:
VL_UNCOPYABLE(VlWorkerThread); VL_UNCOPYABLE(VlWorkerThread);
protected:
friend class VlThreadPool;
const std::thread& cthread() const { return m_cthread; }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit VlWorkerThread(VerilatedContext* contextp); explicit VlWorkerThread(VerilatedContext* contextp);
@ -205,6 +201,13 @@ class VlThreadPool final : public VerilatedVirtualBase {
// MEMBERS // MEMBERS
std::vector<VlWorkerThread*> m_workers; // our workers 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: public:
// CONSTRUCTORS // CONSTRUCTORS
// Construct a thread pool with 'nThreads' dedicated threads. The thread // Construct a thread pool with 'nThreads' dedicated threads. The thread
@ -214,7 +217,21 @@ public:
~VlThreadPool() override; ~VlThreadPool() override;
// METHODS // 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()); } int numThreads() const { return static_cast<int>(m_workers.size()); }
std::string numaStatus() const { return m_numaStatus; }
VlWorkerThread* workerp(int index) { VlWorkerThread* workerp(int index) {
assert(index >= 0); assert(index >= 0);
assert(index < static_cast<int>(m_workers.size())); assert(index < static_cast<int>(m_workers.size()));
@ -223,6 +240,9 @@ public:
private: private:
VL_UNCOPYABLE(VlThreadPool); VL_UNCOPYABLE(VlThreadPool);
static bool isNumactlRunning();
std::string numaAssign();
}; };
#endif #endif

View File

@ -184,8 +184,11 @@ public:
// Word at given 'wordIndex' // Word at given 'wordIndex'
uint64_t word(size_t wordIndex) const { return m_flags[wordIndex]; } uint64_t word(size_t wordIndex) const { return m_flags[wordIndex]; }
// Set specified flag to given value // Set specified word to given value
void set(size_t index, bool 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]; uint64_t& w = m_flags[index / 64];
const size_t bitIndex = index % 64; const size_t bitIndex = index % 64;
w &= ~(1ULL << bitIndex); w &= ~(1ULL << bitIndex);
@ -618,11 +621,13 @@ public:
T_Value& atWriteAppend(int32_t index) { T_Value& atWriteAppend(int32_t index) {
// cppcheck-suppress variableScope // cppcheck-suppress variableScope
static thread_local T_Value t_throwAway; 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(); t_throwAway = atDefault();
return t_throwAway; return t_throwAway;
} else if (VL_UNLIKELY(index == m_deque.size())) {
push_back(atDefault());
} }
return m_deque[index]; return m_deque[index];
} }
@ -921,6 +926,9 @@ std::string VL_TO_STRING(const VlQueue<T_Value, N_MaxSize>& obj) {
return obj.to_string(); 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 // Verilog associative array container
// There are no multithreaded locks on this; the base variable must // 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(); 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> template <typename T_Key, typename T_Value>
void VL_READMEM_N(bool hex, int bits, const std::string& filename, 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 { 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(); 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 // 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 /// \brief Verilated C++ tracing in VCD format implementation code
/// ///
/// This file must be compiled and linked against all Verilated objects /// 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_wrBufp = new char[m_wrChunkSize * 8];
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6; m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
m_writep = m_wrBufp; m_writep = m_wrBufp;
m_wrTimeBeginp = nullptr;
m_wrTimeEndp = nullptr;
} }
void VerilatedVcd::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) { 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) { void VerilatedVcd::emitTimeChange(uint64_t timeui) {
printStr("#"); // Remember pointers when last emitted time stamp; if last output was
const std::string str = std::to_string(timeui); // timestamp backup and overwrite it.
printStr(str.c_str()); // This is faster then checking on every signal change if time needs to
printStr("\n"); // 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() { VerilatedVcd::~VerilatedVcd() {
@ -257,6 +268,10 @@ void VerilatedVcd::bufferResize(size_t minsize) {
m_wrBufp = new char[m_wrChunkSize * 8]; m_wrBufp = new char[m_wrChunkSize * 8];
std::memcpy(m_wrBufp, oldbufp, m_writep - oldbufp); std::memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
m_writep = m_wrBufp + (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; m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
VL_DO_CLEAR(delete[] oldbufp, oldbufp = nullptr); VL_DO_CLEAR(delete[] oldbufp, oldbufp = nullptr);
} }
@ -293,6 +308,8 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
// Reset buffer // Reset buffer
m_writep = m_wrBufp; m_writep = m_wrBufp;
m_wrTimeBeginp = nullptr;
m_wrTimeEndp = nullptr;
} }
//============================================================================= //=============================================================================

View File

@ -55,6 +55,8 @@ private:
char* m_wrBufp; // Output buffer char* m_wrBufp; // Output buffer
char* m_wrFlushp; // Output buffer flush trigger location char* m_wrFlushp; // Output buffer flush trigger location
char* m_writep; // Write pointer into output buffer 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_wrChunkSize; // Output buffer size
size_t m_maxSignalBytes = 0; // Upper bound on number of bytes a single signal can generate 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 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 // 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 // We reserve word zero for the next pointer, as that's safer in case a
// dangling reference to the original remains around. // 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)) if (VL_UNCOVERABLE(size > CHUNK_SIZE))
VL_FATAL_MT(__FILE__, __LINE__, "", "increase CHUNK_SIZE"); VL_FATAL_MT(__FILE__, __LINE__, "", "increase CHUNK_SIZE");
if (VL_LIKELY(t_freeHeadp)) { if (VL_LIKELY(t_freeHeadp)) {
@ -421,7 +421,7 @@ public:
const char* fullname() const override { const char* fullname() const override {
static thread_local std::string t_out; static thread_local std::string t_out;
t_out = std::string{scopep()->name()} + "." + name(); 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(); return t_out.c_str();
} }
void* prevDatap() const { return m_prevDatap; } void* prevDatap() const { return m_prevDatap; }
@ -873,6 +873,7 @@ class VerilatedVpiImp final {
// All only medium-speed, so use singleton function // All only medium-speed, so use singleton function
// Callbacks that are past or at current timestamp // Callbacks that are past or at current timestamp
std::array<VpioCbList, CB_ENUM_MAX_VALUE> m_cbCurrentLists; 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_futureCbs; // Time based callbacks for future timestamps
VpioFutureCbs m_nextCbs; // cbNextSimTime callbacks VpioFutureCbs m_nextCbs; // cbNextSimTime callbacks
std::list<VerilatedVpiPutHolder> m_inertialPuts; // Pending vpi puts due to vpiInertialDelay std::list<VerilatedVpiPutHolder> m_inertialPuts; // Pending vpi puts due to vpiInertialDelay
@ -925,7 +926,13 @@ public:
for (auto& ir : s().m_cbCurrentLists[reason]) { for (auto& ir : s().m_cbCurrentLists[reason]) {
if (ir.id() == id) { if (ir.id() == id) {
ir.invalidate(); 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 { // Remove from cbFuture queue
@ -985,10 +992,9 @@ public:
moveFutureCbs(); moveFutureCbs();
if (s().m_cbCurrentLists[reason].empty()) return false; if (s().m_cbCurrentLists[reason].empty()) return false;
// Iterate on old list, making new list empty, to prevent looping over newly added elements // Iterate on old list, making new list empty, to prevent looping over newly added elements
VpioCbList cbObjList; std::swap(s().m_cbCurrentLists[reason], s().m_cbCallList);
std::swap(s().m_cbCurrentLists[reason], cbObjList);
bool called = false; 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 // cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
if (VL_LIKELY(!ihor.invalid())) { // Not deleted earlier if (VL_LIKELY(!ihor.invalid())) { // Not deleted earlier
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: reason_callback reason=%d id=%" PRId64 "\n", VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: reason_callback reason=%d id=%" PRId64 "\n",
@ -998,6 +1004,7 @@ public:
called = true; called = true;
} }
} }
s().m_cbCallList.clear();
return called; return called;
} }
static bool callValueCbs() VL_MT_UNSAFE_ONE { 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) { void vl_vpi_get_value(const VerilatedVpioVarBase* vop, p_vpi_value valuep) {
const VerilatedVar* varp = vop->varp(); const VerilatedVar* const varp = vop->varp();
void* varDatap = vop->varDatap(); void* const varDatap = vop->varDatap();
const char* fullname = vop->fullname(); const char* fullname = vop->fullname();
if (!vl_check_format(varp, valuep, fullname, true)) return; 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) { } else if (valuep->format == vpiOctStrVal) {
const int len = std::strlen(valuep->value.str); const int len = std::strlen(valuep->value.str);
for (int i = 0; i < len; ++i) { for (int i = 0; i < len; ++i) {
char digit = valuep->value.str[len - i - 1] - '0'; unsigned char digit = valuep->value.str[len - i - 1] - '0';
if (digit < 0 || digit > 7) { if (digit > 7) { // If str was < '0', then as unsigned, digit > 7
VL_VPI_WARNING_(__FILE__, __LINE__, VL_VPI_WARNING_(__FILE__, __LINE__,
"%s: Non octal character '%c' in '%s' as value %s for %s", "%s: Non octal character '%c' in '%s' as value %s for %s",
__func__, digit + '0', valuep->value.str, __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 "type T is not unsigned"); // ensure logical right shift
const unsigned element_size_bytes = VL_BYTES_I(packedSize); const unsigned element_size_bytes = VL_BYTES_I(packedSize);
const unsigned element_size_words = VL_WORDS_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)) { if (sizeof(T) == sizeof(QData)) {
for (unsigned i = 0; i < num; i++) { for (unsigned i = 0; i < num; i++) {
dst[i * 2].aval = static_cast<QData>(src[index]); 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) { PLI_UINT32 num) {
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object); const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
if (!vl_check_array_format(vop->varp(), arrayvalue_p, vop->fullname())) return; 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(); 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]; = leftIsLow ? index_p[0] - vop->rangep()->left() : vop->rangep()->left() - index_p[0];
if (arrayvalue_p->format == vpiShortIntVal) { if (arrayvalue_p->format == vpiShortIntVal) {
@ -3303,9 +3309,8 @@ void vpi_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_IN
return; return;
} }
int lowRange = vop->rangep()->low(); const int lowRange = vop->rangep()->low();
int highRange = vop->rangep()->high(); const int highRange = vop->rangep()->high();
if ((index_p[0] > highRange) || (index_p[0] < lowRange)) { 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]", 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); __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); 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) { PLI_UINT32 num) {
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object); const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
if (!vl_check_array_format(vop->varp(), arrayvalue_p, vop->fullname())) return; if (!vl_check_array_format(vop->varp(), arrayvalue_p, vop->fullname())) return;
const VerilatedVar* const varp = vop->varp(); const VerilatedVar* const varp = vop->varp();
int size = vop->size(); const int size = vop->size();
if (VL_UNCOVERABLE(num > size)) { if (VL_UNCOVERABLE(num > size)) {
VL_VPI_ERROR_(__FILE__, __LINE__, VL_VPI_ERROR_(__FILE__, __LINE__,
"%s: requested elements to set (%u) exceed array size (%u)", __func__, num, "%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(); 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]; = leftIsLow ? index_p[0] - vop->rangep()->left() : vop->rangep()->left() - index_p[0];
if (arrayvalue_p->format == vpiShortIntVal) { if (arrayvalue_p->format == vpiShortIntVal) {
@ -3485,11 +3490,8 @@ void vpi_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_IN
return; return;
} }
const VerilatedVar* const varp = vop->varp(); const int lowRange = vop->rangep()->low();
const int highRange = vop->rangep()->high();
int lowRange = vop->rangep()->low();
int highRange = vop->rangep()->high();
if ((index_p[0] > highRange) || (index_p[0] < lowRange)) { 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]", 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); __func__, index_p[0], vop->fullname(), lowRange, highRange);

View File

@ -632,7 +632,12 @@ namespace VlOs {
/// Get environment variable /// Get environment variable
extern std::string getenvStr(const std::string& envvar, extern std::string getenvStr(const std::string& envvar,
const std::string& defaultValue) VL_MT_SAFE; 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 // Internal: Record CPU time, starting point on construction, and current delta from that
class DeltaCpuTime final { class DeltaCpuTime final {

View File

@ -31,6 +31,13 @@
# include <processthreadsapi.h> // GetProcessTimes # include <processthreadsapi.h> // GetProcessTimes
# include <psapi.h> // GetProcessMemoryInfo # include <psapi.h> // GetProcessMemoryInfo
#endif #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 // clang-format on
namespace VlOs { namespace VlOs {
@ -72,6 +79,28 @@ double DeltaWallTime::gettime() VL_MT_SAFE {
#endif #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 // 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()
print("You may now want to clean up spelling, and commit:") 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(" git ci -am 'Commentary: Changes update'")
print() 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 V3EmitCMain.h
V3EmitCMake.h V3EmitCMake.h
V3EmitMk.h V3EmitMk.h
V3EmitMkJson.h
V3EmitV.h V3EmitV.h
V3EmitXml.h V3EmitXml.h
V3Error.h V3Error.h
@ -177,6 +178,7 @@ set(HEADERS
V3Trace.h V3Trace.h
V3TraceDecl.h V3TraceDecl.h
V3Tristate.h V3Tristate.h
V3Udp.h
V3Undriven.h V3Undriven.h
V3UniqueNames.h V3UniqueNames.h
V3Unknown.h V3Unknown.h
@ -246,6 +248,7 @@ set(COMMON_SOURCES
V3EmitCPch.cpp V3EmitCPch.cpp
V3EmitCSyms.cpp V3EmitCSyms.cpp
V3EmitMk.cpp V3EmitMk.cpp
V3EmitMkJson.cpp
V3EmitV.cpp V3EmitV.cpp
V3EmitXml.cpp V3EmitXml.cpp
V3Error.cpp V3Error.cpp
@ -324,6 +327,7 @@ set(COMMON_SOURCES
V3TraceDecl.cpp V3TraceDecl.cpp
V3Tristate.cpp V3Tristate.cpp
V3TSP.cpp V3TSP.cpp
V3Udp.cpp
V3Undriven.cpp V3Undriven.cpp
V3Unknown.cpp V3Unknown.cpp
V3Unroll.cpp V3Unroll.cpp

View File

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

View File

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

View File

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

View File

@ -95,10 +95,10 @@ private:
if (const AstVarRef* varrefp = VN_CAST(nodep, VarRef)) { if (const AstVarRef* varrefp = VN_CAST(nodep, VarRef)) {
if (varp == varrefp->varp()) nodep->replaceWith(exprp->cloneTree(false)); if (varp == varrefp->varp()) nodep->replaceWith(exprp->cloneTree(false));
} }
replaceVarRefsWithExprRecurse(nodep->op1p(), varp, exprp); if (AstNode* const refp = nodep->op1p()) replaceVarRefsWithExprRecurse(refp, varp, exprp);
replaceVarRefsWithExprRecurse(nodep->op2p(), varp, exprp); if (AstNode* const refp = nodep->op2p()) replaceVarRefsWithExprRecurse(refp, varp, exprp);
replaceVarRefsWithExprRecurse(nodep->op3p(), varp, exprp); if (AstNode* const refp = nodep->op3p()) replaceVarRefsWithExprRecurse(refp, varp, exprp);
replaceVarRefsWithExprRecurse(nodep->op4p(), varp, exprp); if (AstNode* const refp = nodep->op4p()) replaceVarRefsWithExprRecurse(refp, varp, exprp);
} }
AstPropSpec* substitutePropertyCall(AstPropSpec* nodep) { AstPropSpec* substitutePropertyCall(AstPropSpec* nodep) {
if (AstFuncRef* const funcrefp = VN_CAST(nodep->propp(), FuncRef)) { if (AstFuncRef* const funcrefp = VN_CAST(nodep->propp(), FuncRef)) {
@ -295,7 +295,7 @@ private:
popp->makeStmt()}); popp->makeStmt()});
} }
} else { } else {
nodep->v3fatal("Invalid direction"); nodep->v3fatalSrc("Invalid direction");
} }
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); 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_emptyp = std::make_shared<string>("");
const std::shared_ptr<const string> VSelfPointerText::s_thisp = std::make_shared<string>("this"); 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 { string VSelfPointerText::protect(bool useSelfForThis, bool protect) const {
const string& sp return VIdProtect::protectWordsIf(replaceThis(useSelfForThis, asString()), protect);
= useSelfForThis ? VString::replaceWord(asString(), "this", "vlSelf") : asString();
return VIdProtect::protectWordsIf(sp, protect);
} }
//###################################################################### //######################################################################
@ -228,7 +230,7 @@ string AstNode::vpiName(const string& namein) {
// we change that identifier to an escaped identifier, wrapping it with '\' and ' ' // we change that identifier to an escaped identifier, wrapping it with '\' and ' '
// as specified in LRM 23.6 // as specified in LRM 23.6
string name = namein; 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; string pretty;
pretty.reserve(name.length()); pretty.reserve(name.length());
bool inEscapedIdent = false; bool inEscapedIdent = false;
@ -1340,7 +1342,7 @@ void AstNode::dumpTreeFile(const string& filename, bool doDump) {
{ // Write log & close { // Write log & close
UINFO(2, "Dumping " << filename << endl); UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> logsp{V3File::new_ofstream(filename)}; 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 << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
*logsp << "> to <e" << std::dec << editCountGbl() << ">\n"; *logsp << "> to <e" << std::dec << editCountGbl() << ">\n";
if (editCountGbl() == editCountLast() && ::dumpTreeLevel() < 9) { if (editCountGbl() == editCountLast() && ::dumpTreeLevel() < 9) {
@ -1385,7 +1387,7 @@ void AstNode::dumpTreeJsonFile(const string& filename, bool doDump) {
if (!doDump) return; if (!doDump) return;
UINFO(2, "Dumping " << filename << endl); UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> treejsonp{V3File::new_ofstream(filename)}; 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); dumpTreeJson(*treejsonp);
*treejsonp << '\n'; *treejsonp << '\n';
} }
@ -1394,7 +1396,7 @@ void AstNode::dumpJsonMetaFileGdb(const char* filename) { dumpJsonMetaFile(filen
void AstNode::dumpJsonMetaFile(const string& filename) { void AstNode::dumpJsonMetaFile(const string& filename) {
UINFO(2, "Dumping " << filename << endl); UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> treejsonp{V3File::new_ofstream(filename)}; 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 << '{'; *treejsonp << '{';
FileLine::fileNameNumMapDumpJson(*treejsonp); FileLine::fileNameNumMapDumpJson(*treejsonp);
*treejsonp << ','; *treejsonp << ',';
@ -1408,7 +1410,7 @@ void AstNode::dumpTreeDotFile(const string& filename, bool doDump) {
if (doDump) { if (doDump) {
UINFO(2, "Dumping " << filename << endl); UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> treedotp{V3File::new_ofstream(filename)}; 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 << "digraph vTree{\n";
*treedotp << "\tgraph\t[label=\"" << filename + ".dot" *treedotp << "\tgraph\t[label=\"" << filename + ".dot"
<< "\",\n"; << "\",\n";

View File

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

View File

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

View File

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

View File

@ -388,7 +388,7 @@ protected:
AstNodeCase(VNType t, FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp) AstNodeCase(VNType t, FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp)
: AstNodeStmt{t, fl} { : AstNodeStmt{t, fl} {
this->exprp(exprp); this->exprp(exprp);
this->addItemsp(itemsp); addItemsp(itemsp);
} }
public: public:
@ -414,7 +414,7 @@ public:
, m_type{type} , m_type{type}
, m_directive{directive} { , m_directive{directive} {
this->propp(propp); this->propp(propp);
this->addPasssp(passsp); addPasssp(passsp);
} }
ASTGEN_MEMBERS_AstNodeCoverOrAssert; ASTGEN_MEMBERS_AstNodeCoverOrAssert;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name 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, AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp,
AstNode* stmtsp) AstNode* stmtsp)
: AstNodeStmt{t, fl} { : AstNodeStmt{t, fl} {
this->addInitsp(initsp); addInitsp(initsp);
this->condp(condp); this->condp(condp);
this->addIncsp(incsp); addIncsp(incsp);
this->addStmtsp(stmtsp); addStmtsp(stmtsp);
} }
public: public:
@ -459,7 +459,7 @@ public:
AstNodeForeach(VNType t, FileLine* fl, AstNode* arrayp, AstNode* stmtsp) AstNodeForeach(VNType t, FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
: AstNodeStmt(t, fl) { : AstNodeStmt(t, fl) {
this->arrayp(arrayp); this->arrayp(arrayp);
this->addStmtsp(stmtsp); addStmtsp(stmtsp);
} }
ASTGEN_MEMBERS_AstNodeForeach; ASTGEN_MEMBERS_AstNodeForeach;
bool isGateOptimizable() const override { return false; } bool isGateOptimizable() const override { return false; }
@ -477,8 +477,8 @@ protected:
AstNodeIf(VNType t, FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp) AstNodeIf(VNType t, FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
: AstNodeStmt{t, fl} { : AstNodeStmt{t, fl} {
this->condp(condp); this->condp(condp);
this->addThensp(thensp); addThensp(thensp);
this->addElsesp(elsesp); addElsesp(elsesp);
isBoundsCheck(false); isBoundsCheck(false);
} }
@ -598,7 +598,7 @@ public:
: ASTGEN_SUPER_Bind(fl) : ASTGEN_SUPER_Bind(fl)
, m_name{name} { , m_name{name} {
UASSERT_OBJ(VN_IS(cellsp, Cell), cellsp, "Only instances allowed to be bound"); UASSERT_OBJ(VN_IS(cellsp, Cell), cellsp, "Only instances allowed to be bound");
this->addCellsp(cellsp); addCellsp(cellsp);
} }
ASTGEN_MEMBERS_AstBind; ASTGEN_MEMBERS_AstBind;
// ACCESSORS // ACCESSORS
@ -631,8 +631,10 @@ class AstCFunc final : public AstNode {
bool m_isConstructor : 1; // Is C class constructor bool m_isConstructor : 1; // Is C class constructor
bool m_isDestructor : 1; // Is C class destructor bool m_isDestructor : 1; // Is C class destructor
bool m_isMethod : 1; // Is inside a class definition bool m_isMethod : 1; // Is inside a class definition
bool m_isLoose : 1; // Semantically this is a method, but is implemented as a function bool m_isLoose : 1; // Semantically this is a method, but is implemented as a function with
// with an explicitly passed 'self' pointer as the first argument // 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_isInline : 1; // Inline function
bool m_isVirtual : 1; // Virtual function bool m_isVirtual : 1; // Virtual function
bool m_entryPoint : 1; // User may call into this top level function bool m_entryPoint : 1; // User may call into this top level function
@ -762,7 +764,7 @@ class AstCLocalScope final : public AstNode {
public: public:
AstCLocalScope(FileLine* fl, AstNode* stmtsp) AstCLocalScope(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_CLocalScope(fl) { : ASTGEN_SUPER_CLocalScope(fl) {
this->addStmtsp(stmtsp); addStmtsp(stmtsp);
} }
ASTGEN_MEMBERS_AstCLocalScope; ASTGEN_MEMBERS_AstCLocalScope;
}; };
@ -790,8 +792,8 @@ class AstCaseItem final : public AstNode {
public: public:
AstCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* stmtsp) AstCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* stmtsp)
: ASTGEN_SUPER_CaseItem(fl) { : ASTGEN_SUPER_CaseItem(fl) {
this->addCondsp(condsp); addCondsp(condsp);
this->addStmtsp(stmtsp); addStmtsp(stmtsp);
} }
ASTGEN_MEMBERS_AstCaseItem; ASTGEN_MEMBERS_AstCaseItem;
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
@ -824,8 +826,8 @@ public:
, m_hasIfaceVar{false} , m_hasIfaceVar{false}
, m_recursive{false} , m_recursive{false}
, m_trace{true} { , m_trace{true} {
this->addPinsp(pinsp); addPinsp(pinsp);
this->addParamsp(paramsp); addParamsp(paramsp);
this->rangep(rangep); this->rangep(rangep);
} }
ASTGEN_MEMBERS_AstCell; ASTGEN_MEMBERS_AstCell;
@ -915,6 +917,7 @@ class AstClassExtends final : public AstNode {
// during early parse, then moves to dtype // during early parse, then moves to dtype
// @astgen op1 := childDTypep : Optional[AstNodeDType] // @astgen op1 := childDTypep : Optional[AstNodeDType]
// @astgen op2 := classOrPkgsp : Optional[AstNode] // @astgen op2 := classOrPkgsp : Optional[AstNode]
// @astgen op3 := argsp : List[AstNodeExpr]
const bool m_isImplements = false; // class implements const bool m_isImplements = false; // class implements
bool m_parameterized = false; // has parameters in its statement bool m_parameterized = false; // has parameters in its statement
@ -1037,7 +1040,7 @@ public:
AstConstraint(FileLine* fl, const string& name, AstNode* itemsp) AstConstraint(FileLine* fl, const string& name, AstNode* itemsp)
: ASTGEN_SUPER_Constraint(fl) : ASTGEN_SUPER_Constraint(fl)
, m_name(name) { , m_name(name) {
this->addItemsp(itemsp); addItemsp(itemsp);
} }
ASTGEN_MEMBERS_AstConstraint; ASTGEN_MEMBERS_AstConstraint;
void dump(std::ostream& str) const override; void dump(std::ostream& str) const override;
@ -1067,8 +1070,8 @@ class AstConstraintBefore final : public AstNode {
public: public:
AstConstraintBefore(FileLine* fl, AstNodeExpr* lhssp, AstNodeExpr* rhssp) AstConstraintBefore(FileLine* fl, AstNodeExpr* lhssp, AstNodeExpr* rhssp)
: ASTGEN_SUPER_ConstraintBefore(fl) { : ASTGEN_SUPER_ConstraintBefore(fl) {
this->addLhssp(lhssp); addLhssp(lhssp);
this->addRhssp(rhssp); addRhssp(rhssp);
} }
ASTGEN_MEMBERS_AstConstraintBefore; ASTGEN_MEMBERS_AstConstraintBefore;
bool isGateOptimizable() const override { return false; } bool isGateOptimizable() const override { return false; }
@ -1187,7 +1190,7 @@ class AstImplicit final : public AstNode {
public: public:
AstImplicit(FileLine* fl, AstNode* exprsp) AstImplicit(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_Implicit(fl) { : ASTGEN_SUPER_Implicit(fl) {
this->addExprsp(exprsp); addExprsp(exprsp);
} }
ASTGEN_MEMBERS_AstImplicit; ASTGEN_MEMBERS_AstImplicit;
}; };
@ -1250,7 +1253,7 @@ public:
AstModport(FileLine* fl, const string& name, AstNode* varsp) AstModport(FileLine* fl, const string& name, AstNode* varsp)
: ASTGEN_SUPER_Modport(fl) : ASTGEN_SUPER_Modport(fl)
, m_name{name} { , m_name{name} {
this->addVarsp(varsp); addVarsp(varsp);
} }
string verilogKwd() const override { return "modport"; } string verilogKwd() const override { return "modport"; }
string name() const override VL_MT_STABLE { return m_name; } string name() const override VL_MT_STABLE { return m_name; }
@ -1645,7 +1648,7 @@ class AstSenTree final : public AstNode {
public: public:
AstSenTree(FileLine* fl, AstSenItem* sensesp) AstSenTree(FileLine* fl, AstSenItem* sensesp)
: ASTGEN_SUPER_SenTree(fl) { : ASTGEN_SUPER_SenTree(fl) {
this->addSensesp(sensesp); addSensesp(sensesp);
} }
ASTGEN_MEMBERS_AstSenTree; ASTGEN_MEMBERS_AstSenTree;
void dump(std::ostream& str) const override; void dump(std::ostream& str) const override;
@ -1798,18 +1801,47 @@ public:
AstUdpTable(FileLine* fl, AstUdpTableLine* linesp) AstUdpTable(FileLine* fl, AstUdpTableLine* linesp)
: ASTGEN_SUPER_UdpTable(fl) { : ASTGEN_SUPER_UdpTable(fl) {
this->addLinesp(linesp); this->addLinesp(linesp);
if (!v3Global.hasTable()) v3Global.setHasTable();
} }
ASTGEN_MEMBERS_AstUdpTable; ASTGEN_MEMBERS_AstUdpTable;
}; };
class AstUdpTableLine final : public AstNode { 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: public:
AstUdpTableLine(FileLine* fl, const string& text) class UdpCombo {};
AstUdpTableLine(UdpCombo, FileLine* fl, AstUdpTableLineVal* iFieldsp,
AstUdpTableLineVal* oFieldsp)
: ASTGEN_SUPER_UdpTableLine(fl) : 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; 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; } 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; } string text() const VL_MT_SAFE { return m_text; }
}; };
class AstVar final : public AstNode { 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_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_isWrittenBySuspendable : 1; // This variable can be written by a suspendable process
bool m_ignorePostWrite : 1; // Ignore writes in 'Post' blocks during ordering bool m_ignorePostWrite : 1; // Ignore writes in 'Post' blocks during ordering
bool m_ignoreSchedWrite : 1; // Ignore writes in scheduling (for coverage increments)
void init() { void init() {
m_ansi = false; m_ansi = false;
@ -1923,6 +1956,7 @@ class AstVar final : public AstNode {
m_isWrittenByDpi = false; m_isWrittenByDpi = false;
m_isWrittenBySuspendable = false; m_isWrittenBySuspendable = false;
m_ignorePostWrite = false; m_ignorePostWrite = false;
m_ignoreSchedWrite = false;
m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN; m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN;
} }
@ -2080,6 +2114,8 @@ public:
void setWrittenBySuspendable() { m_isWrittenBySuspendable = true; } void setWrittenBySuspendable() { m_isWrittenBySuspendable = true; }
bool ignorePostWrite() const { return m_ignorePostWrite; } bool ignorePostWrite() const { return m_ignorePostWrite; }
void setIgnorePostWrite() { m_ignorePostWrite = true; } void setIgnorePostWrite() { m_ignorePostWrite = true; }
bool ignoreSchedWrite() const { return m_ignoreSchedWrite; }
void setIgnoreSchedWrite() { m_ignoreSchedWrite = true; }
// METHODS // METHODS
void name(const string& name) override { m_name = name; } void name(const string& name) override { m_name = name; }
@ -2165,6 +2201,8 @@ public:
string verilogKwd() const override; string verilogKwd() const override;
void lifetime(const VLifetime& flag) { m_lifetime = flag; } void lifetime(const VLifetime& flag) { m_lifetime = flag; }
VLifetime lifetime() const { return m_lifetime; } VLifetime lifetime() const { return m_lifetime; }
void pinNum(int id) { m_pinNum = id; }
int pinNum() const { return m_pinNum; }
void propagateAttrFrom(const AstVar* fromp) { void propagateAttrFrom(const AstVar* fromp) {
// This is getting connected to fromp; keep attributes // This is getting connected to fromp; keep attributes
// Note the method below too // Note the method below too
@ -2197,9 +2235,11 @@ public:
m_direction = VDirection::NONE; m_direction = VDirection::NONE;
m_name = name; m_name = name;
} }
bool needsCReset() const {
return !isIfaceParent() && !isIfaceRef() && !noReset() && !isParam() && !isStatementTemp()
&& !(basicp() && (basicp()->isEvent() || basicp()->isTriggerVec()));
}
static AstVar* scVarRecurse(AstNode* nodep); static AstVar* scVarRecurse(AstNode* nodep);
void pinNum(int id) { m_pinNum = id; }
int pinNum() const { return m_pinNum; }
}; };
class AstVarScope final : public AstNode { class AstVarScope final : public AstNode {
// A particular scoped usage of a variable // A particular scoped usage of a variable
@ -2302,7 +2342,7 @@ public:
class AstLet final : public AstNodeFTask { class AstLet final : public AstNodeFTask {
// Verilog "let" statement // Verilog "let" statement
// Parents: MODULE // 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: public:
AstLet(FileLine* fl, const string& name) AstLet(FileLine* fl, const string& name)
: ASTGEN_SUPER_Let(fl, name, nullptr) {} : 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_extended = false; // Is extension or extended by other classes
bool m_interfaceClass = false; // Interface class bool m_interfaceClass = false; // Interface class
bool m_needRNG = false; // Need RNG, uses srandom/randomize 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_useVirtualPublic = false; // Subclasses need virtual public as uses interface class
bool m_virtual = false; // Virtual class bool m_virtual = false; // Virtual class
@ -2403,8 +2442,6 @@ public:
void isExtended(bool flag) { m_extended = flag; } void isExtended(bool flag) { m_extended = flag; }
bool isInterfaceClass() const { return m_interfaceClass; } bool isInterfaceClass() const { return m_interfaceClass; }
void isInterfaceClass(bool flag) { m_interfaceClass = flag; } 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; } bool isVirtual() const { return m_virtual; }
void isVirtual(bool flag) { m_virtual = flag; } void isVirtual(bool flag) { m_virtual = flag; }
bool needRNG() const { return m_needRNG; } bool needRNG() const { return m_needRNG; }
@ -2484,14 +2521,28 @@ public:
}; };
class AstModule final : public AstNodeModule { class AstModule final : public AstNodeModule {
// A module declaration // 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: 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) : 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; 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 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 { class AstNotFoundModule final : public AstNodeModule {
// A missing module declaration // A missing module declaration
@ -2740,15 +2791,22 @@ public:
class AstCReset final : public AstNodeStmt { class AstCReset final : public AstNodeStmt {
// Reset variable at startup // Reset variable at startup
// @astgen op1 := varrefp : AstVarRef // @astgen op1 := varrefp : AstVarRef
const bool m_constructing; // Previously cleared by constructor
public: public:
AstCReset(FileLine* fl, AstVarRef* varrefp) AstCReset(FileLine* fl, AstVarRef* varrefp, bool constructing)
: ASTGEN_SUPER_CReset(fl) { : ASTGEN_SUPER_CReset(fl)
, m_constructing(constructing) {
this->varrefp(varrefp); this->varrefp(varrefp);
} }
ASTGEN_MEMBERS_AstCReset; ASTGEN_MEMBERS_AstCReset;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool isGateOptimizable() const override { return false; } bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() 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 { class AstCReturn final : public AstNodeStmt {
// C++ return from a function // C++ return from a function
@ -2768,7 +2826,7 @@ class AstCStmt final : public AstNodeStmt {
public: public:
AstCStmt(FileLine* fl, AstNode* exprsp) AstCStmt(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_CStmt(fl) { : ASTGEN_SUPER_CStmt(fl) {
this->addExprsp(exprsp); addExprsp(exprsp);
} }
inline AstCStmt(FileLine* fl, const string& textStmt); inline AstCStmt(FileLine* fl, const string& textStmt);
ASTGEN_MEMBERS_AstCStmt; ASTGEN_MEMBERS_AstCStmt;
@ -2817,7 +2875,7 @@ class AstConstraintUnique final : public AstNodeStmt {
public: public:
AstConstraintUnique(FileLine* fl, AstNode* rangesp) AstConstraintUnique(FileLine* fl, AstNode* rangesp)
: ASTGEN_SUPER_ConstraintUnique(fl) { : ASTGEN_SUPER_ConstraintUnique(fl) {
this->addRangesp(rangesp); addRangesp(rangesp);
} }
ASTGEN_MEMBERS_AstConstraintUnique; ASTGEN_MEMBERS_AstConstraintUnique;
bool isGateOptimizable() const override { return false; } bool isGateOptimizable() const override { return false; }
@ -2983,14 +3041,14 @@ public:
AstNodeExpr* exprsp, char missingArgChar = 'd') AstNodeExpr* exprsp, char missingArgChar = 'd')
: ASTGEN_SUPER_Display(fl) : ASTGEN_SUPER_Display(fl)
, m_displayType{dispType} { , m_displayType{dispType} {
this->fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar}); fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
this->filep(filep); this->filep(filep);
} }
AstDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* filep, AstNodeExpr* exprsp, AstDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* filep, AstNodeExpr* exprsp,
char missingArgChar = 'd') char missingArgChar = 'd')
: ASTGEN_SUPER_Display(fl) : ASTGEN_SUPER_Display(fl)
, m_displayType{dispType} { , m_displayType{dispType} {
this->fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar}); fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar});
this->filep(filep); this->filep(filep);
} }
ASTGEN_MEMBERS_AstDisplay; ASTGEN_MEMBERS_AstDisplay;
@ -3063,7 +3121,7 @@ public:
AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp)
: ASTGEN_SUPER_EventControl(fl) { : ASTGEN_SUPER_EventControl(fl) {
this->sensesp(sensesp); this->sensesp(sensesp);
this->addStmtsp(stmtsp); addStmtsp(stmtsp);
} }
ASTGEN_MEMBERS_AstEventControl; ASTGEN_MEMBERS_AstEventControl;
string verilogKwd() const override { return "@(%l) %r"; } string verilogKwd() const override { return "@(%l) %r"; }
@ -3144,7 +3202,7 @@ public:
// After construction must call ->labelp to associate with appropriate label // After construction must call ->labelp to associate with appropriate label
AstJumpBlock(FileLine* fl, AstNode* stmtsp) AstJumpBlock(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_JumpBlock(fl) { : ASTGEN_SUPER_JumpBlock(fl) {
this->addStmtsp(stmtsp); addStmtsp(stmtsp);
} }
ASTGEN_MEMBERS_AstJumpBlock; ASTGEN_MEMBERS_AstJumpBlock;
const char* broken() const override; const char* broken() const override;
@ -3276,7 +3334,7 @@ public:
AstRepeat(FileLine* fl, AstNodeExpr* countp, AstNode* stmtsp) AstRepeat(FileLine* fl, AstNodeExpr* countp, AstNode* stmtsp)
: ASTGEN_SUPER_Repeat(fl) { : ASTGEN_SUPER_Repeat(fl) {
this->countp(countp); this->countp(countp);
this->addStmtsp(stmtsp); addStmtsp(stmtsp);
} }
ASTGEN_MEMBERS_AstRepeat; ASTGEN_MEMBERS_AstRepeat;
bool isGateOptimizable() const override { return false; } // Not relevant - converted to FOR 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, AstSFormat(FileLine* fl, AstNodeExpr* lhsp, const string& text, AstNodeExpr* exprsp,
char missingArgChar = 'd') char missingArgChar = 'd')
: ASTGEN_SUPER_SFormat(fl) { : ASTGEN_SUPER_SFormat(fl) {
this->fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar}); fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
this->lhsp(lhsp); this->lhsp(lhsp);
} }
AstSFormat(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* exprsp, char missingArgChar = 'd') AstSFormat(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* exprsp, char missingArgChar = 'd')
: ASTGEN_SUPER_SFormat(fl) { : ASTGEN_SUPER_SFormat(fl) {
this->fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar}); fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar});
this->lhsp(lhsp); this->lhsp(lhsp);
} }
ASTGEN_MEMBERS_AstSFormat; ASTGEN_MEMBERS_AstSFormat;
@ -3327,6 +3385,24 @@ public:
int instrCount() const override { return INSTR_COUNT_PLI; } int instrCount() const override { return INSTR_COUNT_PLI; }
bool sameNode(const AstNode* /*samep*/) const override { return true; } 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 { class AstStackTraceT final : public AstNodeStmt {
// $stacktrace used as task // $stacktrace used as task
public: public:
@ -3540,7 +3616,7 @@ class AstUCStmt final : public AstNodeStmt {
public: public:
AstUCStmt(FileLine* fl, AstNode* exprsp) AstUCStmt(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_UCStmt(fl) { : ASTGEN_SUPER_UCStmt(fl) {
this->addExprsp(exprsp); addExprsp(exprsp);
} }
ASTGEN_MEMBERS_AstUCStmt; ASTGEN_MEMBERS_AstUCStmt;
bool isGateOptimizable() const override { return false; } bool isGateOptimizable() const override { return false; }
@ -3556,7 +3632,7 @@ public:
AstWait(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp) AstWait(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp)
: ASTGEN_SUPER_Wait(fl) { : ASTGEN_SUPER_Wait(fl) {
this->condp(condp); this->condp(condp);
this->addStmtsp(stmtsp); addStmtsp(stmtsp);
} }
ASTGEN_MEMBERS_AstWait; ASTGEN_MEMBERS_AstWait;
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } 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) AstWhile(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp = nullptr, AstNode* incsp = nullptr)
: ASTGEN_SUPER_While(fl) { : ASTGEN_SUPER_While(fl) {
this->condp(condp); this->condp(condp);
this->addStmtsp(stmtsp); addStmtsp(stmtsp);
this->addIncsp(incsp); addIncsp(incsp);
} }
ASTGEN_MEMBERS_AstWhile; ASTGEN_MEMBERS_AstWhile;
void dump(std::ostream& str) const override; void dump(std::ostream& str) const override;
@ -3756,7 +3832,7 @@ public:
AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, VAssertType type, AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, VAssertType type,
VAssertDirectiveType directive, const string& name = "") VAssertDirectiveType directive, const string& name = "")
: ASTGEN_SUPER_Assert(fl, propp, passsp, type, directive, name) { : ASTGEN_SUPER_Assert(fl, propp, passsp, type, directive, name) {
this->addFailsp(failsp); addFailsp(failsp);
} }
}; };
class AstAssertIntrinsic final : public AstNodeCoverOrAssert { class AstAssertIntrinsic final : public AstNodeCoverOrAssert {
@ -3769,7 +3845,7 @@ public:
// Intrinsic asserts are always enabled thus 'type' field is set to INTERNAL. // Intrinsic asserts are always enabled thus 'type' field is set to INTERNAL.
: ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, VAssertType::INTERNAL, : ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, VAssertType::INTERNAL,
VAssertDirectiveType::INTRINSIC, name) { VAssertDirectiveType::INTRINSIC, name) {
this->addFailsp(failsp); addFailsp(failsp);
} }
}; };
class AstCover final : public AstNodeCoverOrAssert { class AstCover final : public AstNodeCoverOrAssert {
@ -3886,6 +3962,14 @@ public:
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; } 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 { class AstScImp final : public AstNodeText {
public: public:
AstScImp(FileLine* fl, const string& textp) 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}; 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) { AstVar* AstClocking::ensureEventp(bool childDType) {
if (!eventp()) { if (!eventp()) {
AstVar* const evp AstVar* const evp
@ -815,12 +824,12 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
} }
} else if (AstArraySel* const arraySelp = VN_CAST(nodep, ArraySel)) { } else if (AstArraySel* const arraySelp = VN_CAST(nodep, ArraySel)) {
if (AstVar* const p = scVarRecurse(arraySelp->fromp())) return p; if (AstVar* const p = scVarRecurse(arraySelp->fromp())) return p;
if (AstVar* const p = scVarRecurse(arraySelp->bitp())) return p;
} }
return nullptr; 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; const AstNodeDType* nodep = this;
while (true) { while (true) {
if (VL_UNLIKELY(VN_IS(nodep, MemberDType) || VN_IS(nodep, ParamTypeDType) 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; nodep = subp;
continue; continue;
} else { } else {
nodep->v3fatalSrc(nodep->prettyTypeName() << " not linked to type"); if (assertOn) nodep->v3fatalSrc(nodep->prettyTypeName() << " not linked to type");
return nullptr; 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(); } bool AstNodeDType::isFourstate() const { return basicp() && basicp()->isFourstate(); }
class AstNodeDType::CTypeRecursed final { class AstNodeDType::CTypeRecursed final {
@ -998,11 +1016,11 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packe
return info; return info;
} }
uint32_t AstNodeDType::arrayUnpackedElements() { uint32_t AstNodeDType::arrayUnpackedElements() const {
uint32_t entries = 1; 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 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(); entries *= adtypep->elementsConst();
dtypep = adtypep->subDTypep(); dtypep = adtypep->subDTypep();
} else { } else {
@ -1986,8 +2004,8 @@ AstMemberSel::AstMemberSel(FileLine* fl, AstNodeExpr* fromp, AstVar* varp)
} }
bool AstMemberSel::sameNode(const AstNode* samep) const { bool AstMemberSel::sameNode(const AstNode* samep) const {
const AstMemberSel* const sp = VN_DBG_AS(samep, MemberSel); const AstMemberSel* const sp = VN_DBG_AS(samep, MemberSel);
return sp != nullptr && access() == sp->access() && fromp()->isSame(sp->fromp()) return sp && access() == sp->access() && fromp()->isSame(sp->fromp()) && name() == sp->name()
&& name() == sp->name() && varp()->sameNode(sp->varp()); && (varp() && sp->varp() && varp()->sameNode(sp->varp()));
} }
void AstMemberSel::dump(std::ostream& str) const { void AstMemberSel::dump(std::ostream& str) const {
@ -2030,6 +2048,16 @@ void AstModportVarRef::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "direction", direction().ascii()); dumpJsonStr(str, "direction", direction().ascii());
dumpJsonGen(str); 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 { void AstPin::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (modVarp()) { if (modVarp()) {
@ -2474,8 +2502,24 @@ void AstNodeVarRef::dumpJson(std::ostream& str) const {
dumpJsonStr(str, "access", access().ascii()); dumpJsonStr(str, "access", access().ascii());
dumpJsonGen(str); 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 { void AstVarXRef::dump(std::ostream& str) const {
this->AstNodeVarRef::dump(str); this->AstNodeVarRef::dump(str);
if (containsGenBlock()) str << " [GENBLK]";
str << ".=" << dotted() << " "; str << ".=" << dotted() << " ";
if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - "; if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - ";
if (varScopep()) { if (varScopep()) {
@ -2487,6 +2531,7 @@ void AstVarXRef::dump(std::ostream& str) const {
} }
} }
void AstVarXRef::dumpJson(std::ostream& str) const { void AstVarXRef::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, containsGenBlock);
dumpJsonStrFunc(str, dotted); dumpJsonStrFunc(str, dotted);
dumpJsonStrFunc(str, inlinedDots); dumpJsonStrFunc(str, inlinedDots);
dumpJsonGen(str); dumpJsonGen(str);
@ -2538,6 +2583,8 @@ void AstVar::dump(std::ostream& str) const {
str << " [FUNC]"; str << " [FUNC]";
} }
if (isDpiOpenArray()) str << " [DPIOPENA]"; if (isDpiOpenArray()) str << " [DPIOPENA]";
if (ignorePostWrite()) str << " [IGNPWR]";
if (ignoreSchedWrite()) str << " [IGNWR]";
if (!attrClocker().unknown()) str << " [" << attrClocker().ascii() << "] "; if (!attrClocker().unknown()) str << " [" << attrClocker().ascii() << "] ";
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] "; if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
str << " " << varType(); str << " " << varType();
@ -2570,6 +2617,8 @@ void AstVar::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, isParam); dumpJsonBoolFunc(str, isParam);
dumpJsonBoolFunc(str, attrScBv); dumpJsonBoolFunc(str, attrScBv);
dumpJsonBoolFunc(str, attrSFormat); dumpJsonBoolFunc(str, attrSFormat);
dumpJsonBoolFunc(str, ignorePostWrite);
dumpJsonBoolFunc(str, ignoreSchedWrite);
dumpJsonGen(str); dumpJsonGen(str);
} }
bool AstVar::sameNode(const AstNode* samep) const { bool AstVar::sameNode(const AstNode* samep) const {
@ -2656,7 +2705,9 @@ AstNodeModule* AstClassOrPackageRef::classOrPackageSkipp() const {
AstNode* lastp = nullptr; AstNode* lastp = nullptr;
while (foundp != lastp) { while (foundp != lastp) {
lastp = foundp; 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 (AstTypedef* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
if (AstClassRefDType* const anodep = VN_CAST(foundp, ClassRefDType)) if (AstClassRefDType* const anodep = VN_CAST(foundp, ClassRefDType))
foundp = anodep->classp(); foundp = anodep->classp();
@ -2988,7 +3039,8 @@ void AstCMethodHard::setPurity() {
{"resume", false}, {"resume", false},
{"reverse", false}, {"reverse", false},
{"rsort", false}, {"rsort", false},
{"set", false}, {"setBit", false},
{"setWord", false},
{"set_randmode", false}, {"set_randmode", false},
{"shuffle", false}, {"shuffle", false},
{"size", true}, {"size", true},
@ -3055,7 +3107,7 @@ AstAlways* AstAssignW::convertToAlways() {
if (hasTimingControl) { if (hasTimingControl) {
// If there's a timing control, put the assignment in a fork..join_none. This process won't // 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 // 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); forkp->joinType(VJoinType::JOIN_NONE);
bodysp = forkp; bodysp = forkp;
} }

View File

@ -99,7 +99,7 @@ public:
} }
// Get a pointer to the user data if exists, otherwise nullptr // 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(); } void clear() { m_allocated.clear(); }
}; };

View File

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

View File

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

View File

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

View File

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

View File

@ -540,6 +540,8 @@ class V3ConfigResolver final {
std::unordered_map<string, std::unordered_map<string, uint64_t>> std::unordered_map<string, std::unordered_map<string, uint64_t>>
m_profileData; // Access to profile_data records m_profileData; // Access to profile_data records
uint8_t m_mode = NONE; uint8_t m_mode = NONE;
std::unordered_map<string, int> m_hierWorkers;
FileLine* m_hierWorkersFileLine = nullptr;
FileLine* m_profileFileLine = nullptr; FileLine* m_profileFileLine = nullptr;
V3ConfigResolver() = default; V3ConfigResolver() = default;
@ -570,6 +572,16 @@ public:
// Empty key for hierarchical DPI wrapper costs. // Empty key for hierarchical DPI wrapper costs.
return getProfileData(hierDpi, ""); 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 { uint64_t getProfileData(const string& model, const string& key) const {
const auto mit = m_profileData.find(model); const auto mit = m_profileData.find(model);
if (mit == m_profileData.cend()) return 0; 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); 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) { void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max) {
if (filename == "*") { if (filename == "*") {
FileLine::globalWarnOff(code, !on); FileLine::globalWarnOff(code, !on);
@ -741,6 +757,12 @@ void V3Config::applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar
if (vp) vp->apply(varp); 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) { uint64_t V3Config::getProfileData(const string& hierDpi) {
return V3ConfigResolver::s().getProfileData(hierDpi); return V3ConfigResolver::s().getProfileData(hierDpi);
} }

View File

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

View File

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

View File

@ -35,6 +35,40 @@
VL_DEFINE_DEBUG_FUNCTIONS; 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 // Coverage state, as a visitor of each AstNode
@ -159,6 +193,7 @@ class CoverageVisitor final : public VNVisitor {
fl_nowarn->modifyWarnOff(V3ErrorCode::UNUSEDSIGNAL, true); fl_nowarn->modifyWarnOff(V3ErrorCode::UNUSEDSIGNAL, true);
AstVar* const varp = new AstVar{fl_nowarn, VVarType::MODULETEMP, trace_var_name, AstVar* const varp = new AstVar{fl_nowarn, VVarType::MODULETEMP, trace_var_name,
incp->findUInt32DType()}; incp->findUInt32DType()};
varp->setIgnoreSchedWrite(); // Ignore the increment output, so no UNOPTFLAT
varp->trace(true); varp->trace(true);
m_modp->addStmtsp(varp); m_modp->addStmtsp(varp);
UINFO(5, "New coverage trace: " << varp << endl); UINFO(5, "New coverage trace: " << varp << endl);
@ -668,6 +703,7 @@ class CoverageVisitor final : public VNVisitor {
m_objective = true; m_objective = true;
iterate(nodep); iterate(nodep);
if (checkMaxExprs(falseExprs.size())) return; if (checkMaxExprs(falseExprs.size())) return;
if (m_seeking == ABORTED) return;
addExprCoverInc(nodep); addExprCoverInc(nodep);
const int start = m_exprs.size(); const int start = m_exprs.size();
@ -871,26 +907,30 @@ class CoverageVisitor final : public VNVisitor {
lineTrack(nodep); lineTrack(nodep);
} }
// Lambdas not supported for expression coverage void visit(AstFuncRef* nodep) override {
void visit(AstWith* nodep) override { if (nodep->taskp()->lifetime().isAutomatic()) {
VL_RESTORER(m_seeking); visit(static_cast<AstNodeExpr*>(nodep));
if (m_seeking == SEEKING) abortExprCoverage(); } else {
m_seeking = ABORTED; exprUnsupported(nodep, "non-automatic function");
iterateChildren(nodep); }
lineTrack(nodep);
} }
void visit(AstNodeExpr* nodep) override { void visit(AstNodeExpr* nodep) override {
if (m_seeking != SEEKING) { if (m_seeking != SEEKING) {
iterateChildren(nodep); iterateChildren(nodep);
} else { } else {
std::stringstream emitV; ExprCoverageEligibleVisitor elgibleVisitor(nodep);
V3EmitV::verilogForTree(nodep, emitV); if (elgibleVisitor.eligible()) {
// Add new expression with a single term std::stringstream emitV;
CoverExpr expr; V3EmitV::verilogForTree(nodep, emitV);
expr.emplace_back(nodep, m_objective, emitV.str()); // Add new expression with a single term
m_exprs.push_back(std::move(expr)); CoverExpr expr;
checkMaxExprs(); expr.emplace_back(nodep, m_objective, emitV.str());
m_exprs.push_back(std::move(expr));
checkMaxExprs();
} else {
exprUnsupported(nodep, "not coverage eligible");
}
} }
lineTrack(nodep); lineTrack(nodep);
} }
@ -901,6 +941,17 @@ class CoverageVisitor final : public VNVisitor {
lineTrack(nodep); 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: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); } explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); }

View File

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

View File

@ -74,7 +74,7 @@ class DescopeVisitor final : public VNVisitor {
string name = scopep->name(); string name = scopep->name();
string::size_type pos; string::size_type pos;
if ((pos = name.rfind('.')) != string::npos) name.erase(0, pos + 1); 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; return ret.thisPtr;
} }
@ -104,9 +104,9 @@ class DescopeVisitor final : public VNVisitor {
if (VN_IS(scopep->modp(), Class)) { if (VN_IS(scopep->modp(), Class)) {
// Direct reference to class members are from within the class itself, references from // Direct reference to class members are from within the class itself, references from
// outside the class must go via AstMemberSel // outside the class must go via AstMemberSel
return VSelfPointerText{VSelfPointerText::This()}; return VSelfPointerText{VSelfPointerText::This{}};
} else if (relativeRefOk && scopep == m_scopep) { } else if (relativeRefOk && scopep == m_scopep) {
return VSelfPointerText{VSelfPointerText::This()}; return VSelfPointerText{VSelfPointerText::This{}};
} else if (relativeRefOk && !m_modSingleton && scopep->aboveScopep() == m_scopep } else if (relativeRefOk && !m_modSingleton && scopep->aboveScopep() == m_scopep
&& VN_IS(scopep->modp(), Module)) { && VN_IS(scopep->modp(), Module)) {
// Reference to scope of instance directly under this module, can just "this->cell", // Reference to scope of instance directly under this module, can just "this->cell",
@ -215,9 +215,9 @@ class DescopeVisitor final : public VNVisitor {
makePublicFuncWrappers(); makePublicFuncWrappers();
} }
void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
VL_RESTORER(m_scopep);
m_scopep = nodep; m_scopep = nodep;
iterateChildren(nodep); iterateChildren(nodep);
m_scopep = nullptr;
} }
void visit(AstVarScope* nodep) override { void visit(AstVarScope* nodep) override {
// Delete the varscope when we're finished // 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 // This generates a file used by graphviz, https://www.graphviz.org
// "hardcoded" parameters: // "hardcoded" parameters:
const std::unique_ptr<std::ofstream> os{V3File::new_ofstream(filename)}; 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); dumpDot(*os.get(), label);
os->close(); os->close();
} }
@ -244,7 +244,7 @@ void DfgGraph::dumpDotUpstreamCone(const string& fileName, const DfgVertex& vtx,
const string& name) const { const string& name) const {
// Open output file // Open output file
const std::unique_ptr<std::ofstream> os{V3File::new_ofstream(fileName)}; 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 // Header
*os << "digraph dfg {\n"; *os << "digraph dfg {\n";
@ -278,7 +278,7 @@ void DfgGraph::dumpDotAllVarConesPrefixed(const string& label) const {
const string coneName{prefix + sinkp->varp()->name()}; const string coneName{prefix + sinkp->varp()->name()};
const string fileName{v3Global.debugFilename(coneName) + ".dot"}; const string fileName{v3Global.debugFilename(coneName) + ".dot"};
const std::unique_ptr<std::ofstream> os{V3File::new_ofstream(fileName)}; 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 // Header
*os << "digraph dfg {\n"; *os << "digraph dfg {\n";

View File

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

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