merge master and resolve conflicts
This commit is contained in:
commit
7372c1b30b
|
|
@ -28,259 +28,143 @@ concurrency:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build-2404-gcc:
|
build-2604-gcc:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
name: Build | 26.04 | gcc
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: gcc
|
||||||
|
runs-on: ubuntu-26.04
|
||||||
|
sha: ${{ github.sha }}
|
||||||
|
|
||||||
|
build-2604-clang:
|
||||||
|
name: Build | 26.04 | clang
|
||||||
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
|
with:
|
||||||
|
cc: clang
|
||||||
|
dev-asan: true # Build (and run) with address sanitizer
|
||||||
|
runs-on: ubuntu-26.04
|
||||||
|
sha: ${{ github.sha }}
|
||||||
|
|
||||||
|
build-2404-gcc:
|
||||||
|
name: Build | 24.04 | gcc
|
||||||
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
|
with:
|
||||||
|
cc: gcc
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: linux
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: ubuntu-24.04, cc: gcc, asan: 0}
|
|
||||||
|
|
||||||
build-2404-clang:
|
build-2404-clang:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
name: Build | 24.04 | clang
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: clang
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: linux
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: ubuntu-24.04, cc: clang, asan: 1}
|
|
||||||
|
|
||||||
build-2204-gcc:
|
build-2204-gcc:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
name: Build | 22.04 | gcc
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: gcc
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: linux
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: ubuntu-22.04, cc: gcc, asan: 0}
|
|
||||||
|
|
||||||
build-2204-clang:
|
build-macos-15-clang:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
name: Build | macos-15 | clang
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: clang
|
||||||
|
runs-on: macos-15
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: linux
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: ubuntu-22.04, cc: clang, asan: 0}
|
|
||||||
|
|
||||||
build-osx-gcc:
|
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
|
||||||
with:
|
|
||||||
sha: ${{ github.sha }}
|
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: osx
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: macos-15, cc: gcc, asan: 0}
|
|
||||||
|
|
||||||
build-osx-clang:
|
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
|
||||||
with:
|
|
||||||
sha: ${{ github.sha }}
|
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: osx
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: macos-15, cc: clang, asan: 0}
|
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}
|
name: Build | windows-2025-vs2026 | msvc
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: windows-2025-vs2026
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: windows-2025-vs2026, cc: msvc}
|
|
||||||
env:
|
|
||||||
CI_OS_NAME: win
|
|
||||||
CCACHE_COMPRESS: 1
|
|
||||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
|
||||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
with:
|
with:
|
||||||
path: repo
|
path: repo
|
||||||
- name: Cache $CCACHE_DIR
|
- name: Cache win_flex_bison
|
||||||
uses: actions/cache@v5
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||||
with:
|
with:
|
||||||
path: ${{ env.CCACHE_DIR }}
|
path: ${{ github.workspace }}/win_flex_bison
|
||||||
key: msbuild-msvc-cmake
|
key: win_flex_bison
|
||||||
- name: compile
|
- name: compile
|
||||||
env:
|
|
||||||
WIN_FLEX_BISON: ${{ github.workspace }}/.ccache
|
|
||||||
run: ./ci/ci-win-compile.ps1
|
run: ./ci/ci-win-compile.ps1
|
||||||
- name: test build
|
- name: test build
|
||||||
run: ./ci/ci-win-test.ps1
|
run: ./ci/ci-win-test.ps1
|
||||||
- name: Zip up repository
|
|
||||||
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
|
test-2604-gcc:
|
||||||
- name: Upload zip archive
|
name: Test | 26.04 | gcc | ${{ matrix.suite }}
|
||||||
uses: actions/upload-artifact@v7
|
needs: build-2604-gcc
|
||||||
with:
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
path: ${{ github.workspace }}/repo/verilator.zip
|
with:
|
||||||
name: verilator-win.zip
|
archive: ${{ needs.build-2604-gcc.outputs.archive }}
|
||||||
|
cc: gcc
|
||||||
|
runs-on: ubuntu-26.04
|
||||||
|
suite: ${{ matrix.suite }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||||
|
|
||||||
|
test-2604-clang:
|
||||||
|
name: Test | 26.04 | clang | ${{ matrix.suite }}
|
||||||
|
needs: build-2604-clang
|
||||||
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
|
with:
|
||||||
|
archive: ${{ needs.build-2604-clang.outputs.archive }}
|
||||||
|
cc: clang
|
||||||
|
runs-on: ubuntu-26.04
|
||||||
|
suite: ${{ matrix.suite }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||||
|
|
||||||
test-2404-gcc:
|
test-2404-gcc:
|
||||||
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
name: Test | 24.04 | gcc | ${{ matrix.suite }}
|
||||||
needs: build-2404-gcc
|
needs: build-2404-gcc
|
||||||
uses: ./.github/workflows/reusable-test.yml
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
with:
|
with:
|
||||||
archive: ${{ needs.build-2404-gcc.outputs.archive }}
|
archive: ${{ needs.build-2404-gcc.outputs.archive }}
|
||||||
os: ${{ matrix.os }}
|
cc: gcc
|
||||||
cc: ${{ matrix.cc }}
|
runs-on: ubuntu-24.04
|
||||||
reloc: ${{ matrix.reloc }}
|
|
||||||
suite: ${{ matrix.suite }}
|
suite: ${{ matrix.suite }}
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||||
# 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}
|
|
||||||
|
|
||||||
test-2404-clang:
|
test-2404-clang:
|
||||||
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
name: Test | 24.04 | clang | ${{ matrix.suite }}
|
||||||
needs: build-2404-clang
|
needs: build-2404-clang
|
||||||
uses: ./.github/workflows/reusable-test.yml
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
with:
|
with:
|
||||||
archive: ${{ needs.build-2404-clang.outputs.archive }}
|
archive: ${{ needs.build-2404-clang.outputs.archive }}
|
||||||
os: ${{ matrix.os }}
|
cc: clang
|
||||||
cc: ${{ matrix.cc }}
|
reloc: true # Test with relocated installation
|
||||||
reloc: ${{ matrix.reloc }}
|
runs-on: ubuntu-24.04
|
||||||
suite: ${{ matrix.suite }}
|
suite: ${{ matrix.suite }}
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||||
# 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}
|
|
||||||
|
|
||||||
test-2204-gcc:
|
test-2204-gcc:
|
||||||
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
name: Test | 22.04 | gcc | ${{ matrix.suite }}
|
||||||
needs: build-2204-gcc
|
needs: build-2204-gcc
|
||||||
uses: ./.github/workflows/reusable-test.yml
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
with:
|
with:
|
||||||
archive: ${{ needs.build-2204-gcc.outputs.archive }}
|
archive: ${{ needs.build-2204-gcc.outputs.archive }}
|
||||||
os: ${{ matrix.os }}
|
cc: gcc
|
||||||
cc: ${{ matrix.cc }}
|
runs-on: ubuntu-22.04
|
||||||
reloc: ${{ matrix.reloc }}
|
|
||||||
suite: ${{ matrix.suite }}
|
suite: ${{ matrix.suite }}
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||||
# 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 }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
|
||||||
needs: build-2204-clang
|
|
||||||
uses: ./.github/workflows/reusable-test.yml
|
|
||||||
with:
|
|
||||||
archive: ${{ needs.build-2204-clang.outputs.archive }}
|
|
||||||
os: ${{ matrix.os }}
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
reloc: ${{ matrix.reloc }}
|
|
||||||
suite: ${{ matrix.suite }}
|
|
||||||
dev-gcov: 0
|
|
||||||
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:
|
||||||
name: Lint Python
|
name: Lint Python
|
||||||
uses: ./.github/workflows/reusable-lint-py.yml
|
uses: ./.github/workflows/reusable-lint-py.yml
|
||||||
|
|
||||||
passed:
|
|
||||||
name: Test suite passed
|
|
||||||
if: always()
|
|
||||||
needs:
|
|
||||||
- build-2404-gcc
|
|
||||||
- build-2404-clang
|
|
||||||
- build-2204-gcc
|
|
||||||
- build-2204-clang
|
|
||||||
- build-osx-gcc
|
|
||||||
- build-osx-clang
|
|
||||||
- build-windows
|
|
||||||
- test-2404-gcc
|
|
||||||
- test-2404-clang
|
|
||||||
- test-2204-gcc
|
|
||||||
- test-2204-clang
|
|
||||||
- lint-py
|
|
||||||
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Decide whether the needed jobs succeeded or failed
|
|
||||||
uses: re-actors/alls-green@release/v1
|
|
||||||
with:
|
|
||||||
jobs: ${{ toJSON(needs) }}
|
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,5 @@ jobs:
|
||||||
name: "'docs/CONTRIBUTORS' was signed"
|
name: "'docs/CONTRIBUTORS' was signed"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
- run: test_regress/t/t_dist_contributors.py
|
- run: test_regress/t/t_dist_contributors.py
|
||||||
|
|
|
||||||
|
|
@ -38,15 +38,13 @@ jobs:
|
||||||
(github.event_name == 'workflow_dispatch')
|
(github.event_name == 'workflow_dispatch')
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: gcc
|
||||||
|
dev-gcov: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
# For pull requests, build the head of the pull request branch, not the
|
# For pull requests, build the head of the pull request branch, not the
|
||||||
# merge commit, otherwise patch coverage would include the changes
|
# merge commit, otherwise patch coverage would include the changes
|
||||||
# between the root of the pull request and the target branch
|
# between the root of the pull request and the target branch
|
||||||
sha: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
sha: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||||
os: ubuntu-24.04
|
|
||||||
os-name: linux
|
|
||||||
cc: gcc
|
|
||||||
dev-asan: 0
|
|
||||||
dev-gcov: 1
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
name: Test | ${{ matrix.test }}${{ matrix.num }}
|
name: Test | ${{ matrix.test }}${{ matrix.num }}
|
||||||
|
|
@ -54,11 +52,10 @@ jobs:
|
||||||
uses: ./.github/workflows/reusable-test.yml
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
with:
|
with:
|
||||||
archive: ${{ needs.build.outputs.archive }}
|
archive: ${{ needs.build.outputs.archive }}
|
||||||
os: ubuntu-24.04
|
|
||||||
cc: gcc
|
cc: gcc
|
||||||
reloc: 0
|
dev-gcov: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
suite: ${{ matrix.test }}${{ matrix.num }}
|
suite: ${{ matrix.test }}${{ matrix.num }}
|
||||||
dev-gcov: 1
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
|
@ -74,10 +71,10 @@ jobs:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
|
|
||||||
- name: Download code coverage data
|
- name: Download code coverage data
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
pattern: code-coverage-*
|
pattern: code-coverage-*
|
||||||
path: obj_coverage
|
path: obj_coverage
|
||||||
|
|
@ -90,7 +87,7 @@ jobs:
|
||||||
find obj_coverage -type f | paste -sd, | sed "s/^/files=/" >> "$GITHUB_OUTPUT"
|
find obj_coverage -type f | paste -sd, | sed "s/^/files=/" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Upload to codecov.io
|
- name: Upload to codecov.io
|
||||||
uses: codecov/codecov-action@v6
|
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7
|
||||||
with:
|
with:
|
||||||
disable_file_fixes: true
|
disable_file_fixes: true
|
||||||
disable_search: true
|
disable_search: true
|
||||||
|
|
@ -114,18 +111,18 @@ jobs:
|
||||||
sudo apt install lcov
|
sudo apt install lcov
|
||||||
|
|
||||||
- name: Download repository archive
|
- name: Download repository archive
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.build.outputs.archive }}
|
name: ${{ needs.build.outputs.archive }}
|
||||||
path: ${{ github.workspace }}
|
path: ${{ github.workspace }}
|
||||||
|
|
||||||
- name: Unpack repository archive
|
- name: Unpack repository archive
|
||||||
run: |
|
run: |
|
||||||
tar -x -z -f ${{ needs.build.outputs.archive }}
|
tar --zstd -x -f ${{ needs.build.outputs.archive }}
|
||||||
ls -lsha
|
ls -lsha
|
||||||
|
|
||||||
- name: Download code coverage data
|
- name: Download code coverage data
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
pattern: code-coverage-*
|
pattern: code-coverage-*
|
||||||
path: repo/obj_coverage
|
path: repo/obj_coverage
|
||||||
|
|
@ -172,14 +169,14 @@ jobs:
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload report
|
- name: Upload report
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: repo/obj_coverage
|
path: repo/obj_coverage
|
||||||
name: coverage-report
|
name: coverage-report
|
||||||
|
|
||||||
- name: Upload notification
|
- name: Upload notification
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: repo/notification
|
path: repo/notification
|
||||||
name: pr-notification
|
name: pr-notification
|
||||||
|
|
@ -195,9 +192,9 @@ jobs:
|
||||||
# Creating issues requires elevated privilege
|
# Creating issues requires elevated privilege
|
||||||
- name: Generate access token
|
- name: Generate access token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@v3.2.0
|
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||||
with:
|
with:
|
||||||
app-id: ${{ vars.VERILATOR_CI_ID }}
|
client-id: ${{ vars.VERILATOR_CI_ID }}
|
||||||
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
||||||
owner: verilator
|
owner: verilator
|
||||||
repositories: verilator
|
repositories: verilator
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
|
|
||||||
- name: Extract context variables
|
- name: Extract context variables
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -54,7 +54,7 @@ jobs:
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: docker_meta
|
id: docker_meta
|
||||||
uses: docker/metadata-action@v6
|
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
||||||
|
|
@ -64,21 +64,21 @@ jobs:
|
||||||
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v4
|
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v4
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||||
with:
|
with:
|
||||||
buildkitd-flags: --debug
|
buildkitd-flags: --debug
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||||
|
|
||||||
- name: Build and Push to Docker
|
- name: Build and Push to Docker
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
||||||
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
|
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
|
||||||
with:
|
with:
|
||||||
context: ${{ env.build_context }}
|
context: ${{ env.build_context }}
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,12 @@ jobs:
|
||||||
format:
|
format:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
name: Ubuntu 24.04 | format
|
name: Ubuntu 24.04 | format
|
||||||
env:
|
|
||||||
CI_OS_NAME: linux
|
|
||||||
CI_RUNS_ON: ubuntu-24.04
|
|
||||||
CI_COMMIT: ${{ github.sha }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Install packages for build
|
- name: Install packages for build
|
||||||
env:
|
|
||||||
CI_BUILD_STAGE_NAME: build
|
|
||||||
run: |
|
run: |
|
||||||
sudo apt install clang-format-18 || \
|
sudo apt install clang-format-18 || \
|
||||||
sudo apt install clang-format-18
|
sudo apt install clang-format-18
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ name: Pages
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches: [master]
|
||||||
paths: ["ci/**", ".github/workflows"]
|
paths: ["ci/**", ".github/workflows/**"]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ["Code coverage", "RTLMeter"]
|
workflows: ["Code coverage", "RTLMeter"]
|
||||||
|
|
@ -22,8 +22,11 @@ permissions:
|
||||||
# Allow only one concurrent deployment, skipping runs queued between the run
|
# Allow only one concurrent deployment, skipping runs queued between the run
|
||||||
# in-progress and latest queued. However, do NOT cancel in-progress runs as we
|
# in-progress and latest queued. However, do NOT cancel in-progress runs as we
|
||||||
# want to allow these deployments to complete.
|
# want to allow these deployments to complete.
|
||||||
|
# A skipped-upstream run does no work (see the build job's if:), so put it in its
|
||||||
|
# own throwaway group: otherwise, as the newest queued run, it would cancel a
|
||||||
|
# pending real run and then deploy nothing.
|
||||||
concurrency:
|
concurrency:
|
||||||
group: "pages"
|
group: ${{ (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'skipped') && format('pages-skip-{0}', github.run_id) || 'pages' }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
|
|
@ -34,11 +37,15 @@ jobs:
|
||||||
build:
|
build:
|
||||||
name: Build content
|
name: Build content
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
# A skipped upstream run (e.g. Code coverage / RTLMeter on a branch push)
|
||||||
|
# still fires workflow_run; don't rebuild and redeploy for it. deploy and
|
||||||
|
# notify need this job, so they cascade-skip too.
|
||||||
|
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion != 'skipped' }}
|
||||||
outputs:
|
outputs:
|
||||||
pr-run-ids: ${{ steps.build.outputs.pr-run-ids }}
|
pr-run-ids: ${{ steps.build.outputs.pr-run-ids }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
- name: Build pages
|
- name: Build pages
|
||||||
id: build
|
id: build
|
||||||
env:
|
env:
|
||||||
|
|
@ -48,7 +55,7 @@ jobs:
|
||||||
ls -lsha
|
ls -lsha
|
||||||
tree -L 3 pages
|
tree -L 3 pages
|
||||||
- name: Upload pages artifact
|
- name: Upload pages artifact
|
||||||
uses: actions/upload-pages-artifact@v5
|
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
|
||||||
with:
|
with:
|
||||||
path: pages
|
path: pages
|
||||||
|
|
||||||
|
|
@ -58,10 +65,17 @@ jobs:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
environment:
|
environment:
|
||||||
name: github-pages
|
name: github-pages
|
||||||
url: ${{ steps.deployment.outputs.page_url }}
|
url: ${{ steps.deploy-2.outputs.page_url || steps.deploy-1.outputs.page_url }}
|
||||||
steps:
|
steps:
|
||||||
|
# GitHub's Pages backend intermittently fails a deployment mid-sync, retry
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
uses: actions/deploy-pages@v5
|
id: deploy-1
|
||||||
|
continue-on-error: true
|
||||||
|
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5
|
||||||
|
- name: Deploy to GitHub Pages (retry)
|
||||||
|
id: deploy-2
|
||||||
|
if: steps.deploy-1.outcome == 'failure'
|
||||||
|
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5
|
||||||
|
|
||||||
notify:
|
notify:
|
||||||
name: Notify
|
name: Notify
|
||||||
|
|
@ -70,13 +84,13 @@ jobs:
|
||||||
if: ${{ github.repository == 'verilator/verilator' }}
|
if: ${{ github.repository == 'verilator/verilator' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
# Use the Verilator CI app to post the comment
|
# Use the Verilator CI app to post the comment
|
||||||
- name: Generate access token
|
- name: Generate access token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@v3.2.0
|
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||||
with:
|
with:
|
||||||
app-id: ${{ vars.VERILATOR_CI_ID }}
|
client-id: ${{ vars.VERILATOR_CI_ID }}
|
||||||
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
||||||
permission-actions: write
|
permission-actions: write
|
||||||
permission-pull-requests: write
|
permission-pull-requests: write
|
||||||
|
|
|
||||||
|
|
@ -7,37 +7,47 @@ name: reusable-build
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
|
cc:
|
||||||
|
description: "Compiler to use: 'gcc' or 'clang'"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
ccwarn:
|
||||||
|
description: "Build Verilator with warnings treated as errors (--enable-ccwarn)"
|
||||||
|
required: false
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
dev-asan:
|
||||||
|
description: "Build Verilator with the address sanitizer (--enable-dev-asan)"
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
dev-gcov:
|
||||||
|
description: "Build Verilator with gcov instrumentation (--enable-dev-gcov)"
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
install:
|
||||||
|
description: "Archive the Verilator installation, not the repo tree"
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
runs-on:
|
||||||
|
description: "Runner to build on, e.g. ubuntu-24.04"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
sha:
|
sha:
|
||||||
description: "Commit SHA to build"
|
description: "Commit SHA to build"
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
os: # e.g. ubuntu-24.04
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
cc: # 'clang' or 'gcc'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
os-name: # 'linux' or 'osx'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
dev-asan:
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
dev-gcov:
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
outputs:
|
outputs:
|
||||||
archive:
|
archive:
|
||||||
description: "Name of the built repository archive artifact"
|
description: "Name of the built archive artifact"
|
||||||
value: ${{ jobs.build.outputs.archive }}
|
value: ${{ jobs.build.outputs.archive }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CI_OS_NAME: ${{ inputs.os-name }}
|
|
||||||
CCACHE_COMPRESS: 1
|
CCACHE_COMPRESS: 1
|
||||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||||
INSTALL_DIR: ${{ github.workspace }}/install
|
|
||||||
RELOC_DIR: ${{ github.workspace }}/relloc
|
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
|
@ -48,27 +58,24 @@ jobs:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build
|
name: Build
|
||||||
runs-on: ${{ inputs.os }}
|
runs-on: ${{ inputs.runs-on }}
|
||||||
outputs:
|
outputs:
|
||||||
archive: ${{ steps.create-archive.outputs.archive }}
|
archive: ${{ steps.create-archive.outputs.archive }}
|
||||||
env:
|
env:
|
||||||
CI_BUILD_STAGE_NAME: build
|
CACHE_BASE_KEY: build-${{ inputs.runs-on }}-${{ inputs.cc }}
|
||||||
CI_DEV_ASAN: ${{ inputs.dev-asan }}
|
CCACHE_MAXSIZE: 1000M
|
||||||
CI_DEV_GCOV: ${{ inputs.dev-gcov }}
|
|
||||||
CI_RUNS_ON: ${{ inputs.os }}
|
|
||||||
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)
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
with:
|
with:
|
||||||
path: repo
|
path: repo
|
||||||
ref: ${{ inputs.sha }}
|
ref: ${{ inputs.sha }}
|
||||||
fetch-depth: ${{ inputs.dev-gcov && '0' || '1' }} # Coverage flow needs full history
|
# Coverage needs full history; install needs it for the 'git describe'
|
||||||
|
# behind 'verilator --version'
|
||||||
|
fetch-depth: ${{ (inputs.install || inputs.dev-gcov) && '0' || '1' }}
|
||||||
|
|
||||||
- name: Cache $CCACHE_DIR
|
- name: Cache $CCACHE_DIR
|
||||||
uses: actions/cache@v5
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||||
env:
|
env:
|
||||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||||
with:
|
with:
|
||||||
|
|
@ -78,22 +85,40 @@ jobs:
|
||||||
${{ env.CACHE_KEY }}-
|
${{ env.CACHE_KEY }}-
|
||||||
|
|
||||||
- name: Install packages for build
|
- name: Install packages for build
|
||||||
run: ./ci/ci-install.bash
|
run: ./ci/ci-install.bash build
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./ci/ci-script.bash
|
run: |
|
||||||
|
./ci/ci-build.bash \
|
||||||
|
--prefix ${{ github.workspace }}/install \
|
||||||
|
--compiler ${{ inputs.cc }} \
|
||||||
|
${{ inputs.ccwarn && '--ccwarn' || '' }} \
|
||||||
|
${{ inputs.dev-asan && '--asan' || '' }} \
|
||||||
|
${{ inputs.dev-gcov && '--gcov' || '' }}
|
||||||
|
|
||||||
- name: Create repository archive
|
- name: Install
|
||||||
|
if: ${{ inputs.install }}
|
||||||
|
run: make install
|
||||||
|
|
||||||
|
- name: Create archive
|
||||||
id: create-archive
|
id: create-archive
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: |
|
run: |
|
||||||
# Name of the archive must be unique based on the build parameters
|
# Archive name, unique per build; flavour tags mark non-default builds
|
||||||
ARCHIVE=verilator-${{ inputs.sha }}-${{ inputs.os }}-${{ inputs.cc }}-${{ inputs.dev-asan }}-${{ inputs.dev-gcov }}.tar.gz
|
ARCHIVE="verilator-${{ inputs.sha }}-${{ inputs.runs-on }}-${{ inputs.cc }}"
|
||||||
tar --posix -c -z -f $ARCHIVE repo
|
ARCHIVE="$ARCHIVE${{ inputs.ccwarn && '-ccwarn' || '' }}"
|
||||||
|
ARCHIVE="$ARCHIVE${{ inputs.dev-asan && '-asan' || '' }}"
|
||||||
|
ARCHIVE="$ARCHIVE${{ inputs.dev-gcov && '-gcov' || '' }}"
|
||||||
|
ARCHIVE="$ARCHIVE.tar.zst"
|
||||||
|
# zstd compresses faster than gzip and decompresses far faster in the many downstream jobs
|
||||||
|
ZSTD_NBTHREADS=0 tar --posix --zstd -c -f "$ARCHIVE" ${{ inputs.install && 'install' || 'repo' }}
|
||||||
echo "archive=$ARCHIVE" >> "$GITHUB_OUTPUT"
|
echo "archive=$ARCHIVE" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Upload repository archive
|
- name: Upload archive
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: ${{ github.workspace }}/${{ steps.create-archive.outputs.archive }}
|
path: ${{ github.workspace }}/${{ steps.create-archive.outputs.archive }}
|
||||||
name: ${{ steps.create-archive.outputs.archive }}
|
name: ${{ steps.create-archive.outputs.archive }}
|
||||||
|
overwrite: true
|
||||||
|
# Archive is already zstd-compressed; skip upload-artifact's zip pass
|
||||||
|
compression-level: 0
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,6 @@ on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CI_OS_NAME: linux
|
|
||||||
CI_BUILD_STAGE_NAME: build
|
|
||||||
CI_RUNS_ON: ubuntu-22.04
|
|
||||||
CCACHE_COMPRESS: 1
|
CCACHE_COMPRESS: 1
|
||||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||||
|
|
@ -27,12 +24,12 @@ jobs:
|
||||||
name: Sub-lint | Python
|
name: Sub-lint | Python
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
with:
|
with:
|
||||||
path: repo
|
path: repo
|
||||||
|
|
||||||
- name: Install packages for build
|
- name: Install packages for build
|
||||||
run: ./ci/ci-install.bash
|
run: ./ci/ci-install.bash build
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
---
|
|
||||||
# DESCRIPTION: Github actions config
|
|
||||||
# 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
|
|
||||||
sha:
|
|
||||||
description: "Git SHA to build"
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
outputs:
|
|
||||||
archive:
|
|
||||||
description: "Name of the built installation archive artifact"
|
|
||||||
value: ${{ jobs.build.outputs.archive }}
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
env:
|
|
||||||
CCACHE_DIR: ${{ github.workspace }}/ccache
|
|
||||||
CCACHE_MAXSIZE: 512M
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build
|
|
||||||
runs-on: ${{ inputs.runs-on }}
|
|
||||||
outputs:
|
|
||||||
archive: ${{ steps.create-archive.outputs.archive }}
|
|
||||||
steps:
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
echo "path-exclude /usr/share/doc/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
|
||||||
echo "path-exclude /usr/share/man/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
|
||||||
echo "path-exclude /usr/share/info/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
|
||||||
sudo apt update || \
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install ccache mold help2man libfl-dev libjemalloc-dev libsystemc-dev || \
|
|
||||||
sudo apt install ccache mold help2man libfl-dev libjemalloc-dev libsystemc-dev
|
|
||||||
|
|
||||||
- name: Use saved ccache
|
|
||||||
uses: actions/cache@v5
|
|
||||||
with:
|
|
||||||
path: ccache
|
|
||||||
key: rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
|
|
||||||
restore-keys: |
|
|
||||||
rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.sha }}-${{ github.run_id }}
|
|
||||||
rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.sha }}
|
|
||||||
rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}
|
|
||||||
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
path: repo
|
|
||||||
ref: ${{ inputs.sha }}
|
|
||||||
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
|
|
||||||
id: create-archive
|
|
||||||
run: |
|
|
||||||
SHA=$(git -C repo rev-parse HEAD)
|
|
||||||
ARCHIVE=verilator-$SHA-rtlmeter-${{ inputs.runs-on }}-${{ inputs.cc }}.tar.gz
|
|
||||||
tar --posix -c -z -f $ARCHIVE install
|
|
||||||
echo "archive=$ARCHIVE" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Upload Verilator installation archive
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
path: ${{ steps.create-archive.outputs.archive }}
|
|
||||||
name: ${{ steps.create-archive.outputs.archive }}
|
|
||||||
overwrite: true
|
|
||||||
|
|
@ -20,11 +20,11 @@ on:
|
||||||
type: string
|
type: string
|
||||||
required: true
|
required: true
|
||||||
verilator-archive-new:
|
verilator-archive-new:
|
||||||
description: "Name of the installation archive artifact from reusable-rtlmeter-build, new version"
|
description: "Name of the installation archive artifact from reusable-build, new version"
|
||||||
type: string
|
type: string
|
||||||
required: true
|
required: true
|
||||||
verilator-archive-old:
|
verilator-archive-old:
|
||||||
description: "Name of the installation archive artifact from reusable-rtlmeter-build, old version"
|
description: "Name of the installation archive artifact from reusable-build, old version"
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
|
|
@ -73,7 +73,7 @@ jobs:
|
||||||
sudo apt install ccache mold libfl-dev libjemalloc-dev libsystemc-dev
|
sudo apt install ccache mold libfl-dev libjemalloc-dev libsystemc-dev
|
||||||
|
|
||||||
- name: Checkout RTLMeter
|
- name: Checkout RTLMeter
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
with:
|
with:
|
||||||
repository: "verilator/rtlmeter"
|
repository: "verilator/rtlmeter"
|
||||||
path: rtlmeter
|
path: rtlmeter
|
||||||
|
|
@ -84,7 +84,7 @@ jobs:
|
||||||
|
|
||||||
- name: Use saved ccache
|
- name: Use saved ccache
|
||||||
if: ${{ env.CCACHE_DISABLE == 0 }}
|
if: ${{ env.CCACHE_DISABLE == 0 }}
|
||||||
uses: actions/cache@v5
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||||
with:
|
with:
|
||||||
path: ${{ env.CCACHE_DIR }}
|
path: ${{ env.CCACHE_DIR }}
|
||||||
key: rtlmeter-run-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.cases }}-${{ inputs.compileArgs }}-${{ github.run_id }}-${{ github.run_attempt }}
|
key: rtlmeter-run-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.cases }}-${{ inputs.compileArgs }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||||
|
|
@ -95,13 +95,13 @@ jobs:
|
||||||
########################################################################
|
########################################################################
|
||||||
|
|
||||||
- name: Download Verilator installation archive - new
|
- name: Download Verilator installation archive - new
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
name: ${{ inputs.verilator-archive-new }}
|
name: ${{ inputs.verilator-archive-new }}
|
||||||
|
|
||||||
- name: Unpack Verilator installation archive - new
|
- name: Unpack Verilator installation archive - new
|
||||||
run: |
|
run: |
|
||||||
tar -x -z -f ${{ inputs.verilator-archive-new }}
|
tar --zstd -x -f ${{ inputs.verilator-archive-new }}
|
||||||
mv install verilator-new
|
mv install verilator-new
|
||||||
|
|
||||||
- name: Compile cases - new
|
- name: Compile cases - new
|
||||||
|
|
@ -135,7 +135,7 @@ jobs:
|
||||||
./rtlmeter report --steps '*' --metrics '*' ../results-${{ steps.results.outputs.hash }}.json
|
./rtlmeter report --steps '*' --metrics '*' ../results-${{ steps.results.outputs.hash }}.json
|
||||||
|
|
||||||
- name: Upload results - new
|
- name: Upload results - new
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: results-${{ steps.results.outputs.hash }}.json
|
path: results-${{ steps.results.outputs.hash }}.json
|
||||||
name: rtlmeter-${{ inputs.tag }}-results-${{ steps.results.outputs.hash }}
|
name: rtlmeter-${{ inputs.tag }}-results-${{ steps.results.outputs.hash }}
|
||||||
|
|
@ -157,14 +157,14 @@ jobs:
|
||||||
|
|
||||||
- name: Download Verilator installation archive - old
|
- name: Download Verilator installation archive - old
|
||||||
if: ${{ inputs.verilator-archive-old != '' }}
|
if: ${{ inputs.verilator-archive-old != '' }}
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
name: ${{ inputs.verilator-archive-old }}
|
name: ${{ inputs.verilator-archive-old }}
|
||||||
|
|
||||||
- name: Unpack Verilator installation archive - old
|
- name: Unpack Verilator installation archive - old
|
||||||
if: ${{ inputs.verilator-archive-old != '' }}
|
if: ${{ inputs.verilator-archive-old != '' }}
|
||||||
run: |
|
run: |
|
||||||
tar -x -z -f ${{ inputs.verilator-archive-old }}
|
tar --zstd -x -f ${{ inputs.verilator-archive-old }}
|
||||||
mv install verilator-old
|
mv install verilator-old
|
||||||
|
|
||||||
- name: Compile cases - old
|
- name: Compile cases - old
|
||||||
|
|
@ -198,7 +198,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload results - old
|
- name: Upload results - old
|
||||||
if: ${{ inputs.verilator-archive-old != '' }}
|
if: ${{ inputs.verilator-archive-old != '' }}
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: reference-${{ steps.results.outputs.hash }}.json
|
path: reference-${{ steps.results.outputs.hash }}.json
|
||||||
name: rtlmeter-${{ inputs.tag }}-reference-${{ steps.results.outputs.hash }}
|
name: rtlmeter-${{ inputs.tag }}-reference-${{ steps.results.outputs.hash }}
|
||||||
|
|
|
||||||
|
|
@ -11,29 +11,33 @@ on:
|
||||||
description: "Name of the repository archive artifact from reusable-build"
|
description: "Name of the repository archive artifact from reusable-build"
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
os: # e.g. ubuntu-24.04
|
cc:
|
||||||
required: true
|
description: "Compiler to use: 'gcc' or 'clang'"
|
||||||
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
|
required: true
|
||||||
type: string
|
type: string
|
||||||
dev-gcov:
|
dev-gcov:
|
||||||
|
description: "Collect gcov coverage data from the test run"
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
reloc:
|
||||||
|
description: "Relocate the installation before testing"
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
runs-on:
|
||||||
|
description: "Runner to test on, e.g. ubuntu-24.04"
|
||||||
required: true
|
required: true
|
||||||
type: number
|
type: string
|
||||||
|
suite:
|
||||||
|
description: "Test suite to run, e.g. dist-vlt-0"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CI_OS_NAME: linux
|
|
||||||
CCACHE_COMPRESS: 1
|
CCACHE_COMPRESS: 1
|
||||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||||
INSTALL_DIR: ${{ github.workspace }}/install
|
|
||||||
RELOC_DIR: ${{ github.workspace }}/relloc
|
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
|
@ -43,19 +47,16 @@ defaults:
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: ${{ inputs.os }}
|
runs-on: ${{ inputs.runs-on }}
|
||||||
name: Test
|
name: Test
|
||||||
env:
|
env:
|
||||||
CI_BUILD_STAGE_NAME: test
|
|
||||||
CI_RUNS_ON: ${{ inputs.os }}
|
|
||||||
CI_RELOC: ${{inputs.reloc }}
|
|
||||||
CXX: ${{ inputs.cc == 'clang' && 'clang++' || 'g++' }}
|
CXX: ${{ inputs.cc == 'clang' && 'clang++' || 'g++' }}
|
||||||
CACHE_BASE_KEY: test-${{ inputs.os }}-${{ inputs.cc }}-${{inputs.reloc }}-${{ inputs.suite }}
|
CACHE_BASE_KEY: test-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.reloc }}-${{ inputs.suite }}
|
||||||
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
|
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Download repository archive
|
- name: Download repository archive
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
name: ${{ inputs.archive }}
|
name: ${{ inputs.archive }}
|
||||||
path: ${{ github.workspace }}
|
path: ${{ github.workspace }}
|
||||||
|
|
@ -63,11 +64,11 @@ jobs:
|
||||||
- name: Unpack repository archive
|
- name: Unpack repository archive
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: |
|
run: |
|
||||||
tar -x -z -f ${{ inputs.archive }}
|
tar --zstd -x -f ${{ inputs.archive }}
|
||||||
ls -lsha
|
ls -lsha
|
||||||
|
|
||||||
- name: Cache $CCACHE_DIR
|
- name: Cache $CCACHE_DIR
|
||||||
uses: actions/cache@v5
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||||
env:
|
env:
|
||||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
||||||
with:
|
with:
|
||||||
|
|
@ -78,17 +79,17 @@ jobs:
|
||||||
|
|
||||||
- name: Install test dependencies
|
- name: Install test dependencies
|
||||||
run: |
|
run: |
|
||||||
./ci/ci-install.bash
|
./ci/ci-install.bash test
|
||||||
make venv
|
make venv
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
id: run-test
|
id: run-test
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
env:
|
|
||||||
TESTS: ${{ inputs.suite }}
|
|
||||||
run: |
|
run: |
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
./ci/ci-script.bash
|
./ci/ci-test.bash \
|
||||||
|
--suite ${{ inputs.suite }} \
|
||||||
|
${{ inputs.reloc && format('--reloc {0}/reloc', github.workspace) || '' }}
|
||||||
|
|
||||||
- name: Combine code coverage data
|
- name: Combine code coverage data
|
||||||
if: ${{ inputs.dev-gcov }}
|
if: ${{ inputs.dev-gcov }}
|
||||||
|
|
@ -99,7 +100,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload code coverage data
|
- name: Upload code coverage data
|
||||||
if: ${{ inputs.dev-gcov }}
|
if: ${{ inputs.dev-gcov }}
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: ${{ github.workspace }}/repo/obj_coverage/verilator-${{ inputs.suite }}.info
|
path: ${{ github.workspace }}/repo/obj_coverage/verilator-${{ inputs.suite }}.info
|
||||||
name: code-coverage-${{ inputs.suite }}
|
name: code-coverage-${{ inputs.suite }}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ jobs:
|
||||||
cases: ${{ steps.cases.outputs.cases }}
|
cases: ${{ steps.cases.outputs.cases }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
|
|
||||||
- name: Startup
|
- name: Startup
|
||||||
id: start
|
id: start
|
||||||
|
|
@ -65,39 +65,47 @@ jobs:
|
||||||
build-gcc-new:
|
build-gcc-new:
|
||||||
name: Build New Verilator - GCC
|
name: Build New Verilator - GCC
|
||||||
needs: start
|
needs: start
|
||||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
cc: gcc
|
cc: gcc
|
||||||
|
ccwarn: false
|
||||||
|
install: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
|
|
||||||
build-clang-new:
|
build-clang-new:
|
||||||
name: Build New Verilator - Clang
|
name: Build New Verilator - Clang
|
||||||
needs: start
|
needs: start
|
||||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
cc: clang
|
cc: clang
|
||||||
|
ccwarn: false
|
||||||
|
install: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
|
|
||||||
build-gcc-old:
|
build-gcc-old:
|
||||||
name: Build Old Verilator - GCC
|
name: Build Old Verilator - GCC
|
||||||
needs: start
|
needs: start
|
||||||
if: ${{ needs.start.outputs.old-sha != '' }}
|
if: ${{ needs.start.outputs.old-sha != '' }}
|
||||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
cc: gcc
|
cc: gcc
|
||||||
|
ccwarn: false
|
||||||
|
install: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ needs.start.outputs.old-sha }}
|
sha: ${{ needs.start.outputs.old-sha }}
|
||||||
|
|
||||||
build-clang-old:
|
build-clang-old:
|
||||||
name: Build Old Verilator - Clang
|
name: Build Old Verilator - Clang
|
||||||
needs: start
|
needs: start
|
||||||
if: ${{ needs.start.outputs.old-sha != '' }}
|
if: ${{ needs.start.outputs.old-sha != '' }}
|
||||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
cc: clang
|
cc: clang
|
||||||
|
ccwarn: false
|
||||||
|
install: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ needs.start.outputs.old-sha }}
|
sha: ${{ needs.start.outputs.old-sha }}
|
||||||
|
|
||||||
run-gcc:
|
run-gcc:
|
||||||
|
|
@ -208,7 +216,7 @@ jobs:
|
||||||
run: echo "tags=$(jq -r 'keys | map(sub("^run-"; "")) | join(" ")' <<< '${{ toJSON(needs) }}')" >> "$GITHUB_OUTPUT"
|
run: echo "tags=$(jq -r 'keys | map(sub("^run-"; "")) | join(" ")' <<< '${{ toJSON(needs) }}')" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Checkout RTLMeter
|
- name: Checkout RTLMeter
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
with:
|
with:
|
||||||
repository: "verilator/rtlmeter"
|
repository: "verilator/rtlmeter"
|
||||||
path: rtlmeter
|
path: rtlmeter
|
||||||
|
|
@ -232,7 +240,7 @@ jobs:
|
||||||
./rtlmeter collate ../all-results-$tag/*.json > ../all-results-$tag.json
|
./rtlmeter collate ../all-results-$tag/*.json > ../all-results-$tag.json
|
||||||
done
|
done
|
||||||
- name: Upload combined results
|
- name: Upload combined results
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: all-results-*.json
|
path: all-results-*.json
|
||||||
name: all-results
|
name: all-results
|
||||||
|
|
@ -259,7 +267,7 @@ jobs:
|
||||||
done
|
done
|
||||||
- name: Upload reference results
|
- name: Upload reference results
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: all-reference-*.json
|
path: all-reference-*.json
|
||||||
name: all-reference
|
name: all-reference
|
||||||
|
|
@ -278,27 +286,27 @@ jobs:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Download combined results
|
- name: Download combined results
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
name: all-results
|
name: all-results
|
||||||
path: results
|
path: results
|
||||||
- name: Upload published results
|
- name: Upload published results
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: results/*.json
|
path: results/*.json
|
||||||
name: published-results
|
name: published-results
|
||||||
# Pushing to verilator/verilator-rtlmeter-results requires elevated permissions
|
# Pushing to verilator/verilator-rtlmeter-results requires elevated permissions
|
||||||
- name: Generate access token
|
- name: Generate access token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@v3.2.0
|
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||||
with:
|
with:
|
||||||
app-id: ${{ vars.VERILATOR_CI_ID }}
|
client-id: ${{ vars.VERILATOR_CI_ID }}
|
||||||
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
||||||
owner: verilator
|
owner: verilator
|
||||||
repositories: verilator-rtlmeter-results
|
repositories: verilator-rtlmeter-results
|
||||||
permission-contents: write
|
permission-contents: write
|
||||||
- name: Checkout verilator-rtlmeter-results
|
- name: Checkout verilator-rtlmeter-results
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
with:
|
with:
|
||||||
repository: "verilator/verilator-rtlmeter-results"
|
repository: "verilator/verilator-rtlmeter-results"
|
||||||
token: ${{ steps.generate-token.outputs.token }}
|
token: ${{ steps.generate-token.outputs.token }}
|
||||||
|
|
@ -331,7 +339,7 @@ jobs:
|
||||||
actions: read
|
actions: read
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout RTLMeter
|
- name: Checkout RTLMeter
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
with:
|
with:
|
||||||
repository: "verilator/rtlmeter"
|
repository: "verilator/rtlmeter"
|
||||||
path: rtlmeter
|
path: rtlmeter
|
||||||
|
|
@ -341,7 +349,7 @@ jobs:
|
||||||
run: make venv
|
run: make venv
|
||||||
|
|
||||||
- name: Checkout Verilator
|
- name: Checkout Verilator
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||||
with:
|
with:
|
||||||
path: verilator
|
path: verilator
|
||||||
|
|
||||||
|
|
@ -367,13 +375,13 @@ jobs:
|
||||||
echo ${{ github.event.number }} > ../notification-artifact/pr-number.txt
|
echo ${{ github.event.number }} > ../notification-artifact/pr-number.txt
|
||||||
|
|
||||||
- name: Upload report
|
- name: Upload report
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: report-artifact
|
path: report-artifact
|
||||||
name: rtlmeter-report
|
name: rtlmeter-report
|
||||||
|
|
||||||
- name: Upload notification
|
- name: Upload notification
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: notification-artifact
|
path: notification-artifact
|
||||||
name: pr-notification
|
name: pr-notification
|
||||||
|
|
@ -392,9 +400,9 @@ jobs:
|
||||||
# Creating issues requires elevated privilege
|
# Creating issues requires elevated privilege
|
||||||
- name: Generate access token
|
- name: Generate access token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@v3.2.0
|
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||||
with:
|
with:
|
||||||
app-id: ${{ vars.VERILATOR_CI_ID }}
|
client-id: ${{ vars.VERILATOR_CI_ID }}
|
||||||
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
||||||
owner: verilator
|
owner: verilator
|
||||||
repositories: verilator
|
repositories: verilator
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
<!-- DESCRIPTION: Verilator: Repository-wide guidelines for AI coding agents
|
||||||
|
SPDX-FileCopyrightText: 2026-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -->
|
||||||
|
|
||||||
|
# Verilator Guidelines for AI Coding Agents
|
||||||
|
|
||||||
|
These files are the general layer an agent loads first -- nearest file wins, so
|
||||||
|
you read this repository-root file plus the one for the directory you are
|
||||||
|
editing. They stay deliberately high-level: where to start, how the tree is laid
|
||||||
|
out, and the conventions reviewers otherwise enforce by hand. They are an index,
|
||||||
|
not the architecture reference -- for depth (how a pass works internally, the
|
||||||
|
algorithms, node lifetime) they point you to `docs/internals.rst`. When the
|
||||||
|
guidance here is not enough, that is where to look next.
|
||||||
|
|
||||||
|
This file has two parts. **Orientation** gets you productive in the codebase from
|
||||||
|
a cold start. **Before you open a PR** is the checklist of conventions reviewers
|
||||||
|
otherwise have to enforce by hand -- read it before submitting any change.
|
||||||
|
|
||||||
|
Then read the directory guide for the area you are editing:
|
||||||
|
|
||||||
|
- [src/AGENTS.md](src/AGENTS.md) -- compiler C++ sources: AST, visitors, passes, parser, style
|
||||||
|
- [include/AGENTS.md](include/AGENTS.md) -- runtime library (`verilated*`): C++14, MT-safety, fixed-width types
|
||||||
|
- [test_regress/AGENTS.md](test_regress/AGENTS.md) -- regression tests: harness, drivers, golden files
|
||||||
|
- [docs/AGENTS.md](docs/AGENTS.md) -- documentation (`*.rst`)
|
||||||
|
|
||||||
|
______________________________________________________________________
|
||||||
|
|
||||||
|
# Orientation
|
||||||
|
|
||||||
|
## What Verilator is
|
||||||
|
|
||||||
|
Verilator is a *compiler*, not an interpreter. It translates synthesizable (and
|
||||||
|
much behavioral) SystemVerilog into a cycle-accurate C++ model that you then
|
||||||
|
compile and run. Almost every decision is made at compile ("verilation") time;
|
||||||
|
the generated C++ just advances state each evaluation. Optimize for verilation-
|
||||||
|
time work over runtime work.
|
||||||
|
|
||||||
|
## The pipeline is the spine
|
||||||
|
|
||||||
|
A run is an ordered sequence of passes over one shared AST (abstract syntax
|
||||||
|
tree). In source order:
|
||||||
|
|
||||||
|
| Stage | What it does | Key files |
|
||||||
|
|---|---|---|
|
||||||
|
| Preprocess + parse | Lex and parse text into a raw AST -- builds nodes only, no semantic checks | `verilog.l`, `verilog.y` |
|
||||||
|
| Link / elaborate | Resolve names, scopes, parameters; instantiate the hierarchy | `V3LinkParse`, `V3LinkDot`, `V3Param` |
|
||||||
|
| Width / type | Assign and check data types and bit widths | `V3Width` |
|
||||||
|
| Transform / optimize / schedule | Constant fold, lower language features, schedule events | `V3Const`, `V3Randomize`, `V3Assert*`, `V3Sched`, `V3Timing`, `V3Dfg` |
|
||||||
|
| Emit | Lower the final AST to generated C++ | `V3EmitC*` |
|
||||||
|
| Runtime | Library the generated model links against | `include/verilated*` |
|
||||||
|
|
||||||
|
This table is the map; `docs/internals.rst` has the detail behind each stage.
|
||||||
|
|
||||||
|
## Where to make a change
|
||||||
|
|
||||||
|
Map the symptom to the pass that owns it, then start by reading that pass's
|
||||||
|
top-of-file comment.
|
||||||
|
|
||||||
|
| Symptom or feature area | Start in |
|
||||||
|
|---|---|
|
||||||
|
| Type/width error, "what type is this", implicit conversion | `V3Width` |
|
||||||
|
| Name/scope/parameter resolution ("Can't find...", hierarchy) | `V3LinkDot`, `V3Param` |
|
||||||
|
| `randomize` / `constraint` / `rand` / `randc` | `V3Randomize` |
|
||||||
|
| `assert` / `property` / `sequence` / `cover` | `V3Assert`, `V3AssertPre`, `V3AssertNfa` |
|
||||||
|
| `fork` / timing / `#delay` / NBA / event scheduling | `V3Sched`, `V3Timing`, `V3Fork` |
|
||||||
|
| Syntax wrongly accepted or rejected | `verilog.y`, `verilog.l` |
|
||||||
|
| Wrong generated C++ | `V3EmitC*` |
|
||||||
|
| Runtime model behavior | `include/verilated*` |
|
||||||
|
|
||||||
|
## Build and run a test
|
||||||
|
|
||||||
|
- Build in the source tree: `autoconf && ./configure && make -j8`. Configure with
|
||||||
|
`--enable-ccwarn` so a new compiler warning stops the build.
|
||||||
|
- Run one test from the repository root: `test_regress/t/t_<name>.py`.
|
||||||
|
- Run the full regression with `make test`. The complete suite requires
|
||||||
|
configuring with `--enable-longtests` (works on every OS, including macOS).
|
||||||
|
|
||||||
|
______________________________________________________________________
|
||||||
|
|
||||||
|
# Before you open a PR
|
||||||
|
|
||||||
|
## Scope and process
|
||||||
|
|
||||||
|
- [ ] Searched open PRs and issues -- duplicating in-flight work wastes review time.
|
||||||
|
- [ ] Fixed the general root cause, not just the reported case -- if it also
|
||||||
|
affects other modules/classes/interfaces, cover them or expect rejection.
|
||||||
|
- [ ] PR is single-purpose. Refactors, drive-by fixes found along the way, and new
|
||||||
|
features each go in separate PRs; land standalone cleanups first.
|
||||||
|
- [ ] Every bug fix has a test that fails *without* the fix; include the issue's
|
||||||
|
own reproducer when possible.
|
||||||
|
- [ ] New code aims for 100% line coverage; branch coverage far below line coverage
|
||||||
|
signals guards callers never violate -- justify or remove them.
|
||||||
|
- [ ] Ran `make format` (clang-format), `make cppcheck`, and `make lint-py`;
|
||||||
|
self-reviewed the diff for leftover debug code, stale comments, and
|
||||||
|
copy-paste errors.
|
||||||
|
- [ ] Ran the full regression on at least one OS before submitting. Partial runs
|
||||||
|
are fine during development, but the submitted PR is expected to pass every
|
||||||
|
test.
|
||||||
|
- [ ] Did not edit `docs/CONTRIBUTORS` (humans only) or `Changes` (maintainer
|
||||||
|
updates it near release).
|
||||||
|
|
||||||
|
## Pick the right diagnostic (and its required test)
|
||||||
|
|
||||||
|
The API you choose determines which test must accompany the change.
|
||||||
|
|
||||||
|
| API | Output | Meaning | Required test |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `v3error("...")` | `%Error:` | User wrote invalid SystemVerilog | `t_*_bad*.v` + `.out` golden |
|
||||||
|
| `v3error("Unsupported: ...")` | `%Error-UNSUPPORTED:` | Legal SV that Verilator does not yet support | `t_*_unsup*.v` + `.out` golden |
|
||||||
|
| `v3warn(CODE, "...")` | `%Warning-CODE:` | Legal but suspicious code | warning test + `.out` golden |
|
||||||
|
| `v3fatalSrc("...")` | `%Error: Internal Error` | Should-never-happen internal assertion | none -- not user-triggerable |
|
||||||
|
|
||||||
|
- Every `v3error`/`v3warn` needs a test in `test_regress/t/` -- enforced by the
|
||||||
|
warn-coverage distribution test. `v3fatalSrc` is exempt.
|
||||||
|
- Reserve "Unsupported:" for not-yet-implemented features, never for user mistakes.
|
||||||
|
- When an error enforces a spec-defined restriction, cite the clause
|
||||||
|
(`IEEE 1800-2023 11.4.7`) so it is verifiable. Update `docs/guide/warnings.rst`
|
||||||
|
when adding or changing a warning.
|
||||||
|
- On error paths, clean up or replace invalid AST (e.g. `AstConst::BitFalse`) so
|
||||||
|
later passes do not crash after the error.
|
||||||
|
|
||||||
|
## Cross-cutting code rules
|
||||||
|
|
||||||
|
- [ ] No non-ASCII characters in C++ sources or headers: write `--` (two ASCII
|
||||||
|
hyphens) rather than a Unicode em-dash, and a plain `'` rather than a smart
|
||||||
|
quote. At write time, not when CI complains.
|
||||||
|
- [ ] Lists stay sorted: lexer/parser tokens, option declarations, enum values,
|
||||||
|
configure feature lists, documented option lists.
|
||||||
|
- [ ] `bin/` scripts are Python (distributed cross-platform); `nodist/` may use
|
||||||
|
bash and platform-specific code (developer-only, not packaged).
|
||||||
|
- [ ] Runtime code in `include/` targets C++14 (`--no-timing` builds must work);
|
||||||
|
C++20 only in timing code paths.
|
||||||
|
- [ ] In `include/` public headers, prefix public classes with `Verilated`/`Vl`
|
||||||
|
and document the API with `///` comments.
|
||||||
|
- [ ] A new code pattern is applied globally or not at all -- no one-off
|
||||||
|
convention in a single file.
|
||||||
|
|
||||||
|
## Commits
|
||||||
|
|
||||||
|
- Subject line is short and imperative and conventionally ends with the PR number:
|
||||||
|
`Support property case (#7721)`. A body is optional and common for non-trivial
|
||||||
|
changes.
|
||||||
|
|
@ -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.049
|
VERSION 5.051
|
||||||
HOMEPAGE_URL https://verilator.org
|
HOMEPAGE_URL https://verilator.org
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
|
||||||
95
Changes
95
Changes
|
|
@ -10,12 +10,26 @@ The changes in each Verilator version are described below. The
|
||||||
contributors that suggested or implemented a given issue are shown in []. Thanks!
|
contributors that suggested or implemented a given issue are shown in []. Thanks!
|
||||||
|
|
||||||
|
|
||||||
Verilator 5.049 devel
|
Verilator 5.051 devel
|
||||||
|
==========================
|
||||||
|
|
||||||
|
**Other:**
|
||||||
|
|
||||||
|
* Add comments as a branch description in coverage .info files (#7843). [Eryk Szpotanski]
|
||||||
|
* Optimize random initialization. [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix DFG misoptimizing bound checks (#7755). [Jakub Michalski]
|
||||||
|
* Fix unique0 case side effects (#7787). [Pawel Klopotek]
|
||||||
|
* Fix cleaning purity cache after assertions. [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix clang++ ambiguous overload of '==' operator (#7863). [Pawel Kojma, Antmicro Ltd.]
|
||||||
|
* Fix heap-use-after-free in `VlRNG::VlRNG()` (#7865). [Dragon-Git]
|
||||||
|
|
||||||
|
|
||||||
|
Verilator 5.050 2026-07-01
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
**Important:**
|
**Important:**
|
||||||
|
|
||||||
* Support covergroups, coverpoints, and bins (#784) (#7117). [Matthew Ballance]
|
* Support covergroups, coverpoints, and bins (#784) (#7117) (#7728). [Matthew Ballance]
|
||||||
* Support new FST writer API (#6871) (#6992). [Yu-Sheng Lin]
|
* Support new FST writer API (#6871) (#6992). [Yu-Sheng Lin]
|
||||||
Use of FST may requiring installing liblz4 and/or liblz4-dev packages, see docs/install.rst.
|
Use of FST may requiring installing liblz4 and/or liblz4-dev packages, see docs/install.rst.
|
||||||
|
|
||||||
|
|
@ -27,9 +41,12 @@ Verilator 5.049 devel
|
||||||
* Add `--coverage-per-instance` (#7636). [Yogish Sekhar]
|
* Add `--coverage-per-instance` (#7636). [Yogish Sekhar]
|
||||||
* Add NOTREDOP error on reduction and negation operators (#7417) (#7623) (#7624).
|
* Add NOTREDOP error on reduction and negation operators (#7417) (#7623) (#7624).
|
||||||
* Add hierarchy-aware reporting to `verilator_coverage` (#7657). [Yogish Sekhar]
|
* Add hierarchy-aware reporting to `verilator_coverage` (#7657). [Yogish Sekhar]
|
||||||
|
* Add FINALDLY error (#7754). [Igor Zaworski, Antmicro Ltd.]
|
||||||
|
* Deprecate isolate_assignments attribute (#7774) (#7144). [Geza Lore, Testorrent USA, Inc.]
|
||||||
* Improve `--coverage-fsm` (#7490) (#7529) (#7561) (#7573) (#7619). [Yogish Sekhar]
|
* Improve `--coverage-fsm` (#7490) (#7529) (#7561) (#7573) (#7619). [Yogish Sekhar]
|
||||||
* Change `+verilator+seed` to default to 1, and 0 to randomly select (#7325) (#7516). [Miguel]
|
* Change `+verilator+seed` to default to 1, and 0 to randomly select (#7325) (#7516). [Miguel]
|
||||||
* Change JSON to include parameter constant mnemonics for FSM Coverage (#7531). [Yogish Sekhar]
|
* Change JSON to include parameter constant mnemonics for FSM Coverage (#7531). [Yogish Sekhar]
|
||||||
|
* Support assert property `default disable iff` (#4848) (#7723). [Artur Bieniek, Antmicro Ltd.]
|
||||||
* Support printing enum names for %p and %s (#5523) (#7338 repair) (#7521) (#7527). [Nick Brereton]
|
* Support printing enum names for %p and %s (#5523) (#7338 repair) (#7521) (#7527). [Nick Brereton]
|
||||||
* Support weak `until` / `until_with` property operators (#7290) (#7548) (#7685). [Yilou Wang]
|
* Support weak `until` / `until_with` property operators (#7290) (#7548) (#7685). [Yilou Wang]
|
||||||
* Support `s_eventually` (#7291) (#7508). [Bartłomiej Chmiel, Antmicro Ltd.]
|
* Support `s_eventually` (#7291) (#7508). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||||
|
|
@ -50,6 +67,7 @@ Verilator 5.049 devel
|
||||||
* Support procedural concurrent assertions with inferred clock (#7581). [Yilou Wang]
|
* Support procedural concurrent assertions with inferred clock (#7581). [Yilou Wang]
|
||||||
* Support calling interface functions without parens (#7584). [Krzysztof Bieganski, Antmicro Ltd.]
|
* Support calling interface functions without parens (#7584). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
* Support streaming on queues (#7597). [Benjamin Collier, Secturion Systems, Inc.]
|
* Support streaming on queues (#7597). [Benjamin Collier, Secturion Systems, Inc.]
|
||||||
|
* Support clocking event on a sequence declaration body (#7598) (#7793). [Yilou Wang]
|
||||||
* Support generic interface arrays (#7604). [Krzysztof Bieganski, Antmicro Ltd.]
|
* Support generic interface arrays (#7604). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
* Support FSM detection in primitive wrappers (#7607). [Yogish Sekhar]
|
* Support FSM detection in primitive wrappers (#7607). [Yogish Sekhar]
|
||||||
* Support busses with mix of pullup/pulldown (#7632). [Lucas Amaral]
|
* Support busses with mix of pullup/pulldown (#7632). [Lucas Amaral]
|
||||||
|
|
@ -59,6 +77,24 @@ Verilator 5.049 devel
|
||||||
* Support if/if-else in properties (#7692). [Artur Bieniek, Antmicro Ltd.]
|
* Support if/if-else in properties (#7692). [Artur Bieniek, Antmicro Ltd.]
|
||||||
* Support process::self().srand() (#7695). [Igor Zaworski, Antmicro Ltd.]
|
* Support process::self().srand() (#7695). [Igor Zaworski, Antmicro Ltd.]
|
||||||
* Support MacOS lldb (#7697). [Tracy Narine]
|
* Support MacOS lldb (#7697). [Tracy Narine]
|
||||||
|
* Support assoc array methods with wide value types (#7680). [pawelktk]
|
||||||
|
* Support property case (#7682) (#7721). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Support `s_until` and `s_until_with`(#7722). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Support covergroup runtime model Phase A1 (#7728). [Matthew Ballance]
|
||||||
|
* Support hierarchical reference cross members (#7749) (#7820). [Matthew Ballance]
|
||||||
|
* Support reduction XOR/AND operations in constraints (#7753). [Kornel Uriasz, Antmicro Ltd.]
|
||||||
|
* Support NBAs in initial blocks (#7754). [Igor Zaworski, Antmicro Ltd.]
|
||||||
|
* Support assertion control system tasks in classes and interfaces (#7761). [Yilou Wang]
|
||||||
|
* Support cover sequence statement (#7764). [Yilou Wang]
|
||||||
|
* Support unpacked struct stream (#7767). [Nick Brereton]
|
||||||
|
* Support $assertcontrol control_type from lock to kill (#7788). [Yilou Wang]
|
||||||
|
* Support unbounded always [m:$] and strong s_always liveness (#7798). [Yilou Wang]
|
||||||
|
* Support method calls on a sub-interface via a virtual interface (#7800). [Yilou Wang]
|
||||||
|
* Support global $assertcontrol (#7807). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Support VPI access to unpacked struct members (#7823). [Nick Brereton]
|
||||||
|
* Support variable-length intersect in SVA sequences (#7835). [Yilou Wang]
|
||||||
|
* Support dynamic loading of VPI extensions (#7727). [Matthew Ballance]
|
||||||
|
* Optimize DFG cycle breaking to do less work (#7210). [Geza Lore, Testorrent USA, Inc.]
|
||||||
* Optimize emitting to_string() for compiler speedup (#7468). [Jakub Michalski, Antmicro Ltd.]
|
* Optimize emitting to_string() for compiler speedup (#7468). [Jakub Michalski, Antmicro Ltd.]
|
||||||
* Optimize additional DFG peephole cases (#7553). [Varun Koyyalagunta, Testorrent USA, Inc.]
|
* Optimize additional DFG peephole cases (#7553). [Varun Koyyalagunta, Testorrent USA, Inc.]
|
||||||
* Optimize forced signal handling (#7554 partial) (#7572) (#7594) (#7596). [Krzysztof Bieganski, Artur Bieniek, Antmicro Ltd.]
|
* Optimize forced signal handling (#7554 partial) (#7572) (#7594) (#7596). [Krzysztof Bieganski, Artur Bieniek, Antmicro Ltd.]
|
||||||
|
|
@ -71,9 +107,27 @@ Verilator 5.049 devel
|
||||||
* Optimize runtime assertOn() checks (#7707). [Geza Lore, Testorrent USA, Inc.]
|
* Optimize runtime assertOn() checks (#7707). [Geza Lore, Testorrent USA, Inc.]
|
||||||
* Optimize $countones and $onehot in DFG. [Geza Lore, Testorrent USA, Inc.]
|
* Optimize $countones and $onehot in DFG. [Geza Lore, Testorrent USA, Inc.]
|
||||||
* Optimize procedural loop unrolling. [Geza Lore, Testorrent USA, Inc.]
|
* Optimize procedural loop unrolling. [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize V3Gate inlining heuristic (#7716). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize reset in DFG (#7737). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize DFG with relaxed live variable analysis (#7739). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize conditional patterns sharing common MBSs/LSBs in DfgPeephole (#7760). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize bit select removal earlier in DFG (#7762). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize away proven redundant case statement assertions (#7771). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize table lookups in DFG (#7772). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize input combinational logic by change detection (#7784). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize decoder case statements into lookup tables (#7795). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize wide decoder case statements into decoder expressions (#7804). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize statically known oversize shifts (#7806). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize generated function inlining (#7811). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize bit-scan loops into most-set-bit or $countones (#7822). [Thomas Santerre]
|
||||||
|
* Optimize additional expression patterns (#7824). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize module inlining heuristic (#7837). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix `$bits` on unpacked structs (#4521) (#7796). [Nick Brereton]
|
||||||
* Fix TSP variable ordering for mtasks (#5342) (#7610). [Muzaffer Kal]
|
* Fix TSP variable ordering for mtasks (#5342) (#7610). [Muzaffer Kal]
|
||||||
* Fix inlining static initializer in V3Gate (#5381) (#7503). [Andrew Nolte] [Geza Lore, Testorrent USA, Inc.]
|
* Fix inlining static initializer in V3Gate (#5381) (#7503). [Andrew Nolte] [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix timed nested fork block with disable (#6720) (#7743). [Marco Bartoli]
|
||||||
* Fix segmentation fault when using --trace with --lib-create (#7299) (#7518). [anonkey]
|
* Fix segmentation fault when using --trace with --lib-create (#7299) (#7518). [anonkey]
|
||||||
|
* Fix cross-hierarchy tristate drivers of interface nets (#7339) (#7801). [Yilou Wang]
|
||||||
* Fix destructive event state before dynamic waits (#7340). [Nick Brereton]
|
* Fix destructive event state before dynamic waits (#7340). [Nick Brereton]
|
||||||
* Fix ALWCOMBORDER on variable ordering (#7350) (#7608). [Cookie]
|
* Fix ALWCOMBORDER on variable ordering (#7350) (#7608). [Cookie]
|
||||||
* Fix false MULTIDRIVEN warning on always_ff variables (#7351) (#7621) (#7672).
|
* Fix false MULTIDRIVEN warning on always_ff variables (#7351) (#7621) (#7672).
|
||||||
|
|
@ -118,6 +172,7 @@ Verilator 5.049 devel
|
||||||
* Fix reference counting for modport task references (#7628). [Nick Brereton]
|
* Fix reference counting for modport task references (#7628). [Nick Brereton]
|
||||||
* Fix internal error when handling typedefs containing parameterized class type members (#7635) (#7661). [em2machine]
|
* Fix internal error when handling typedefs containing parameterized class type members (#7635) (#7661). [em2machine]
|
||||||
* Fix forceable signal with a procedural continuous assign (#7638) (#7639). [Zubin Jain]
|
* Fix forceable signal with a procedural continuous assign (#7638) (#7639). [Zubin Jain]
|
||||||
|
* Fix scheduling of virtual interface method writes (#7641). [Artur Bieniek, Antmicro Ltd.]
|
||||||
* Fix implicit conversions of VlWide (#7642). [Geza Lore, Testorrent USA, Inc.]
|
* Fix implicit conversions of VlWide (#7642). [Geza Lore, Testorrent USA, Inc.]
|
||||||
* Fix CASEINCOMPLETE to not warn on `unique0 case` (#7647).
|
* Fix CASEINCOMPLETE to not warn on `unique0 case` (#7647).
|
||||||
* Fix hierarchical coverage counts for duplicate no-inline module instances (#7649). [Yogish Sekhar]
|
* Fix hierarchical coverage counts for duplicate no-inline module instances (#7649). [Yogish Sekhar]
|
||||||
|
|
@ -128,13 +183,45 @@ Verilator 5.049 devel
|
||||||
* Fix loss of events due to bit shift (#7670). [Artur Bieniek, Antmicro Ltd.]
|
* Fix loss of events due to bit shift (#7670). [Artur Bieniek, Antmicro Ltd.]
|
||||||
* Fix parameter read through locally-declared interface instance (#7679). [Nick Brereton]
|
* Fix parameter read through locally-declared interface instance (#7679). [Nick Brereton]
|
||||||
* Fix skipping nulls in $sscanf (#7689).
|
* Fix skipping nulls in $sscanf (#7689).
|
||||||
|
* Fix bounds checks in expressions with read/write references (#7694). [Ryszard Rozak, Antmicro Ltd.]
|
||||||
* Fix (const) ref default task argument handling (#7698). [Nick Brereton]
|
* Fix (const) ref default task argument handling (#7698). [Nick Brereton]
|
||||||
* Fix `ref` argument type check for packed arrays with differing range directions (#7700). [Nick Brereton]
|
* Fix `ref` argument type check for packed arrays with differing range directions (#7700). [Nick Brereton]
|
||||||
* Fix ignoring not-found modules with encoded names (#7706). [Igor Zaworski, Antmicro Ltd.]
|
* Fix ignoring not-found modules with encoded names (#7706). [Igor Zaworski, Antmicro Ltd.]
|
||||||
* Fix MULTIDRIVEN in generates (#7709). [Todd Strader]
|
* Fix MULTIDRIVEN in generates (#7709). [Todd Strader]
|
||||||
|
* Fix parameter pollution when using class parameters (#7711) (#7763). [em2machine]
|
||||||
* Fix Makefile action to not write to ${srcdir} (#7715). [Larry Doolittle]
|
* Fix Makefile action to not write to ${srcdir} (#7715). [Larry Doolittle]
|
||||||
* Fix splitting functions containing fork logic (#7717). [Mateusz Gancarz, Antmicro Ltd.]
|
* Fix splitting functions containing fork logic (#7717). [Mateusz Gancarz, Antmicro Ltd.]
|
||||||
* Fix optimizations of assignments with timing controls (#7718). [Ryszard Rozak, Antmicro Ltd.]
|
* Fix optimizations of assignments with timing controls (#7718). [Ryszard Rozak, Antmicro Ltd.]
|
||||||
|
* Fix s_eventually on interface (#7731) (#7733). [Marco Bartoli]
|
||||||
|
* Fix parameter values in coverage bins widths (#7732) (#7734). [Marco Bartoli]
|
||||||
|
* Fix configure fall back on dynamic malloc libraries (#7736). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix crash on overlapping priority case. [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix s_eventually in parameterized interfaces (#7741). [Nick Brereton]
|
||||||
|
* Fix dpi export pointers (#7742) (#7751). [Yilin Li]
|
||||||
|
* Fix force on unpacked bit select (#7744) (#7745). [Nikolai Kumar]
|
||||||
|
* Fix `$` as unsupported coverpoint-bin range bounds (#7750) (#7825). [Matthew Ballance]
|
||||||
|
* Fix FSM detect unchecked casts and variable redeclaration (#7758). [Adam Kostrzewski, Antmicro Ltd.]
|
||||||
|
* Fix no-scope internal error on virtual interface method calls (#7759). [Yilou Wang]
|
||||||
|
* Fix `case (_) inside` with x wildcards (#7766). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix not failing assertion when RHS of a range window rejects once (#7773). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix $fflush and autoflush with --threads (#7782).
|
||||||
|
* Fix out-of-bounds read value for 2-state types (#7785). [Jakub Michalski]
|
||||||
|
* Fix `cover property` of an implication counting vacuous matches (#7789). [Yilou Wang]
|
||||||
|
* Fix randomization of dynamic arrays of objects (#7790). [Ryszard Rozak, Antmicro Ltd.]
|
||||||
|
* Fix randomize() with skipping derived pre/post_randomize (#7799). [Yilou Wang]
|
||||||
|
* Fix skewed dist operator for arrays (#7802). [Jakub Wasilewski, Antmicro Ltd.]
|
||||||
|
* Fix assertion when loop unrolling failed (#7810). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix CASEINCOMPLETE for all uncovered enum items (#7815) (#7817). [Saksham]
|
||||||
|
* Fix split optimization nested-class crash (#7826). [Igor Zaworski, Antmicro Ltd.]
|
||||||
|
* Fix class/var named identically to an enclosing-scope type (#7827) (#7828). [Tom Jackson]
|
||||||
|
* Fix performance on large package-scoped structs (#7830). [Wolfgang Mayerwieser]
|
||||||
|
* Fix unclocked concurrent assertion misreported as unsupported (#7831). [Yilou Wang]
|
||||||
|
* Fix insertion of expression coverage statement (#7832). [Ryszard Rozak, Antmicro Ltd.]
|
||||||
|
* Fix lifetime of expression coverage variable (#7834). [Ryszard Rozak, Antmicro Ltd.]
|
||||||
|
* Fix disable iff ignored when its condition is held continuously true (#7841). [Yilou Wang]
|
||||||
|
* Fix constant pool cache after dead scope removal (#7845). [Nick Brereton]
|
||||||
|
* Fix covergroups without --coverage (#7848) (#7849). [Joshua Leahy]
|
||||||
|
* Fix class scope '::' reference through an inherited type parameter (#7844). [Sergey Chusov]
|
||||||
|
|
||||||
|
|
||||||
Verilator 5.048 2026-04-26
|
Verilator 5.048 2026-04-26
|
||||||
|
|
@ -471,7 +558,7 @@ Verilator 5.044 2026-01-01
|
||||||
* Support clocking output delay `1step` (#6681). [Ondrej Ille]
|
* Support clocking output delay `1step` (#6681). [Ondrej Ille]
|
||||||
* Support parsing of dotted `bins_expression` (#6683). [Pawel Kojma, Antmicro Ltd.]
|
* Support parsing of dotted `bins_expression` (#6683). [Pawel Kojma, Antmicro Ltd.]
|
||||||
* Support constant expression cycle delays in sequences (#6691). [Ryszard Rozak, Antmicro Ltd.]
|
* Support constant expression cycle delays in sequences (#6691). [Ryszard Rozak, Antmicro Ltd.]
|
||||||
* Support general global constraints (#6709) (#6711). [Yilou Wang]
|
* Support general global constraints (#6709) (#6711) (#7833) (#7838). [Yilou Wang]
|
||||||
* Support complex std::randomize patterns (#6736) (#6737). [Yilou Wang]
|
* Support complex std::randomize patterns (#6736) (#6737). [Yilou Wang]
|
||||||
* Support `rand_mode` in global constraint gathering (#6740) (#6752). [Yilou Wang]
|
* Support `rand_mode` in global constraint gathering (#6740) (#6752). [Yilou Wang]
|
||||||
* Support reduction or in constraints (#6840). [Pawel Kojma, Antmicro Ltd.]
|
* Support reduction or in constraints (#6840). [Pawel Kojma, Antmicro Ltd.]
|
||||||
|
|
@ -5665,7 +5752,7 @@ Verilator 3.104 2003-04-30
|
||||||
**Major:**
|
**Major:**
|
||||||
|
|
||||||
* Indicate direction of ports with VL_IN and VL_OUT.
|
* Indicate direction of ports with VL_IN and VL_OUT.
|
||||||
* Allow $c32, etc, to specify width of the $c statement for VCS.
|
* Allow $c32, etc, to specify width of the $c statement.
|
||||||
* Numerous performance improvements, worth about 25%
|
* Numerous performance improvements, worth about 25%
|
||||||
|
|
||||||
**Minor:**
|
**Minor:**
|
||||||
|
|
|
||||||
28
Makefile.in
28
Makefile.in
|
|
@ -495,6 +495,11 @@ MAKE_FILES = \
|
||||||
src/Makefile*.in \
|
src/Makefile*.in \
|
||||||
test_regress/Makefile* \
|
test_regress/Makefile* \
|
||||||
|
|
||||||
|
# Markdown
|
||||||
|
MD_FILES = \
|
||||||
|
*.md \
|
||||||
|
*/*.md \
|
||||||
|
|
||||||
# Perl programs
|
# Perl programs
|
||||||
PERL_PROGRAMS = \
|
PERL_PROGRAMS = \
|
||||||
bin/redirect \
|
bin/redirect \
|
||||||
|
|
@ -541,6 +546,13 @@ PY_FILES = \
|
||||||
# Python files, test_regress tests
|
# Python files, test_regress tests
|
||||||
PY_TEST_FILES = test_regress/t/*.py
|
PY_TEST_FILES = test_regress/t/*.py
|
||||||
|
|
||||||
|
# reStructuredText Sphinx files
|
||||||
|
RST_FILES = \
|
||||||
|
*.rst \
|
||||||
|
*/*.rst \
|
||||||
|
ci/docker/*/*.rst \
|
||||||
|
docs/guide/*.rst \
|
||||||
|
|
||||||
# YAML files
|
# YAML files
|
||||||
YAML_FILES = \
|
YAML_FILES = \
|
||||||
.*.yaml \
|
.*.yaml \
|
||||||
|
|
@ -553,7 +565,7 @@ YAML_FILES = \
|
||||||
# Format
|
# Format
|
||||||
|
|
||||||
format:
|
format:
|
||||||
$(MAKE) -j 5 format-c format-cmake format-exec format-py format-yaml
|
$(MAKE) -j 5 format-c format-cmake format-exec format-md format-py format-rst format-yaml
|
||||||
|
|
||||||
BEAUTYSH = beautysh
|
BEAUTYSH = beautysh
|
||||||
BEAUTYSH_FLAGS = --indent-size 2
|
BEAUTYSH_FLAGS = --indent-size 2
|
||||||
|
|
@ -590,6 +602,13 @@ format-make mbake:
|
||||||
$(MBAKE) --version
|
$(MBAKE) --version
|
||||||
$(MBAKE) $(MBAKE_FLAGS) $(MAKE_FILES)
|
$(MBAKE) $(MBAKE_FLAGS) $(MAKE_FILES)
|
||||||
|
|
||||||
|
MDFORMAT = mdformat
|
||||||
|
MDFORMAT_FLAGS =
|
||||||
|
|
||||||
|
format-md:
|
||||||
|
$(MDFORMAT) --version
|
||||||
|
$(MDFORMAT) $(MDFORMAT_FLAGS) $(MD_FILES)
|
||||||
|
|
||||||
YAPF = yapf
|
YAPF = yapf
|
||||||
YAPF_FLAGS = -i --parallel
|
YAPF_FLAGS = -i --parallel
|
||||||
|
|
||||||
|
|
@ -597,6 +616,13 @@ format-py yapf:
|
||||||
$(YAPF) --version
|
$(YAPF) --version
|
||||||
$(YAPF) $(YAPF_FLAGS) $(PY_FILES)
|
$(YAPF) $(YAPF_FLAGS) $(PY_FILES)
|
||||||
|
|
||||||
|
DOCSTRFMT = docstrfmt
|
||||||
|
DOCSTRFMT_FLAGS = --line-length 75 --indent-width 3 --keep-blanks --ordered-marker "\#" --preserve-adornments --no-center-section-titles
|
||||||
|
|
||||||
|
format-rst:
|
||||||
|
$(DOCSTRFMT) --version
|
||||||
|
$(DOCSTRFMT) $(DOCSTRFMT_FLAGS) $(RST_FILES)
|
||||||
|
|
||||||
YAMLFIX = YAMLFIX_WHITELINES=1 YAMLFIX_LINE_LENGTH=200 YAMLFIX_preserve_quotes=true yamlfix
|
YAMLFIX = YAMLFIX_WHITELINES=1 YAMLFIX_LINE_LENGTH=200 YAMLFIX_preserve_quotes=true yamlfix
|
||||||
YAMLFIX_FLAGS =
|
YAMLFIX_FLAGS =
|
||||||
|
|
||||||
|
|
|
||||||
69
README.rst
69
README.rst
|
|
@ -1,58 +1,63 @@
|
||||||
.. Github doesn't render images unless absolute URL
|
..
|
||||||
.. Do not know of a conditional tag, "only: github" nor "github display" works
|
Github doesn't render images unless absolute URL
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
Do not know of a conditional tag, "only: github" nor "github display" works
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|badge1| |badge2| |badge3| |badge4| |badge5| |badge7| |badge8|
|
|badge1| |badge2| |badge3| |badge4| |badge5| |badge7| |badge8|
|
||||||
|
|
||||||
.. |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
|
||||||
|
|
||||||
.. |badge2| image:: https://img.shields.io/badge/License-LGPL%20v3-blue.svg
|
.. |badge2| image:: https://img.shields.io/badge/License-LGPL%20v3-blue.svg
|
||||||
:target: https://www.gnu.org/licenses/lgpl-3.0
|
:target: https://www.gnu.org/licenses/lgpl-3.0
|
||||||
|
|
||||||
.. |badge3| image:: https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg
|
.. |badge3| image:: https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg
|
||||||
:target: https://opensource.org/licenses/Artistic-2.0
|
:target: https://opensource.org/licenses/Artistic-2.0
|
||||||
|
|
||||||
.. |badge4| image:: https://repology.org/badge/tiny-repos/verilator.svg?header=distro%20packages
|
.. |badge4| image:: https://repology.org/badge/tiny-repos/verilator.svg?header=distro%20packages
|
||||||
: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
|
||||||
|
|
||||||
.. |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
|
||||||
|
|
||||||
.. |badge8| image:: https://img.shields.io/github/actions/workflow/status/verilator/verilator/rtlmeter.yml?branch=master&event=schedule&label=benchmarks
|
.. |badge8| image:: https://img.shields.io/github/actions/workflow/status/verilator/verilator/rtlmeter.yml?branch=master&event=schedule&label=benchmarks
|
||||||
:target: https://verilator.github.io/verilator-rtlmeter-results
|
:target: https://verilator.github.io/verilator-rtlmeter-results
|
||||||
|
|
||||||
|
|
||||||
Welcome to Verilator
|
Welcome to Verilator
|
||||||
====================
|
====================
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
|
|
||||||
* - **Welcome to Verilator, the fastest Verilog/SystemVerilog simulator.**
|
- - **Welcome to Verilator, the fastest Verilog/SystemVerilog simulator.**
|
||||||
* Accepts Verilog or SystemVerilog
|
- Accepts Verilog or SystemVerilog
|
||||||
* Performs lint code-quality checks
|
- Performs lint code-quality checks
|
||||||
* Compiles into multithreaded C++, or SystemC
|
- Compiles into multithreaded C++, or SystemC
|
||||||
* Creates JSON to front-end your own tools
|
- Creates JSON to front-end your own tools
|
||||||
- |Logo|
|
- |Logo|
|
||||||
* - |verilator multithreaded performance|
|
- - |verilator multithreaded performance|
|
||||||
- **Fast**
|
- **Fast**
|
||||||
* Outperforms many closed-source commercial simulators
|
- Outperforms many closed-source commercial simulators
|
||||||
* Single- and multithreaded output models
|
- Single- and multithreaded output models
|
||||||
* - **Widely Used**
|
- - **Widely Used**
|
||||||
* Wide industry and academic deployment
|
- Wide industry and academic deployment
|
||||||
* Out-of-the-box support from Arm and RISC-V vendor IP
|
- Out-of-the-box support from Arm and RISC-V vendor IP
|
||||||
* Over 700 contributors
|
- Over 700 contributors
|
||||||
- |verilator usage|
|
- |verilator usage|
|
||||||
* - |verilator community|
|
- - |verilator community|
|
||||||
- **Community Driven & Openly Licensed**
|
- **Community Driven & Openly Licensed**
|
||||||
* Guided by the `CHIPS Alliance`_ and `Linux Foundation`_
|
- Guided by the `CHIPS Alliance`_ and `Linux Foundation`_
|
||||||
* Open, and free as in both speech and beer
|
- Open, and free as in both speech and beer
|
||||||
* More simulation for your verification budget
|
- More simulation for your verification budget
|
||||||
* - **Commercial Support Available**
|
- - **Commercial Support Available**
|
||||||
* Commercial support contracts
|
- Commercial support contracts
|
||||||
* Design support contracts
|
- Design support contracts
|
||||||
* Enhancement contracts
|
- Enhancement contracts
|
||||||
- |verilator support|
|
- |verilator support|
|
||||||
|
|
||||||
|
|
||||||
What Verilator Does
|
What Verilator Does
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
|
@ -77,7 +82,6 @@ SDF annotation, or mixed-signal simulation. However, if you are looking for
|
||||||
a path to migrate SystemVerilog to C++/SystemC, or want high-speed
|
a path to migrate SystemVerilog to C++/SystemC, or want high-speed
|
||||||
simulation, Verilator is the tool for you.
|
simulation, Verilator is the tool for you.
|
||||||
|
|
||||||
|
|
||||||
Performance
|
Performance
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
|
@ -96,7 +100,6 @@ Mentor ModelSim/Questa, Synopsys VCS, VTOC, and Pragmatic CVer/CVC). But,
|
||||||
Verilator is open-sourced, so you can spend on computes rather than
|
Verilator is open-sourced, so you can spend on computes rather than
|
||||||
licenses. Thus, Verilator gives you the best simulation cycles/dollar.
|
licenses. Thus, Verilator gives you the best simulation cycles/dollar.
|
||||||
|
|
||||||
|
|
||||||
Installation & Documentation
|
Installation & Documentation
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
|
@ -115,7 +118,6 @@ For more information:
|
||||||
|
|
||||||
- `Verilator issues <https://verilator.org/issues>`_
|
- `Verilator issues <https://verilator.org/issues>`_
|
||||||
|
|
||||||
|
|
||||||
Support
|
Support
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
@ -132,7 +134,6 @@ Verilator also supports and encourages commercial support models and
|
||||||
organizations; please see `Verilator Commercial Support
|
organizations; please see `Verilator Commercial Support
|
||||||
<https://verilator.org/verilator_commercial_support>`_.
|
<https://verilator.org/verilator_commercial_support>`_.
|
||||||
|
|
||||||
|
|
||||||
Related Projects
|
Related Projects
|
||||||
================
|
================
|
||||||
|
|
||||||
|
|
@ -149,7 +150,6 @@ Related Projects
|
||||||
- `Surfer <https://surfer-project.org/>`_ - Web or offline waveform viewer
|
- `Surfer <https://surfer-project.org/>`_ - Web or offline waveform viewer
|
||||||
for Verilator traces.
|
for Verilator traces.
|
||||||
|
|
||||||
|
|
||||||
Open License
|
Open License
|
||||||
============
|
============
|
||||||
|
|
||||||
|
|
@ -161,10 +161,17 @@ the terms of either the GNU Lesser General Public License Version 3 or the
|
||||||
Perl Artistic License Version 2.0. See the documentation for more details.
|
Perl Artistic License Version 2.0. See the documentation for more details.
|
||||||
|
|
||||||
.. _chips alliance: https://chipsalliance.org
|
.. _chips alliance: https://chipsalliance.org
|
||||||
|
|
||||||
.. _icarus verilog: https://steveicarus.github.io/iverilog
|
.. _icarus verilog: https://steveicarus.github.io/iverilog
|
||||||
|
|
||||||
.. _linux foundation: https://www.linuxfoundation.org
|
.. _linux foundation: https://www.linuxfoundation.org
|
||||||
|
|
||||||
.. |Logo| image:: https://www.veripool.org/img/verilator_256_200_min.png
|
.. |Logo| image:: https://www.veripool.org/img/verilator_256_200_min.png
|
||||||
|
|
||||||
.. |verilator multithreaded performance| image:: https://www.veripool.org/img/verilator_multithreaded_performance_bg-min.png
|
.. |verilator multithreaded performance| image:: https://www.veripool.org/img/verilator_multithreaded_performance_bg-min.png
|
||||||
|
|
||||||
.. |verilator usage| image:: https://www.veripool.org/img/verilator_usage_400x200-min.png
|
.. |verilator usage| image:: https://www.veripool.org/img/verilator_usage_400x200-min.png
|
||||||
|
|
||||||
.. |verilator community| image:: https://www.veripool.org/img/verilator_community_400x125-min.png
|
.. |verilator community| image:: https://www.veripool.org/img/verilator_community_400x125-min.png
|
||||||
|
|
||||||
.. |verilator support| image:: https://www.veripool.org/img/verilator_support_400x125-min.png
|
.. |verilator support| image:: https://www.veripool.org/img/verilator_support_400x125-min.png
|
||||||
|
|
|
||||||
|
|
@ -438,6 +438,7 @@ detailed descriptions of these arguments.
|
||||||
--diagnostics-sarif-output <filename> Set SARIF diagnostics output file
|
--diagnostics-sarif-output <filename> Set SARIF diagnostics output file
|
||||||
--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-<srcfile> Enable dumping everything in source file
|
||||||
|
--dump-ast-patterns Enable dumping Ast pattern statistics
|
||||||
--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-dfg-patterns Enable dumping Dfg pattern statistics
|
--dump-dfg-patterns Enable dumping Dfg pattern statistics
|
||||||
|
|
@ -652,6 +653,7 @@ description of these arguments.
|
||||||
+verilator+solver+file+<filename> Set random solver log filename
|
+verilator+solver+file+<filename> Set random solver log filename
|
||||||
+verilator+V Show verbose version and config
|
+verilator+V Show verbose version and config
|
||||||
+verilator+version Show version and exit
|
+verilator+version Show version and exit
|
||||||
|
+verilator+vpi+<library>[:<bootstrap>] Load VPI shared library
|
||||||
+verilator+wno+unsatconstr+<value> Disable constraint warnings
|
+verilator+wno+unsatconstr+<value> Disable constraint warnings
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# DESCRIPTION: Verilator: CI build job script
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Executed in the 'build' stage.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# Destructive to the checkout (reconfigures and rebuilds); never run locally
|
||||||
|
if [ "$GITHUB_ACTIONS" != "true" ]; then
|
||||||
|
echo "ERROR: $(basename "$0") must only be run in GitHub Actions CI" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
source "$(dirname "$0")/ci-common.bash"
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Parse arguments
|
||||||
|
|
||||||
|
OPT_ASAN=0
|
||||||
|
OPT_CCWARN=0
|
||||||
|
OPT_GCOV=0
|
||||||
|
OPT_COMPILER=
|
||||||
|
OPT_PREFIX=
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--asan) OPT_ASAN=1 ;;
|
||||||
|
--ccwarn) OPT_CCWARN=1 ;;
|
||||||
|
--compiler)
|
||||||
|
[ $# -ge 2 ] || fatal "--compiler requires an argument"
|
||||||
|
OPT_COMPILER="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--gcov) OPT_GCOV=1 ;;
|
||||||
|
--prefix)
|
||||||
|
[ $# -ge 2 ] || fatal "--prefix requires an argument"
|
||||||
|
OPT_PREFIX="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*) fatal "Unknown option: '$1'" ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -n "$OPT_COMPILER" ] || fatal "--compiler is required"
|
||||||
|
[ -n "$OPT_PREFIX" ] || fatal "--prefix is required"
|
||||||
|
|
||||||
|
# Map the compiler name to the executable name configure CXX expects
|
||||||
|
case "$OPT_COMPILER" in
|
||||||
|
clang) CXX=clang++ ;;
|
||||||
|
gcc) CXX=g++ ;;
|
||||||
|
*) fatal "Unknown compiler: '$OPT_COMPILER'" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Configure
|
||||||
|
|
||||||
|
CONFIGURE_ARGS="--prefix=$OPT_PREFIX --enable-longtests"
|
||||||
|
if [ "$OPT_CCWARN" = 1 ]; then
|
||||||
|
CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-ccwarn"
|
||||||
|
fi
|
||||||
|
if [ "$OPT_ASAN" = 1 ]; then
|
||||||
|
CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-dev-asan"
|
||||||
|
CXX="$CXX -DVL_LEAK_CHECKS"
|
||||||
|
fi
|
||||||
|
if [ "$OPT_GCOV" = 1 ]; then
|
||||||
|
CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-dev-gcov"
|
||||||
|
fi
|
||||||
|
autoconf
|
||||||
|
./configure $CONFIGURE_ARGS CXX="$CXX"
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Build
|
||||||
|
|
||||||
|
ccache -z
|
||||||
|
"$MAKE" -j "$NPROC" -k
|
||||||
|
ccache -svv
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
# DESCRIPTION: Verilator: CI common definitions, sourced by the stage scripts
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Common definitions sourced by the CI stage scripts; not executed directly.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
fatal() {
|
||||||
|
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Linux)
|
||||||
|
HOST_OS=linux
|
||||||
|
MAKE=make
|
||||||
|
NPROC=$(nproc)
|
||||||
|
# Distro id/version; subshell keeps os-release out of our namespace
|
||||||
|
if [ -r /etc/os-release ]; then
|
||||||
|
DISTRO_ID=$(. /etc/os-release; echo "$ID")
|
||||||
|
DISTRO_VERSION=$(. /etc/os-release; echo "$VERSION_ID")
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
Darwin)
|
||||||
|
HOST_OS=macOS
|
||||||
|
MAKE=make
|
||||||
|
NPROC=$(sysctl -n hw.logicalcpu)
|
||||||
|
# Disable ccache, doesn't always work in GitHub Actions
|
||||||
|
export OBJCACHE=
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
fatal "Unknown host OS: '$(uname -s)'"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
export MAKE
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# DESCRIPTION: Verilator: CI dependency install script
|
# DESCRIPTION: Verilator: CI dependency install script
|
||||||
#
|
#
|
||||||
# SPDX-FileCopyrightText: 2020 Geza Lore
|
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
@ -10,30 +10,33 @@
|
||||||
# required by the particular build stage.
|
# required by the particular build stage.
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
# Installs system packages with sudo; never run locally
|
||||||
|
if [ "$GITHUB_ACTIONS" != "true" ]; then
|
||||||
|
echo "ERROR: $(basename "$0") must only be run in GitHub Actions CI" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
cd $(dirname "$0")/..
|
cd $(dirname "$0")/..
|
||||||
|
|
||||||
|
source "$(dirname "$0")/ci-common.bash"
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Parse arguments
|
||||||
|
|
||||||
|
# Which stage to install dependencies for: 'build' or 'test'
|
||||||
|
STAGE="$1"
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Install dependencies
|
||||||
|
|
||||||
# Avoid occasional cpan failures "Issued certificate has expired."
|
# Avoid occasional cpan failures "Issued certificate has expired."
|
||||||
export PERL_LWP_SSL_VERIFY_HOSTNAME=0
|
export PERL_LWP_SSL_VERIFY_HOSTNAME=0
|
||||||
echo "check_certificate = off" >> ~/.wgetrc
|
echo "check_certificate = off" >> ~/.wgetrc
|
||||||
|
|
||||||
fatal() {
|
if [ "$HOST_OS" = "linux" ]; then
|
||||||
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
|
||||||
MAKE=make
|
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
|
||||||
MAKE=make
|
|
||||||
elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
|
||||||
MAKE=gmake
|
|
||||||
else
|
|
||||||
fatal "Unknown CI_OS_NAME: '$CI_OS_NAME'"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
|
||||||
# Avoid slow "processing triggers for man db"
|
# Avoid slow "processing triggers for man db"
|
||||||
echo "path-exclude /usr/share/doc/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
echo "path-exclude /usr/share/doc/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
||||||
echo "path-exclude /usr/share/man/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
echo "path-exclude /usr/share/man/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
||||||
|
|
@ -44,100 +47,100 @@ install-wavediff() {
|
||||||
source ci/docker/buildenv/wavetools.conf
|
source ci/docker/buildenv/wavetools.conf
|
||||||
local _base_url="https://github.com/hudson-trading/wavetools/releases/download/${WAVETOOLS_VERSION}"
|
local _base_url="https://github.com/hudson-trading/wavetools/releases/download/${WAVETOOLS_VERSION}"
|
||||||
local _platform
|
local _platform
|
||||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
if [ "$HOST_OS" = "linux" ]; then
|
||||||
_platform="linux-x86_64"
|
_platform="linux-x86_64"
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
elif [ "$HOST_OS" = "macOS" ]; then
|
||||||
_platform="macos-arm64"
|
_platform="macos-arm64"
|
||||||
elif [ "$CI_OS_NAME" = "windows" ]; then
|
|
||||||
_platform="windows-x86_64"
|
|
||||||
else
|
else
|
||||||
echo "WARNING: No wavetools binary available for CI_OS_NAME=$CI_OS_NAME, skipping"
|
echo "WARNING: No wavetools binary available for HOST_OS=$HOST_OS, skipping"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
local _tmpdir
|
local _tmpdir
|
||||||
_tmpdir=$(mktemp -d)
|
_tmpdir=$(mktemp -d)
|
||||||
local _archive="wavetools-${WAVETOOLS_VERSION}-${_platform}"
|
local _archive="wavetools-${WAVETOOLS_VERSION}-${_platform}"
|
||||||
if [ "$CI_OS_NAME" = "windows" ]; then
|
wget -q -O "${_tmpdir}/${_archive}.tar.gz" "${_base_url}/${_archive}.tar.gz"
|
||||||
wget -q -O "${_tmpdir}/${_archive}.zip" "${_base_url}/${_archive}.zip"
|
tar -xzf "${_tmpdir}/${_archive}.tar.gz" -C "${_tmpdir}"
|
||||||
unzip -o "${_tmpdir}/${_archive}.zip" -d "${_tmpdir}"
|
|
||||||
else
|
|
||||||
wget -q -O "${_tmpdir}/${_archive}.tar.gz" "${_base_url}/${_archive}.tar.gz"
|
|
||||||
tar -xzf "${_tmpdir}/${_archive}.tar.gz" -C "${_tmpdir}"
|
|
||||||
fi
|
|
||||||
sudo cp "${_tmpdir}/${_archive}/wavediff" /usr/local/bin/wavediff
|
sudo cp "${_tmpdir}/${_archive}/wavediff" /usr/local/bin/wavediff
|
||||||
rm -rf "${_tmpdir}"
|
rm -rf "${_tmpdir}"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
if [ "$STAGE" = "build" ]; then
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Dependencies of jobs in the 'build' stage, i.e.: packages required to
|
# Dependencies of jobs in the 'build' stage, i.e.: packages required to
|
||||||
# build Verilator
|
# build Verilator
|
||||||
|
|
||||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
if [ "$HOST_OS" = "linux" ]; then
|
||||||
sudo apt-get update ||
|
if [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||||
sudo apt-get update
|
PACKAGES=(
|
||||||
sudo apt-get install --yes ccache help2man libfl-dev ||
|
bear
|
||||||
sudo apt-get install --yes ccache help2man libfl-dev
|
ccache
|
||||||
if [[ ! "$CI_RUNS_ON" =~ "ubuntu-22.04" ]]; then
|
help2man
|
||||||
# Some conflict of libunwind verison on 22.04, can live without it for now
|
libfl-dev
|
||||||
sudo apt-get install --yes libjemalloc-dev ||
|
libsystemc-dev
|
||||||
sudo apt-get install --yes libjemalloc-dev
|
mold
|
||||||
fi
|
)
|
||||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
# libunwind conflict on 22.04, can live without libjemalloc there
|
||||||
if [[ ! "$CI_RUNS_ON" =~ "-riscv" ]]; then
|
if [ "$DISTRO_VERSION" != "22.04" ]; then
|
||||||
sudo apt-get install --yes libsystemc libsystemc-dev ||
|
PACKAGES+=(libjemalloc-dev)
|
||||||
sudo apt-get install --yes libsystemc libsystemc-dev
|
|
||||||
fi
|
fi
|
||||||
|
sudo apt-get update ||
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install --yes "${PACKAGES[@]}" ||
|
||||||
|
sudo apt-get install --yes "${PACKAGES[@]}"
|
||||||
fi
|
fi
|
||||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
elif [ "$HOST_OS" = "macOS" ]; then
|
||||||
sudo apt-get install --yes bear mold ||
|
PACKAGES=(
|
||||||
sudo apt-get install --yes bear mold
|
autoconf
|
||||||
fi
|
bison
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
ccache
|
||||||
|
flex
|
||||||
|
gperftools
|
||||||
|
help2man
|
||||||
|
perl
|
||||||
|
)
|
||||||
brew update ||
|
brew update ||
|
||||||
brew update
|
brew update
|
||||||
brew install ccache perl gperftools autoconf bison flex help2man ||
|
brew install "${PACKAGES[@]}" ||
|
||||||
brew install ccache perl gperftools autoconf bison flex help2man
|
brew install "${PACKAGES[@]}"
|
||||||
elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
|
||||||
sudo pkg install -y autoconf bison ccache gmake perl5
|
|
||||||
else
|
else
|
||||||
fatal "Unknown CI_OS_NAME: '$CI_OS_NAME'"
|
fatal "Unknown HOST_OS: '$HOST_OS'"
|
||||||
fi
|
fi
|
||||||
|
elif [ "$STAGE" = "test" ]; then
|
||||||
if [ -n "$CCACHE_DIR" ]; then
|
|
||||||
mkdir -p "$CCACHE_DIR"
|
|
||||||
fi
|
|
||||||
elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Dependencies of jobs in the 'test' stage, i.e.: packages required to
|
# Dependencies of jobs in the 'test' stage, i.e.: packages required to
|
||||||
# run the tests
|
# run the tests
|
||||||
|
|
||||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
if [ "$HOST_OS" = "linux" ]; then
|
||||||
sudo apt-get update ||
|
if [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||||
sudo apt-get update
|
PACKAGES=(
|
||||||
# libfl-dev needed for internal coverage's test runs
|
ccache
|
||||||
sudo apt-get install --yes gdb gtkwave lcov libfl-dev ccache jq z3 ||
|
gdb
|
||||||
sudo apt-get install --yes gdb gtkwave lcov libfl-dev ccache jq z3
|
jq
|
||||||
# Required for test_regress/t/t_dist_attributes.py
|
lcov
|
||||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
libfl-dev
|
||||||
sudo apt-get install --yes python3-clang mold ||
|
libsystemc-dev
|
||||||
sudo apt-get install --yes python3-clang mold
|
mold
|
||||||
|
python3-clang
|
||||||
|
z3
|
||||||
|
)
|
||||||
|
sudo apt-get update ||
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install --yes "${PACKAGES[@]}" ||
|
||||||
|
sudo apt-get install --yes "${PACKAGES[@]}"
|
||||||
fi
|
fi
|
||||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
elif [ "$HOST_OS" = "macOS" ]; then
|
||||||
if [[ ! "$CI_RUNS_ON" =~ "-riscv" ]]; then
|
PACKAGES=(
|
||||||
sudo apt-get install --yes libsystemc libsystemc-dev ||
|
ccache
|
||||||
sudo apt-get install --yes libsystemc libsystemc-dev
|
jq
|
||||||
fi
|
perl
|
||||||
fi
|
z3
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
)
|
||||||
|
brew update ||
|
||||||
brew update
|
brew update
|
||||||
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
|
brew install "${PACKAGES[@]}" ||
|
||||||
brew install ccache perl jq z3
|
brew install "${PACKAGES[@]}"
|
||||||
elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
|
||||||
# fst2vcd fails with "Could not open '<input file>', exiting."
|
|
||||||
sudo pkg install -y ccache gmake perl5 python3 jq z3
|
|
||||||
else
|
else
|
||||||
fatal "Unknown CI_OS_NAME: '$CI_OS_NAME'"
|
fatal "Unknown HOST_OS: '$HOST_OS'"
|
||||||
fi
|
fi
|
||||||
# Common installs
|
# Common installs
|
||||||
install-wavediff
|
install-wavediff
|
||||||
|
|
@ -146,5 +149,13 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
||||||
else
|
else
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Unknown build stage
|
# Unknown build stage
|
||||||
fatal "Unknown CI_BUILD_STAGE_NAME: '$CI_BUILD_STAGE_NAME'"
|
fatal "Unknown stage '$STAGE' (expected 'build' or 'test')"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Report where the tools we may have installed live (ok if some are missing)
|
||||||
|
set +x
|
||||||
|
echo "Tools:"
|
||||||
|
for bin in autoconf bear bison ccache flex gdb help2man jq lcov mold perl wavediff z3; do
|
||||||
|
echo -n " $bin: "
|
||||||
|
which "$bin" || echo "Not found"
|
||||||
|
done
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,14 @@ for RUN_ID in ${PR_RUN_IDS//,/ }; do
|
||||||
cat ${ARTIFACTS_DIR}/body.txt
|
cat ${ARTIFACTS_DIR}/body.txt
|
||||||
gh pr comment $(cat ${ARTIFACTS_DIR}/pr-number.txt) --body-file ${ARTIFACTS_DIR}/body.txt
|
gh pr comment $(cat ${ARTIFACTS_DIR}/pr-number.txt) --body-file ${ARTIFACTS_DIR}/body.txt
|
||||||
|
|
||||||
# Get the artifact ID
|
# Get the artifact IDs. Note there can be more than one artifact named
|
||||||
ARTIFACT_ID=$(gh api "repos/{owner}/{repo}/actions/runs/${RUN_ID}/artifacts" --jq '.artifacts[] | select(.name == "pr-notification") | .id')
|
# 'pr-notification' for a single run, as the artifacts endpoint lists
|
||||||
|
# artifacts across all run attempts, and a re-run uploads a new one while
|
||||||
|
# keeping the previous attempt's artifact.
|
||||||
|
ARTIFACT_IDS=$(gh api "repos/{owner}/{repo}/actions/runs/${RUN_ID}/artifacts" --jq '.artifacts[] | select(.name == "pr-notification") | .id')
|
||||||
|
|
||||||
# Delete it, so we only notify once
|
# Delete them all, so we only notify once
|
||||||
gh api --method DELETE "repos/{owner}/{repo}/actions/artifacts/${ARTIFACT_ID}"
|
for ARTIFACT_ID in ${ARTIFACT_IDS}; do
|
||||||
|
gh api --method DELETE "repos/{owner}/{repo}/actions/artifacts/${ARTIFACT_ID}"
|
||||||
|
done
|
||||||
done
|
done
|
||||||
|
|
|
||||||
|
|
@ -1,208 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
# DESCRIPTION: Verilator: CI main job script
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2020 Geza Lore
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# This is the main script executed in the 'script' phase by all jobs. We use a
|
|
||||||
# single script to keep the CI setting simple. We pass job parameters via
|
|
||||||
# environment variables using 'env' keys.
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
set -e
|
|
||||||
set -x
|
|
||||||
|
|
||||||
fatal() {
|
|
||||||
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
|
||||||
export MAKE=make
|
|
||||||
NPROC=$(nproc)
|
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
|
||||||
export MAKE=make
|
|
||||||
NPROC=$(sysctl -n hw.logicalcpu)
|
|
||||||
# Disable ccache, doesn't always work in GitHub Actions
|
|
||||||
export OBJCACHE=
|
|
||||||
elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
|
||||||
export MAKE=gmake
|
|
||||||
NPROC=$(sysctl -n hw.ncpu)
|
|
||||||
else
|
|
||||||
fatal "Unknown CI_OS_NAME: '$CI_OS_NAME'"
|
|
||||||
fi
|
|
||||||
NPROC=$(expr $NPROC '+' 1)
|
|
||||||
|
|
||||||
if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
|
||||||
##############################################################################
|
|
||||||
# Build verilator
|
|
||||||
|
|
||||||
autoconf
|
|
||||||
CONFIGURE_ARGS="--enable-longtests --enable-ccwarn"
|
|
||||||
if [ "$CI_DEV_ASAN" = 1 ]; then
|
|
||||||
CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-dev-asan"
|
|
||||||
CXX="$CXX -DVL_LEAK_CHECKS"
|
|
||||||
fi
|
|
||||||
if [ "$CI_DEV_GCOV" = 1 ]; then
|
|
||||||
CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-dev-gcov"
|
|
||||||
fi
|
|
||||||
./configure $CONFIGURE_ARGS --prefix="$INSTALL_DIR"
|
|
||||||
ccache -z
|
|
||||||
"$MAKE" -j "$NPROC" -k
|
|
||||||
# 22.04: ccache -s -v
|
|
||||||
ccache -s
|
|
||||||
if [ "$CI_OS_NAME" = "osx" ]; then
|
|
||||||
file bin/verilator_bin
|
|
||||||
file bin/verilator_bin_dbg
|
|
||||||
md5 bin/verilator_bin
|
|
||||||
md5 bin/verilator_bin_dbg
|
|
||||||
stat bin/verilator_bin
|
|
||||||
stat bin/verilator_bin_dbg
|
|
||||||
fi
|
|
||||||
elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|
||||||
##############################################################################
|
|
||||||
# Run tests
|
|
||||||
|
|
||||||
export VERILATOR_TEST_NO_CONTRIBUTORS=1 # Separate workflow check
|
|
||||||
export VERILATOR_TEST_NO_LINT_PY=1 # Separate workflow check
|
|
||||||
|
|
||||||
if [ "$CI_OS_NAME" = "osx" ]; then
|
|
||||||
export VERILATOR_TEST_NO_GDB=1 # Pain to get GDB to work on OS X
|
|
||||||
# TODO below may no longer be required as configure checks for -pg
|
|
||||||
export VERILATOR_TEST_NO_GPROF=1 # Apple Clang has no -pg
|
|
||||||
# export PATH="/Applications/gtkwave.app/Contents/Resources/bin:$PATH" # fst2vcd
|
|
||||||
file bin/verilator_bin
|
|
||||||
file bin/verilator_bin_dbg
|
|
||||||
md5 bin/verilator_bin
|
|
||||||
md5 bin/verilator_bin_dbg
|
|
||||||
stat bin/verilator_bin
|
|
||||||
stat bin/verilator_bin_dbg
|
|
||||||
# For some reason, the dbg exe is corrupted by this point ('file' reports
|
|
||||||
# it as data rather than a Mach-O). Unclear if this is an OS X issue or
|
|
||||||
# CI's. Remove the file and re-link...
|
|
||||||
rm bin/verilator_bin_dbg
|
|
||||||
"$MAKE" -j "$NPROC" -k
|
|
||||||
elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
|
||||||
export VERILATOR_TEST_NO_GDB=1 # Disable for now, ideally should run
|
|
||||||
# TODO below may no longer be required as configure checks for -pg
|
|
||||||
export VERILATOR_TEST_NO_GPROF=1 # gprof is a bit different on FreeBSD, disable
|
|
||||||
fi
|
|
||||||
|
|
||||||
TEST_REGRESS=test_regress
|
|
||||||
if [ "$CI_RELOC" == 1 ]; then
|
|
||||||
# Testing that the installation is relocatable.
|
|
||||||
"$MAKE" install
|
|
||||||
mkdir -p "$RELOC_DIR"
|
|
||||||
mv "$INSTALL_DIR" "$RELOC_DIR/relocated-install"
|
|
||||||
export VERILATOR_ROOT="$RELOC_DIR/relocated-install/share/verilator"
|
|
||||||
TEST_REGRESS="$RELOC_DIR/test_regress"
|
|
||||||
mv test_regress "$TEST_REGRESS"
|
|
||||||
NODIST="$RELOC_DIR/nodist"
|
|
||||||
mv nodist "$NODIST"
|
|
||||||
# Feeling brave?
|
|
||||||
find . -delete
|
|
||||||
ls -la .
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run the specified test
|
|
||||||
ccache -z
|
|
||||||
case $TESTS in
|
|
||||||
dist-vlt-0)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean" DRIVER_HASHSET=--hashset=0/4
|
|
||||||
;;
|
|
||||||
dist-vlt-1)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean" DRIVER_HASHSET=--hashset=1/4
|
|
||||||
;;
|
|
||||||
dist-vlt-2)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean" DRIVER_HASHSET=--hashset=2/4
|
|
||||||
;;
|
|
||||||
dist-vlt-3)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean" DRIVER_HASHSET=--hashset=3/4
|
|
||||||
;;
|
|
||||||
vltmt-0)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt --driver-clean" DRIVER_HASHSET=--hashset=0/3
|
|
||||||
;;
|
|
||||||
vltmt-1)
|
|
||||||
"$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-dist)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist"
|
|
||||||
;;
|
|
||||||
coverage-vlt-0)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=0/10
|
|
||||||
;;
|
|
||||||
coverage-vlt-1)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=1/10
|
|
||||||
;;
|
|
||||||
coverage-vlt-2)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=2/10
|
|
||||||
;;
|
|
||||||
coverage-vlt-3)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=3/10
|
|
||||||
;;
|
|
||||||
coverage-vlt-4)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=4/10
|
|
||||||
;;
|
|
||||||
coverage-vlt-5)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=5/10
|
|
||||||
;;
|
|
||||||
coverage-vlt-6)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=6/10
|
|
||||||
;;
|
|
||||||
coverage-vlt-7)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=7/10
|
|
||||||
;;
|
|
||||||
coverage-vlt-8)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=8/10
|
|
||||||
;;
|
|
||||||
coverage-vlt-9)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=9/10
|
|
||||||
;;
|
|
||||||
coverage-vltmt-0)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=0/10
|
|
||||||
;;
|
|
||||||
coverage-vltmt-1)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=1/10
|
|
||||||
;;
|
|
||||||
coverage-vltmt-2)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=2/10
|
|
||||||
;;
|
|
||||||
coverage-vltmt-3)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=3/10
|
|
||||||
;;
|
|
||||||
coverage-vltmt-4)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=4/10
|
|
||||||
;;
|
|
||||||
coverage-vltmt-5)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=5/10
|
|
||||||
;;
|
|
||||||
coverage-vltmt-6)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=6/10
|
|
||||||
;;
|
|
||||||
coverage-vltmt-7)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=7/10
|
|
||||||
;;
|
|
||||||
coverage-vltmt-8)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=8/10
|
|
||||||
;;
|
|
||||||
coverage-vltmt-9)
|
|
||||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=9/10
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
fatal "Unknown TESTS: $TESTS"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# To see load average (1 minute, 5 minute, 15 minute)
|
|
||||||
uptime
|
|
||||||
# 22.04: ccache -s -v
|
|
||||||
ccache -s
|
|
||||||
|
|
||||||
else
|
|
||||||
##############################################################################
|
|
||||||
# Unknown build stage
|
|
||||||
fatal "Unknown CI_BUILD_STAGE_NAME: '$CI_BUILD_STAGE_NAME'"
|
|
||||||
fi
|
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# DESCRIPTION: Verilator: CI test job script
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Executed in the 'test' stage.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# Destructive to the checkout (runs 'find . -delete'); never run locally
|
||||||
|
if [ "$GITHUB_ACTIONS" != "true" ]; then
|
||||||
|
echo "ERROR: $(basename "$0") must only be run in GitHub Actions CI" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
source "$(dirname "$0")/ci-common.bash"
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Parse arguments
|
||||||
|
|
||||||
|
OPT_RELOC=
|
||||||
|
OPT_SUITE=
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--reloc)
|
||||||
|
[ $# -ge 2 ] || fatal "--reloc requires an argument"
|
||||||
|
OPT_RELOC="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--suite)
|
||||||
|
[ $# -ge 2 ] || fatal "--suite requires an argument"
|
||||||
|
OPT_SUITE="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*) fatal "Unknown option: '$1'" ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -n "$OPT_SUITE" ] || fatal "--suite is required"
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Run tests
|
||||||
|
|
||||||
|
export VERILATOR_TEST_NO_CONTRIBUTORS=1 # Separate workflow check
|
||||||
|
export VERILATOR_TEST_NO_LINT_PY=1 # Separate workflow check
|
||||||
|
|
||||||
|
if [ "$HOST_OS" = "macOS" ]; then
|
||||||
|
export VERILATOR_TEST_NO_GDB=1 # No working GDB on macOS
|
||||||
|
fi
|
||||||
|
|
||||||
|
TEST_REGRESS=test_regress
|
||||||
|
if [ -n "$OPT_RELOC" ]; then
|
||||||
|
# Testing that the installation is relocatable.
|
||||||
|
"$MAKE" install
|
||||||
|
# Install prefix, as configured into the Makefile at build time
|
||||||
|
INSTALL_DIR=$(sed -n 's/^prefix = //p' Makefile)
|
||||||
|
mkdir -p "$OPT_RELOC"
|
||||||
|
mv "$INSTALL_DIR" "$OPT_RELOC/relocated-install"
|
||||||
|
export VERILATOR_ROOT="$OPT_RELOC/relocated-install/share/verilator"
|
||||||
|
TEST_REGRESS="$OPT_RELOC/test_regress"
|
||||||
|
mv test_regress "$TEST_REGRESS"
|
||||||
|
NODIST="$OPT_RELOC/nodist"
|
||||||
|
mv nodist "$NODIST"
|
||||||
|
# Delete everything else
|
||||||
|
find . -delete
|
||||||
|
ls -la .
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the specified suite
|
||||||
|
ccache -z
|
||||||
|
case $OPT_SUITE in
|
||||||
|
dist-vlt-0)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean" DRIVER_HASHSET=--hashset=0/4
|
||||||
|
;;
|
||||||
|
dist-vlt-1)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean" DRIVER_HASHSET=--hashset=1/4
|
||||||
|
;;
|
||||||
|
dist-vlt-2)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean" DRIVER_HASHSET=--hashset=2/4
|
||||||
|
;;
|
||||||
|
dist-vlt-3)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt --driver-clean" DRIVER_HASHSET=--hashset=3/4
|
||||||
|
;;
|
||||||
|
vltmt-0)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt --driver-clean" DRIVER_HASHSET=--hashset=0/3
|
||||||
|
;;
|
||||||
|
vltmt-1)
|
||||||
|
"$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-dist)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist"
|
||||||
|
;;
|
||||||
|
coverage-vlt-0)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=0/10
|
||||||
|
;;
|
||||||
|
coverage-vlt-1)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=1/10
|
||||||
|
;;
|
||||||
|
coverage-vlt-2)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=2/10
|
||||||
|
;;
|
||||||
|
coverage-vlt-3)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=3/10
|
||||||
|
;;
|
||||||
|
coverage-vlt-4)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=4/10
|
||||||
|
;;
|
||||||
|
coverage-vlt-5)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=5/10
|
||||||
|
;;
|
||||||
|
coverage-vlt-6)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=6/10
|
||||||
|
;;
|
||||||
|
coverage-vlt-7)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=7/10
|
||||||
|
;;
|
||||||
|
coverage-vlt-8)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=8/10
|
||||||
|
;;
|
||||||
|
coverage-vlt-9)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt" DRIVER_HASHSET=--hashset=9/10
|
||||||
|
;;
|
||||||
|
coverage-vltmt-0)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=0/10
|
||||||
|
;;
|
||||||
|
coverage-vltmt-1)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=1/10
|
||||||
|
;;
|
||||||
|
coverage-vltmt-2)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=2/10
|
||||||
|
;;
|
||||||
|
coverage-vltmt-3)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=3/10
|
||||||
|
;;
|
||||||
|
coverage-vltmt-4)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=4/10
|
||||||
|
;;
|
||||||
|
coverage-vltmt-5)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=5/10
|
||||||
|
;;
|
||||||
|
coverage-vltmt-6)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=6/10
|
||||||
|
;;
|
||||||
|
coverage-vltmt-7)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=7/10
|
||||||
|
;;
|
||||||
|
coverage-vltmt-8)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=8/10
|
||||||
|
;;
|
||||||
|
coverage-vltmt-9)
|
||||||
|
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=9/10
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
fatal "Unknown suite: $OPT_SUITE"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
ccache -svv
|
||||||
|
uptime # To see load average
|
||||||
|
|
@ -6,19 +6,33 @@
|
||||||
|
|
||||||
Set-PSDebug -Trace 1
|
Set-PSDebug -Trace 1
|
||||||
|
|
||||||
if (-Not (Test-Path $PWD/../.ccache/win_bison.exe)) {
|
$NPROC = $env:NUMBER_OF_PROCESSORS
|
||||||
|
|
||||||
|
# Absolute path for the win_flex_bison install; CMake reads this from the environment
|
||||||
|
$env:WIN_FLEX_BISON = "$(Resolve-Path ..)/win_flex_bison"
|
||||||
|
|
||||||
|
if (-Not (Test-Path $env:WIN_FLEX_BISON/win_bison.exe)) {
|
||||||
git clone --depth 1 https://github.com/lexxmark/winflexbison
|
git clone --depth 1 https://github.com/lexxmark/winflexbison
|
||||||
cd winflexbison
|
cd winflexbison
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. --install-prefix $PWD/../../../.ccache
|
cmake .. --install-prefix $env:WIN_FLEX_BISON
|
||||||
cmake --build . --config Release -j 3
|
cmake --build . --config Release -j $NPROC
|
||||||
cmake --install . --prefix $PWD/../../../.ccache
|
cmake --install . --prefix $env:WIN_FLEX_BISON
|
||||||
cd ../..
|
cd ../..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Enter the MSVC developer shell so cl/link are on PATH for the Ninja generator
|
||||||
|
$VsPath = & "${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe" -latest -products * -property installationPath
|
||||||
|
Import-Module "$VsPath/Common7/Tools/Microsoft.VisualStudio.DevShell.dll"
|
||||||
|
Enter-VsDevShell -VsInstallPath $VsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64"
|
||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. --install-prefix $PWD/../install
|
# Ninja saturates all cores; the MSBuild generator only parallelizes across
|
||||||
cmake --build . --config Release -j 3
|
# projects and Verilator is a single target, so it compiles serially. /Od skips
|
||||||
|
# optimization: this job only checks that Verilator builds and can verilate an
|
||||||
|
# example, so an optimized binary is not needed and the codegen time dominates.
|
||||||
|
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release --install-prefix $PWD/../install "-DCMAKE_CXX_FLAGS_RELEASE=/Od /DNDEBUG"
|
||||||
|
cmake --build .
|
||||||
cmake --install . --prefix $PWD/../install
|
cmake --install . --prefix $PWD/../install
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,17 @@
|
||||||
|
|
||||||
Set-PSDebug -Trace 1
|
Set-PSDebug -Trace 1
|
||||||
|
|
||||||
|
$NPROC = $env:NUMBER_OF_PROCESSORS
|
||||||
|
|
||||||
cd install
|
cd install
|
||||||
$Env:VERILATOR_ROOT=$PWD
|
$Env:VERILATOR_ROOT=$PWD
|
||||||
cd examples/cmake_tracing_c
|
cd examples/cmake_tracing_c
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
# /Od skips optimization; this only checks the example verilates and builds, so
|
||||||
cmake --build . --config Release -j 3
|
# an optimized binary is not needed (see ci-win-compile.ps1).
|
||||||
|
cmake .. "-DCMAKE_CXX_FLAGS_RELEASE=/Od /DNDEBUG"
|
||||||
|
cmake --build . --config Release -j $NPROC
|
||||||
|
|
||||||
# TODO put this back in, see issue# 5163
|
# TODO put this back in, see issue# 5163
|
||||||
# Release/example.exe
|
# Release/example.exe
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _verilator build docker container:
|
.. _verilator build docker container:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
Verilator Executable Docker Container
|
Verilator Executable Docker Container
|
||||||
=====================================
|
=====================================
|
||||||
|
|
|
||||||
30
configure.ac
30
configure.ac
|
|
@ -12,7 +12,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.049 devel],
|
AC_INIT([Verilator],[5.051 devel],
|
||||||
[https://verilator.org],
|
[https://verilator.org],
|
||||||
[verilator],[https://verilator.org])
|
[verilator],[https://verilator.org])
|
||||||
|
|
||||||
|
|
@ -589,6 +589,34 @@ m4_foreach([ldflag], [
|
||||||
AC_SUBST(CFG_LDLIBS_THREADS)
|
AC_SUBST(CFG_LDLIBS_THREADS)
|
||||||
AC_SUBST(CFG_LDFLAGS_THREADS_CMAKE)
|
AC_SUBST(CFG_LDFLAGS_THREADS_CMAKE)
|
||||||
|
|
||||||
|
# Find link flags for runtime VPI library loading (+verilator+vpi+<lib>).
|
||||||
|
# The model executable must export its VPI symbols so the dlopen'd library can
|
||||||
|
# resolve them: -rdynamic (GNU ld) or -Wl,-export_dynamic (Darwin); the first the
|
||||||
|
# linker accepts wins. -ldl provides dlopen/dlsym where it is a separate library.
|
||||||
|
_MY_LDLIBS_CHECK_SET(CFG_LDFLAGS_DYNAMIC, -rdynamic)
|
||||||
|
# -Wl,-export_dynamic contains a comma, so probe it directly rather than through
|
||||||
|
# the _MY_LDLIBS_CHECK_* macros (which re-expand their flag argument unquoted).
|
||||||
|
if test "$CFG_LDFLAGS_DYNAMIC" = ""; then
|
||||||
|
ACO_SAVE_LIBS="$LIBS"
|
||||||
|
LIBS="$LIBS -Wl,-export_dynamic"
|
||||||
|
AC_MSG_CHECKING([whether $CXX linker accepts -Wl,-export_dynamic])
|
||||||
|
AC_LINK_IFELSE(
|
||||||
|
[AC_LANG_PROGRAM([[]])],
|
||||||
|
[_my_result=yes
|
||||||
|
if test -s conftest.err; then
|
||||||
|
if grep -e "-export_dynamic" conftest.err >/dev/null; then
|
||||||
|
_my_result=no
|
||||||
|
fi
|
||||||
|
fi],
|
||||||
|
[_my_result=no])
|
||||||
|
AC_MSG_RESULT($_my_result)
|
||||||
|
LIBS="$ACO_SAVE_LIBS"
|
||||||
|
if test "$_my_result" = "yes"; then CFG_LDFLAGS_DYNAMIC="-Wl,-export_dynamic"; fi
|
||||||
|
fi
|
||||||
|
AC_SUBST(CFG_LDFLAGS_DYNAMIC)
|
||||||
|
_MY_LDLIBS_CHECK_OPT(CFG_LDLIBS_DYNAMIC, -ldl)
|
||||||
|
AC_SUBST(CFG_LDLIBS_DYNAMIC)
|
||||||
|
|
||||||
# If 'mold' is installed, use it to link for faster buildtimes
|
# If 'mold' is installed, use it to link for faster buildtimes
|
||||||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -fuse-ld=mold)
|
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -fuse-ld=mold)
|
||||||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_VERILATED, -fuse-ld=mold)
|
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_VERILATED, -fuse-ld=mold)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<!-- DESCRIPTION: Verilator: docs/ guidelines for AI coding agents
|
||||||
|
SPDX-FileCopyrightText: 2026-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -->
|
||||||
|
|
||||||
|
# docs/ Guidelines -- Verilator documentation (\*.rst)
|
||||||
|
|
||||||
|
When to check: before editing anything under `docs/`.
|
||||||
|
Read the repository-root [AGENTS.md](../AGENTS.md) first for process and cross-cutting rules.
|
||||||
|
|
||||||
|
## Writing rules
|
||||||
|
|
||||||
|
- Rewrap paragraphs after editing -- keep consistent line length in `*.rst` files.
|
||||||
|
|
||||||
|
- Document only stable, implemented features -- never planned or in-development capabilities; prevents user confusion and support burden.
|
||||||
|
|
||||||
|
- Explain WHAT and WHEN, not HOW -- conceptual purpose and practical use cases over implementation mechanics; describe behavior ("optimized as pure", not "treated as pure") and clarify ambiguous referents ("in the internals of Verilator").
|
||||||
|
|
||||||
|
- Keep terminology consistent -- one term per concept; update docs when renaming code constructs; spell out full terms, avoiding abbreviations like "sim"/"sims".
|
||||||
|
|
||||||
|
- Use "how many" for countable nouns (threads, tasks, workers) and "how much" for uncountable quantities.
|
||||||
|
|
||||||
|
- Mark internal or experimental features "for internal use only" -- prevents user dependence and forced deprecation cycles later.
|
||||||
|
|
||||||
|
- Use specific IEEE references: `IEEE {number}-{year}` plus the section (e.g. `Annex I`) -- a vague "IEEE spec requires" is unverifiable.
|
||||||
|
|
||||||
|
- Document all flags with descriptions, not just syntax.
|
||||||
|
|
||||||
|
## reStructuredText mechanics
|
||||||
|
|
||||||
|
- Use the `:vlopt:` role for Verilator option references -- makes cross-references clickable and consistent.
|
||||||
|
|
||||||
|
- Escape angle brackets (`\<`, `\>`) in link targets -- prevents broken links to command-line options.
|
||||||
|
|
||||||
|
- Generate documentation examples with `test.extract` from `test_regress` test files -- examples stay synced with actually tested behavior.
|
||||||
|
|
||||||
|
## Hard constraint
|
||||||
|
|
||||||
|
- Never edit `docs/CONTRIBUTORS` -- only humans may, after reading and agreeing to its statement; remind the user instead.
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
Contributing to Verilator
|
Contributing to Verilator
|
||||||
=========================
|
=========================
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
||||||
|
|
||||||
404allen404
|
404allen404
|
||||||
Adam Bagley
|
Adam Bagley
|
||||||
|
Adam Kostrzewski
|
||||||
Adrian Sampson
|
Adrian Sampson
|
||||||
Adrien Le Masle
|
Adrien Le Masle
|
||||||
أحمد المحمودي (Ahmed El-Mahmoudy)
|
أحمد المحمودي (Ahmed El-Mahmoudy)
|
||||||
|
|
@ -60,6 +61,7 @@ David Turner
|
||||||
Dercury
|
Dercury
|
||||||
Diego Roux
|
Diego Roux
|
||||||
Dominick Grochowina
|
Dominick Grochowina
|
||||||
|
Dragon-Git
|
||||||
Don Williamson
|
Don Williamson
|
||||||
Drew Ranck
|
Drew Ranck
|
||||||
Drew Taussig
|
Drew Taussig
|
||||||
|
|
@ -68,6 +70,7 @@ Edgar E. Iglesias
|
||||||
Eric Mejdrich
|
Eric Mejdrich
|
||||||
Eric Müller
|
Eric Müller
|
||||||
Eric Rippey
|
Eric Rippey
|
||||||
|
Eryk Szpotański
|
||||||
Eunseo Song
|
Eunseo Song
|
||||||
Ethan Sifferman
|
Ethan Sifferman
|
||||||
Eyck Jentzsch
|
Eyck Jentzsch
|
||||||
|
|
@ -145,6 +148,7 @@ Jose Loyola
|
||||||
Josep Sans
|
Josep Sans
|
||||||
Joseph Nwabueze
|
Joseph Nwabueze
|
||||||
Josh Redford
|
Josh Redford
|
||||||
|
Joshua Leahy
|
||||||
Julian Carrier
|
Julian Carrier
|
||||||
Julian Daube
|
Julian Daube
|
||||||
Julie Schwartz
|
Julie Schwartz
|
||||||
|
|
@ -158,6 +162,7 @@ Kefa Chen
|
||||||
Keith Colbert
|
Keith Colbert
|
||||||
Kevin Kiningham
|
Kevin Kiningham
|
||||||
Kevin Nygaard
|
Kevin Nygaard
|
||||||
|
Kornel Uriasz
|
||||||
Kritik Bhimani
|
Kritik Bhimani
|
||||||
Krzysztof Bieganski
|
Krzysztof Bieganski
|
||||||
Krzysztof Boronski
|
Krzysztof Boronski
|
||||||
|
|
@ -250,10 +255,12 @@ Rowan Goemans
|
||||||
Rupert Swarbrick
|
Rupert Swarbrick
|
||||||
Ryan Ziegler
|
Ryan Ziegler
|
||||||
Ryszard Rozak
|
Ryszard Rozak
|
||||||
|
Saksham Gupta
|
||||||
Samuel Riedel
|
Samuel Riedel
|
||||||
Sean Cross
|
Sean Cross
|
||||||
Sebastien Van Cauwenberghe
|
Sebastien Van Cauwenberghe
|
||||||
Secturion
|
Secturion
|
||||||
|
Sergey Chusov
|
||||||
Sergey Fedorov
|
Sergey Fedorov
|
||||||
Sergi Granell
|
Sergi Granell
|
||||||
Seth Pellegrino
|
Seth Pellegrino
|
||||||
|
|
@ -270,12 +277,14 @@ Teng Huang
|
||||||
Thomas Aldrian
|
Thomas Aldrian
|
||||||
Thomas Brown
|
Thomas Brown
|
||||||
Thomas Dybdahl Ahle
|
Thomas Dybdahl Ahle
|
||||||
|
Thomas Santerre
|
||||||
Tim Hutt
|
Tim Hutt
|
||||||
Tim Snyder
|
Tim Snyder
|
||||||
Tobias Jensen
|
Tobias Jensen
|
||||||
Tobias Rosenkranz
|
Tobias Rosenkranz
|
||||||
Tobias Wölfel
|
Tobias Wölfel
|
||||||
Todd Strader
|
Todd Strader
|
||||||
|
Tom Jackson
|
||||||
Tom Manner
|
Tom Manner
|
||||||
Tomasz Gorochowik
|
Tomasz Gorochowik
|
||||||
Topa Topino
|
Topa Topino
|
||||||
|
|
@ -297,6 +306,7 @@ Vito Gamberini
|
||||||
Wei-Lun Chiu
|
Wei-Lun Chiu
|
||||||
William D. Jones
|
William D. Jones
|
||||||
Wilson Snyder
|
Wilson Snyder
|
||||||
|
Wolfgang Mayerwieser
|
||||||
Xi Zhang
|
Xi Zhang
|
||||||
Yan Xu
|
Yan Xu
|
||||||
Yangyu Chen
|
Yangyu Chen
|
||||||
|
|
@ -326,3 +336,4 @@ Yogish Sekhar
|
||||||
Zubin Jain
|
Zubin Jain
|
||||||
Muzaffer Kal
|
Muzaffer Kal
|
||||||
Yilin Li
|
Yilin Li
|
||||||
|
Shashvat Prabhu
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
Verilator Documentation
|
Verilator Documentation
|
||||||
=======================
|
=======================
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
.. comment: generated by t_finaldly_bad
|
||||||
|
.. code-block:: sv
|
||||||
|
:linenos:
|
||||||
|
:emphasize-lines: 2
|
||||||
|
|
||||||
|
bit foo;
|
||||||
|
final foo <= 1; // <--- Error
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
.. comment: generated by t_finaldly_bad
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
%Error-FINALDLY: example.v:1:13 Non-blocking assignment '<=' in final block
|
||||||
|
9 | final foo <= 1;
|
||||||
|
| ^~
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
****************
|
****************
|
||||||
Revision History
|
Revision History
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _connecting:
|
.. _connecting:
|
||||||
|
|
||||||
|
|
@ -28,13 +29,13 @@ The generated model class file manages all internal state required by the
|
||||||
model, and exposes the following interface that allows interaction with the
|
model, and exposes the following interface that allows interaction with the
|
||||||
model:
|
model:
|
||||||
|
|
||||||
* Top level IO ports are exposed as references to the appropriate internal
|
- Top level IO ports are exposed as references to the appropriate internal
|
||||||
equivalents.
|
equivalents.
|
||||||
|
|
||||||
* Public top level module instances are exposed as pointers to allow access
|
- Public top level module instances are exposed as pointers to allow access
|
||||||
to ``/* verilator public */`` items.
|
to ``/* verilator public */`` items.
|
||||||
|
|
||||||
* The root of the design hierarchy (as in SystemVerilog ``$root``) is
|
- The root of the design hierarchy (as in SystemVerilog ``$root``) is
|
||||||
exposed via the ``rootp`` member pointer to allow access to model
|
exposed via the ``rootp`` member pointer to allow access to model
|
||||||
internals, including ``/* verilator public_flat */`` items.
|
internals, including ``/* verilator public_flat */`` items.
|
||||||
|
|
||||||
|
|
@ -58,22 +59,22 @@ This means that user code that accesses internal signals in the model
|
||||||
(likely including ``/* verilator public_flat */`` signals, as they are
|
(likely including ``/* verilator public_flat */`` signals, as they are
|
||||||
often inlined into the root scope) will need to be updated as follows:
|
often inlined into the root scope) will need to be updated as follows:
|
||||||
|
|
||||||
* No change required for accessing top level IO signals. These are directly
|
- No change required for accessing top level IO signals. These are directly
|
||||||
accessible in the model class via references.
|
accessible in the model class via references.
|
||||||
|
|
||||||
* No change required for accessing ``/* verilator public */`` items. These
|
- No change required for accessing ``/* verilator public */`` items. These
|
||||||
are directly accessible via sub-module pointers in the model class.
|
are directly accessible via sub-module pointers in the model class.
|
||||||
|
|
||||||
* Accessing any other internal members, including
|
- Accessing any other internal members, including ``/* verilator
|
||||||
``/* verilator public_flat */`` items requires the following changes:
|
public_flat */`` items requires the following changes:
|
||||||
|
|
||||||
* Additionally include :file:`{prefix}___024root.h`. This header defines
|
- Additionally include :file:`{prefix}___024root.h`. This header defines
|
||||||
type of the ``rootp`` pointer within the model class. Note the
|
type of the ``rootp`` pointer within the model class. Note the
|
||||||
``__024`` substring is the Verilator escape sequence for the ``$``
|
``__024`` substring is the Verilator escape sequence for the ``$``
|
||||||
character, i.e.: ``rootp`` points to the Verilated SystemVerilog
|
character, i.e.: ``rootp`` points to the Verilated SystemVerilog
|
||||||
``$root`` scope.
|
``$root`` scope.
|
||||||
|
|
||||||
* Replace ``modelp->internal->member`` references with
|
- Replace ``modelp->internal->member`` references with
|
||||||
``modelp->rootp->internal->member`` references, which contain one
|
``modelp->rootp->internal->member`` references, which contain one
|
||||||
additional indirection via the ``rootp`` pointer.
|
additional indirection via the ``rootp`` pointer.
|
||||||
|
|
||||||
|
|
@ -210,9 +211,9 @@ Verilator extends the DPI format to allow using the same scheme to
|
||||||
efficiently add system functions. Use a dollar-sign prefixed system
|
efficiently add system functions. Use a dollar-sign prefixed system
|
||||||
function name for the import, but note it must be escaped.
|
function name for the import, but note it must be escaped.
|
||||||
|
|
||||||
.. code-block:: sv
|
.. code-block::
|
||||||
|
|
||||||
export "DPI-C" function integer \$myRand;
|
import "DPI-C" function integer \$myRand;
|
||||||
|
|
||||||
initial $display("myRand=%d", $myRand());
|
initial $display("myRand=%d", $myRand());
|
||||||
|
|
||||||
|
|
@ -502,9 +503,9 @@ described above is just a wrapper which calls these two functions.
|
||||||
3. If using delays and :vlopt:`--timing`, there are two additional methods
|
3. If using delays and :vlopt:`--timing`, there are two additional methods
|
||||||
the user should call:
|
the user should call:
|
||||||
|
|
||||||
* ``designp->eventsPending()``, which returns ``true`` if there are any
|
- ``designp->eventsPending()``, which returns ``true`` if there are any
|
||||||
delayed events pending,
|
delayed events pending,
|
||||||
* ``designp->nextTimeSlot()``, which returns the simulation time of the
|
- ``designp->nextTimeSlot()``, which returns the simulation time of the
|
||||||
next delayed event. This method can only be called if
|
next delayed event. This method can only be called if
|
||||||
``designp->eventsPending()`` returned ``true``.
|
``designp->eventsPending()`` returned ``true``.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
*******************************
|
*******************************
|
||||||
Contributing and Reporting Bugs
|
Contributing and Reporting Bugs
|
||||||
|
|
@ -86,7 +87,8 @@ Please refer to `sv-bugpoint README
|
||||||
<https://github.com/antmicro/sv-bugpoint/blob/main/README.md>`_ for more
|
<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
|
||||||
|
============
|
||||||
|
|
||||||
.. include:: ../CONTRIBUTING.rst
|
.. include:: ../CONTRIBUTING.rst
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
************************
|
************************
|
||||||
Contributors and Origins
|
Contributors and Origins
|
||||||
|
|
@ -29,10 +30,10 @@ Alliance <https://chipsalliance.org>`_, and `Antmicro Ltd
|
||||||
Previous major corporate sponsors of Verilator, by providing significant
|
Previous major corporate sponsors of Verilator, by providing significant
|
||||||
contributions of time or funds include: Antmicro Ltd., Atmel Corporation,
|
contributions of time or funds include: Antmicro Ltd., Atmel Corporation,
|
||||||
Compaq Corporation, Digital Equipment Corporation, Embecosm Ltd., Fractile
|
Compaq Corporation, Digital Equipment Corporation, Embecosm Ltd., Fractile
|
||||||
Ltd., Hicamp Systems, Intel Corporation, Marvell Inc., Mindspeed Technologies
|
Ltd., Hicamp Systems, Intel Corporation, Marvell Inc., Mindspeed
|
||||||
Inc., MicroTune Inc., picoChip Designs Ltd., Sun Microsystems Inc., Nauticus
|
Technologies Inc., MicroTune Inc., picoChip Designs Ltd., Sun Microsystems
|
||||||
Networks Inc., SiCortex Inc, Shunyao CAD, Tenstorrent USA, Inc. and Western
|
Inc., Nauticus Networks Inc., SiCortex Inc, Shunyao CAD, Tenstorrent USA,
|
||||||
Digital Inc.
|
Inc. and Western Digital Inc.
|
||||||
|
|
||||||
The contributors of major functionality are: Jeremy Bennett, Krzysztof
|
The contributors of major functionality are: Jeremy Bennett, Krzysztof
|
||||||
Bieganski, Byron Bradley, Lane Brooks, John Coiner, Duane Galbi, Arkadiusz
|
Bieganski, Byron Bradley, Lane Brooks, John Coiner, Duane Galbi, Arkadiusz
|
||||||
|
|
@ -142,18 +143,18 @@ Krzysztof Obłonczek, Danny Oler, Andreas Olofsson, Baltazar Ortiz,
|
||||||
Aleksander Osman, Don Owen, Tim Paine, Deepa Palaniappan, James Pallister,
|
Aleksander Osman, Don Owen, Tim Paine, Deepa Palaniappan, James Pallister,
|
||||||
Vassilis Papaefstathiou, Sanggyu Park, Brad Parker, Risto Pejašinović, Seth
|
Vassilis Papaefstathiou, Sanggyu Park, Brad Parker, Risto Pejašinović, Seth
|
||||||
Pellegrino, Joel Peltonen, Morten Borup Petersen, Dan Petrisko, Thanh Tung
|
Pellegrino, Joel Peltonen, Morten Borup Petersen, Dan Petrisko, Thanh Tung
|
||||||
Pham, Wesley Piard, Maciej Piechotka, David Pierce, Cody Piersall,
|
Pham, Wesley Piard, Maciej Piechotka, David Pierce, Cody Piersall, T.
|
||||||
T. Platz, Michael Platzer, Dominic Plunkett, Nolan Poe, Tuomas Poikela,
|
Platz, Michael Platzer, Dominic Plunkett, Nolan Poe, Tuomas Poikela, George
|
||||||
George Polack, David Poole, Michael Popoloski, Roman Popov, Aylon Chaim
|
Polack, David Poole, Michael Popoloski, Roman Popov, Aylon Chaim Porat,
|
||||||
Porat, Oron Port, Rich Porter, Rick Porter, Stefan Post, Niranjan Prabhu,
|
Oron Port, Rich Porter, Rick Porter, Stefan Post, Niranjan Prabhu, Damien
|
||||||
Damien Pretet, Harald Pretl, Bill Pringlemeir, Usha Priyadharshini, Mark
|
Pretet, Harald Pretl, Bill Pringlemeir, Usha Priyadharshini, Mark Jackson
|
||||||
Jackson Pulver, Prateek Puri, Nikolay Puzanov, Han Qi, Jiacheng Qian,
|
Pulver, Prateek Puri, Nikolay Puzanov, Han Qi, Jiacheng Qian, Marshal Qiao,
|
||||||
Marshal Qiao, Raynard Qiao, Yujia Qiao, Jasen Qin, Frank Qiu, Nandu Raj,
|
Raynard Qiao, Yujia Qiao, Jasen Qin, Frank Qiu, Nandu Raj, Kamil Rakoczy,
|
||||||
Kamil Rakoczy, Danilo Ramos, Drew Ranck, Chris Randall, Anton Rapp, Josh
|
Danilo Ramos, Drew Ranck, Chris Randall, Anton Rapp, Josh Redford, Odd
|
||||||
Redford, Odd Magne Reitan, Frédéric Requin, Wajahat Riaz, Dustin Richmond,
|
Magne Reitan, Frédéric Requin, Wajahat Riaz, Dustin Richmond, Samuel
|
||||||
Samuel Riedel, Alberto Del Rio, Eric Rippey, Narcis Rodas, Oleg Rodionov,
|
Riedel, Alberto Del Rio, Eric Rippey, Narcis Rodas, Oleg Rodionov, Ludwig
|
||||||
Ludwig Rogiers, Paul Rolfe, Michail Rontionov, Arjen Roodselaar, Arthur
|
Rogiers, Paul Rolfe, Michail Rontionov, Arjen Roodselaar, Arthur Rosa,
|
||||||
Rosa, Tobias Rosenkranz, Yernagula Roshit, Diego Roux, Ryszard Rozak, Dan
|
Tobias Rosenkranz, Yernagula Roshit, Diego Roux, Ryszard Rozak, Dan
|
||||||
Ruelas-Petrisko, Luca Rufer, Huang Rui, Graham Rushton, Jan Egil Ruud,
|
Ruelas-Petrisko, Luca Rufer, Huang Rui, Graham Rushton, Jan Egil Ruud,
|
||||||
Denis Rystsov, Pawel Sagan, Robert Sammelson, Adrian Sampson, John
|
Denis Rystsov, Pawel Sagan, Robert Sammelson, Adrian Sampson, John
|
||||||
Sanguinetti, Josep Sans, Dave Sargeant, Luca Sasselli, Philippe Sauter,
|
Sanguinetti, Josep Sans, Dave Sargeant, Luca Sasselli, Philippe Sauter,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _verilator control files:
|
.. _verilator control files:
|
||||||
|
|
||||||
|
|
@ -187,6 +188,10 @@ The grammar of control commands is as follows:
|
||||||
|
|
||||||
.. option:: isolate_assignments -module "<modulename>" [-task "<taskname>"] -var "<signame>"
|
.. option:: isolate_assignments -module "<modulename>" [-task "<taskname>"] -var "<signame>"
|
||||||
|
|
||||||
|
Deprecated and has no effect (ignored).
|
||||||
|
|
||||||
|
In versions before 5.050:
|
||||||
|
|
||||||
Used to indicate that the assignments to this signal in any blocks
|
Used to indicate that the assignments to this signal in any blocks
|
||||||
should be isolated into new blocks. Same as
|
should be isolated into new blocks. Same as
|
||||||
:option:`/*verilator&32;isolate_assignments*/` metacomment.
|
:option:`/*verilator&32;isolate_assignments*/` metacomment.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
*********
|
*********
|
||||||
Copyright
|
Copyright
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
Deprecations
|
Deprecations
|
||||||
============
|
============
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _environment:
|
.. _environment:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _example create-binary execution:
|
.. _example create-binary execution:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _example c++ execution:
|
.. _example c++ execution:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
First you need Verilator installed, see :ref:`Installation`. In brief, if
|
First you need Verilator installed, see :ref:`Installation`. In brief, if
|
||||||
you installed Verilator using the package manager of your operating system,
|
you installed Verilator using the package manager of your operating system,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _examples in the distribution:
|
.. _examples in the distribution:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _example systemc execution:
|
.. _example systemc execution:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _examples:
|
.. _examples:
|
||||||
|
|
||||||
|
|
@ -9,10 +10,10 @@ Examples
|
||||||
|
|
||||||
This section covers the following examples:
|
This section covers the following examples:
|
||||||
|
|
||||||
* :ref:`Example Create-Binary Execution`
|
- :ref:`Example Create-Binary Execution`
|
||||||
* :ref:`Example C++ Execution`
|
- :ref:`Example C++ Execution`
|
||||||
* :ref:`Example SystemC Execution`
|
- :ref:`Example SystemC Execution`
|
||||||
* :ref:`Examples in the Distribution`
|
- :ref:`Examples in the Distribution`
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _simulation runtime arguments:
|
.. _simulation runtime arguments:
|
||||||
|
|
||||||
|
|
@ -50,8 +51,8 @@ Options:
|
||||||
|
|
||||||
.. option:: +verilator+log+file+<filename>
|
.. option:: +verilator+log+file+<filename>
|
||||||
|
|
||||||
Log all stdout and stderr to the specified output filename. If not specified
|
Log all stdout and stderr to the specified output filename. If not specified
|
||||||
the normal stdout/stderr streams are used.
|
the normal stdout/stderr streams are used.
|
||||||
|
|
||||||
.. option:: +verilator+noassert
|
.. option:: +verilator+noassert
|
||||||
|
|
||||||
|
|
@ -138,6 +139,20 @@ Options:
|
||||||
|
|
||||||
Displays program version and exits.
|
Displays program version and exits.
|
||||||
|
|
||||||
|
.. option:: +verilator+vpi+<library>[:<bootstrap>]
|
||||||
|
|
||||||
|
Load a VPI shared library before simulation starts. Only available when the
|
||||||
|
model was Verilated with :vlopt:`--vpi` and :vlopt:`--main` (or
|
||||||
|
:vlopt:`--binary`). ``<library>`` is the path to the shared library. If
|
||||||
|
``:<bootstrap>`` is given, that named no-argument function is called;
|
||||||
|
otherwise the library's ``vlog_startup_routines`` array (IEEE 1800 38.37.2) is
|
||||||
|
invoked. May be repeated to load multiple libraries.
|
||||||
|
|
||||||
|
Runtime loading is supported on POSIX platforms only (it relies on the
|
||||||
|
executable exporting its VPI symbols to the loaded library); on Windows the
|
||||||
|
argument is rejected and the VPI code must instead be statically linked
|
||||||
|
into the model.
|
||||||
|
|
||||||
.. option:: +verilator+wno+unsatconstr+<value>
|
.. option:: +verilator+wno+unsatconstr+<value>
|
||||||
|
|
||||||
Disable unsatisfied constraint warnings at simulation runtime. When set to
|
Disable unsatisfied constraint warnings at simulation runtime. When set to
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
===================
|
===================
|
||||||
verilator Arguments
|
verilator Arguments
|
||||||
|
|
@ -490,6 +491,10 @@ Summary:
|
||||||
Rarely needed - for developer use. Enable all dumping in the given
|
Rarely needed - for developer use. Enable all dumping in the given
|
||||||
source file at level 3.
|
source file at level 3.
|
||||||
|
|
||||||
|
.. option:: --dump-ast-patterns
|
||||||
|
|
||||||
|
Rarely needed. Enable dumping AstNodeExpr pattern statistics.
|
||||||
|
|
||||||
.. 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
|
||||||
|
|
@ -657,8 +662,28 @@ Summary:
|
||||||
|
|
||||||
.. option:: -fno-assemble
|
.. option:: -fno-assemble
|
||||||
|
|
||||||
|
.. option:: -fno-bit-scan-loops
|
||||||
|
|
||||||
|
Rarely needed. Disable converting bit counting loops into built-in operations.
|
||||||
|
|
||||||
.. option:: -fno-case
|
.. option:: -fno-case
|
||||||
|
|
||||||
|
Rarely needed. Disable all case statement optimizations.
|
||||||
|
|
||||||
|
Alias for all other `-fno-case-*` options.
|
||||||
|
|
||||||
|
.. option:: -fno-case-decoder
|
||||||
|
|
||||||
|
Rarely needed. Disable converting case statements into decoder tables.
|
||||||
|
|
||||||
|
.. option:: -fno-case-table
|
||||||
|
|
||||||
|
Rarely needed. Disable converting case statements into table lookups.
|
||||||
|
|
||||||
|
.. option:: -fno-case-tree
|
||||||
|
|
||||||
|
Rarely needed. Disable converting case statements into bit-wise branch trees.
|
||||||
|
|
||||||
.. option:: -fno-combine
|
.. option:: -fno-combine
|
||||||
|
|
||||||
.. option:: -fno-const
|
.. option:: -fno-const
|
||||||
|
|
@ -737,12 +762,41 @@ Summary:
|
||||||
this is not recommended as may cause additional warnings and ordering
|
this is not recommended as may cause additional warnings and ordering
|
||||||
issues.
|
issues.
|
||||||
|
|
||||||
|
.. option:: -fno-ico-change-detect
|
||||||
|
|
||||||
|
Rarely needed. Disable input change detection in the input combinational
|
||||||
|
('ico') region. With change detection enabled (the default, unless
|
||||||
|
:vlopt:`--vpi` is passed), the input combinational logic is evaluated only
|
||||||
|
when a top level input has actually changed, rather than unconditionally on
|
||||||
|
the first scheduling iteration.
|
||||||
|
|
||||||
|
The change detection logic assumes a top level input only ever changes
|
||||||
|
externally between evaluations. The optimization is automatically disabled
|
||||||
|
for top level input signals that are written within the design. Accesses via
|
||||||
|
the VPI cannot be analyzed at compile time, therefore :vlopt:`--vpi`
|
||||||
|
disables this optimization for all inputs; it may be turned back on by
|
||||||
|
explicitly passing :vlopt:`-fico-change-detect <-fno-ico-change-detect>`.
|
||||||
|
|
||||||
.. option:: -fno-inline
|
.. option:: -fno-inline
|
||||||
|
|
||||||
|
Rarely needed. Disable module inlining.
|
||||||
|
|
||||||
|
.. option:: -fno-inline-cfuncs
|
||||||
|
|
||||||
|
Rarely needed. Disable inlining of small generated C++ functions into their
|
||||||
|
callers.
|
||||||
|
|
||||||
|
This optimization is automatically disabled when :vlopt:`--prof-cfuncs` is
|
||||||
|
used.
|
||||||
|
|
||||||
.. option:: -fno-inline-funcs
|
.. option:: -fno-inline-funcs
|
||||||
|
|
||||||
|
Rarely needed. Disable inlining of SystemVerilog functions and tasks.
|
||||||
|
|
||||||
.. option:: -fno-inline-funcs-eager
|
.. option:: -fno-inline-funcs-eager
|
||||||
|
|
||||||
|
Rarely needed. Disable eager inlining of SystemVerilog functions and tasks.
|
||||||
|
|
||||||
.. option:: -fno-life
|
.. option:: -fno-life
|
||||||
|
|
||||||
.. option:: -fno-life-post
|
.. option:: -fno-life-post
|
||||||
|
|
@ -944,27 +998,21 @@ Summary:
|
||||||
|
|
||||||
.. option:: --inline-cfuncs <value>
|
.. option:: --inline-cfuncs <value>
|
||||||
|
|
||||||
Inline small C++ function (internal AstCFunc) calls directly into their
|
Tune the inlining of small generated C++ function. Functions no bigger than
|
||||||
callers when the function has at most <value> nodes. This reduces
|
<value> nodes will be inlined if possible. The default is 20.
|
||||||
function call overhead when :vlopt:`--output-split-cfuncs` places
|
|
||||||
functions in separate compilation units that the C++ compiler cannot
|
|
||||||
inline.
|
|
||||||
|
|
||||||
Set to 0 to disable this optimization. The default is 20.
|
See also :vlopt:`--inline-cfuncs-product` and :vlopt:`-fno-inline-cfuncs`.
|
||||||
|
|
||||||
This optimization is automatically disabled when :vlopt:`--prof-cfuncs`
|
|
||||||
or :vlopt:`--trace` is used.
|
|
||||||
|
|
||||||
.. option:: --inline-cfuncs-product <value>
|
.. option:: --inline-cfuncs-product <value>
|
||||||
|
|
||||||
Tune the inlining of C++ function (internal AstCFunc) calls for larger
|
Tune the inlining of small generated C++ function. If a function's node
|
||||||
functions. When a function is too large to always inline (exceeds
|
count multiplied by the number of calls is not bigger than <value>, the
|
||||||
:vlopt:`--inline-cfuncs` threshold), it may still be inlined if the
|
function will be inlined if possible.
|
||||||
function size multiplied by the number of call sites is at most <value>.
|
|
||||||
|
|
||||||
This allows functions that are called only once or twice to be inlined
|
This allows functions that are called only once or twice to be inlined even
|
||||||
even if they exceed the small function threshold. Set to 0 to only inline
|
if they exceed the small function threshold. The default is 200.
|
||||||
functions below the :vlopt:`--inline-cfuncs` threshold. The default is 200.
|
|
||||||
|
See also :vlopt:`--inline-cfuncs` and :vlopt:`-fno-inline-cfuncs`.
|
||||||
|
|
||||||
.. option:: --inline-mult <value>
|
.. option:: --inline-mult <value>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
verilator_coverage
|
verilator_coverage
|
||||||
==================
|
==================
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
verilator_gantt
|
verilator_gantt
|
||||||
===============
|
===============
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
verilator_profcfunc
|
verilator_profcfunc
|
||||||
===================
|
===================
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
*********************************
|
*********************************
|
||||||
Executable and Argument Reference
|
Executable and Argument Reference
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
===================
|
===================
|
||||||
Language Extensions
|
Language Extensions
|
||||||
|
|
@ -341,6 +342,10 @@ or "`ifdef`"'s may break other tools.
|
||||||
|
|
||||||
.. option:: /*verilator&32;isolate_assignments*/
|
.. option:: /*verilator&32;isolate_assignments*/
|
||||||
|
|
||||||
|
Deprecated and has no effect (ignored).
|
||||||
|
|
||||||
|
In versions before 5.050:
|
||||||
|
|
||||||
Used after a signal declaration to indicate the assignments to this
|
Used after a signal declaration to indicate the assignments to this
|
||||||
signal in any blocks should be isolated into new blocks. When large
|
signal in any blocks should be isolated into new blocks. When large
|
||||||
combinatorial block results in a :option:`UNOPTFLAT` warning, attaching
|
combinatorial block results in a :option:`UNOPTFLAT` warning, attaching
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
******************************
|
******************************
|
||||||
FAQ/Frequently Asked Questions
|
FAQ/Frequently Asked Questions
|
||||||
|
|
@ -82,17 +83,17 @@ the licenses for details.
|
||||||
|
|
||||||
Some examples:
|
Some examples:
|
||||||
|
|
||||||
* Any SystemVerilog or other input fed into Verilator remains your own.
|
- Any SystemVerilog or other input fed into Verilator remains your own.
|
||||||
|
|
||||||
* Any of your VPI/DPI C++ routines that Verilator calls remain your own.
|
- Any of your VPI/DPI C++ routines that Verilator calls remain your own.
|
||||||
|
|
||||||
* Any of your main() C++ code that calls into Verilator remains your own.
|
- Any of your main() C++ code that calls into Verilator remains your own.
|
||||||
|
|
||||||
* If you change Verilator itself, for example, changing or adding a file
|
- If you change Verilator itself, for example, changing or adding a file
|
||||||
under the src/ directory in the repository, you must make the source code
|
under the src/ directory in the repository, you must make the source code
|
||||||
available under the GNU Lesser Public License.
|
available under the GNU Lesser Public License.
|
||||||
|
|
||||||
* If you change a header Verilator provides, for example, under include/ in
|
- If you change a header Verilator provides, for example, under include/ in
|
||||||
the repository, you must make the source code available under the GNU
|
the repository, you must make the source code available under the GNU
|
||||||
Lesser Public License.
|
Lesser Public License.
|
||||||
|
|
||||||
|
|
@ -384,33 +385,33 @@ example of how to do this.
|
||||||
How do I get faster build times?
|
How do I get faster build times?
|
||||||
""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
* When running make, pass the make variable VM_PARALLEL_BUILDS=1, so that
|
- When running make, pass the make variable VM_PARALLEL_BUILDS=1, so that
|
||||||
builds occur in parallel. Note this is now set by default if an output
|
builds occur in parallel. Note this is now set by default if an output
|
||||||
file is large enough to be split due to the :vlopt:`--output-split`
|
file is large enough to be split due to the :vlopt:`--output-split`
|
||||||
option.
|
option.
|
||||||
|
|
||||||
* Verilator emits any infrequently executed "cold" routines into separate
|
- Verilator emits any infrequently executed "cold" routines into separate
|
||||||
__Slow.cpp files. This can accelerate compilation as optimization can be
|
__Slow.cpp files. This can accelerate compilation as optimization can be
|
||||||
disabled on these routines. See the OPT_FAST and OPT_SLOW make variables
|
disabled on these routines. See the OPT_FAST and OPT_SLOW make variables
|
||||||
and :ref:`Benchmarking & Optimization`.
|
and :ref:`Benchmarking & Optimization`.
|
||||||
|
|
||||||
* Use a recent compiler. Newer compilers tend to be faster.
|
- Use a recent compiler. Newer compilers tend to be faster.
|
||||||
|
|
||||||
* Compile in parallel on many machines and use caching; see the web for the
|
- Compile in parallel on many machines and use caching; see the web for the
|
||||||
ccache, sccache, distcc, or icecream packages. ccache will skip GCC runs
|
ccache, sccache, distcc, or icecream packages. ccache will skip GCC runs
|
||||||
between identical source builds, even across different users. If ccache
|
between identical source builds, even across different users. If ccache
|
||||||
was installed when Verilator was built, it is used, or see OBJCACHE
|
was installed when Verilator was built, it is used, or see OBJCACHE
|
||||||
environment variable to override this. Also see the
|
environment variable to override this. Also see the
|
||||||
:vlopt:`--output-split` option and :ref: `Profiling ccache efficiency`.
|
:vlopt:`--output-split` option and :ref: `Profiling ccache efficiency`.
|
||||||
|
|
||||||
* To reduce the compile time of classes that use a Verilated module (e.g.,
|
- To reduce the compile time of classes that use a Verilated module (e.g.,
|
||||||
a top CPP file) you may wish to add a
|
a top CPP file) you may wish to add a
|
||||||
:option:`/*verilator&32;no_inline_module*/` metacomment to your top-level
|
:option:`/*verilator&32;no_inline_module*/` metacomment to your top-level
|
||||||
module. This will decrease the amount of code in the model's Verilated
|
module. This will decrease the amount of code in the model's Verilated
|
||||||
class, improving compile times of any instantiating top-level C++ code,
|
class, improving compile times of any instantiating top-level C++ code,
|
||||||
at a relatively small cost of execution performance.
|
at a relatively small cost of execution performance.
|
||||||
|
|
||||||
* Use :ref:`hierarchical verilation`.
|
- Use :ref:`hierarchical verilation`.
|
||||||
|
|
||||||
|
|
||||||
Why do so many files need to recompile when I add a signal?
|
Why do so many files need to recompile when I add a signal?
|
||||||
|
|
@ -498,12 +499,12 @@ equal, the best performance is when Verilator sees all of the design. So,
|
||||||
look at the hierarchy of your design, labeling instances as to if they are
|
look at the hierarchy of your design, labeling instances as to if they are
|
||||||
SystemC or Verilog. Then:
|
SystemC or Verilog. Then:
|
||||||
|
|
||||||
* A module with only SystemC instances below must be SystemC.
|
- A module with only SystemC instances below must be SystemC.
|
||||||
|
|
||||||
* A module with a mix of Verilog and SystemC instances below must be
|
- A module with a mix of Verilog and SystemC instances below must be
|
||||||
SystemC. (As Verilator cannot connect to lower-level SystemC instances.)
|
SystemC. (As Verilator cannot connect to lower-level SystemC instances.)
|
||||||
|
|
||||||
* A module with only Verilog instances below can be either, but for best
|
- A module with only Verilog instances below can be either, but for best
|
||||||
performance should be Verilog. (The exception is if you have a design
|
performance should be Verilog. (The exception is if you have a design
|
||||||
that is instantiated many times; in this case, Verilating one of the
|
that is instantiated many times; in this case, Verilating one of the
|
||||||
lower modules and instantiating that Verilated instances multiple times
|
lower modules and instantiating that Verilated instances multiple times
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
*****
|
*****
|
||||||
Files
|
Files
|
||||||
|
|
@ -42,138 +43,141 @@ For --cc/--sc, it creates:
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
|
|
||||||
* - *{prefix}*.json
|
- - *{prefix}*.json
|
||||||
- JSON build definition compiling (from --make json)
|
- JSON build definition compiling (from --make json)
|
||||||
* - *{prefix}*.mk
|
- - *{prefix}*.mk
|
||||||
- Make include file for compiling (from --make gmake)
|
- Make include file for compiling (from --make gmake)
|
||||||
* - *{prefix}*\ _classes.mk
|
- - *{prefix}*\ _classes.mk
|
||||||
- Make include file with class names (from --make gmake)
|
- Make include file with class names (from --make gmake)
|
||||||
* - *{prefix}*.h
|
- - *{prefix}*.h
|
||||||
- Model header
|
- Model header
|
||||||
* - *{prefix}*.cpp
|
- - *{prefix}*.cpp
|
||||||
- Model C++ file
|
- Model C++ file
|
||||||
* - *{prefix}*\ ___024root.h
|
- - *{prefix}*\ ___024root.h
|
||||||
- Top-level internal header file (from SystemVerilog $root)
|
- Top-level internal header file (from SystemVerilog $root)
|
||||||
* - *{prefix}*\ ___024root.cpp
|
- - *{prefix}*\ ___024root.cpp
|
||||||
- Top-level internal C++ file (from SystemVerilog $root)
|
- Top-level internal C++ file (from SystemVerilog $root)
|
||||||
* - *{prefix}*\ ___024root\ *{__n}*.cpp
|
- - *{prefix}*\ ___024root\ *{__n}*.cpp
|
||||||
- Additional top-level internal C++ files
|
- Additional top-level internal C++ files
|
||||||
* - *{prefix}*\ ___024root__Slow\ *{__n}*.cpp
|
- - *{prefix}*\ ___024root__Slow\ *{__n}*.cpp
|
||||||
- Infrequent cold routines
|
- Infrequent cold routines
|
||||||
* - *{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
|
||||||
- Global DPI export wrappers (from --dpi)
|
- Global DPI export wrappers (from --dpi)
|
||||||
* - *{prefix}*\ __Dpi_Export\ *{__n}*.cpp
|
- - *{prefix}*\ __Dpi_Export\ *{__n}*.cpp
|
||||||
- DPI export wrappers scoped to this particular model (from --dpi)
|
- DPI export wrappers scoped to this particular model (from --dpi)
|
||||||
* - *{prefix}*\ __Inlines.h
|
- - *{prefix}*\ __Inlines.h
|
||||||
- Inline support functions
|
- Inline support functions
|
||||||
* - *{prefix}*\ __Syms.h
|
- - *{prefix}*\ __Syms.h
|
||||||
- Global symbol table header
|
- Global symbol table header
|
||||||
* - *{prefix}*\ __Syms.cpp
|
- - *{prefix}*\ __Syms.cpp
|
||||||
- Global symbol table C++
|
- Global symbol table C++
|
||||||
* - *{prefix}{each_verilog_module}*.h
|
- - *{prefix}{each_verilog_module}*.h
|
||||||
- Lower level internal header files
|
- Lower level internal header files
|
||||||
* - *{prefix}{each_verilog_module}*.cpp
|
- - *{prefix}{each_verilog_module}*.cpp
|
||||||
- Lower level internal C++ files
|
- Lower level internal C++ files
|
||||||
* - *{prefix}{each_verilog_module}{__n}*.cpp
|
- - *{prefix}{each_verilog_module}{__n}*.cpp
|
||||||
- Additional lower C++ files
|
- Additional lower C++ files
|
||||||
|
|
||||||
For --hierarchical mode, it creates:
|
For --hierarchical mode, it creates:
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
|
|
||||||
* - V\ *{hier_block}*\ /
|
- - V\ *{hier_block}*/
|
||||||
- Directory to Verilate each hierarchical block (from --hierarchical)
|
- Directory to Verilate each hierarchical block (from --hierarchical)
|
||||||
* - *{prefix}*\ __hierVer.d
|
- - *{prefix}*\ __hierVer.d
|
||||||
- Make dependencies of the top module (from --hierarchical)
|
- Make dependencies of the top module (from --hierarchical)
|
||||||
* - *{prefix}*\ _hier.mk
|
- - *{prefix}*\ _hier.mk
|
||||||
- Make file for hierarchical blocks (from --make gmake)
|
- Make file for hierarchical blocks (from --make gmake)
|
||||||
* - *{prefix}*\ __hierMkJsonArgs.f
|
- - *{prefix}*\ __hierMkJsonArgs.f
|
||||||
- Arguments for hierarchical Verilation (from --make json)
|
- Arguments for hierarchical Verilation (from --make json)
|
||||||
* - *{prefix}*\ __hierMkArgs.f
|
- - *{prefix}*\ __hierMkArgs.f
|
||||||
- Arguments for hierarchical Verilation (from --make gmake)
|
- Arguments for hierarchical Verilation (from --make gmake)
|
||||||
* - *{prefix}*\ __hierParameters.v
|
- - *{prefix}*\ __hierParameters.v
|
||||||
- Module parameters for hierarchical blocks
|
- Module parameters for hierarchical blocks
|
||||||
* - *{prefix}*\ __hier.dir
|
- - *{prefix}*\ __hier.dir
|
||||||
- Directory to store .dot, .vpp, .tree of top module (from --hierarchical)
|
- Directory to store .dot, .vpp, .tree of top module (from
|
||||||
|
--hierarchical)
|
||||||
|
|
||||||
In specific debug and other modes, it also creates:
|
In specific debug and other modes, it also creates:
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
|
|
||||||
* - *{prefix}*.sarif
|
- - *{prefix}*.sarif
|
||||||
- SARIF diagnostics (from --diagnostics-sarif)
|
- SARIF diagnostics (from --diagnostics-sarif)
|
||||||
* - *{prefix}*.tree.json
|
- - *{prefix}*.tree.json
|
||||||
- JSON tree information (from --json-only)
|
- JSON tree information (from --json-only)
|
||||||
* - *{prefix}*.tree.meta.json
|
- - *{prefix}*.tree.meta.json
|
||||||
- JSON tree metadata (from --json-only)
|
- JSON tree metadata (from --json-only)
|
||||||
* - *{prefix}*\ __cdc.txt
|
- - *{prefix}*\ __cdc.txt
|
||||||
- Clock Domain Crossing checks (from --cdc)
|
- Clock Domain Crossing checks (from --cdc)
|
||||||
* - *{prefix}*\ __stats.txt
|
- - *{prefix}*\ __stats.txt
|
||||||
- Statistics (from --stats)
|
- Statistics (from --stats)
|
||||||
* - *{prefix}*\ __idmap.txt
|
- - *{prefix}*\ __idmap.txt
|
||||||
- Symbol demangling (from --protect-ids)
|
- Symbol demangling (from --protect-ids)
|
||||||
* - *{prefix}*\ __ver.d
|
- - *{prefix}*\ __ver.d
|
||||||
- Make dependencies (from -MMD)
|
- Make dependencies (from -MMD)
|
||||||
* - *{prefix}*\ __verFiles.dat
|
- - *{prefix}*\ __verFiles.dat
|
||||||
- Timestamps (from --skip-identical)
|
- Timestamps (from --skip-identical)
|
||||||
* - *{prefix}{misc}*.dot
|
- - *{prefix}{misc}*.dot
|
||||||
- Debugging graph files (from --debug)
|
- Debugging graph files (from --debug)
|
||||||
* - *{prefix}{misc}*.tree
|
- - *{prefix}{misc}*.tree
|
||||||
- Debugging files (from --debug)
|
- Debugging files (from --debug)
|
||||||
* - *{prefix}*\ __inputs.vpp
|
- - *{prefix}*\ __inputs.vpp
|
||||||
- Pre-processed verilog for all files (from --debug)
|
- Pre-processed verilog for all files (from --debug)
|
||||||
* - *{prefix}*\ _ *{each_verilog_base_filename}*.vpp
|
- - *{prefix}*\ _ *{each_verilog_base_filename}*.vpp
|
||||||
- Pre-processed verilog for each file (from --debug)
|
- Pre-processed verilog for each file (from --debug)
|
||||||
|
|
||||||
After running Make, the C++ compiler may produce the following:
|
After running Make, the C++ compiler may produce the following:
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
|
|
||||||
* - verilated{misc}*.d
|
- - verilated{misc}*.d
|
||||||
- Intermediate dependencies
|
- Intermediate dependencies
|
||||||
* - verilated{misc}*.o
|
- - verilated{misc}*.o
|
||||||
- Intermediate objects
|
- Intermediate objects
|
||||||
* - {mod_prefix}{misc}*.d
|
- - {mod_prefix}{misc}*.d
|
||||||
- Intermediate dependencies
|
- Intermediate dependencies
|
||||||
* - {mod_prefix}{misc}*.o
|
- - {mod_prefix}{misc}*.o
|
||||||
- Intermediate objects
|
- Intermediate objects
|
||||||
* - *{prefix}*\
|
- - *{prefix}*\
|
||||||
- Final executable (from --exe)
|
- Final executable (from --exe)
|
||||||
* - lib\ *{prefix}*.a
|
- - lib\ *{prefix}*.a
|
||||||
- Final archive (default lib mode)
|
- Final archive (default lib mode)
|
||||||
* - libverilated.a
|
- - libverilated.a
|
||||||
- Runtime for verilated model (default lib mode)
|
- Runtime for verilated model (default lib mode)
|
||||||
* - *{prefix}*\ __ALL.a
|
- - *{prefix}*\ __ALL.a
|
||||||
- Library of all Verilated objects
|
- Library of all Verilated objects
|
||||||
* - *{prefix}*\ __ALL.cpp
|
- - *{prefix}*\ __ALL.cpp
|
||||||
- Include of all code for single compile
|
- Include of all code for single compile
|
||||||
* - *{prefix}{misc}*.d
|
- - *{prefix}{misc}*.d
|
||||||
- Intermediate dependencies
|
- Intermediate dependencies
|
||||||
* - *{prefix}{misc}*.o
|
- - *{prefix}{misc}*.o
|
||||||
- Intermediate objects
|
- Intermediate objects
|
||||||
|
|
||||||
The Verilated executable may produce the following:
|
The Verilated executable may produce the following:
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
|
|
||||||
* - coverage.dat
|
- - coverage.dat
|
||||||
- Code coverage output, and default input filename for :command:`verilator_coverage`
|
- Code coverage output, and default input filename for
|
||||||
* - gmon.out
|
:command:`verilator_coverage`
|
||||||
- GCC/clang code profiler output, often fed into :command:`verilator_profcfunc`
|
- - gmon.out
|
||||||
* - profile.vlt
|
- GCC/clang code profiler output, often fed into
|
||||||
|
:command:`verilator_profcfunc`
|
||||||
|
- - profile.vlt
|
||||||
- --prof-pgo data file for :ref:`Thread PGO`
|
- --prof-pgo data file for :ref:`Thread PGO`
|
||||||
* - profile_exec.dat
|
- - profile_exec.dat
|
||||||
- --prof-exec data file for :command:`verilator_gantt`
|
- --prof-exec data file for :command:`verilator_gantt`
|
||||||
|
|
||||||
Verilator_gantt may produce the following:
|
Verilator_gantt may produce the following:
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
|
|
||||||
* - profile_exec.vcd
|
- - profile_exec.vcd
|
||||||
- Gantt report waveform output
|
- Gantt report waveform output
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
######################
|
######################
|
||||||
Verilator User's Guide
|
Verilator User's Guide
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _cmakeinstallation:
|
.. _cmakeinstallation:
|
||||||
|
|
||||||
|
|
@ -16,16 +17,16 @@ Linux).
|
||||||
Quick Install
|
Quick Install
|
||||||
=============
|
=============
|
||||||
|
|
||||||
1. Install Python for your platform from https://www.python.org/downloads/.
|
#. Install Python for your platform from https://www.python.org/downloads/.
|
||||||
2. Install CMake for your platform from https://cmake.org/download/ or
|
#. Install CMake for your platform from https://cmake.org/download/ or
|
||||||
build it from source.
|
build it from source.
|
||||||
3. If the compiler of your choice is MSVC, then install
|
#. If the compiler of your choice is MSVC, then install
|
||||||
https://visualstudio.microsoft.com/downloads/. If the compiler of your
|
https://visualstudio.microsoft.com/downloads/. If the compiler of your
|
||||||
choice is Clang, then install https://releases.llvm.org/download.html or
|
choice is Clang, then install https://releases.llvm.org/download.html or
|
||||||
build it from source.
|
build it from source.
|
||||||
4. For flex and bison use https://github.com/lexxmark/winflexbison to build
|
#. For flex and bison use https://github.com/lexxmark/winflexbison to build
|
||||||
and install.
|
and install.
|
||||||
5. For build on Windows using MSVC set environment variable WIN_FLEX_BISON
|
#. For build on Windows using MSVC set environment variable WIN_FLEX_BISON
|
||||||
to install directory. For build on Windows/Linux/OS-X using ninja set
|
to install directory. For build on Windows/Linux/OS-X using ninja set
|
||||||
the environment variable FLEX_INCLUDE to the directory containing
|
the environment variable FLEX_INCLUDE to the directory containing
|
||||||
FlexLexer.h and ensure that flex/bison is available within the PATH.
|
FlexLexer.h and ensure that flex/bison is available within the PATH.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _installation:
|
.. _installation:
|
||||||
|
|
||||||
|
|
@ -384,12 +385,10 @@ the files:
|
||||||
|
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
|
||||||
.. Docker Build Environment
|
.. Docker Build Environment
|
||||||
|
|
||||||
.. include:: ../../ci/docker/buildenv/README.rst
|
.. include:: ../../ci/docker/buildenv/README.rst
|
||||||
|
|
||||||
|
|
||||||
.. Docker Run Environment
|
.. Docker Run Environment
|
||||||
|
|
||||||
.. include:: ../../ci/docker/run/README.rst
|
.. include:: ../../ci/docker/run/README.rst
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
***************
|
***************
|
||||||
Input Languages
|
Input Languages
|
||||||
|
|
@ -102,11 +103,11 @@ Time
|
||||||
|
|
||||||
With :vlopt:`--timing`, all timing controls are supported:
|
With :vlopt:`--timing`, all timing controls are supported:
|
||||||
|
|
||||||
* delay statements,
|
- delay statements,
|
||||||
* event control statements not only at the top of a process,
|
- event control statements not only at the top of a process,
|
||||||
* intra-assignment timing controls,
|
- intra-assignment timing controls,
|
||||||
* net delays,
|
- net delays,
|
||||||
* ``wait`` statements,
|
- ``wait`` statements,
|
||||||
|
|
||||||
as well as all flavors of ``fork``.
|
as well as all flavors of ``fork``.
|
||||||
|
|
||||||
|
|
@ -128,26 +129,26 @@ simulation (perhaps using :vlopt:`--build`) and run it.
|
||||||
With :vlopt:`--no-timing`, all timing controls cause the :option:`NOTIMING`
|
With :vlopt:`--no-timing`, all timing controls cause the :option:`NOTIMING`
|
||||||
error, except:
|
error, except:
|
||||||
|
|
||||||
* delay statements - they are ignored (as they are in synthesis), though they
|
- delay statements - they are ignored (as they are in synthesis), though
|
||||||
do issue a :option:`STMTDLY` warning,
|
they do issue a :option:`STMTDLY` warning,
|
||||||
* intra-assignment timing controls - they are ignored, though they do issue
|
- intra-assignment timing controls - they are ignored, though they do issue
|
||||||
an :option:`ASSIGNDLY` warning,
|
an :option:`ASSIGNDLY` warning,
|
||||||
* net delays - they are ignored,
|
- net delays - they are ignored,
|
||||||
* event controls at the top of the procedure,
|
- event controls at the top of the procedure,
|
||||||
|
|
||||||
Forks cause this error as well, except:
|
Forks cause this error as well, except:
|
||||||
|
|
||||||
* forks with no statements,
|
- forks with no statements,
|
||||||
* ``fork..join`` or ``fork..join_any`` with one statement,
|
- ``fork..join`` or ``fork..join_any`` with one statement,
|
||||||
* forks with :vlopt:`--bbox-unsup`.
|
- forks with :vlopt:`--bbox-unsup`.
|
||||||
|
|
||||||
If neither :vlopt:`--timing` nor :vlopt:`--no-timing` is specified, all
|
If neither :vlopt:`--timing` nor :vlopt:`--no-timing` is specified, all
|
||||||
timing controls cause the :option:`NEEDTIMINGOPT` error, except event
|
timing controls cause the :option:`NEEDTIMINGOPT` error, except event
|
||||||
controls at the top of the process. Forks cause this error as well, except:
|
controls at the top of the process. Forks cause this error as well, except:
|
||||||
|
|
||||||
* forks with no statements,
|
- forks with no statements,
|
||||||
* ``fork..join`` or ``fork..join_any`` with one statement,
|
- ``fork..join`` or ``fork..join_any`` with one statement,
|
||||||
* forks with :vlopt:`--bbox-unsup`.
|
- forks with :vlopt:`--bbox-unsup`.
|
||||||
|
|
||||||
Timing controls and forks can also be ignored in specific files or parts of
|
Timing controls and forks can also be ignored in specific files or parts of
|
||||||
files. The :option:`/*verilator&32;timing_off*/` and
|
files. The :option:`/*verilator&32;timing_off*/` and
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
********
|
********
|
||||||
Overview
|
Overview
|
||||||
|
|
@ -47,9 +48,9 @@ The best place to get started is to try the :ref:`Examples`.
|
||||||
uses the shorthand, e.g., "IEEE 1364-2005", to refer to the, e.g., 2005
|
uses the shorthand, e.g., "IEEE 1364-2005", to refer to the, e.g., 2005
|
||||||
version of this standard.
|
version of this standard.
|
||||||
|
|
||||||
.. [#] SystemVerilog is defined by the `Institute of Electrical and
|
.. [#] SystemVerilog is defined by the `Institute of Electrical and Electronics
|
||||||
Electronics Engineers (IEEE) Standard for SystemVerilog - Unified
|
Engineers (IEEE) Standard for SystemVerilog - Unified Hardware Design,
|
||||||
Hardware Design, Specification, and Verification Language`, Standard
|
Specification, and Verification Language`, Standard 1800, released in
|
||||||
1800, released in 2005, 2009, 2012, 2017, and 2023. The Verilator
|
2005, 2009, 2012, 2017, and 2023. The Verilator documentation uses the
|
||||||
documentation uses the shorthand e.g., "IEEE 1800-2023", to refer to
|
shorthand e.g., "IEEE 1800-2023", to refer to the, e.g., 2023 version of
|
||||||
the, e.g., 2023 version of this standard.
|
this standard.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
.. _simulating:
|
.. _simulating:
|
||||||
|
|
||||||
|
|
@ -209,7 +210,8 @@ For simple coverage points, use the ``cover property`` construct:
|
||||||
|
|
||||||
DefaultClock: cover property (@(posedge clk) cyc==3);
|
DefaultClock: cover property (@(posedge clk) cyc==3);
|
||||||
|
|
||||||
This adds a coverage point that tracks whether the condition has been observed.
|
This adds a coverage point that tracks whether the condition has been
|
||||||
|
observed.
|
||||||
|
|
||||||
.. _covergroup coverage:
|
.. _covergroup coverage:
|
||||||
|
|
||||||
|
|
@ -218,8 +220,8 @@ Covergroup Coverage
|
||||||
|
|
||||||
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
|
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
|
||||||
translate covergroup coverage points the user has inserted manually in
|
translate covergroup coverage points the user has inserted manually in
|
||||||
SystemVerilog code into the Verilated model. Verilator supports
|
SystemVerilog code into the Verilated model. Verilator supports coverpoints
|
||||||
coverpoints with value and transition bins, and cross points.
|
with value and transition bins, and cross points.
|
||||||
|
|
||||||
|
|
||||||
.. _fsm coverage:
|
.. _fsm coverage:
|
||||||
|
|
@ -244,15 +246,15 @@ encodings in these common forms:
|
||||||
- Single-process FSMs, whose state dispatch is written as ``case (state)``
|
- Single-process FSMs, whose state dispatch is written as ``case (state)``
|
||||||
or as a top-level ``if`` / ``else if`` chain comparing the same state
|
or as a top-level ``if`` / ``else if`` chain comparing the same state
|
||||||
variable against known state values
|
variable against known state values
|
||||||
- Two-process and three-block FSMs, where a clocked state register is paired
|
- Two-process and three-block FSMs, where a clocked state register is
|
||||||
with a combinational next-state block using the same supported
|
paired with a combinational next-state block using the same supported
|
||||||
``case`` or top-level ``if`` / ``else if`` dispatch forms
|
``case`` or top-level ``if`` / ``else if`` dispatch forms
|
||||||
|
|
||||||
Scalar state encodings may be wider than 32 bits. This allows sparse
|
Scalar state encodings may be wider than 32 bits. This allows sparse state
|
||||||
state encodings, such as high-Hamming-distance enum or localparam values,
|
encodings, such as high-Hamming-distance enum or localparam values, to be
|
||||||
to be preserved in the detected FSM model. Verilator uses the declared
|
preserved in the detected FSM model. Verilator uses the declared enum item
|
||||||
enum item name, parameter name, or localparam name as the reported state
|
name, parameter name, or localparam name as the reported state label where
|
||||||
label where possible.
|
possible.
|
||||||
|
|
||||||
Simple input guards are supported when they appear inside a recognized
|
Simple input guards are supported when they appear inside a recognized
|
||||||
state branch, or as a top-level conjunction containing exactly one state
|
state branch, or as a top-level conjunction containing exactly one state
|
||||||
|
|
@ -267,18 +269,17 @@ deeply nested control recovery, or cross-module state alias tracing.
|
||||||
The following metacomments may be attached to the state variable to steer
|
The following metacomments may be attached to the state variable to steer
|
||||||
the extracted coverage model:
|
the extracted coverage model:
|
||||||
|
|
||||||
- ``/*verilator fsm_state*/`` forces the variable to be treated as
|
- ``/*verilator fsm_state*/`` forces the variable to be treated as FSM
|
||||||
FSM state.
|
state.
|
||||||
- ``/*verilator fsm_reset_arc*/`` marks reset transitions as
|
- ``/*verilator fsm_reset_arc*/`` marks reset transitions as user-visible
|
||||||
user-visible reset arcs instead of defaulting to a hidden reset-only
|
reset arcs instead of defaulting to a hidden reset-only summary.
|
||||||
summary.
|
- ``/*verilator fsm_arc_include_cond*/`` keeps conditional branch arcs that
|
||||||
- ``/*verilator fsm_arc_include_cond*/`` keeps conditional branch
|
would otherwise be skipped by the conservative extractor.
|
||||||
arcs that would otherwise be skipped by the conservative extractor.
|
|
||||||
|
|
||||||
State registers may also be wrapped by a transparent instance, for
|
State registers may also be wrapped by a transparent instance, for example
|
||||||
example a project flop wrapper or primitive. Such wrappers must be
|
a project flop wrapper or primitive. Such wrappers must be described
|
||||||
described explicitly with a VLT command file action before Verilator will
|
explicitly with a VLT command file action before Verilator will use their
|
||||||
use their data, state, clock, or reset connections for FSM extraction:
|
data, state, clock, or reset connections for FSM extraction:
|
||||||
|
|
||||||
.. code-block:: sv
|
.. code-block:: sv
|
||||||
|
|
||||||
|
|
@ -298,11 +299,10 @@ Optional reset metadata may also be supplied:
|
||||||
fsm_register_wrapper -module "my_fsm_flop" -d "state_i" -q "state_o" -clock "clk_i" \
|
fsm_register_wrapper -module "my_fsm_flop" -d "state_i" -q "state_o" -clock "clk_i" \
|
||||||
-reset "rst_ni" -reset_value "ResetValue"
|
-reset "rst_ni" -reset_value "ResetValue"
|
||||||
|
|
||||||
Reset arcs are emitted only when the configured reset port has an
|
Reset arcs are emitted only when the configured reset port has an inferable
|
||||||
inferable edge in the wrapper and the configured reset value parameter is
|
edge in the wrapper and the configured reset value parameter is statically
|
||||||
statically resolvable. If reset metadata is incomplete, Verilator warns
|
resolvable. If reset metadata is incomplete, Verilator warns and may still
|
||||||
and may still emit FSM state and transition coverage, but reset arcs are
|
emit FSM state and transition coverage, but reset arcs are omitted.
|
||||||
omitted.
|
|
||||||
|
|
||||||
Reset transitions are included in the collected data either way. By
|
Reset transitions are included in the collected data either way. By
|
||||||
default, :command:`verilator_coverage` summarizes reset-only arcs rather
|
default, :command:`verilator_coverage` summarizes reset-only arcs rather
|
||||||
|
|
@ -433,11 +433,11 @@ coverage point insertions into the model and collect the coverage data.
|
||||||
|
|
||||||
To get the coverage data from the model, write the coverage with either:
|
To get the coverage data from the model, write the coverage with either:
|
||||||
|
|
||||||
1. Using :vlopt:`--binary` or :vlopt:`--main`, and Verilator will dump
|
#. Using :vlopt:`--binary` or :vlopt:`--main`, and Verilator will dump
|
||||||
coverage when the test completes to the filename specified with
|
coverage when the test completes to the filename specified with
|
||||||
:vlopt:`+verilator+coverage+file+\<filename\>`.
|
:vlopt:`+verilator+coverage+file+\<filename\>`.
|
||||||
|
|
||||||
2. In the user wrapper code, typically at the end once a test passes, call
|
#. In the user wrapper code, typically at the end once a test passes, call
|
||||||
``Verilated::threadContextp()->coveragep()->write`` with an argument of
|
``Verilated::threadContextp()->coveragep()->write`` with an argument of
|
||||||
the filename for the coverage data file to write coverage data to
|
the filename for the coverage data file to write coverage data to
|
||||||
(typically "logs/coverage.dat").
|
(typically "logs/coverage.dat").
|
||||||
|
|
@ -502,12 +502,12 @@ how execution time is distributed in a verilated model.
|
||||||
|
|
||||||
With the :vlopt:`--prof-exec` option, Verilator will:
|
With the :vlopt:`--prof-exec` option, Verilator will:
|
||||||
|
|
||||||
* Add code to the Verilated model to record execution flow.
|
- Add code to the Verilated model to record execution flow.
|
||||||
|
|
||||||
* Add code to save profiling data in non-human-friendly form to the file
|
- Add code to save profiling data in non-human-friendly form to the file
|
||||||
specified with :vlopt:`+verilator+prof+exec+file+\<filename\>`.
|
specified with :vlopt:`+verilator+prof+exec+file+\<filename\>`.
|
||||||
|
|
||||||
* In multithreaded models, add code to record each macro-task's start and
|
- In multithreaded models, add code to record each macro-task's start and
|
||||||
end time across several calls to eval. (What is a macro-task? See the
|
end time across several calls to eval. (What is a macro-task? See the
|
||||||
Verilator internals document (:file:`docs/internals.rst` in the
|
Verilator internals document (:file:`docs/internals.rst` in the
|
||||||
distribution.)
|
distribution.)
|
||||||
|
|
@ -607,8 +607,8 @@ There are two forms of profile-guided optimizations. Unfortunately, for
|
||||||
best results, they must each be performed from the highest level code to
|
best results, they must each be performed from the highest level code to
|
||||||
the lowest, which means performing them separately and in this order:
|
the lowest, which means performing them separately and in this order:
|
||||||
|
|
||||||
* :ref:`Thread PGO`
|
- :ref:`Thread PGO`
|
||||||
* :ref:`Compiler PGO`
|
- :ref:`Compiler PGO`
|
||||||
|
|
||||||
Other forms of PGO may be supported in the future, such as clock and reset
|
Other forms of PGO may be supported in the future, such as clock and reset
|
||||||
toggle rate PGO, branch prediction PGO, statement execution time PGO, or
|
toggle rate PGO, branch prediction PGO, statement execution time PGO, or
|
||||||
|
|
@ -674,7 +674,7 @@ multithreaded models.
|
||||||
Please see the appropriate compiler documentation to use PGO with GCC or
|
Please see the appropriate compiler documentation to use PGO with GCC or
|
||||||
Clang. The process in GCC 10 was as follows:
|
Clang. The process in GCC 10 was as follows:
|
||||||
|
|
||||||
1. Compile the Verilated model with the compiler's "-fprofile-generate"
|
#. Compile the Verilated model with the compiler's "-fprofile-generate"
|
||||||
flag:
|
flag:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
@ -685,10 +685,10 @@ Clang. The process in GCC 10 was as follows:
|
||||||
Or, if calling make yourself, add -fprofile-generate appropriately to
|
Or, if calling make yourself, add -fprofile-generate appropriately to
|
||||||
your Makefile.
|
your Makefile.
|
||||||
|
|
||||||
2. Run your simulation. This will create \*.gcda file(s) in the same
|
#. Run your simulation. This will create \*.gcda file(s) in the same
|
||||||
directory as the source files.
|
directory as the source files.
|
||||||
|
|
||||||
3. Recompile the model with -fprofile-use. The compiler will read the
|
#. Recompile the model with -fprofile-use. The compiler will read the
|
||||||
\*.gcda file(s).
|
\*.gcda file(s).
|
||||||
|
|
||||||
For GCC:
|
For GCC:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
**********
|
**********
|
||||||
Verilating
|
Verilating
|
||||||
|
|
@ -7,21 +8,21 @@ Verilating
|
||||||
|
|
||||||
Verilator may be used in five major ways:
|
Verilator may be used in five major ways:
|
||||||
|
|
||||||
* With the :vlopt:`--binary` option, Verilator will translate the design
|
- With the :vlopt:`--binary` option, Verilator will translate the design
|
||||||
into an executable, via generating C++ and compiling it. See
|
into an executable, via generating C++ and compiling it. See
|
||||||
:ref:`Binary, C++ and SystemC Generation`.
|
:ref:`Binary, C++ and SystemC Generation`.
|
||||||
|
|
||||||
* With the :vlopt:`--cc` or :vlopt:`--sc` options, Verilator will translate
|
- With the :vlopt:`--cc` or :vlopt:`--sc` options, Verilator will translate
|
||||||
the design into C++ or SystemC code, respectively. See :ref:`Binary, C++
|
the design into C++ or SystemC code, respectively. See :ref:`Binary, C++
|
||||||
and SystemC Generation`.
|
and SystemC Generation`.
|
||||||
|
|
||||||
* With the :vlopt:`--lint-only` option, Verilator will lint the design to
|
- With the :vlopt:`--lint-only` option, Verilator will lint the design to
|
||||||
check for warnings but will not typically create any output files.
|
check for warnings but will not typically create any output files.
|
||||||
|
|
||||||
* With the :vlopt:`--json-only` option, Verilator will create JSON output
|
- With the :vlopt:`--json-only` option, Verilator will create JSON output
|
||||||
that may be used to feed into other user-designed tools.
|
that may be used to feed into other user-designed tools.
|
||||||
|
|
||||||
* With the :vlopt:`-E` option, Verilator will preprocess the code according
|
- With the :vlopt:`-E` option, Verilator will preprocess the code according
|
||||||
to IEEE preprocessing rules and write the output to standard out. This is
|
to IEEE preprocessing rules and write the output to standard out. This is
|
||||||
useful to feed other tools and to debug how "\`define" statements are
|
useful to feed other tools and to debug how "\`define" statements are
|
||||||
expanded.
|
expanded.
|
||||||
|
|
@ -127,9 +128,9 @@ Usage
|
||||||
Users need to mark one or more moderate-size modules as hierarchy block(s).
|
Users need to mark one or more moderate-size modules as hierarchy block(s).
|
||||||
There are two ways to mark a module:
|
There are two ways to mark a module:
|
||||||
|
|
||||||
* Write :option:`/*verilator&32;hier_block*/` metacomment in HDL code.
|
- Write :option:`/*verilator&32;hier_block*/` metacomment in HDL code.
|
||||||
|
|
||||||
* Add a :option:`hier_block` line in the :ref:`Verilator Control Files`.
|
- Add a :option:`hier_block` line in the :ref:`Verilator Control Files`.
|
||||||
|
|
||||||
Then pass the :vlopt:`--hierarchical` option to Verilator.
|
Then pass the :vlopt:`--hierarchical` option to Verilator.
|
||||||
|
|
||||||
|
|
@ -145,28 +146,28 @@ Limitations
|
||||||
|
|
||||||
Hierarchy blocks have some limitations, including:
|
Hierarchy blocks have some limitations, including:
|
||||||
|
|
||||||
* Internals of the hierarchy block cannot be accessed using dot (.) from
|
- Internals of the hierarchy block cannot be accessed using dot (.) from
|
||||||
the upper module(s) or other hierarchy blocks, except that ports of a
|
the upper module(s) or other hierarchy blocks, except that ports of a
|
||||||
hierarchy block instance can be accessed from the directly enclosing
|
hierarchy block instance can be accessed from the directly enclosing
|
||||||
nested hierarchy block, or from the top level non-hierarchical portions
|
nested hierarchy block, or from the top level non-hierarchical portions
|
||||||
of the design if not a nested hierarchy block.
|
of the design if not a nested hierarchy block.
|
||||||
|
|
||||||
* Modport cannot be used at the hierarchical block boundary.
|
- Modport cannot be used at the hierarchical block boundary.
|
||||||
|
|
||||||
* The simulation speed is likely not as fast as flat Verilation, in which
|
- The simulation speed is likely not as fast as flat Verilation, in which
|
||||||
all modules are globally scheduled.
|
all modules are globally scheduled.
|
||||||
|
|
||||||
* Generated clocks may not work correctly if generated in the hierarchical
|
- Generated clocks may not work correctly if generated in the hierarchical
|
||||||
model and passed into another hierarchical model or the top module.
|
model and passed into another hierarchical model or the top module.
|
||||||
|
|
||||||
* Delays are not allowed in hierarchy blocks.
|
- Delays are not allowed in hierarchy blocks.
|
||||||
|
|
||||||
But, the following usage is supported:
|
But, the following usage is supported:
|
||||||
|
|
||||||
* Nested hierarchy blocks. A hierarchy block may instantiate other
|
- Nested hierarchy blocks. A hierarchy block may instantiate other
|
||||||
hierarchy blocks.
|
hierarchy blocks.
|
||||||
|
|
||||||
* Parameterized hierarchy block. Parameters of a hierarchy block can be
|
- Parameterized hierarchy block. Parameters of a hierarchy block can be
|
||||||
overridden using ``#(.param_name(value))`` construct.
|
overridden using ``#(.param_name(value))`` construct.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
..
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
===================
|
===================
|
||||||
Errors and Warnings
|
Errors and Warnings
|
||||||
|
|
@ -882,6 +883,22 @@ List Of Warnings
|
||||||
with a newline."
|
with a newline."
|
||||||
|
|
||||||
|
|
||||||
|
.. option:: FINALDLY
|
||||||
|
|
||||||
|
Error issued when a non-blocking assignment `<=` is used in a
|
||||||
|
`final` block.
|
||||||
|
|
||||||
|
This error can be disabled. If disabled, the assignment will be
|
||||||
|
executed as a `=` blocking assignment.
|
||||||
|
|
||||||
|
Faulty example:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_FINALDLY_faulty.rst
|
||||||
|
|
||||||
|
Results in:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_FINALDLY_msg.rst
|
||||||
|
|
||||||
.. option:: FSMMULTI
|
.. option:: FSMMULTI
|
||||||
|
|
||||||
Warns that the same always block contains multiple enum-typed case
|
Warns that the same always block contains multiple enum-typed case
|
||||||
|
|
@ -1178,7 +1195,7 @@ List Of Warnings
|
||||||
|
|
||||||
.. option:: INITIALDLY
|
.. option:: INITIALDLY
|
||||||
|
|
||||||
.. TODO better example
|
Historical, never issued since version 5.050.
|
||||||
|
|
||||||
Warns that the code has a delayed assignment inside of an ``initial`` or
|
Warns that the code has a delayed assignment inside of an ``initial`` or
|
||||||
``final`` block. If this message is suppressed, Verilator will convert
|
``final`` block. If this message is suppressed, Verilator will convert
|
||||||
|
|
@ -2366,11 +2383,6 @@ List Of Warnings
|
||||||
the conflict. If you run with :vlopt:`--report-unoptflat`, Verilator will
|
the conflict. If you run with :vlopt:`--report-unoptflat`, Verilator will
|
||||||
suggest possible candidates for :option:`/*verilator&32;split_var*/`.
|
suggest possible candidates for :option:`/*verilator&32;split_var*/`.
|
||||||
|
|
||||||
The UNOPTFLAT warning may also occur where outputs from a block of logic
|
|
||||||
are independent, but occur in the same always block. To fix this, use
|
|
||||||
the :option:`/*verilator&32;isolate_assignments*/` metacomment described
|
|
||||||
above.
|
|
||||||
|
|
||||||
Before version 5.000, the UNOPTFLAT warning may also have been due to
|
Before version 5.000, the UNOPTFLAT warning may also have been due to
|
||||||
clock enables, identified from the reported path going through a clock
|
clock enables, identified from the reported path going through a clock
|
||||||
gating instance. To fix these, the clock_enable meta comment was used.
|
gating instance. To fix these, the clock_enable meta comment was used.
|
||||||
|
|
|
||||||
|
|
@ -113,9 +113,9 @@ pointer to the ``AstNode`` currently being processed.
|
||||||
|
|
||||||
There are notable sub-hierarchies of the ``AstNode`` sub-types, namely:
|
There are notable sub-hierarchies of the ``AstNode`` sub-types, namely:
|
||||||
|
|
||||||
1. All AST nodes representing data types derive from ``AstNodeDType``.
|
#. All AST nodes representing data types derive from ``AstNodeDType``.
|
||||||
|
|
||||||
2. All AST nodes representing expressions (i.e.: anything that stands for,
|
#. All AST nodes representing expressions (i.e.: anything that stands for,
|
||||||
or evaluates to a value) derive from ``AstNodeExpr``.
|
or evaluates to a value) derive from ``AstNodeExpr``.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -666,23 +666,23 @@ The second visitor in ``V3Timing.cpp``, ``TimingControlVisitor``, uses the
|
||||||
information provided by ``TimingSuspendableVisitor`` and transforms each
|
information provided by ``TimingSuspendableVisitor`` and transforms each
|
||||||
timing control into a ``co_await``.
|
timing control into a ``co_await``.
|
||||||
|
|
||||||
* event controls are turned into ``co_await`` on a trigger scheduler's
|
- event controls are turned into ``co_await`` on a trigger scheduler's
|
||||||
``trigger`` method. The awaited trigger scheduler is the one
|
``trigger`` method. The awaited trigger scheduler is the one
|
||||||
corresponding to the sentree referenced by the event control. This
|
corresponding to the sentree referenced by the event control. This
|
||||||
sentree is also referenced by the ``AstCAwait`` node, to be used later by
|
sentree is also referenced by the ``AstCAwait`` node, to be used later by
|
||||||
the static scheduling code.
|
the static scheduling code.
|
||||||
|
|
||||||
* if an event control waits on a local variable or class member, it uses a
|
- if an event control waits on a local variable or class member, it uses a
|
||||||
local trigger which it evaluates inline. It awaits a dynamic trigger
|
local trigger which it evaluates inline. It awaits a dynamic trigger
|
||||||
scheduler multiple times: for trigger evaluation, updates, and
|
scheduler multiple times: for trigger evaluation, updates, and
|
||||||
resumption. The dynamic trigger scheduler is responsible for resuming the
|
resumption. The dynamic trigger scheduler is responsible for resuming the
|
||||||
coroutine at the correct point of evaluation.
|
coroutine at the correct point of evaluation.
|
||||||
|
|
||||||
* delays are turned into ``co_await`` on a delay scheduler's ``delay``
|
- delays are turned into ``co_await`` on a delay scheduler's ``delay``
|
||||||
method. The created ``AstCAwait`` nodes also reference a special sentree
|
method. The created ``AstCAwait`` nodes also reference a special sentree
|
||||||
related to delays, to be used later by the static scheduling code.
|
related to delays, to be used later by the static scheduling code.
|
||||||
|
|
||||||
* ``join`` and ``join_any`` are turned into ``co_await`` on a
|
- ``join`` and ``join_any`` are turned into ``co_await`` on a
|
||||||
``VlForkSync``'s ``join`` method. Each forked process gets a
|
``VlForkSync``'s ``join`` method. Each forked process gets a
|
||||||
``VlForkSync::done`` call at the end.
|
``VlForkSync::done`` call at the end.
|
||||||
|
|
||||||
|
|
@ -732,24 +732,24 @@ event `a` was called first - which is necessary to know.
|
||||||
|
|
||||||
There are two functions for managing timing logic called by ``_eval()``:
|
There are two functions for managing timing logic called by ``_eval()``:
|
||||||
|
|
||||||
* ``_timing_ready()``, which commits all coroutines whose triggers were
|
- ``_timing_ready()``, which commits all coroutines whose triggers were not
|
||||||
not set in the current iteration,
|
set in the current iteration,
|
||||||
* ``_timing_resume()``, which calls `resume()` on all trigger and delay
|
- ``_timing_resume()``, which calls `resume()` on all trigger and delay
|
||||||
schedulers whose triggers were set in the current iteration.
|
schedulers whose triggers were set in the current iteration.
|
||||||
|
|
||||||
Thanks to this separation a coroutine:
|
Thanks to this separation a coroutine:
|
||||||
|
|
||||||
* awaiting a trigger cannot be suspended and resumed in the same iteration
|
- awaiting a trigger cannot be suspended and resumed in the same iteration
|
||||||
(``test_regress/t/t_timing_eval_act.v``) - which is necessary to make
|
(``test_regress/t/t_timing_eval_act.v``) - which is necessary to make
|
||||||
Verilator more predictable; this is the reason for introduction of 3rd
|
Verilator more predictable; this is the reason for introduction of 3rd
|
||||||
stage in `VlTriggerScheduler` and thanks to this it is guaranteed that
|
stage in `VlTriggerScheduler` and thanks to this it is guaranteed that
|
||||||
downstream logic will be evaluated before resumption (assuming that the
|
downstream logic will be evaluated before resumption (assuming that the
|
||||||
coroutine wasn't already triggered in previous iteration);
|
coroutine wasn't already triggered in previous iteration);
|
||||||
* cannot be resumed before it is suspended -
|
- cannot be resumed before it is suspended -
|
||||||
``test_regress/t/t_event_control_double_excessive.v``;
|
``test_regress/t/t_event_control_double_excessive.v``;
|
||||||
* firing cannot cannot be lost
|
- firing cannot cannot be lost
|
||||||
(``test_regress/t/t_event_control_double_lost.v``) - which is possible when
|
(``test_regress/t/t_event_control_double_lost.v``) - which is possible
|
||||||
triggers are not evaluated right before awaiting.
|
when triggers are not evaluated right before awaiting.
|
||||||
|
|
||||||
All coroutines are committed and resumed in the 'act' eval loop. With
|
All coroutines are committed and resumed in the 'act' eval loop. With
|
||||||
timing features enabled, the ``_eval()`` function takes this form:
|
timing features enabled, the ``_eval()`` function takes this form:
|
||||||
|
|
@ -937,14 +937,15 @@ macro-task's dataset fits in one core's local caches.
|
||||||
|
|
||||||
To achieve spatial locality, we tag each variable with the set of
|
To achieve spatial locality, we tag each variable with the set of
|
||||||
macro-tasks that access it. Let's call this set the "footprint" of that
|
macro-tasks that access it. Let's call this set the "footprint" of that
|
||||||
variable. The variables in a given module have a set of footprints. We group
|
variable. The variables in a given module have a set of footprints. We
|
||||||
variables with identical non-empty footprints, emit those groups in deterministic
|
group variables with identical non-empty footprints, emit those groups in
|
||||||
footprint-key order, then emit variables with no footprint information last.
|
deterministic footprint-key order, then emit variables with no footprint
|
||||||
|
information last.
|
||||||
|
|
||||||
The first emitted variable in each footprint group is aligned to a cache-line
|
The first emitted variable in each footprint group is aligned to a
|
||||||
boundary. This avoids false sharing between different macro-task footprints
|
cache-line boundary. This avoids false sharing between different macro-task
|
||||||
without building a complete pairwise-distance graph over all footprints, which
|
footprints without building a complete pairwise-distance graph over all
|
||||||
would use excessive memory on very large models.
|
footprints, which would use excessive memory on very large models.
|
||||||
|
|
||||||
This is an old idea. Simulators designed at DEC in the early 1990s used
|
This is an old idea. Simulators designed at DEC in the early 1990s used
|
||||||
similar techniques to optimize both single-thread and multithread modes.
|
similar techniques to optimize both single-thread and multithread modes.
|
||||||
|
|
@ -1299,15 +1300,15 @@ the ``<description>`` field is ``<identifier> : <type>``, where
|
||||||
``<identifier>`` will be used as the base name of the generated operand
|
``<identifier>`` will be used as the base name of the generated operand
|
||||||
accessors, and ``<type>`` is one of:
|
accessors, and ``<type>`` is one of:
|
||||||
|
|
||||||
1. An ``AstNode`` sub-class, defining the operand to be of that type,
|
#. An ``AstNode`` sub-class, defining the operand to be of that type,
|
||||||
always no-null, and with an always null ``nextp()``. That is, the child
|
always no-null, and with an always null ``nextp()``. That is, the child
|
||||||
node is always present, and is a single ``AstNode`` (as opposed to a
|
node is always present, and is a single ``AstNode`` (as opposed to a
|
||||||
list).
|
list).
|
||||||
|
|
||||||
2. ``Optional[<AstNode sub-class>]``. This is just like in point 1 above,
|
#. ``Optional[<AstNode sub-class>]``. This is just like in point 1 above,
|
||||||
but defines the child node to be optional, meaning it may be null.
|
but defines the child node to be optional, meaning it may be null.
|
||||||
|
|
||||||
3. ``List[AstNode sub-class]`` describes a list operand, which means the
|
#. ``List[AstNode sub-class]`` describes a list operand, which means the
|
||||||
child node may have a non-null ``nextp()`` and in addition the child
|
child node may have a non-null ``nextp()`` and in addition the child
|
||||||
itself may be null, representing an empty list.
|
itself may be null, representing an empty list.
|
||||||
|
|
||||||
|
|
@ -1394,7 +1395,7 @@ calling ``accept`` on ``AstIf`` will look in turn for:
|
||||||
|
|
||||||
There are three ways data is passed between visitor functions.
|
There are three ways data is passed between visitor functions.
|
||||||
|
|
||||||
1. A visitor-class member variable. This is generally for passing "parent"
|
#. A visitor-class member variable. This is generally for passing "parent"
|
||||||
information down to children. ``m_modp`` is a common example. It's set
|
information down to children. ``m_modp`` is a common example. It's set
|
||||||
to NULL in the constructor, where that node (``AstModule`` visitor) sets
|
to NULL in the constructor, where that node (``AstModule`` visitor) sets
|
||||||
it, then the children are iterated, then it's cleared. Children under an
|
it, then the children are iterated, then it's cleared. Children under an
|
||||||
|
|
@ -1404,7 +1405,7 @@ There are three ways data is passed between visitor functions.
|
||||||
visitor; otherwise exiting the lower for will lose the upper for's
|
visitor; otherwise exiting the lower for will lose the upper for's
|
||||||
setting.
|
setting.
|
||||||
|
|
||||||
2. User attributes. Each ``AstNode`` (**Note.** The AST node, not the
|
#. User attributes. Each ``AstNode`` (**Note.** The AST node, not the
|
||||||
visitor) has five user attributes, which may be accessed as an integer
|
visitor) has five user attributes, which may be accessed as an integer
|
||||||
using the ``user1()`` through ``user4()`` methods, or as a pointer (of
|
using the ``user1()`` through ``user4()`` methods, or as a pointer (of
|
||||||
type ``AstNUser``) using the ``user1p()`` through ``user4p()`` methods
|
type ``AstNUser``) using the ``user1p()`` through ``user4p()`` methods
|
||||||
|
|
@ -1435,7 +1436,7 @@ There are three ways data is passed between visitor functions.
|
||||||
so it's ok to call fairly often. For example, it's commonly called on
|
so it's ok to call fairly often. For example, it's commonly called on
|
||||||
every module.
|
every module.
|
||||||
|
|
||||||
3. Parameters can be passed between the visitors in close to the "normal"
|
#. Parameters can be passed between the visitors in close to the "normal"
|
||||||
function caller to callee way. This is the second ``vup`` parameter of
|
function caller to callee way. This is the second ``vup`` parameter of
|
||||||
type ``AstNUser`` that is ignored on most of the visitor functions.
|
type ``AstNUser`` that is ignored on most of the visitor functions.
|
||||||
V3Width does this, but it proved messier than the above and is
|
V3Width does this, but it proved messier than the above and is
|
||||||
|
|
@ -2125,19 +2126,19 @@ To print a node:
|
||||||
``src/.gdbinit`` and ``src/.gdbinit.py`` define handy utilities for working
|
``src/.gdbinit`` and ``src/.gdbinit.py`` define handy utilities for working
|
||||||
with JSON AST dumps. For example:
|
with JSON AST dumps. For example:
|
||||||
|
|
||||||
* ``jstash nodep`` - Perform a JSON AST dump and save it into GDB value
|
- ``jstash nodep`` - Perform a JSON AST dump and save it into GDB value
|
||||||
history (e.g. ``$1``)
|
history (e.g. ``$1``)
|
||||||
|
|
||||||
* ``jtree nodep`` - Perform a JSON AST dump and pretty print it using
|
- ``jtree nodep`` - Perform a JSON AST dump and pretty print it using
|
||||||
``astsee_verilator``.
|
``astsee_verilator``.
|
||||||
* ``jtree $1`` - Pretty print a dump that was previously saved by
|
- ``jtree $1`` - Pretty print a dump that was previously saved by
|
||||||
``jstash``.
|
``jstash``.
|
||||||
* ``jtree nodep -d '.file, .timeunit'`` - Perform a JSON AST dump, filter
|
- ``jtree nodep -d '.file, .timeunit'`` - Perform a JSON AST dump, filter
|
||||||
out some fields and pretty print it.
|
out some fields and pretty print it.
|
||||||
|
|
||||||
* ``jtree 0x55555613dca0`` - Pretty print using address literal (rather
|
- ``jtree 0x55555613dca0`` - Pretty print using address literal (rather
|
||||||
than actual pointer).
|
than actual pointer).
|
||||||
* ``jtree $1 nodep`` - Diff ``nodep`` against an older dump.
|
- ``jtree $1 nodep`` - Diff ``nodep`` against an older dump.
|
||||||
|
|
||||||
A detailed description of ``jstash`` and ``jtree`` can be displayed using
|
A detailed description of ``jstash`` and ``jtree`` can be displayed using
|
||||||
``gdb``'s ``help`` command.
|
``gdb``'s ``help`` command.
|
||||||
|
|
@ -2243,25 +2244,25 @@ Adding a New Feature
|
||||||
|
|
||||||
Generally, what would you do to add a new feature?
|
Generally, what would you do to add a new feature?
|
||||||
|
|
||||||
1. File an issue (if there isn't already) so others know what you're
|
#. File an issue (if there isn't already) so others know what you're
|
||||||
working on.
|
working on.
|
||||||
|
|
||||||
2. Make a testcase in the test_regress/t/t_EXAMPLE format, see `Testing`.
|
#. Make a testcase in the test_regress/t/t_EXAMPLE format, see `Testing`.
|
||||||
|
|
||||||
3. If grammar changes are needed, look at the IEEE 1800-2023 Appendix A, as
|
#. If grammar changes are needed, look at the IEEE 1800-2023 Appendix A, as
|
||||||
src/verilog.y generally follows the same rule layout.
|
src/verilog.y generally follows the same rule layout.
|
||||||
|
|
||||||
4. If a new Ast type is needed, add it to the appropriate V3AstNode*.h.
|
#. If a new Ast type is needed, add it to the appropriate V3AstNode*.h.
|
||||||
Follow the convention described above about the AstNode type hierarchy.
|
Follow the convention described above about the AstNode type hierarchy.
|
||||||
Ordering of definitions is enforced by ``astgen``.
|
Ordering of definitions is enforced by ``astgen``.
|
||||||
|
|
||||||
5. Now you can run ``test_regress/t/t_<newtestcase>.py --debug`` and it'll
|
#. Now you can run ``test_regress/t/t_<newtestcase>.py --debug`` and it'll
|
||||||
probably fail, but you'll see a
|
probably fail, but you'll see a
|
||||||
``test_regress/obj_dir/t_<newtestcase>/*.tree`` file which you can
|
``test_regress/obj_dir/t_<newtestcase>/*.tree`` file which you can
|
||||||
examine to see if the parsing worked. See also the sections above on
|
examine to see if the parsing worked. See also the sections above on
|
||||||
debugging.
|
debugging.
|
||||||
|
|
||||||
6. Modify the later visitor functions to process the new feature as needed.
|
#. Modify the later visitor functions to process the new feature as needed.
|
||||||
|
|
||||||
|
|
||||||
Adding a New Pass
|
Adding a New Pass
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
.. for github, vim: syntax=reStructuredText
|
..
|
||||||
.. SPDX-FileCopyrightText: 2025-2026 Wilson Snyder
|
for github, vim: syntax=reStructuredText
|
||||||
.. SPDX-License-Identifier: CC0-1.0
|
SPDX-FileCopyrightText: 2025-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
Security Policy
|
Security Policy
|
||||||
===============
|
===============
|
||||||
|
|
|
||||||
|
|
@ -477,6 +477,7 @@ Syms
|
||||||
Synopsys
|
Synopsys
|
||||||
SystemC
|
SystemC
|
||||||
SystemVerilog
|
SystemVerilog
|
||||||
|
Szpotanski
|
||||||
Takatsukasa
|
Takatsukasa
|
||||||
Tambe
|
Tambe
|
||||||
Tarik
|
Tarik
|
||||||
|
|
@ -537,6 +538,7 @@ Verilog
|
||||||
Vighnesh
|
Vighnesh
|
||||||
Viktor
|
Viktor
|
||||||
Vilp
|
Vilp
|
||||||
|
VlRNG
|
||||||
VlWide
|
VlWide
|
||||||
Vlip
|
Vlip
|
||||||
Vm
|
Vm
|
||||||
|
|
@ -684,6 +686,7 @@ countones
|
||||||
cout
|
cout
|
||||||
covergroup
|
covergroup
|
||||||
covergroups
|
covergroups
|
||||||
|
coverpoint
|
||||||
coverpoints
|
coverpoints
|
||||||
cpp
|
cpp
|
||||||
cppstyle
|
cppstyle
|
||||||
|
|
@ -861,6 +864,7 @@ hx
|
||||||
hyperthreading
|
hyperthreading
|
||||||
hyperthreads
|
hyperthreads
|
||||||
icecream
|
icecream
|
||||||
|
ico
|
||||||
idmap
|
idmap
|
||||||
ifdef
|
ifdef
|
||||||
ifdefed
|
ifdefed
|
||||||
|
|
@ -916,6 +920,7 @@ linters
|
||||||
linux
|
linux
|
||||||
liu
|
liu
|
||||||
livelock
|
livelock
|
||||||
|
liveness
|
||||||
lldb
|
lldb
|
||||||
ln
|
ln
|
||||||
loc
|
loc
|
||||||
|
|
@ -924,6 +929,7 @@ localparams
|
||||||
localtime
|
localtime
|
||||||
logicals
|
logicals
|
||||||
longint
|
longint
|
||||||
|
lookups
|
||||||
lossy
|
lossy
|
||||||
lsb
|
lsb
|
||||||
lubc
|
lubc
|
||||||
|
|
@ -943,6 +949,7 @@ misconnected
|
||||||
misconversion
|
misconversion
|
||||||
misdetecting
|
misdetecting
|
||||||
misoptimized
|
misoptimized
|
||||||
|
misoptimizing
|
||||||
missized
|
missized
|
||||||
mk
|
mk
|
||||||
mno
|
mno
|
||||||
|
|
@ -1204,6 +1211,7 @@ typename
|
||||||
uint
|
uint
|
||||||
un
|
un
|
||||||
unbased
|
unbased
|
||||||
|
unclocked
|
||||||
uncomment
|
uncomment
|
||||||
undef
|
undef
|
||||||
undefineall
|
undefineall
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
<!-- DESCRIPTION: Verilator: include/ guidelines for AI coding agents
|
||||||
|
SPDX-FileCopyrightText: 2026-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -->
|
||||||
|
|
||||||
|
# include/ -- Verilator runtime library
|
||||||
|
|
||||||
|
Covers the C++ runtime under `include/` (`verilated.h/.cpp`, `verilated_*.h/.cpp`)
|
||||||
|
that every generated model links against. Read the repository-root
|
||||||
|
[AGENTS.md](../AGENTS.md) first. The rules here differ from `src/`: this code
|
||||||
|
ships to users, runs every simulation cycle, and must stay portable and fast.
|
||||||
|
|
||||||
|
______________________________________________________________________
|
||||||
|
|
||||||
|
# Orientation
|
||||||
|
|
||||||
|
- **This is the runtime, not the compiler.** The passes in `src/` *emit* C++ that
|
||||||
|
calls into this library; this code then *runs* during simulation. Optimize it
|
||||||
|
for execution speed and portability, not for compile-time clarity.
|
||||||
|
- **Key files:** `verilated.h` (core model API), `verilated_types.h` (data
|
||||||
|
types), `verilated_random.cpp` (constrained-random runtime), `verilated_cov.*`
|
||||||
|
(coverage), `verilated_threads.*` (MT runtime), `verilated_timing.*`
|
||||||
|
(`--timing` runtime), `verilated_vcd_c.*`/`verilated_fst_c.*` (tracing).
|
||||||
|
- A runtime-only fix lives entirely here and does not rebuild `verilator_bin`.
|
||||||
|
|
||||||
|
______________________________________________________________________
|
||||||
|
|
||||||
|
# Before you open a PR
|
||||||
|
|
||||||
|
- **C++14 baseline.** The runtime must build under `--no-timing` with C++14; C++20
|
||||||
|
features are allowed only in `--timing` code paths.
|
||||||
|
- **Public API naming and docs.** Prefix public classes and types with
|
||||||
|
`Verilated`/`Vl` to avoid collisions with user code, and document the API with
|
||||||
|
`///` comments -- they feed doc generation.
|
||||||
|
- **No exceptions in runtime code** -- use error returns or assertions; exceptions
|
||||||
|
add overhead on every path.
|
||||||
|
- **Use fixed-width model types** (`CData`/`SData`/`IData`/`QData`/`VlWide`), never
|
||||||
|
`size_t`, for model data. Process wide data word-by-word (`VL_ZERO_W`,
|
||||||
|
`VL_MEMCPY_W`), never bit-by-bit or byte-by-byte.
|
||||||
|
- **Do all string parsing at verilation time** -- never parse strings during
|
||||||
|
simulation; emit structured data or compile-time hints instead.
|
||||||
|
- **Keep per-cycle code lean.** Do not add vtables to high-frequency objects
|
||||||
|
(8 bytes per instance); guard optional features behind
|
||||||
|
`hasClasses()`/`hasEvents()`-style checks; functions called per cycle must avoid
|
||||||
|
mutexes -- use atomics or lockless designs.
|
||||||
|
- **Emit no runtime loops** the compiler could have expanded at verilation time;
|
||||||
|
prefer a single runtime call.
|
||||||
|
- **Thread safety.** Annotate with the hierarchy `VL_PURE` > `VL_MT_SAFE` >
|
||||||
|
`VL_MT_STABLE`; annotations must match the implementation. Annotate
|
||||||
|
mutex-protected members with `VL_GUARDED_BY` and document acquisition ordering.
|
||||||
|
Prefer has-a over is-a: a guarded class wrapping the unguarded internal one, with
|
||||||
|
the guarded version as the default public API.
|
||||||
|
- **Keep runtime and compiler headers separate** -- never include `verilated.h`
|
||||||
|
into the compiler in `src/`.
|
||||||
|
|
||||||
|
## File-specific rules
|
||||||
|
|
||||||
|
| File | Rule |
|
||||||
|
|---|---|
|
||||||
|
| `verilated_random.cpp` | Emit only portable SMT-LIB 2.6 -- no solver-specific or MaxSMT extensions; the generated solver text is the model's runtime constraint interface |
|
||||||
|
| `verilated_cov.cpp` | Coverage runtime is shared by all models -- keep per-point overhead minimal and the on-disk format stable for `verilator_coverage` |
|
||||||
|
|
@ -81,6 +81,12 @@
|
||||||
std::abort(); \
|
std::abort(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FST_FAIL_STRING(s) \
|
||||||
|
do { \
|
||||||
|
std::cerr << (s) << std::endl; \
|
||||||
|
std::abort(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
// We turn on all DCHECKs to CHECKs temporarily for better safety.
|
// We turn on all DCHECKs to CHECKs temporarily for better safety.
|
||||||
#if 1
|
#if 1
|
||||||
# define FST_DCHECK(a) FST_CHECK(a)
|
# define FST_DCHECK(a) FST_CHECK(a)
|
||||||
|
|
|
||||||
|
|
@ -335,10 +335,10 @@ public:
|
||||||
// Double variables should not use these array-based emitValueChange overloads.
|
// Double variables should not use these array-based emitValueChange overloads.
|
||||||
// We implement them to satisfy the VairableInfo::dispatchHelper template instantiation.
|
// We implement them to satisfy the VairableInfo::dispatchHelper template instantiation.
|
||||||
void emitValueChange(uint64_t, const uint32_t *, EncodingType) {
|
void emitValueChange(uint64_t, const uint32_t *, EncodingType) {
|
||||||
throw std::runtime_error("emitValueChange(uint32_t*) not supported for Double");
|
FST_FAIL_STRING("emitValueChange(uint32_t*) not supported for Double");
|
||||||
}
|
}
|
||||||
void emitValueChange(uint64_t, const uint64_t *, EncodingType) {
|
void emitValueChange(uint64_t, const uint64_t *, EncodingType) {
|
||||||
throw std::runtime_error("emitValueChange(uint64_t*) not supported for Double");
|
FST_FAIL_STRING("emitValueChange(uint64_t*) not supported for Double");
|
||||||
}
|
}
|
||||||
|
|
||||||
void dumpInitialBits(std::vector<uint8_t> &buf) const {
|
void dumpInitialBits(std::vector<uint8_t> &buf) const {
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ Handle Writer::createVar(
|
||||||
// (void)type;
|
// (void)type;
|
||||||
// (void)svt;
|
// (void)svt;
|
||||||
// (void)sdt;
|
// (void)sdt;
|
||||||
// throw std::runtime_error("TODO");
|
// FST_FAIL_STRING("TODO");
|
||||||
// return 0;
|
// return 0;
|
||||||
// }
|
// }
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
|
|
@ -353,11 +353,7 @@ void compressUsingZlib(
|
||||||
uncompressed_size,
|
uncompressed_size,
|
||||||
level
|
level
|
||||||
);
|
);
|
||||||
if (z_status != Z_OK) {
|
FST_CHECK_EQ(z_status, Z_OK);
|
||||||
throw std::runtime_error(
|
|
||||||
"Failed to compress data with zlib, error code: " + std::to_string(z_status)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
compressed_data.resize(compressed_bound);
|
compressed_data.resize(compressed_bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,12 @@
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# define _VL_HAVE_GETRLIMIT
|
# define _VL_HAVE_GETRLIMIT
|
||||||
#endif
|
#endif
|
||||||
|
#if VM_VPI
|
||||||
|
# include <cstring>
|
||||||
|
# ifndef _WIN32
|
||||||
|
# include <dlfcn.h> // dlopen
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "verilated_threads.h"
|
#include "verilated_threads.h"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
@ -260,6 +266,58 @@ void VL_WARN_MT(const char* filename, int linenum, const char* hier, const char*
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
// Runtime VPI shared library loading (--vpi)
|
||||||
|
|
||||||
|
// Load one VPI shared library named by a +verilator+vpi+<lib>[:<bootstrap>] argument.
|
||||||
|
// 'arg' is the payload after the prefix: either "<lib>" (invoke the library's
|
||||||
|
// vlog_startup_routines array) or "<lib>:<bootstrap>" (invoke the named bootstrap).
|
||||||
|
void Verilated::loadVpiLib(const std::string& arg) VL_MT_UNSAFE {
|
||||||
|
#if VM_VPI
|
||||||
|
if (arg.empty()) return;
|
||||||
|
#ifdef _WIN32
|
||||||
|
VL_FATAL_MT("", 0, "",
|
||||||
|
"+verilator+vpi+: runtime VPI library loading is not supported on"
|
||||||
|
" Windows; link the VPI code into the model instead");
|
||||||
|
#else
|
||||||
|
using vlog_startup_t = void (*)();
|
||||||
|
// Split <lib>:<bootstrap> on the last ':'
|
||||||
|
const std::string::size_type colon_pos = arg.rfind(':');
|
||||||
|
const bool has_entry = (colon_pos != std::string::npos);
|
||||||
|
const std::string libpath = has_entry ? arg.substr(0, colon_pos) : arg;
|
||||||
|
const std::string entry_name = has_entry ? arg.substr(colon_pos + 1) : std::string{};
|
||||||
|
void* handle = dlopen(libpath.c_str(), RTLD_LAZY);
|
||||||
|
if (!handle)
|
||||||
|
// The library path is stable; the dlerror() text is platform-specific, so put it on
|
||||||
|
// a separate "- " line (test golden files strip "- " lines, keeping output portable).
|
||||||
|
VL_FATAL_MT(
|
||||||
|
"", 0, "",
|
||||||
|
(std::string{"Cannot load VPI library: "} + libpath + "\n- dlerror: " + dlerror())
|
||||||
|
.c_str());
|
||||||
|
if (has_entry) {
|
||||||
|
vlog_startup_t bsp = reinterpret_cast<vlog_startup_t>(dlsym(handle, entry_name.c_str()));
|
||||||
|
if (!bsp)
|
||||||
|
VL_FATAL_MT(
|
||||||
|
"", 0, "",
|
||||||
|
(std::string{"Cannot find VPI bootstrap '"} + entry_name + "' in: " + libpath)
|
||||||
|
.c_str());
|
||||||
|
bsp();
|
||||||
|
} else {
|
||||||
|
vlog_startup_t* routinesp
|
||||||
|
= reinterpret_cast<vlog_startup_t*>(dlsym(handle, "vlog_startup_routines"));
|
||||||
|
if (!routinesp)
|
||||||
|
VL_FATAL_MT(
|
||||||
|
"", 0, "",
|
||||||
|
(std::string{"Cannot find 'vlog_startup_routines' in: "} + libpath).c_str());
|
||||||
|
for (int j = 0; routinesp[j]; ++j) routinesp[j]();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Never reached: the command-line handler only calls this when compiled with --vpi.
|
||||||
|
(void)arg;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
// Debug prints
|
// Debug prints
|
||||||
|
|
||||||
|
|
@ -318,6 +376,12 @@ void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE {
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VL_FFLUSH_MT() VL_MT_SAFE {
|
||||||
|
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
|
||||||
|
Verilated::runFlushCallbacks();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
template <typename... snprintf_args_ts>
|
template <typename... snprintf_args_ts>
|
||||||
static size_t _vl_snprintf_string(std::string& str, const char* format,
|
static size_t _vl_snprintf_string(std::string& str, const char* format,
|
||||||
snprintf_args_ts... args) VL_MT_SAFE {
|
snprintf_args_ts... args) VL_MT_SAFE {
|
||||||
|
|
@ -499,9 +563,10 @@ IData VL_URANDOM_SEEDED_II(IData seed) VL_MT_SAFE {
|
||||||
}
|
}
|
||||||
|
|
||||||
IData VL_SCOPED_RAND_RESET_I(int obits, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE {
|
IData VL_SCOPED_RAND_RESET_I(int obits, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE {
|
||||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
const int randReset = Verilated::threadContextp()->randReset();
|
||||||
|
if (randReset == 0) return 0;
|
||||||
IData data = ~0;
|
IData data = ~0;
|
||||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
if (randReset != 1) { // if 2, randomize
|
||||||
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
||||||
data = rng.rand64();
|
data = rng.rand64();
|
||||||
}
|
}
|
||||||
|
|
@ -510,9 +575,10 @@ IData VL_SCOPED_RAND_RESET_I(int obits, uint64_t scopeHash, uint64_t salt) VL_MT
|
||||||
}
|
}
|
||||||
|
|
||||||
QData VL_SCOPED_RAND_RESET_Q(int obits, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE {
|
QData VL_SCOPED_RAND_RESET_Q(int obits, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE {
|
||||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
const int randReset = Verilated::threadContextp()->randReset();
|
||||||
|
if (randReset == 0) return 0;
|
||||||
QData data = ~0ULL;
|
QData data = ~0ULL;
|
||||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
if (randReset != 1) { // if 2, randomize
|
||||||
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
||||||
data = rng.rand64();
|
data = rng.rand64();
|
||||||
}
|
}
|
||||||
|
|
@ -522,10 +588,17 @@ QData VL_SCOPED_RAND_RESET_Q(int obits, uint64_t scopeHash, uint64_t salt) VL_MT
|
||||||
|
|
||||||
WDataOutP VL_SCOPED_RAND_RESET_W(int obits, WDataOutP outwp, uint64_t scopeHash,
|
WDataOutP VL_SCOPED_RAND_RESET_W(int obits, WDataOutP outwp, uint64_t scopeHash,
|
||||||
uint64_t salt) VL_MT_UNSAFE {
|
uint64_t salt) VL_MT_UNSAFE {
|
||||||
if (Verilated::threadContextp()->randReset() != 2) { return VL_RAND_RESET_W(obits, outwp); }
|
const int words = VL_WORDS_I(obits);
|
||||||
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
const int randReset = Verilated::threadContextp()->randReset();
|
||||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = rng.rand64();
|
if (randReset == 0) {
|
||||||
outwp[VL_WORDS_I(obits) - 1] = rng.rand64() & VL_MASK_E(obits);
|
VL_MEMSET_ZERO_W(outwp, words);
|
||||||
|
} else if (randReset == 1) {
|
||||||
|
VL_MEMSET_ONES_W(outwp, words);
|
||||||
|
} else {
|
||||||
|
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
||||||
|
for (int i = 0; i < words; ++i) outwp[i] = rng.rand64();
|
||||||
|
}
|
||||||
|
outwp[words - 1] &= VL_MASK_E(obits);
|
||||||
return outwp;
|
return outwp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -550,30 +623,14 @@ WDataOutP VL_SCOPED_RAND_RESET_ASSIGN_W(int obits, WDataOutP outwp, uint64_t sco
|
||||||
}
|
}
|
||||||
|
|
||||||
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
||||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
const int randReset = Verilated::threadContextp()->randReset();
|
||||||
|
if (randReset == 0) return 0;
|
||||||
IData data = ~0;
|
IData data = ~0;
|
||||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
if (randReset != 1) data = VL_RANDOM_I(); // if 2, randomize
|
||||||
data = VL_RANDOM_I();
|
|
||||||
}
|
|
||||||
data &= VL_MASK_I(obits);
|
data &= VL_MASK_I(obits);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
|
|
||||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
|
||||||
QData data = ~0ULL;
|
|
||||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
|
||||||
data = VL_RANDOM_Q();
|
|
||||||
}
|
|
||||||
data &= VL_MASK_Q(obits);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
|
||||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = VL_RAND_RESET_I(32);
|
|
||||||
outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_I(32) & VL_MASK_E(obits);
|
|
||||||
return outwp;
|
|
||||||
}
|
|
||||||
WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||||
// Not inlined to speed up compilation of slowpath code
|
// Not inlined to speed up compilation of slowpath code
|
||||||
return VL_ZERO_W(obits, outwp);
|
return VL_ZERO_W(obits, outwp);
|
||||||
|
|
@ -3028,40 +3085,97 @@ void VerilatedContext::assertOn(bool flag) VL_MT_SAFE {
|
||||||
}
|
}
|
||||||
bool VerilatedContext::assertOnGet(VerilatedAssertType_t type,
|
bool VerilatedContext::assertOnGet(VerilatedAssertType_t type,
|
||||||
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE {
|
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE {
|
||||||
// Check if selected directive type bit in the assertOn is enabled for assertion type.
|
return assertCtlGet(VerilatedAssertCtlQuery::ASSERT_CTL_ON, type, directive);
|
||||||
// Note: it is assumed that this is checked only for one type at the time.
|
}
|
||||||
|
uint32_t VerilatedContext::assertOnMask(VerilatedAssertType_t types,
|
||||||
// Flag unspecified assertion types as disabled.
|
VerilatedAssertDirectiveType_t directives) VL_PURE {
|
||||||
if (type == 0) return false;
|
// Place the directive bits at each selected assertion type's 3-bit group.
|
||||||
|
uint32_t mask = 0;
|
||||||
// Get index of 3-bit group guarding assertion type status.
|
for (int i = 0; i < std::numeric_limits<VerilatedAssertType_t>::digits; ++i) {
|
||||||
// Since the assertOnGet is generated __always__ for a single assert type, we assume that only
|
if (VL_BITISSET_I(types, i)) mask |= directives << (i * ASSERT_DIRECTIVE_TYPE_MASK_WIDTH);
|
||||||
// a single bit will be set. Thus, ceil log2 will work fine.
|
}
|
||||||
VL_DEBUG_IFDEF(assert((type & (type - 1)) == 0););
|
return mask;
|
||||||
const IData typeMaskPosition = VL_CLOG2_I(type);
|
|
||||||
|
|
||||||
// Check if directive type bit is enabled in corresponding assertion type bits.
|
|
||||||
return m_s.m_assertOn & (directive << (typeMaskPosition * ASSERT_DIRECTIVE_TYPE_MASK_WIDTH));
|
|
||||||
}
|
}
|
||||||
void VerilatedContext::assertOnSet(VerilatedAssertType_t types,
|
void VerilatedContext::assertOnSet(VerilatedAssertType_t types,
|
||||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||||
// For each assertion type, set directive bits.
|
m_s.m_assertOn |= assertOnMask(types, directives);
|
||||||
|
|
||||||
// Iterate through all positions of assertion type bits. If bit for this assertion type is set,
|
|
||||||
// set directive type bits mask at this group index.
|
|
||||||
for (int i = 0; i < std::numeric_limits<VerilatedAssertType_t>::digits; ++i) {
|
|
||||||
if (VL_BITISSET_I(types, i))
|
|
||||||
m_s.m_assertOn |= directives << (i * ASSERT_DIRECTIVE_TYPE_MASK_WIDTH);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void VerilatedContext::assertOnClear(VerilatedAssertType_t types,
|
void VerilatedContext::assertOnClear(VerilatedAssertType_t types,
|
||||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||||
// Iterate through all positions of assertion type bits. If bit for this assertion type is set,
|
m_s.m_assertOn &= ~assertOnMask(types, directives);
|
||||||
// clear directive type bits mask at this group index.
|
}
|
||||||
for (int i = 0; i < std::numeric_limits<VerilatedAssertType_t>::digits; ++i) {
|
void VerilatedContext::assertCtl(uint32_t controlType, VerilatedAssertType_t types,
|
||||||
if (VL_BITISSET_I(types, i))
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||||
m_s.m_assertOn &= ~(directives << (i * ASSERT_DIRECTIVE_TYPE_MASK_WIDTH));
|
// IEEE 1800-2023 Table 20-5 control_type. Lock freezes the On/Off state of the
|
||||||
|
// selected bits until Unlock; On/Off/Kill leave locked bits unchanged.
|
||||||
|
const uint32_t mask = assertOnMask(types, directives);
|
||||||
|
const uint32_t lockedMask = mask & ~m_s.m_assertLock;
|
||||||
|
switch (controlType) {
|
||||||
|
case 1: // Lock
|
||||||
|
m_s.m_assertLock |= mask;
|
||||||
|
break;
|
||||||
|
case 2: // Unlock
|
||||||
|
m_s.m_assertLock &= ~mask;
|
||||||
|
break;
|
||||||
|
case 3: // On
|
||||||
|
m_s.m_assertOn |= lockedMask;
|
||||||
|
break;
|
||||||
|
case 4: // Off
|
||||||
|
m_s.m_assertOn &= ~lockedMask;
|
||||||
|
break;
|
||||||
|
case 5: { // Kill
|
||||||
|
m_s.m_assertOn &= ~lockedMask;
|
||||||
|
for (int slot = 0; slot < static_cast<int>(ASSERT_CONTROL_SLOT_COUNT); ++slot) {
|
||||||
|
if (VL_BITISSET_I(lockedMask, slot)) { m_s.m_assertKill[slot]++; }
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case 6: // PassOn
|
||||||
|
m_s.m_assertPassOnVacuous |= lockedMask;
|
||||||
|
m_s.m_assertPassOnNonvacuous |= lockedMask;
|
||||||
|
break;
|
||||||
|
case 7: // PassOff
|
||||||
|
m_s.m_assertPassOnVacuous &= ~lockedMask;
|
||||||
|
m_s.m_assertPassOnNonvacuous &= ~lockedMask;
|
||||||
|
break;
|
||||||
|
case 8: // FailOn
|
||||||
|
m_s.m_assertFailOn |= lockedMask;
|
||||||
|
break;
|
||||||
|
case 9: // FailOff
|
||||||
|
m_s.m_assertFailOn &= ~lockedMask;
|
||||||
|
break;
|
||||||
|
case 10: // NonvacuousOn
|
||||||
|
m_s.m_assertPassOnNonvacuous |= lockedMask;
|
||||||
|
break;
|
||||||
|
case 11: // VacuousOff
|
||||||
|
m_s.m_assertPassOnVacuous &= ~lockedMask;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
VL_WARN_MT("", 0, "",
|
||||||
|
("Bad $assertcontrol control_type '" + std::to_string(controlType)
|
||||||
|
+ "' (IEEE 1800-2023 Table 20-5)")
|
||||||
|
.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t
|
||||||
|
VerilatedContext::assertCtlGet(VerilatedAssertCtlQuery query, VerilatedAssertType_t type,
|
||||||
|
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE {
|
||||||
|
const uint32_t mask = assertOnMask(type, directive);
|
||||||
|
if (!mask) return 0;
|
||||||
|
switch (query) { // LCOV_EXCL_BR_LINE
|
||||||
|
case VerilatedAssertCtlQuery::ASSERT_CTL_ON: return (m_s.m_assertOn & mask) != 0;
|
||||||
|
case VerilatedAssertCtlQuery::ASSERT_CTL_KILL:
|
||||||
|
assert(mask && (mask & (mask - 1)) == 0);
|
||||||
|
return m_s.m_assertKill[VL_CLOG2_I(mask)];
|
||||||
|
case VerilatedAssertCtlQuery::ASSERT_CTL_PASS_ON_VACUOUS:
|
||||||
|
return (m_s.m_assertPassOnVacuous & mask) != 0;
|
||||||
|
case VerilatedAssertCtlQuery::ASSERT_CTL_PASS_ON_NONVACUOUS:
|
||||||
|
return (m_s.m_assertPassOnNonvacuous & mask) != 0;
|
||||||
|
case VerilatedAssertCtlQuery::ASSERT_CTL_FAIL_ON: return (m_s.m_assertFailOn & mask) != 0;
|
||||||
|
default: // LCOV_EXCL_START
|
||||||
|
VL_FATAL_MT("", 0, "", "Internal: Bad assertCtlGet query");
|
||||||
|
VL_UNREACHABLE;
|
||||||
|
} // LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
void VerilatedContext::calcUnusedSigs(bool flag) VL_MT_SAFE {
|
void VerilatedContext::calcUnusedSigs(bool flag) VL_MT_SAFE {
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
|
|
@ -3480,6 +3594,17 @@ void VerilatedContextImp::commandArgVl(const std::string& arg) {
|
||||||
// and the run can be reproduced by passing +verilator+seed+<that_value>.
|
// and the run can be reproduced by passing +verilator+seed+<that_value>.
|
||||||
if (u64 == 0) u64 = pickRandomSeed();
|
if (u64 == 0) u64 = pickRandomSeed();
|
||||||
randSeed(static_cast<int>(u64));
|
randSeed(static_cast<int>(u64));
|
||||||
|
} else if (commandArgVlString(arg, "+verilator+vpi+", str)) {
|
||||||
|
// With --vpi, load the requested shared library now. Without --vpi there is
|
||||||
|
// no VPI runtime, so warn the argument is ignored.
|
||||||
|
#if VM_VPI
|
||||||
|
Verilated::loadVpiLib(str);
|
||||||
|
#else
|
||||||
|
VL_WARN_MT(
|
||||||
|
"COMMAND_LINE", 0, "",
|
||||||
|
("+verilator+vpi+ ignored: simulation was not compiled with --vpi '" + arg + "'")
|
||||||
|
.c_str()); // LCOV_EXCL_LINE (gcov zeroes this wrapped continuation line)
|
||||||
|
#endif
|
||||||
} else if (arg == "+verilator+V") {
|
} else if (arg == "+verilator+V") {
|
||||||
VerilatedImp::versionDump(); // Someday more info too
|
VerilatedImp::versionDump(); // Someday more info too
|
||||||
VL_FATAL_MT("COMMAND_LINE", 0, "",
|
VL_FATAL_MT("COMMAND_LINE", 0, "",
|
||||||
|
|
@ -3893,6 +4018,7 @@ std::unique_ptr<VerilatedTraceConfig> VerilatedModel::traceConfig() const { retu
|
||||||
|
|
||||||
// cppcheck-suppress unusedFunction // Used by applications
|
// cppcheck-suppress unusedFunction // Used by applications
|
||||||
uint32_t VerilatedVarProps::entSize() const VL_MT_SAFE {
|
uint32_t VerilatedVarProps::entSize() const VL_MT_SAFE {
|
||||||
|
if (m_entSize) return m_entSize;
|
||||||
uint32_t size = 1;
|
uint32_t size = 1;
|
||||||
switch (vltype()) {
|
switch (vltype()) {
|
||||||
case VLVT_PTR: size = sizeof(void*); break;
|
case VLVT_PTR: size = sizeof(void*); break;
|
||||||
|
|
@ -4009,6 +4135,27 @@ VerilatedVar* VerilatedScope::varInsert(const char* namep, void* datap, bool isP
|
||||||
return &(m_varsp->find(namep)->second);
|
return &(m_varsp->find(namep)->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VerilatedVar* VerilatedScope::varInsertSized(const char* namep, void* datap, bool isParam,
|
||||||
|
VerilatedVarType vltype, int vlflags, int udims,
|
||||||
|
uint32_t entSize...) VL_MT_UNSAFE {
|
||||||
|
if (!m_varsp) m_varsp = new VerilatedVarNameMap;
|
||||||
|
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), udims, 0,
|
||||||
|
isParam, entSize);
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, entSize);
|
||||||
|
for (int i = 0; i < udims; ++i) {
|
||||||
|
const int msb = va_arg(ap, int);
|
||||||
|
const int lsb = va_arg(ap, int);
|
||||||
|
var.m_unpacked[i].m_left = msb;
|
||||||
|
var.m_unpacked[i].m_right = lsb;
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
m_varsp->emplace(namep, std::move(var));
|
||||||
|
return &(m_varsp->find(namep)->second);
|
||||||
|
}
|
||||||
|
|
||||||
VerilatedVar*
|
VerilatedVar*
|
||||||
VerilatedScope::forceableVarInsert(const char* namep, void* datap, bool isParam,
|
VerilatedScope::forceableVarInsert(const char* namep, void* datap, bool isParam,
|
||||||
VerilatedVarType vltype, int vlflags, void* forceReadSignalData,
|
VerilatedVarType vltype, int vlflags, void* forceReadSignalData,
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,9 @@ enum VerilatedVarType : uint8_t {
|
||||||
VLVT_UINT64, // AKA QData
|
VLVT_UINT64, // AKA QData
|
||||||
VLVT_WDATA, // AKA VlWide
|
VLVT_WDATA, // AKA VlWide
|
||||||
VLVT_STRING, // C++ string
|
VLVT_STRING, // C++ string
|
||||||
VLVT_REAL // AKA double
|
VLVT_REAL, // AKA double
|
||||||
|
VLVT_STRUCT, // SystemVerilog unpacked struct
|
||||||
|
VLVT_UNION // SystemVerilog unpacked union
|
||||||
};
|
};
|
||||||
|
|
||||||
enum VerilatedVarFlags : uint32_t {
|
enum VerilatedVarFlags : uint32_t {
|
||||||
|
|
@ -154,7 +156,8 @@ enum VerilatedVarFlags : uint32_t {
|
||||||
VLVF_CONTINUOUSLY = (1 << 11), // Is continously assigned
|
VLVF_CONTINUOUSLY = (1 << 11), // Is continously assigned
|
||||||
VLVF_FORCEABLE = (1 << 12), // Forceable
|
VLVF_FORCEABLE = (1 << 12), // Forceable
|
||||||
VLVF_SIGNED = (1 << 13), // Signed integer
|
VLVF_SIGNED = (1 << 13), // Signed integer
|
||||||
VLVF_BITVAR = (1 << 14) // Four state bit (vs two state logic)
|
VLVF_BITVAR = (1 << 14), // Four state bit (vs two state logic)
|
||||||
|
VLVF_NET = (1 << 15) // Net object
|
||||||
};
|
};
|
||||||
|
|
||||||
// IEEE 1800-2023 Table 20-6
|
// IEEE 1800-2023 Table 20-6
|
||||||
|
|
@ -175,6 +178,15 @@ enum class VerilatedAssertDirectiveType : uint8_t {
|
||||||
DIRECTIVE_TYPE_COVER = (1 << 1),
|
DIRECTIVE_TYPE_COVER = (1 << 1),
|
||||||
DIRECTIVE_TYPE_ASSUME = (1 << 2),
|
DIRECTIVE_TYPE_ASSUME = (1 << 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Runtime query selector for assertion-control state
|
||||||
|
enum class VerilatedAssertCtlQuery : uint8_t {
|
||||||
|
ASSERT_CTL_ON,
|
||||||
|
ASSERT_CTL_KILL,
|
||||||
|
ASSERT_CTL_PASS_ON_VACUOUS,
|
||||||
|
ASSERT_CTL_PASS_ON_NONVACUOUS,
|
||||||
|
ASSERT_CTL_FAIL_ON,
|
||||||
|
};
|
||||||
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;
|
||||||
|
|
||||||
|
|
@ -356,6 +368,10 @@ private:
|
||||||
static constexpr size_t ASSERT_ON_WIDTH
|
static constexpr size_t ASSERT_ON_WIDTH
|
||||||
= ASSERT_DIRECTIVE_TYPE_MASK_WIDTH * std::numeric_limits<VerilatedAssertType_t>::digits
|
= ASSERT_DIRECTIVE_TYPE_MASK_WIDTH * std::numeric_limits<VerilatedAssertType_t>::digits
|
||||||
+ 1;
|
+ 1;
|
||||||
|
// Build the assertion-control bit mask for the given assertion x directive types.
|
||||||
|
static uint32_t assertOnMask(VerilatedAssertType_t types,
|
||||||
|
VerilatedAssertDirectiveType_t directives) VL_PURE;
|
||||||
|
static constexpr size_t ASSERT_CONTROL_SLOT_COUNT = ASSERT_ON_WIDTH - 1;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// TYPES
|
// TYPES
|
||||||
|
|
@ -375,6 +391,16 @@ protected:
|
||||||
// for each VerilatedAssertType we store
|
// for each VerilatedAssertType we store
|
||||||
// 3-bits, one for each directive type. Last
|
// 3-bits, one for each directive type. Last
|
||||||
// bit guards internal directive types.
|
// bit guards internal directive types.
|
||||||
|
std::atomic<uint32_t> m_assertLock{0}; // Locked assertion bits (IEEE 1800-2023 20.11
|
||||||
|
// Lock/Unlock); same layout as m_assertOn. While
|
||||||
|
// a bit is locked, On/Off/Kill leave it unchanged.
|
||||||
|
std::atomic<uint32_t> m_assertPassOnVacuous{
|
||||||
|
std::numeric_limits<uint32_t>::max()}; // Enabled vacuous pass actions
|
||||||
|
std::atomic<uint32_t> m_assertPassOnNonvacuous{
|
||||||
|
std::numeric_limits<uint32_t>::max()}; // Enabled nonvacuous pass actions
|
||||||
|
std::atomic<uint32_t> m_assertFailOn{
|
||||||
|
std::numeric_limits<uint32_t>::max()}; // Enabled fail actions
|
||||||
|
std::array<std::atomic<uint32_t>, ASSERT_CONTROL_SLOT_COUNT> m_assertKill{};
|
||||||
bool m_calcUnusedSigs = false; // Waves file on, need all signals calculated
|
bool m_calcUnusedSigs = false; // Waves file on, need all signals calculated
|
||||||
bool m_fatalOnError = true; // Fatal on $stop/non-fatal error
|
bool m_fatalOnError = true; // Fatal on $stop/non-fatal error
|
||||||
bool m_fatalOnVpiError = true; // Fatal on vpi error/unsupported
|
bool m_fatalOnVpiError = true; // Fatal on vpi error/unsupported
|
||||||
|
|
@ -484,6 +510,13 @@ public:
|
||||||
/// Clear enabled status for given assertion types
|
/// Clear enabled status for given assertion types
|
||||||
void assertOnClear(VerilatedAssertType_t types,
|
void assertOnClear(VerilatedAssertType_t types,
|
||||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
|
||||||
|
/// Apply assertion control for given control, assertion, and directive types
|
||||||
|
void assertCtl(uint32_t controlType, VerilatedAssertType_t types,
|
||||||
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
|
||||||
|
/// Get assertion-control runtime state. Boolean queries return 0/1, Kill returns
|
||||||
|
/// the generation count.
|
||||||
|
uint32_t assertCtlGet(VerilatedAssertCtlQuery query, VerilatedAssertType_t type,
|
||||||
|
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE;
|
||||||
/// Return if calculating of unused signals (for traces)
|
/// Return if calculating of unused signals (for traces)
|
||||||
bool calcUnusedSigs() const VL_MT_SAFE { return m_s.m_calcUnusedSigs; }
|
bool calcUnusedSigs() const VL_MT_SAFE { return m_s.m_calcUnusedSigs; }
|
||||||
/// Enable calculation of unused signals (for traces)
|
/// Enable calculation of unused signals (for traces)
|
||||||
|
|
@ -751,6 +784,9 @@ public: // But internals only - called from verilated modules, VerilatedSyms
|
||||||
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
|
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
|
||||||
VerilatedVar* varInsert(const char* namep, void* datap, bool isParam, VerilatedVarType vltype,
|
VerilatedVar* varInsert(const char* namep, void* datap, bool isParam, VerilatedVarType vltype,
|
||||||
int vlflags, int udims, int pdims, ...) VL_MT_UNSAFE;
|
int vlflags, int udims, int pdims, ...) VL_MT_UNSAFE;
|
||||||
|
VerilatedVar* varInsertSized(const char* namep, void* datap, bool isParam,
|
||||||
|
VerilatedVarType vltype, int vlflags, int udims, uint32_t entSize,
|
||||||
|
...) VL_MT_UNSAFE;
|
||||||
VerilatedVar* forceableVarInsert(const char* namep, void* datap, bool isParam,
|
VerilatedVar* forceableVarInsert(const char* namep, void* datap, bool isParam,
|
||||||
VerilatedVarType vltype, int vlflags,
|
VerilatedVarType vltype, int vlflags,
|
||||||
void* forceReadSignalData, const char* forceReadSignalName,
|
void* forceReadSignalData, const char* forceReadSignalName,
|
||||||
|
|
@ -1000,6 +1036,9 @@ public:
|
||||||
static void scTraceBeforeElaborationError() VL_ATTR_NORETURN VL_MT_SAFE;
|
static void scTraceBeforeElaborationError() VL_ATTR_NORETURN VL_MT_SAFE;
|
||||||
static void stackCheck(QData needSize) VL_MT_UNSAFE;
|
static void stackCheck(QData needSize) VL_MT_UNSAFE;
|
||||||
|
|
||||||
|
// Internal: Load a VPI shared library (+verilator+vpi+<lib>[:<bootstrap>])
|
||||||
|
static void loadVpiLib(const std::string& arg) VL_MT_UNSAFE;
|
||||||
|
|
||||||
// Internal: Get and set DPI context
|
// Internal: Get and set DPI context
|
||||||
static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; }
|
static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; }
|
||||||
static void dpiScope(const VerilatedScope* scopep) VL_MT_SAFE { t_s.t_dpiScopep = scopep; }
|
static void dpiScope(const VerilatedScope* scopep) VL_MT_SAFE { t_s.t_dpiScopep = scopep; }
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,9 @@ CFG_GCH_IF_CLANG = @CFG_GCH_IF_CLANG@
|
||||||
CFG_LDFLAGS_VERILATED = @CFG_LDFLAGS_VERILATED@
|
CFG_LDFLAGS_VERILATED = @CFG_LDFLAGS_VERILATED@
|
||||||
# Linker libraries for multithreading
|
# Linker libraries for multithreading
|
||||||
CFG_LDLIBS_THREADS = @CFG_LDLIBS_THREADS@
|
CFG_LDLIBS_THREADS = @CFG_LDLIBS_THREADS@
|
||||||
|
# Linker flags/libraries for runtime VPI library loading (+verilator+vpi+<lib>)
|
||||||
|
CFG_LDFLAGS_DYNAMIC = @CFG_LDFLAGS_DYNAMIC@
|
||||||
|
CFG_LDLIBS_DYNAMIC = @CFG_LDLIBS_DYNAMIC@
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Programs
|
# Programs
|
||||||
|
|
@ -93,6 +96,7 @@ VK_CPPFLAGS_ALWAYS += \
|
||||||
-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) \
|
-DVM_TRACE_SAIF=$(VM_TRACE_SAIF) \
|
||||||
|
-DVM_VPI=$(VM_VPI) \
|
||||||
$(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
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// Code available from: https://verilator.org
|
||||||
|
//
|
||||||
|
// 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-FileCopyrightText: 2024-2026 Wilson Snyder
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Verilated functional-coverage model interfaces
|
||||||
|
///
|
||||||
|
/// Defines interface classes to runtime covergroup coverage-collection classes.
|
||||||
|
/// These are used to query coverage achievement at runtime, and (future)
|
||||||
|
/// when writing coverage to the coverage database.
|
||||||
|
///
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
#ifndef VERILATOR_VERILATED_COV_MODEL_H_
|
||||||
|
#define VERILATOR_VERILATED_COV_MODEL_H_
|
||||||
|
|
||||||
|
#include "verilatedos.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// Per-bin classification. A bin's kind is which set it lives in (structural),
|
||||||
|
// not a per-bin field. Only Normal feeds coverage(); the rest are recorded.
|
||||||
|
// Enumerators are 'KIND_'-prefixed because the bare LRM terms collide with
|
||||||
|
// <windows.h> macros (e.g. IGNORE), which the preprocessor would expand.
|
||||||
|
enum class VlCovBinKind : uint8_t {
|
||||||
|
KIND_NORMAL = 0, // Base coverage-collecting bin
|
||||||
|
KIND_DEFAULT = 1, // Bin declared with 'default' range (which is excluded per LRM)
|
||||||
|
KIND_IGNORE = 2, // Ignore bin
|
||||||
|
KIND_ILLEGAL = 3 // Illegal bin
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VlCoverpointIf
|
||||||
|
/// Read-side view of a coverpoint. The writer queries bins by index; the
|
||||||
|
/// implementor computes names/kinds on demand. Bounded bin count, so random
|
||||||
|
/// access by index is the primary usage.
|
||||||
|
|
||||||
|
class VlCoverpointIf VL_NOT_FINAL {
|
||||||
|
public:
|
||||||
|
// CONSTRUCTORS
|
||||||
|
virtual ~VlCoverpointIf() = default;
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
// All bins, across every set; index range [0, binCount())
|
||||||
|
virtual int binCount() const = 0;
|
||||||
|
// Bin name in declaration order (e.g. "myBin" or "b[3]")
|
||||||
|
virtual std::string binName(int i) const = 0;
|
||||||
|
virtual VlCovBinKind binKind(int i) const = 0;
|
||||||
|
// Bins covered / effective total (Normal set only) for the coverage calc
|
||||||
|
virtual void coverageParts(double& covered, double& total) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Guard
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// Code available from: https://verilator.org
|
||||||
|
//
|
||||||
|
// 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-FileCopyrightText: 2024-2026 Wilson Snyder
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Verilated functional-coverage collection runtime implementation
|
||||||
|
///
|
||||||
|
/// Linked when covergroups are present. The coverage-database registration
|
||||||
|
/// is compiled only with "verilator --coverage".
|
||||||
|
///
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
#include "verilatedos.h"
|
||||||
|
|
||||||
|
#include "verilated_covergroup.h"
|
||||||
|
|
||||||
|
#if VM_COVERAGE
|
||||||
|
#include "verilated_cov.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void VlCoverpoint::init(const char* hier, uint32_t atLeast, int nBins) {
|
||||||
|
m_hier = hier;
|
||||||
|
m_atLeast = atLeast;
|
||||||
|
m_total = nBins;
|
||||||
|
m_counts.assign(nBins, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VlCoverpoint::addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name,
|
||||||
|
const char* file, int line, int col) {
|
||||||
|
m_namers.emplace_back(set, count, m_nextBase, naming, name, file, line, col);
|
||||||
|
m_nextBase += count;
|
||||||
|
if (set == VlCovBinKind::KIND_NORMAL) m_normal += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VlCovNamer& VlCoverpoint::namerFor(int i) const {
|
||||||
|
// Namers are appended in ascending, contiguous index order covering [0, m_total),
|
||||||
|
// and i is always a valid bin index, so the matching namer always exists.
|
||||||
|
for (const VlCovNamer& nm : m_namers) {
|
||||||
|
if (i < nm.base() + nm.count()) return nm;
|
||||||
|
}
|
||||||
|
VL_UNREACHABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string VlCoverpoint::binName(int i) const {
|
||||||
|
const VlCovNamer& nm = namerFor(i);
|
||||||
|
std::string name = nm.name();
|
||||||
|
if (nm.naming() == VlCovBinNaming::Array) name += '[' + std::to_string(i - nm.base()) + ']';
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if VM_COVERAGE
|
||||||
|
void VlCoverpoint::registerBins(VerilatedCovContext* covcontextp, const char* page) {
|
||||||
|
for (int i = 0; i < binCount(); ++i) {
|
||||||
|
const VlCovNamer& nm = namerFor(i);
|
||||||
|
const VlCovBinKind kind = binKind(i);
|
||||||
|
const std::string binp = binName(i);
|
||||||
|
const std::string full = m_hier + "." + binp;
|
||||||
|
const std::string lineStr = std::to_string(nm.line());
|
||||||
|
const std::string colStr = std::to_string(nm.col());
|
||||||
|
if (kind == VlCovBinKind::KIND_NORMAL) {
|
||||||
|
VL_COVER_INSERT(covcontextp, full.c_str(), &m_counts[i], "page", page, "filename",
|
||||||
|
nm.file(), "lineno", lineStr.c_str(), "column", colStr.c_str(), "bin",
|
||||||
|
binp.c_str());
|
||||||
|
} else {
|
||||||
|
const char* const binType = kind == VlCovBinKind::KIND_IGNORE ? "ignore"
|
||||||
|
: kind == VlCovBinKind::KIND_ILLEGAL ? "illegal"
|
||||||
|
: "default";
|
||||||
|
VL_COVER_INSERT(covcontextp, full.c_str(), &m_counts[i], "page", page, "filename",
|
||||||
|
nm.file(), "lineno", lineStr.c_str(), "column", colStr.c_str(), "bin",
|
||||||
|
binp.c_str(), "bin_type", binType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // VM_COVERAGE
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// Code available from: https://verilator.org
|
||||||
|
//
|
||||||
|
// 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-FileCopyrightText: 2024-2026 Wilson Snyder
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Verilated functional-coverage collection runtime
|
||||||
|
///
|
||||||
|
/// VlCoverpoint owns per-instance bin-count storage for one coverpoint,
|
||||||
|
/// computes coverage, builds bin names on demand, and registers bins with the
|
||||||
|
/// coverage database. It implements the VlCoverpointIf read interface.
|
||||||
|
///
|
||||||
|
/// Generated covergroup code holds one VlCoverpoint per coverpoint, configures
|
||||||
|
/// it in the constructor (init + add*Namer), increments bins from sample(),
|
||||||
|
/// and registers via registerBins().
|
||||||
|
///
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
#ifndef VERILATOR_VERILATED_COVERGROUP_H_
|
||||||
|
#define VERILATOR_VERILATED_COVERGROUP_H_
|
||||||
|
|
||||||
|
#include "verilatedos.h"
|
||||||
|
|
||||||
|
#include "verilated_cov_model.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class VerilatedCovContext;
|
||||||
|
|
||||||
|
// How a namer builds the names of the bins it covers.
|
||||||
|
enum class VlCovBinNaming : uint8_t {
|
||||||
|
Single, // "<name>" one bin
|
||||||
|
Array, // "<name>[i]" bins b[N] value array
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specifies the naming scheme for a range of bins, allowing the
|
||||||
|
// specific name to be computed on-demand.
|
||||||
|
// All name strings are borrowed literals from the generated code.
|
||||||
|
class VlCovNamer final {
|
||||||
|
// MEMBERS
|
||||||
|
VlCovBinKind m_set; // which set the bins belong to
|
||||||
|
int m_count; // bins this namer covers (1 for Single)
|
||||||
|
int m_base; // first bin index (declaration order), assigned on append
|
||||||
|
VlCovBinNaming m_naming; // how bin names are built
|
||||||
|
const char* m_name; // bin name (Single) or array base name (Array)
|
||||||
|
const char* m_file; // declaration file
|
||||||
|
int m_line; // declaration line
|
||||||
|
int m_col; // declaration column
|
||||||
|
|
||||||
|
public:
|
||||||
|
// CONSTRUCTORS
|
||||||
|
VlCovNamer(VlCovBinKind set, int count, int base, VlCovBinNaming naming, const char* name,
|
||||||
|
const char* file, int line, int col)
|
||||||
|
: m_set{set}
|
||||||
|
, m_count{count}
|
||||||
|
, m_base{base}
|
||||||
|
, m_naming{naming}
|
||||||
|
, m_name{name}
|
||||||
|
, m_file{file}
|
||||||
|
, m_line{line}
|
||||||
|
, m_col{col} {}
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
VlCovBinKind set() const { return m_set; }
|
||||||
|
int count() const { return m_count; }
|
||||||
|
int base() const { return m_base; }
|
||||||
|
VlCovBinNaming naming() const { return m_naming; }
|
||||||
|
const char* name() const { return m_name; }
|
||||||
|
const char* file() const { return m_file; }
|
||||||
|
int line() const { return m_line; }
|
||||||
|
int col() const { return m_col; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VlCoverpoint
|
||||||
|
/// Per-instance coverpoint runtime. Bins are stored in declaration order; a
|
||||||
|
/// bin's set/name come from the owning namer. coverage() is computed on demand
|
||||||
|
/// by scanning bin counts, keeping the sample() hot path a plain counter bump.
|
||||||
|
|
||||||
|
class VlCoverpoint final : public VlCoverpointIf {
|
||||||
|
// MEMBERS
|
||||||
|
std::string m_hier; // "covergroup.coverpoint"
|
||||||
|
uint32_t m_atLeast = 1; // option.at_least (coverpoint-wide)
|
||||||
|
int m_total = 0; // bins across all sets
|
||||||
|
int m_normal = 0; // Normal bins (coverage denominator)
|
||||||
|
int m_nextBase = 0; // running append cursor
|
||||||
|
std::vector<uint32_t> m_counts; // [m_total], one per bin
|
||||||
|
std::vector<VlCovNamer> m_namers; // appended in declaration order
|
||||||
|
|
||||||
|
// PRIVATE METHODS
|
||||||
|
const VlCovNamer& namerFor(int i) const; // obtain the bin-specific name producer
|
||||||
|
void addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name,
|
||||||
|
const char* file, int line, int col);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// CONSTRUCTORS
|
||||||
|
VlCoverpoint() = default;
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
// ---- configuration (from generated constructor) ----
|
||||||
|
void init(const char* hier, uint32_t atLeast, int nBins);
|
||||||
|
void addSingleNamer(VlCovBinKind set, const char* name, const char* file, int line, int col) {
|
||||||
|
addNamer(set, 1, VlCovBinNaming::Single, name, file, line, col);
|
||||||
|
}
|
||||||
|
void addArrayNamer(VlCovBinKind set, int count, const char* name, const char* file, int line,
|
||||||
|
int col) {
|
||||||
|
addNamer(set, count, VlCovBinNaming::Array, name, file, line, col);
|
||||||
|
}
|
||||||
|
void registerBins(VerilatedCovContext* covcontextp, const char* page);
|
||||||
|
|
||||||
|
// ---- hot path (from generated sample()) ----
|
||||||
|
void incrementBin(int i) { ++m_counts[i]; } // Normal bin: count only
|
||||||
|
void recordHit(int i) { ++m_counts[i]; } // Ignore/Illegal/Default: count only
|
||||||
|
|
||||||
|
// ---- VlCoverpointIf ----
|
||||||
|
int binCount() const override { return m_total; }
|
||||||
|
std::string binName(int i) const override;
|
||||||
|
VlCovBinKind binKind(int i) const override { return namerFor(i).set(); }
|
||||||
|
void coverageParts(double& covered, double& total) const override {
|
||||||
|
// Count Normal bins that reached option.at_least on demand, so the hot
|
||||||
|
// path (incrementBin) stays a plain counter bump.
|
||||||
|
int numCovered = 0;
|
||||||
|
for (const VlCovNamer& nm : m_namers) {
|
||||||
|
if (nm.set() != VlCovBinKind::KIND_NORMAL) continue;
|
||||||
|
for (int i = nm.base(); i < nm.base() + nm.count(); ++i) {
|
||||||
|
if (m_counts[i] >= m_atLeast) ++numCovered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
covered = numCovered;
|
||||||
|
total = m_normal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Guard
|
||||||
|
|
@ -101,12 +101,13 @@ using VlForceStorageType = typename VlForceStorageTypeOf<VlForceBaseType<T>>::ty
|
||||||
class VlForceVec final {
|
class VlForceVec final {
|
||||||
private:
|
private:
|
||||||
struct Entry final {
|
struct Entry final {
|
||||||
int m_lsb; // Inclusive lower bit
|
int m_lsb; // Inclusive lower bit for scalar path or element index for unpacked
|
||||||
int m_msb; // Inclusive upper bit
|
int m_msb; // Inclusive upper bit for scalar path or element index for unpacked
|
||||||
int m_rhsLsb; // Destination index that maps to RHS index 0
|
int m_rhsLsb; // Destination index that maps to RHS index 0
|
||||||
const void* m_rhsDatap; // Pointer to RHS storage
|
const void* m_rhsDatap; // Pointer to RHS storage
|
||||||
|
int m_bitLsb = 0;
|
||||||
bool operator<(const Entry& other) const { return m_msb < other.m_msb; }
|
int m_bitMsb = 0;
|
||||||
|
int m_elemWidth = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Entry> m_entries; // Sorted by msb, non-overlapping
|
std::vector<Entry> m_entries; // Sorted by msb, non-overlapping
|
||||||
|
|
@ -134,6 +135,41 @@ private:
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t trimElementBitRange(int elem, int bitLsb, int bitMsb) {
|
||||||
|
auto it = std::lower_bound(m_entries.begin(), m_entries.end(), elem,
|
||||||
|
[](const Entry& e, int idx) { return e.m_msb < idx; });
|
||||||
|
while (it != m_entries.end() && it->m_lsb <= elem) {
|
||||||
|
if (it->m_elemWidth == 0 || it->m_bitMsb < bitLsb || it->m_bitLsb > bitMsb) {
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it->m_bitLsb < bitLsb && it->m_bitMsb > bitMsb) {
|
||||||
|
Entry high = *it;
|
||||||
|
high.m_bitLsb = bitMsb + 1;
|
||||||
|
it->m_bitMsb = bitLsb - 1;
|
||||||
|
m_entries.insert(it + 1, high);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (it->m_bitLsb < bitLsb) {
|
||||||
|
it->m_bitMsb = bitLsb - 1;
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it->m_bitMsb > bitMsb) {
|
||||||
|
it->m_bitLsb = bitMsb + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
it = m_entries.erase(it);
|
||||||
|
}
|
||||||
|
auto ins = std::lower_bound(m_entries.begin(), m_entries.end(), elem,
|
||||||
|
[](const Entry& e, int idx) { return e.m_msb < idx; });
|
||||||
|
while (ins != m_entries.end() && ins->m_lsb <= elem
|
||||||
|
&& (ins->m_elemWidth == 0 || ins->m_bitLsb <= bitLsb)) {
|
||||||
|
++ins;
|
||||||
|
}
|
||||||
|
return static_cast<std::size_t>(ins - m_entries.begin());
|
||||||
|
}
|
||||||
|
|
||||||
static QData extractRhsChunk(const Entry& entry, int rhsLsb, int width) {
|
static QData extractRhsChunk(const Entry& entry, int rhsLsb, int width) {
|
||||||
assert(width > 0 && width <= VL_QUADSIZE);
|
assert(width > 0 && width <= VL_QUADSIZE);
|
||||||
assert(rhsLsb >= 0);
|
assert(rhsLsb >= 0);
|
||||||
|
|
@ -195,6 +231,22 @@ private:
|
||||||
return *static_cast<const VlForceBaseType<T>*>(entry.m_rhsDatap);
|
return *static_cast<const VlForceBaseType<T>*>(entry.m_rhsDatap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Elem>
|
||||||
|
static typename std::enable_if<!VlIsVlWide<Elem>::value, Elem>::type
|
||||||
|
blendElem(Elem cur, const Entry& e) {
|
||||||
|
const Entry bitEntry{e.m_bitLsb, e.m_bitMsb, e.m_rhsLsb, e.m_rhsDatap, 0, 0, 0};
|
||||||
|
return applyEntry(cur, bitEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Elem>
|
||||||
|
static typename std::enable_if<VlIsVlWide<Elem>::value, Elem>::type blendElem(Elem cur,
|
||||||
|
const Entry& e) {
|
||||||
|
Elem res = cur;
|
||||||
|
const Entry bitEntry{e.m_bitLsb, e.m_bitMsb, e.m_rhsLsb, e.m_rhsDatap, 0, 0, 0};
|
||||||
|
applyEntry(res, bitEntry, e.m_bitLsb, e.m_bitMsb, 0);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<VlIsVlWide<T>::value>::type applyEntries(T& val) const {
|
typename std::enable_if<VlIsVlWide<T>::value>::type applyEntries(T& val) const {
|
||||||
for (const auto& entry : m_entries) {
|
for (const auto& entry : m_entries) {
|
||||||
|
|
@ -229,15 +281,19 @@ public:
|
||||||
using ElemRef
|
using ElemRef
|
||||||
= decltype(VlForceArrayIndexer<T>::elem(result, static_cast<std::size_t>(0)));
|
= decltype(VlForceArrayIndexer<T>::elem(result, static_cast<std::size_t>(0)));
|
||||||
using Elem = VlForceBaseType<ElemRef>;
|
using Elem = VlForceBaseType<ElemRef>;
|
||||||
const int total = static_cast<int>(VlForceArrayIndexer<T>::size);
|
|
||||||
for (const auto& entry : m_entries) {
|
for (const auto& entry : m_entries) {
|
||||||
const Elem* const rhsBasep = static_cast<const Elem*>(entry.m_rhsDatap);
|
|
||||||
const int startIdx = entry.m_lsb;
|
const int startIdx = entry.m_lsb;
|
||||||
const int endIdx = entry.m_msb;
|
const int endIdx = entry.m_msb;
|
||||||
for (int idx = startIdx; idx <= endIdx; idx++) {
|
for (int idx = startIdx; idx <= endIdx; idx++) {
|
||||||
const int rhsIndex = idx - entry.m_rhsLsb;
|
|
||||||
const std::size_t uidx = static_cast<std::size_t>(idx);
|
const std::size_t uidx = static_cast<std::size_t>(idx);
|
||||||
VlForceArrayIndexer<T>::elem(result, uidx) = rhsBasep[rhsIndex];
|
Elem& dst = VlForceArrayIndexer<T>::elem(result, uidx);
|
||||||
|
if (entry.m_elemWidth == 0) {
|
||||||
|
const Elem* const rhsBasep = static_cast<const Elem*>(entry.m_rhsDatap);
|
||||||
|
const int rhsIndex = idx - entry.m_rhsLsb;
|
||||||
|
dst = rhsBasep[rhsIndex];
|
||||||
|
} else {
|
||||||
|
dst = blendElem<Elem>(dst, entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -250,14 +306,18 @@ public:
|
||||||
T readIndex(T origVal, int index) const {
|
T readIndex(T origVal, int index) const {
|
||||||
if (m_entries.empty()) return origVal;
|
if (m_entries.empty()) return origVal;
|
||||||
|
|
||||||
const auto it = std::lower_bound(m_entries.begin(), m_entries.end(), index,
|
T result = origVal;
|
||||||
[](const Entry& e, int idx) { return e.m_msb < idx; });
|
for (auto it = std::lower_bound(m_entries.begin(), m_entries.end(), index,
|
||||||
if (it != m_entries.end() && it->m_lsb <= index) {
|
[](const Entry& e, int idx) { return e.m_msb < idx; });
|
||||||
const int rhsIndex = index - it->m_rhsLsb;
|
it != m_entries.end() && it->m_lsb <= index; ++it) {
|
||||||
const T* const rhsBasep = static_cast<const T*>(it->m_rhsDatap);
|
if (it->m_elemWidth == 0) {
|
||||||
return rhsBasep[rhsIndex];
|
const int rhsIndex = index - it->m_rhsLsb;
|
||||||
|
result = static_cast<const T*>(it->m_rhsDatap)[rhsIndex];
|
||||||
|
} else {
|
||||||
|
result = blendElem<T>(result, *it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return origVal;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
IData readSelI(int lbits, WDataInP valp, int lsb, int width) const {
|
IData readSelI(int lbits, WDataInP valp, int lsb, int width) const {
|
||||||
|
|
@ -291,11 +351,28 @@ public:
|
||||||
m_entries.insert(it, {lsb, msb, rhsLsb, rhsDatap});
|
m_entries.insert(it, {lsb, msb, rhsLsb, rhsDatap});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addForce(int lsb, int msb, const void* rhsDatap, int rhsLsb, int bitLsb, int bitMsb,
|
||||||
|
int elemWidth) {
|
||||||
|
assert(lsb == msb);
|
||||||
|
assert(rhsDatap);
|
||||||
|
assert(elemWidth > 0);
|
||||||
|
assert(0 <= bitLsb && bitLsb <= bitMsb && bitMsb < elemWidth);
|
||||||
|
const std::size_t at = trimElementBitRange(lsb, bitLsb, bitMsb);
|
||||||
|
m_entries.insert(m_entries.begin() + at,
|
||||||
|
Entry{lsb, msb, rhsLsb, rhsDatap, bitLsb, bitMsb, elemWidth});
|
||||||
|
}
|
||||||
|
|
||||||
void release(int lsb, int msb) {
|
void release(int lsb, int msb) {
|
||||||
assert(lsb <= msb);
|
assert(lsb <= msb);
|
||||||
trimEntries(lsb, msb);
|
trimEntries(lsb, msb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void release(int lsb, int msb, int bitLsb, int bitMsb) {
|
||||||
|
assert(lsb == msb);
|
||||||
|
assert(bitLsb <= bitMsb);
|
||||||
|
trimElementBitRange(lsb, bitLsb, bitMsb);
|
||||||
|
}
|
||||||
|
|
||||||
void touch() {}
|
void touch() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,8 @@ extern void VL_FATAL_MT(const char* filename, int linenum, const char* hier,
|
||||||
extern void VL_WARN_MT(const char* filename, int linenum, const char* hier,
|
extern void VL_WARN_MT(const char* filename, int linenum, const char* hier,
|
||||||
const char* msg) VL_MT_SAFE;
|
const char* msg) VL_MT_SAFE;
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
/// Print a string, multithread safe. Eventually VL_PRINTF will get called.
|
/// Print a string, multithread safe. Eventually VL_PRINTF will get called.
|
||||||
extern void VL_PRINTF_MT(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
extern void VL_PRINTF_MT(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
/// Print a debug message from internals with standard prefix, with printf style format
|
/// Print a debug message from internals with standard prefix, with printf style format
|
||||||
extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
||||||
|
|
@ -85,6 +83,9 @@ extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
||||||
/// Print a debug message from string via VL_DBG_MSGF
|
/// Print a debug message from string via VL_DBG_MSGF
|
||||||
inline void VL_DBG_MSGS(const std::string& str) VL_MT_SAFE { VL_DBG_MSGF("%s", str.c_str()); }
|
inline void VL_DBG_MSGS(const std::string& str) VL_MT_SAFE { VL_DBG_MSGF("%s", str.c_str()); }
|
||||||
|
|
||||||
|
/// Flush stdout
|
||||||
|
extern void VL_FFLUSH_MT() VL_MT_SAFE;
|
||||||
|
|
||||||
// EMIT_RULE: VL_RANDOM: oclean=dirty
|
// EMIT_RULE: VL_RANDOM: oclean=dirty
|
||||||
inline IData VL_RANDOM_I() VL_MT_SAFE { return vl_rand64(); }
|
inline IData VL_RANDOM_I() VL_MT_SAFE { return vl_rand64(); }
|
||||||
inline QData VL_RANDOM_Q() VL_MT_SAFE { return vl_rand64(); }
|
inline QData VL_RANDOM_Q() VL_MT_SAFE { return vl_rand64(); }
|
||||||
|
|
@ -123,10 +124,6 @@ extern WDataOutP VL_SCOPED_RAND_RESET_ASSIGN_W(int obits, WDataOutP outwp, uint6
|
||||||
|
|
||||||
/// Random reset a signal of given width (init time only)
|
/// Random reset a signal of given width (init time only)
|
||||||
extern IData VL_RAND_RESET_I(int obits) VL_MT_SAFE;
|
extern IData VL_RAND_RESET_I(int obits) VL_MT_SAFE;
|
||||||
/// Random reset a signal of given width (init time only)
|
|
||||||
extern QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE;
|
|
||||||
/// Random reset a signal of given width (init time only)
|
|
||||||
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
|
||||||
|
|
||||||
/// Zero reset a signal (slow - else use VL_ZERO_W)
|
/// Zero reset a signal (slow - else use VL_ZERO_W)
|
||||||
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
||||||
|
|
@ -268,6 +265,41 @@ static inline VlQueue<T> VL_CVT_UNPACK_TO_Q(const VlUnpacked<T, N_Depth>& q) VL_
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Masked match functions
|
||||||
|
static inline IData VL_MATCHMASKED_I(int, IData lhs, WDataInP matchp) VL_PURE {
|
||||||
|
size_t i = 0;
|
||||||
|
while (true) {
|
||||||
|
const IData mask = matchp[i * 2];
|
||||||
|
const IData bits = matchp[i * 2 + 1];
|
||||||
|
if ((mask & lhs) == bits) break;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
static inline IData VL_MATCHMASKED_Q(int, QData lhs, WDataInP matchp) VL_PURE {
|
||||||
|
size_t i = 0;
|
||||||
|
while (true) {
|
||||||
|
const QData mask = VL_SET_QW(matchp + i * 4);
|
||||||
|
const QData bits = VL_SET_QW(matchp + i * 4 + 2);
|
||||||
|
if ((mask & lhs) == bits) break;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
static inline IData VL_MATCHMASKED_W(int lbits, WDataInP lhsp, WDataInP matchp) VL_MT_SAFE {
|
||||||
|
const int iwords = VL_WORDS_I(lbits);
|
||||||
|
size_t i = 0;
|
||||||
|
while (true) {
|
||||||
|
const WDataInP maskp = matchp + (i * iwords * 2);
|
||||||
|
const WDataInP bitsp = matchp + (i * iwords * 2 + iwords);
|
||||||
|
EData diff = 0;
|
||||||
|
for (int j = 0; j < iwords; ++j) diff |= (maskp[j] & lhsp[j]) ^ bitsp[j];
|
||||||
|
if (!diff) break;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
|
|
@ -867,15 +899,31 @@ static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_PURE {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline IData VL_MOSTSETBITP1_I(IData lhs) VL_PURE {
|
||||||
|
if (VL_UNLIKELY(!lhs)) return 0; // __builtin_clz is undefined for 0
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS)
|
||||||
|
return VL_EDATASIZE - __builtin_clz(lhs);
|
||||||
|
#else
|
||||||
|
for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) {
|
||||||
|
if (VL_BITISSET_E(lhs, bit)) return bit + 1;
|
||||||
|
}
|
||||||
|
return 0; // LCOV_EXCL_LINE // Can't get here - one bit must be set
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static inline IData VL_MOSTSETBITP1_Q(QData lhs) VL_PURE {
|
||||||
|
if (VL_UNLIKELY(!lhs)) return 0;
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS)
|
||||||
|
return 64 - __builtin_clzll(static_cast<unsigned long long>(lhs));
|
||||||
|
#else
|
||||||
|
const IData hi = static_cast<IData>(lhs >> 32ULL);
|
||||||
|
return hi ? (VL_EDATASIZE + VL_MOSTSETBITP1_I(hi))
|
||||||
|
: VL_MOSTSETBITP1_I(static_cast<IData>(lhs));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
static inline IData VL_MOSTSETBITP1_W(int words, WDataInP const lwp) VL_PURE {
|
static inline IData VL_MOSTSETBITP1_W(int words, WDataInP const lwp) VL_PURE {
|
||||||
// MSB set bit plus one; similar to FLS. 0=value is zero
|
|
||||||
for (int i = words - 1; i >= 0; --i) {
|
for (int i = words - 1; i >= 0; --i) {
|
||||||
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
|
// Shorter worst case if predict not taken
|
||||||
for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) {
|
if (VL_UNLIKELY(lwp[i])) return i * VL_EDATASIZE + VL_MOSTSETBITP1_I(lwp[i]);
|
||||||
if (VL_UNLIKELY(VL_BITISSET_E(lwp[i], bit))) return i * VL_EDATASIZE + bit + 1;
|
|
||||||
}
|
|
||||||
// Can't get here - one bit must be set
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -973,14 +1021,10 @@ static inline IData VL_EQ_R(int words, VlQueue<T> q, WDataInP const rwp) VL_PURE
|
||||||
} else if (sizeof(T) == 4) {
|
} else if (sizeof(T) == 4) {
|
||||||
for (int i = 0; (i < wordsInQ + 1); ++i) { nequal |= (q.at(wordsInQ - i) ^ rwp[i]); }
|
for (int i = 0; (i < wordsInQ + 1); ++i) { nequal |= (q.at(wordsInQ - i) ^ rwp[i]); }
|
||||||
} else if (sizeof(T) == 8) {
|
} else if (sizeof(T) == 8) {
|
||||||
QData temp = 0;
|
|
||||||
int qSize = q.size() - 1;
|
int qSize = q.size() - 1;
|
||||||
for (int i = 0; (i < qSize); i += 2) {
|
for (int i = 0; (i < qSize); i += 2) {
|
||||||
temp = q.at(qSize - i);
|
|
||||||
nequal |= (static_cast<QData>(q.at(qSize - i)) >> 32 ^ rwp[i + 1]);
|
nequal |= (static_cast<QData>(q.at(qSize - i)) >> 32 ^ rwp[i + 1]);
|
||||||
temp = rwp[i + 1];
|
|
||||||
nequal |= (static_cast<QData>(q.at(qSize - i)) ^ rwp[i]);
|
nequal |= (static_cast<QData>(q.at(qSize - i)) ^ rwp[i]);
|
||||||
temp = rwp[i];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (nequal == 0);
|
return (nequal == 0);
|
||||||
|
|
@ -990,7 +1034,6 @@ template <std::size_t N_Words>
|
||||||
static inline IData VL_EQ_R(int words, const VlQueue<VlWide<N_Words>>& q,
|
static inline IData VL_EQ_R(int words, const VlQueue<VlWide<N_Words>>& q,
|
||||||
WDataInP const rwp) VL_PURE {
|
WDataInP const rwp) VL_PURE {
|
||||||
EData nequal = 0;
|
EData nequal = 0;
|
||||||
const int wordsInQ = q.size() * N_Words;
|
|
||||||
if ((q.size() * N_Words) != words) { return false; }
|
if ((q.size() * N_Words) != words) { return false; }
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int qIndex = q.size() - 1; qIndex >= 0; qIndex--) {
|
for (int qIndex = q.size() - 1; qIndex >= 0; qIndex--) {
|
||||||
|
|
@ -1901,7 +1944,6 @@ static inline void VL_STREAMR_RRI(int lbits, VlQueue<T_Value>& to_q,
|
||||||
const VlQueue<VlWide<N_Words>>& from_q, IData rd) VL_MT_SAFE {
|
const VlQueue<VlWide<N_Words>>& from_q, IData rd) VL_MT_SAFE {
|
||||||
to_q.clear();
|
to_q.clear();
|
||||||
|
|
||||||
VL_CONSTEXPR_CXX17 size_t otherSize = 4 * N_Words;
|
|
||||||
VL_CONSTEXPR_CXX17 size_t sizeOfThis = sizeof(T_Value);
|
VL_CONSTEXPR_CXX17 size_t sizeOfThis = sizeof(T_Value);
|
||||||
T_Value temp = 0;
|
T_Value temp = 0;
|
||||||
for (auto val : from_q) {
|
for (auto val : from_q) {
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ class VerilatedVarProps VL_NOT_FINAL {
|
||||||
const uint32_t m_magic; // Magic number
|
const uint32_t m_magic; // Magic number
|
||||||
const VerilatedVarType m_vltype; // Data type
|
const VerilatedVarType m_vltype; // Data type
|
||||||
const VerilatedVarFlags m_vlflags; // Direction
|
const VerilatedVarFlags m_vlflags; // Direction
|
||||||
|
const uint32_t m_entSize; // Element size in bytes, or 0 to derive from type
|
||||||
std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
|
std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
|
||||||
std::vector<VerilatedRange> m_packed; // Packed array ranges
|
std::vector<VerilatedRange> m_packed; // Packed array ranges
|
||||||
VerilatedRange m_packedDpi; // Flattened packed array range
|
VerilatedRange m_packedDpi; // Flattened packed array range
|
||||||
|
|
@ -104,10 +105,12 @@ class VerilatedVarProps VL_NOT_FINAL {
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
protected:
|
protected:
|
||||||
friend class VerilatedScope;
|
friend class VerilatedScope;
|
||||||
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int udims, int pdims)
|
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int udims, int pdims,
|
||||||
|
uint32_t entSize = 0)
|
||||||
: m_magic{MAGIC}
|
: m_magic{MAGIC}
|
||||||
, m_vltype{vltype}
|
, m_vltype{vltype}
|
||||||
, m_vlflags{vlflags} {
|
, m_vlflags{vlflags}
|
||||||
|
, m_entSize{entSize} {
|
||||||
// Only preallocate the ranges
|
// Only preallocate the ranges
|
||||||
initUnpacked(udims, nullptr);
|
initUnpacked(udims, nullptr);
|
||||||
initPacked(pdims, nullptr);
|
initPacked(pdims, nullptr);
|
||||||
|
|
@ -119,12 +122,14 @@ public:
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
||||||
: m_magic{MAGIC}
|
: m_magic{MAGIC}
|
||||||
, m_vltype{vltype}
|
, m_vltype{vltype}
|
||||||
, m_vlflags(VerilatedVarFlags(vlflags)) {} // Need () or GCC 4.8 false warning
|
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||||
|
, m_entSize{0} {}
|
||||||
|
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
|
||||||
: m_magic{MAGIC}
|
: m_magic{MAGIC}
|
||||||
, m_vltype{vltype}
|
, m_vltype{vltype}
|
||||||
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
|
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||||
|
, m_entSize{0} {
|
||||||
initUnpacked(udims, ulims);
|
initUnpacked(udims, ulims);
|
||||||
}
|
}
|
||||||
// With packed
|
// With packed
|
||||||
|
|
@ -132,14 +137,16 @@ public:
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pdims, const int* plims)
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pdims, const int* plims)
|
||||||
: m_magic{MAGIC}
|
: m_magic{MAGIC}
|
||||||
, m_vltype{vltype}
|
, m_vltype{vltype}
|
||||||
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
|
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||||
|
, m_entSize{0} {
|
||||||
initPacked(pdims, plims);
|
initPacked(pdims, plims);
|
||||||
}
|
}
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims,
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims,
|
||||||
Packed, int pdims, const int* plims)
|
Packed, int pdims, const int* plims)
|
||||||
: m_magic{MAGIC}
|
: m_magic{MAGIC}
|
||||||
, m_vltype{vltype}
|
, m_vltype{vltype}
|
||||||
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
|
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||||
|
, m_entSize{0} {
|
||||||
initUnpacked(udims, ulims);
|
initUnpacked(udims, ulims);
|
||||||
initPacked(pdims, plims);
|
initPacked(pdims, plims);
|
||||||
}
|
}
|
||||||
|
|
@ -164,6 +171,7 @@ public:
|
||||||
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
|
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
|
||||||
bool isSigned() const { return ((m_vlflags & VLVF_SIGNED) != 0); }
|
bool isSigned() const { return ((m_vlflags & VLVF_SIGNED) != 0); }
|
||||||
bool isBitVar() const { return ((m_vlflags & VLVF_BITVAR) != 0); }
|
bool isBitVar() const { return ((m_vlflags & VLVF_BITVAR) != 0); }
|
||||||
|
bool isNet() const { return ((m_vlflags & VLVF_NET) != 0); }
|
||||||
int udims() const VL_MT_SAFE { return m_unpacked.size(); }
|
int udims() const VL_MT_SAFE { return m_unpacked.size(); }
|
||||||
int pdims() const VL_MT_SAFE { return m_packed.size(); }
|
int pdims() const VL_MT_SAFE { return m_packed.size(); }
|
||||||
int dims() const VL_MT_SAFE { return pdims() + udims(); }
|
int dims() const VL_MT_SAFE { return pdims() + udims(); }
|
||||||
|
|
@ -265,6 +273,8 @@ protected:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||||
VerilatedVarFlags vlflags, int udims, int pdims, bool isParam);
|
VerilatedVarFlags vlflags, int udims, int pdims, bool isParam);
|
||||||
|
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||||
|
VerilatedVarFlags vlflags, int udims, int pdims, bool isParam, uint32_t entSize);
|
||||||
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||||
VerilatedVarFlags vlflags, int udims, int pdims, bool isParam,
|
VerilatedVarFlags vlflags, int udims, int pdims, bool isParam,
|
||||||
std::unique_ptr<const VerilatedForceControlSignals> forceControlSignals);
|
std::unique_ptr<const VerilatedForceControlSignals> forceControlSignals);
|
||||||
|
|
@ -296,6 +306,13 @@ inline VerilatedVar::VerilatedVar(const char* namep, void* datap, VerilatedVarTy
|
||||||
, m_datap{datap}
|
, m_datap{datap}
|
||||||
, m_namep{namep}
|
, m_namep{namep}
|
||||||
, m_isParam{isParam} {}
|
, m_isParam{isParam} {}
|
||||||
|
inline VerilatedVar::VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||||
|
VerilatedVarFlags vlflags, int udims, int pdims, bool isParam,
|
||||||
|
uint32_t entSize)
|
||||||
|
: VerilatedVarProps{vltype, vlflags, udims, pdims, entSize}
|
||||||
|
, m_datap{datap}
|
||||||
|
, m_namep{namep}
|
||||||
|
, m_isParam{isParam} {}
|
||||||
inline VerilatedVar::VerilatedVar(
|
inline VerilatedVar::VerilatedVar(
|
||||||
const char* namep, void* datap, VerilatedVarType vltype, VerilatedVarFlags vlflags, int udims,
|
const char* namep, void* datap, VerilatedVarType vltype, VerilatedVarFlags vlflags, int udims,
|
||||||
int pdims, bool isParam,
|
int pdims, bool isParam,
|
||||||
|
|
|
||||||
|
|
@ -337,6 +337,7 @@ public:
|
||||||
|
|
||||||
~VlProcess() {
|
~VlProcess() {
|
||||||
if (m_parentp) m_parentp->detach(this);
|
if (m_parentp) m_parentp->detach(this);
|
||||||
|
if (t_currentp == this) t_currentp = m_parentp.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void attach(VlProcess* childp) { m_children.insert(childp); }
|
void attach(VlProcess* childp) { m_children.insert(childp); }
|
||||||
|
|
@ -2069,8 +2070,24 @@ struct VlNull final {
|
||||||
operator T*() const {
|
operator T*() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
template <class T>
|
||||||
|
bool operator==(T* rhs) const {
|
||||||
|
return !rhs;
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
bool operator==(const T* rhs) const {
|
||||||
|
return !rhs;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
inline bool operator==(const void* ptr, VlNull) { return !ptr; }
|
|
||||||
|
template <class T>
|
||||||
|
inline bool operator==(T* lhs, VlNull) {
|
||||||
|
return !lhs;
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
inline bool operator==(const T* lhs, VlNull) {
|
||||||
|
return !lhs;
|
||||||
|
}
|
||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
// Verilog class reference container
|
// Verilog class reference container
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
@ -68,6 +69,25 @@ constexpr unsigned VL_VPI_LINE_SIZE_ = 8192;
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Implementation
|
// Implementation
|
||||||
|
|
||||||
|
static const char* _vl_vpi_find_unescaped_dot(const char* posp) {
|
||||||
|
for (; *posp; ++posp) {
|
||||||
|
if (*posp == '\\') {
|
||||||
|
while (*posp && *posp != ' ') ++posp;
|
||||||
|
if (!*posp) return nullptr;
|
||||||
|
} else if (*posp == '.') {
|
||||||
|
return posp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string _vl_vpi_member_local_name(const char* const namep) {
|
||||||
|
const char* localp = namep;
|
||||||
|
const char* posp = namep;
|
||||||
|
while ((posp = _vl_vpi_find_unescaped_dot(posp))) localp = ++posp;
|
||||||
|
return localp;
|
||||||
|
}
|
||||||
|
|
||||||
// Base VPI handled object
|
// Base VPI handled object
|
||||||
class VerilatedVpio VL_NOT_FINAL {
|
class VerilatedVpio VL_NOT_FINAL {
|
||||||
// CONSTANTS
|
// CONSTANTS
|
||||||
|
|
@ -201,6 +221,9 @@ public:
|
||||||
}
|
}
|
||||||
const VerilatedVar* varp() const { return m_varp; }
|
const VerilatedVar* varp() const { return m_varp; }
|
||||||
const VerilatedScope* scopep() const { return m_scopep; }
|
const VerilatedScope* scopep() const { return m_scopep; }
|
||||||
|
bool isStructOrUnion() const {
|
||||||
|
return varp()->vltype() == VLVT_STRUCT || varp()->vltype() == VLVT_UNION;
|
||||||
|
}
|
||||||
// Returns the number of the currently indexed dimension (starting at -1 for none).
|
// Returns the number of the currently indexed dimension (starting at -1 for none).
|
||||||
int32_t indexedDim() const { return m_indexedDim; }
|
int32_t indexedDim() const { return m_indexedDim; }
|
||||||
// Returns whether the currently indexed dimension is unpacked.
|
// Returns whether the currently indexed dimension is unpacked.
|
||||||
|
|
@ -363,6 +386,8 @@ class VerilatedVpioVar VL_NOT_FINAL : public VerilatedVpioVarBase {
|
||||||
uint32_t m_entSize = 0; // memoized variable size
|
uint32_t m_entSize = 0; // memoized variable size
|
||||||
uint32_t m_bitOffset = 0;
|
uint32_t m_bitOffset = 0;
|
||||||
int32_t m_partselBits = -1; // Part-select width, -1 means no part-select active
|
int32_t m_partselBits = -1; // Part-select width, -1 means no part-select active
|
||||||
|
std::string m_name;
|
||||||
|
std::string m_fullNameOverride;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void* m_varDatap = nullptr; // varp()->datap() adjusted for array entries
|
void* m_varDatap = nullptr; // varp()->datap() adjusted for array entries
|
||||||
|
|
@ -373,6 +398,17 @@ public:
|
||||||
: VerilatedVpioVarBase{varp, scopep} {
|
: VerilatedVpioVarBase{varp, scopep} {
|
||||||
m_entSize = varp->entSize();
|
m_entSize = varp->entSize();
|
||||||
m_varDatap = varp->datap();
|
m_varDatap = varp->datap();
|
||||||
|
if (_vl_vpi_find_unescaped_dot(varp->name())) {
|
||||||
|
m_name = _vl_vpi_member_local_name(varp->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep, void* datap,
|
||||||
|
const std::string& name, const std::string& fullname)
|
||||||
|
: VerilatedVpioVarBase{varp, scopep} {
|
||||||
|
m_entSize = varp->entSize();
|
||||||
|
m_varDatap = datap;
|
||||||
|
m_name = name;
|
||||||
|
m_fullNameOverride = fullname;
|
||||||
}
|
}
|
||||||
explicit VerilatedVpioVar(const VerilatedVpioVar* vop)
|
explicit VerilatedVpioVar(const VerilatedVpioVar* vop)
|
||||||
: VerilatedVpioVarBase{vop} {
|
: VerilatedVpioVarBase{vop} {
|
||||||
|
|
@ -380,6 +416,8 @@ public:
|
||||||
m_entSize = vop->m_entSize;
|
m_entSize = vop->m_entSize;
|
||||||
m_varDatap = vop->m_varDatap;
|
m_varDatap = vop->m_varDatap;
|
||||||
m_index = vop->m_index;
|
m_index = vop->m_index;
|
||||||
|
m_name = vop->m_name;
|
||||||
|
m_fullNameOverride = vop->m_fullNameOverride;
|
||||||
m_partselBits = vop->m_partselBits;
|
m_partselBits = vop->m_partselBits;
|
||||||
m_bitOffset = vop->m_bitOffset;
|
m_bitOffset = vop->m_bitOffset;
|
||||||
// Not copying m_prevDatap, must be nullptr
|
// Not copying m_prevDatap, must be nullptr
|
||||||
|
|
@ -395,15 +433,22 @@ public:
|
||||||
uint32_t bitOffset() const override { return m_bitOffset; }
|
uint32_t bitOffset() const override { return m_bitOffset; }
|
||||||
int32_t partselBits() const { return m_partselBits; }
|
int32_t partselBits() const { return m_partselBits; }
|
||||||
uint32_t bitSize() const {
|
uint32_t bitSize() const {
|
||||||
|
if (isStructOrUnion() && !isIndexedDimUnpacked()) return 0;
|
||||||
if (m_partselBits >= 0) return static_cast<uint32_t>(m_partselBits);
|
if (m_partselBits >= 0) return static_cast<uint32_t>(m_partselBits);
|
||||||
return VerilatedVpioVarBase::bitSize();
|
return VerilatedVpioVarBase::bitSize();
|
||||||
}
|
}
|
||||||
uint32_t size() const override {
|
uint32_t size() const override {
|
||||||
|
if (isStructOrUnion() && !isIndexedDimUnpacked()) return 0;
|
||||||
if (m_partselBits >= 0) return static_cast<uint32_t>(m_partselBits);
|
if (m_partselBits >= 0) return static_cast<uint32_t>(m_partselBits);
|
||||||
return VerilatedVpioVarBase::size();
|
return VerilatedVpioVarBase::size();
|
||||||
}
|
}
|
||||||
|
const VerilatedRange* rangep() const override {
|
||||||
|
if (isStructOrUnion() && !isIndexedDimUnpacked()) return nullptr;
|
||||||
|
return VerilatedVpioVarBase::rangep();
|
||||||
|
}
|
||||||
uint32_t entSize() const { return m_entSize; }
|
uint32_t entSize() const { return m_entSize; }
|
||||||
const std::vector<int32_t>& index() const { return m_index; }
|
const std::vector<int32_t>& index() const { return m_index; }
|
||||||
|
const char* name() const override { return m_name.empty() ? varp()->name() : m_name.c_str(); }
|
||||||
// Create a part-selected view of this variable with the given bit range [hi:lo].
|
// Create a part-selected view of this variable with the given bit range [hi:lo].
|
||||||
VerilatedVpioVar* withPartSelect(int32_t hi, int32_t lo) const {
|
VerilatedVpioVar* withPartSelect(int32_t hi, int32_t lo) const {
|
||||||
if (isIndexedDimUnpacked()) return nullptr;
|
if (isIndexedDimUnpacked()) return nullptr;
|
||||||
|
|
@ -456,22 +501,43 @@ public:
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
VerilatedVpioVar* withMember(const VerilatedVar* memberVarp) const {
|
||||||
|
const char* const parentName = varp()->name();
|
||||||
|
const std::string memberName = memberVarp->name();
|
||||||
|
const size_t parentLen = std::strlen(parentName);
|
||||||
|
|
||||||
|
void* const parentDatap = varp()->datap();
|
||||||
|
void* const memberDatap = memberVarp->datap();
|
||||||
|
if (VL_UNLIKELY(!parentDatap) || VL_UNLIKELY(!memberDatap)) return nullptr;
|
||||||
|
const auto offset
|
||||||
|
= static_cast<uint8_t*>(memberDatap) - static_cast<uint8_t*>(parentDatap);
|
||||||
|
|
||||||
|
const std::string localName = _vl_vpi_member_local_name(memberVarp->name());
|
||||||
|
|
||||||
|
return new VerilatedVpioVar{memberVarp, scopep(),
|
||||||
|
static_cast<uint8_t*>(varDatap()) + offset, localName,
|
||||||
|
std::string{fullname()} + memberName.substr(parentLen)};
|
||||||
|
}
|
||||||
uint32_t type() const override {
|
uint32_t type() const override {
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
// TODO have V3EmitCSyms.cpp put vpiType directly into constant table
|
// TODO have V3EmitCSyms.cpp put vpiType directly into constant table
|
||||||
switch (varp()->vltype()) {
|
switch (varp()->vltype()) {
|
||||||
case VLVT_REAL: type = vpiRealVar; break;
|
case VLVT_REAL: type = vpiRealVar; break;
|
||||||
case VLVT_STRING: type = vpiStringVar; break;
|
case VLVT_STRING: type = vpiStringVar; break;
|
||||||
|
case VLVT_STRUCT: type = varp()->isNet() ? vpiStructNet : vpiStructVar; break;
|
||||||
|
case VLVT_UNION: type = varp()->isNet() ? vpiUnionNet : vpiUnionVar; break;
|
||||||
default: type = varp()->isBitVar() ? vpiBitVar : vpiReg; break;
|
default: type = varp()->isBitVar() ? vpiBitVar : vpiReg; break;
|
||||||
}
|
}
|
||||||
if (isIndexedDimUnpacked()) return vpiRegArray;
|
if (isIndexedDimUnpacked())
|
||||||
|
return isStructOrUnion() && varp()->isNet() ? vpiNetArray : vpiRegArray;
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
const char* fullname() const override {
|
const char* fullname() const override {
|
||||||
static thread_local std::string t_out;
|
m_fullname = m_fullNameOverride.empty()
|
||||||
t_out = std::string{scopep()->name()} + "." + name();
|
? std::string{scopep()->name()} + "." + varp()->name()
|
||||||
for (auto idx : index()) t_out += "[" + std::to_string(idx) + "]";
|
: m_fullNameOverride;
|
||||||
return t_out.c_str();
|
for (auto idx : index()) m_fullname += "[" + std::to_string(idx) + "]";
|
||||||
|
return m_fullname.c_str();
|
||||||
}
|
}
|
||||||
void* prevDatap() const { return m_prevDatap; }
|
void* prevDatap() const { return m_prevDatap; }
|
||||||
void* varDatap() const override { return m_varDatap; }
|
void* varDatap() const override { return m_varDatap; }
|
||||||
|
|
@ -590,25 +656,63 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VerilatedVpioMemberIter final : public VerilatedVpio {
|
||||||
|
const VerilatedScope* const m_scopep;
|
||||||
|
const VerilatedVarNameMap* const m_varsp;
|
||||||
|
VerilatedVarNameMap::const_iterator m_it;
|
||||||
|
VerilatedVpioVar* m_varp;
|
||||||
|
const std::string m_namePrefix;
|
||||||
|
bool m_started = false;
|
||||||
|
|
||||||
|
static std::string namePrefix(const VerilatedVpioVar* vop) {
|
||||||
|
return std::string{vop->varp()->name()} + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
vpiHandle atEnd() {
|
||||||
|
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VerilatedVpioMemberIter(const VerilatedVpioVar* vop)
|
||||||
|
: m_scopep{vop->scopep()}
|
||||||
|
, m_varsp{m_scopep->varsp()}
|
||||||
|
, m_varp{new VerilatedVpioVar{vop}}
|
||||||
|
, m_namePrefix{namePrefix(vop)} {}
|
||||||
|
~VerilatedVpioMemberIter() override { VL_DO_CLEAR(delete m_varp, m_varp = nullptr); }
|
||||||
|
// cppcheck-suppress duplInheritedMember
|
||||||
|
static VerilatedVpioMemberIter* castp(vpiHandle h) {
|
||||||
|
return dynamic_cast<VerilatedVpioMemberIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||||
|
}
|
||||||
|
uint32_t type() const override { return vpiIterator; }
|
||||||
|
vpiHandle dovpi_scan() override {
|
||||||
|
if (VL_UNLIKELY(!m_varsp)) return atEnd();
|
||||||
|
if (VL_UNLIKELY(!m_started)) {
|
||||||
|
m_it = m_varsp->begin();
|
||||||
|
m_started = true;
|
||||||
|
} else if (VL_LIKELY(m_it != m_varsp->end())) {
|
||||||
|
++m_it;
|
||||||
|
}
|
||||||
|
for (; m_it != m_varsp->end(); ++m_it) {
|
||||||
|
const char* const name = m_it->second.name();
|
||||||
|
if (std::strncmp(name, m_namePrefix.c_str(), m_namePrefix.length()) != 0) continue;
|
||||||
|
// Only direct members, not grandchildren
|
||||||
|
if (_vl_vpi_find_unescaped_dot(name + m_namePrefix.length())) continue;
|
||||||
|
VerilatedVpioVar* const memberp = m_varp->withMember(&(m_it->second));
|
||||||
|
if (VL_UNLIKELY(!memberp)) continue;
|
||||||
|
return memberp->castVpiHandle();
|
||||||
|
}
|
||||||
|
return atEnd();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class VerilatedVpioModule final : public VerilatedVpioScope {
|
class VerilatedVpioModule final : public VerilatedVpioScope {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit VerilatedVpioModule(const VerilatedScope* modulep)
|
explicit VerilatedVpioModule(const VerilatedScope* modulep)
|
||||||
: VerilatedVpioScope{modulep} {
|
: VerilatedVpioScope{modulep} {
|
||||||
// Look for '.' not inside escaped identifier
|
// Look for '.' not inside escaped identifier
|
||||||
const std::string scopename = m_fullname;
|
if (VL_UNLIKELY(!_vl_vpi_find_unescaped_dot(m_fullname))) m_toplevel = true;
|
||||||
std::string::size_type pos = std::string::npos;
|
|
||||||
size_t i = 0;
|
|
||||||
while (i < scopename.length()) {
|
|
||||||
if (scopename[i] == '\\') {
|
|
||||||
while (i < scopename.length() && scopename[i] != ' ') ++i;
|
|
||||||
++i; // Proc ' ', it should always be there. Then grab '.' on next cycle
|
|
||||||
} else {
|
|
||||||
while (i < scopename.length() && scopename[i] != '.') ++i;
|
|
||||||
if (i < scopename.length()) pos = i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (VL_UNLIKELY(pos == std::string::npos)) m_toplevel = true;
|
|
||||||
}
|
}
|
||||||
// cppcheck-suppress duplInheritedMember
|
// cppcheck-suppress duplInheritedMember
|
||||||
static VerilatedVpioModule* castp(vpiHandle h) {
|
static VerilatedVpioModule* castp(vpiHandle h) {
|
||||||
|
|
@ -1770,6 +1874,8 @@ const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_PURE {
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
|
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
|
||||||
|
// vpiUnionNet is outside the otherwise contiguous SystemVerilog object type range.
|
||||||
|
if (vpiVal == vpiUnionNet) return "vpiUnionNet";
|
||||||
if (vpiVal <= vpiAutomatics) return names[vpiVal];
|
if (vpiVal <= vpiAutomatics) return names[vpiVal];
|
||||||
if (vpiVal >= vpiPackage && vpiVal <= vpiPropFormalDecl)
|
if (vpiVal >= vpiPackage && vpiVal <= vpiPropFormalDecl)
|
||||||
return sv_names1[(vpiVal - vpiPackage)];
|
return sv_names1[(vpiVal - vpiPackage)];
|
||||||
|
|
@ -2135,6 +2241,7 @@ void VerilatedVpiError::selfTest() VL_MT_UNSAFE_ONE {
|
||||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEnumVar);
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEnumVar);
|
||||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStructVar);
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStructVar);
|
||||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUnionVar);
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUnionVar);
|
||||||
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUnionNet);
|
||||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiBitVar);
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiBitVar);
|
||||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassObj);
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassObj);
|
||||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiChandleVar);
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiChandleVar);
|
||||||
|
|
@ -2404,6 +2511,162 @@ static bool vl_vpi_parse_indices(std::string& name, std::vector<PLI_INT32>& indi
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const VerilatedScope* _vl_vpi_top_port_scopep(const VerilatedScope* const scopep) {
|
||||||
|
if (VL_UNLIKELY(!scopep)) return nullptr;
|
||||||
|
if (scopep->type() != VerilatedScope::SCOPE_MODULE) return nullptr;
|
||||||
|
if (std::strcmp(scopep->name(), "TOP") == 0) return nullptr;
|
||||||
|
if (_vl_vpi_find_unescaped_dot(scopep->name())) return nullptr;
|
||||||
|
return Verilated::threadContextp()->scopeFind("TOP");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _vl_vpi_find_dotted_var(const std::string& scopename, const std::string& basename,
|
||||||
|
const VerilatedScope*& scopep, const VerilatedVar*& varp,
|
||||||
|
std::string& fullname) {
|
||||||
|
if (scopename.empty()) return false;
|
||||||
|
|
||||||
|
// Unpacked struct/union members are exposed as synthetic vars whose names contain dots
|
||||||
|
// (e.g. "mystruct.member"), so the boundary between the scope and the variable name is
|
||||||
|
// ambiguous. Walk the boundary leftward, moving one scope segment at a time onto the front
|
||||||
|
// of the dotted variable name, and try each candidate scope. An exhausted scope means the
|
||||||
|
// variable lives in the toplevel "TOP" scope.
|
||||||
|
std::string dottedName = basename;
|
||||||
|
std::string dottedScope = scopename;
|
||||||
|
while (true) {
|
||||||
|
const std::string::size_type lastDot = dottedScope.rfind('.');
|
||||||
|
dottedName = (lastDot == std::string::npos ? dottedScope : dottedScope.substr(lastDot + 1))
|
||||||
|
+ "." + dottedName;
|
||||||
|
dottedScope.resize(lastDot == std::string::npos ? 0 : lastDot);
|
||||||
|
scopep = Verilated::threadContextp()->scopeFind(dottedScope.empty() ? "TOP"
|
||||||
|
: dottedScope.c_str());
|
||||||
|
if (scopep) {
|
||||||
|
if (const VerilatedScope* const topScopep = _vl_vpi_top_port_scopep(scopep)) {
|
||||||
|
if (const VerilatedVar* const topVarp = topScopep->varFind(dottedName.c_str())) {
|
||||||
|
scopep = topScopep;
|
||||||
|
varp = topVarp;
|
||||||
|
fullname = dottedScope.empty() ? dottedName : dottedScope + "." + dottedName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
varp = scopep->varFind(dottedName.c_str());
|
||||||
|
if (varp) return true;
|
||||||
|
}
|
||||||
|
if (lastDot == std::string::npos) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VerilatedVpioVar* _vl_vpi_handle_member_by_name(const std::string& name,
|
||||||
|
const VerilatedVpioVar* vop) {
|
||||||
|
const VerilatedScope* const scopep = vop->scopep();
|
||||||
|
if (VL_UNLIKELY(!scopep)) return nullptr;
|
||||||
|
const std::string memberName = std::string{vop->varp()->name()} + "." + name;
|
||||||
|
const VerilatedVar* const memberVarp = scopep->varFind(memberName.c_str());
|
||||||
|
if (!memberVarp) return nullptr;
|
||||||
|
return vop->withMember(memberVarp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VerilatedVpioVar* _vl_vpi_handle_apply_indices(VerilatedVpioVar* vop,
|
||||||
|
const std::vector<PLI_INT32>& indices) {
|
||||||
|
for (const PLI_INT32 index : indices) {
|
||||||
|
VerilatedVpioVar* const nextVop = vop->withIndex(index);
|
||||||
|
VL_DO_CLEAR(delete vop, vop = nullptr);
|
||||||
|
if (!nextVop) return nullptr;
|
||||||
|
vop = nextVop;
|
||||||
|
}
|
||||||
|
return vop;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _vl_vpi_parse_optional_indices(std::string& name, std::vector<PLI_INT32>& indices) {
|
||||||
|
indices.clear();
|
||||||
|
if (name.empty()) return false;
|
||||||
|
if (name.back() != ']') return true;
|
||||||
|
|
||||||
|
VlVpiBitRange bitRange;
|
||||||
|
return vl_vpi_parse_indices(name, indices, &bitRange) && !bitRange.valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _vl_vpi_split_dotted_name(const std::string& name, std::vector<std::string>& parts) {
|
||||||
|
parts.clear();
|
||||||
|
const char* const namep = name.c_str();
|
||||||
|
const char* beginp = namep;
|
||||||
|
const char* posp = beginp;
|
||||||
|
while ((posp = _vl_vpi_find_unescaped_dot(posp))) {
|
||||||
|
parts.emplace_back(beginp, posp - beginp);
|
||||||
|
beginp = ++posp;
|
||||||
|
}
|
||||||
|
parts.emplace_back(beginp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VerilatedVpioVar*
|
||||||
|
_vl_vpi_handle_indexed_member_from_scope(const VerilatedScope* const scopep,
|
||||||
|
const std::vector<std::string>& parts,
|
||||||
|
const size_t firstPart) {
|
||||||
|
if (VL_UNLIKELY(!scopep) || VL_UNLIKELY(firstPart >= parts.size())) return nullptr;
|
||||||
|
|
||||||
|
std::string baseName = parts[firstPart];
|
||||||
|
std::vector<PLI_INT32> indices;
|
||||||
|
if (!_vl_vpi_parse_optional_indices(baseName, indices)) return nullptr;
|
||||||
|
|
||||||
|
const VerilatedScope* varScopep = scopep;
|
||||||
|
const VerilatedVar* baseVarp = nullptr;
|
||||||
|
std::string fullnameOverride;
|
||||||
|
if (const VerilatedScope* const topScopep = _vl_vpi_top_port_scopep(scopep)) {
|
||||||
|
if (const VerilatedVar* const topVarp = topScopep->varFind(baseName.c_str())) {
|
||||||
|
varScopep = topScopep;
|
||||||
|
baseVarp = topVarp;
|
||||||
|
fullnameOverride = std::string{scopep->name()} + "." + baseName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!baseVarp) baseVarp = scopep->varFind(baseName.c_str());
|
||||||
|
if (!baseVarp) return nullptr;
|
||||||
|
|
||||||
|
VerilatedVpioVar* baseVop
|
||||||
|
= fullnameOverride.empty()
|
||||||
|
? new VerilatedVpioVar{baseVarp, varScopep}
|
||||||
|
: new VerilatedVpioVar{baseVarp, varScopep, baseVarp->datap(),
|
||||||
|
_vl_vpi_member_local_name(baseVarp->name()),
|
||||||
|
fullnameOverride};
|
||||||
|
VerilatedVpioVar* vop = _vl_vpi_handle_apply_indices(baseVop, indices);
|
||||||
|
if (!vop) return nullptr;
|
||||||
|
|
||||||
|
for (size_t i = firstPart + 1; i < parts.size(); ++i) {
|
||||||
|
std::string memberName = parts[i];
|
||||||
|
if (!_vl_vpi_parse_optional_indices(memberName, indices)) {
|
||||||
|
VL_DO_CLEAR(delete vop, vop = nullptr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VerilatedVpioVar* const memberVop = _vl_vpi_handle_member_by_name(memberName, vop);
|
||||||
|
VL_DO_CLEAR(delete vop, vop = nullptr);
|
||||||
|
if (!memberVop) return nullptr;
|
||||||
|
|
||||||
|
vop = _vl_vpi_handle_apply_indices(memberVop, indices);
|
||||||
|
if (!vop) return nullptr;
|
||||||
|
}
|
||||||
|
return vop;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VerilatedVpioVar*
|
||||||
|
_vl_vpi_handle_dotted_indexed_member_by_name(const std::string& scopeAndName) {
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
_vl_vpi_split_dotted_name(scopeAndName, parts);
|
||||||
|
if (parts.size() < 2) return nullptr;
|
||||||
|
|
||||||
|
for (size_t firstPart = parts.size() - 1; firstPart > 0; --firstPart) {
|
||||||
|
std::string scopeName = parts[0];
|
||||||
|
for (size_t i = 1; i < firstPart; ++i) scopeName += "." + parts[i];
|
||||||
|
const VerilatedScope* const scopep
|
||||||
|
= Verilated::threadContextp()->scopeFind(scopeName.c_str());
|
||||||
|
if (!scopep) continue;
|
||||||
|
if (VerilatedVpioVar* const vop
|
||||||
|
= _vl_vpi_handle_indexed_member_from_scope(scopep, parts, firstPart)) {
|
||||||
|
return vop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const VerilatedScope* const topScopep = Verilated::threadContextp()->scopeFind("TOP");
|
||||||
|
return _vl_vpi_handle_indexed_member_from_scope(topScopep, parts, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// for obtaining handles
|
// for obtaining handles
|
||||||
|
|
||||||
vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
||||||
|
|
@ -2425,7 +2688,9 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
||||||
|
|
||||||
const VerilatedVar* varp = nullptr;
|
const VerilatedVar* varp = nullptr;
|
||||||
const VerilatedScope* scopep;
|
const VerilatedScope* scopep;
|
||||||
|
std::string fullnameOverride;
|
||||||
const VerilatedVpioScope* const voScopep = VerilatedVpioScope::castp(scope);
|
const VerilatedVpioScope* const voScopep = VerilatedVpioScope::castp(scope);
|
||||||
|
const VerilatedVpioVar* const voVarp = VerilatedVpioVar::castp(scope);
|
||||||
|
|
||||||
if (0 == std::strncmp(scopeAndName.c_str(), "$root.", std::strlen("$root."))) {
|
if (0 == std::strncmp(scopeAndName.c_str(), "$root.", std::strlen("$root."))) {
|
||||||
scopeAndName.erase(0, std::strlen("$root."));
|
scopeAndName.erase(0, std::strlen("$root."));
|
||||||
|
|
@ -2433,6 +2698,12 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
||||||
const bool scopeIsPackage = VerilatedVpioPackage::castp(scope) != nullptr;
|
const bool scopeIsPackage = VerilatedVpioPackage::castp(scope) != nullptr;
|
||||||
scopeAndName
|
scopeAndName
|
||||||
= std::string{voScopep->fullname()} + (scopeIsPackage ? "" : ".") + scopeAndName;
|
= std::string{voScopep->fullname()} + (scopeIsPackage ? "" : ".") + scopeAndName;
|
||||||
|
} else if (voVarp && voVarp->isStructOrUnion()) {
|
||||||
|
if (VerilatedVpioVar* const memberp
|
||||||
|
= _vl_vpi_handle_member_by_name(scopeAndName, voVarp)) {
|
||||||
|
return memberp->castVpiHandle();
|
||||||
|
}
|
||||||
|
scopeAndName = std::string{voVarp->fullname()} + "." + scopeAndName;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// This doesn't yet follow the hierarchy in the proper way
|
// This doesn't yet follow the hierarchy in the proper way
|
||||||
|
|
@ -2491,8 +2762,18 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
||||||
}
|
}
|
||||||
if (!varp) {
|
if (!varp) {
|
||||||
scopep = Verilated::threadContextp()->scopeFind(scopename.c_str());
|
scopep = Verilated::threadContextp()->scopeFind(scopename.c_str());
|
||||||
if (!scopep) return nullptr;
|
if (scopep) { varp = scopep->varFind(basename.c_str()); }
|
||||||
varp = scopep->varFind(basename.c_str());
|
// Unpacked struct members are exposed as synthetic variables with dotted names.
|
||||||
|
// Exact unindexed member names can be found directly; indexed member paths need the
|
||||||
|
// component walker so array indices are applied before member offsets.
|
||||||
|
if (!varp
|
||||||
|
&& !_vl_vpi_find_dotted_var(scopename, basename, scopep, varp, fullnameOverride)) {
|
||||||
|
if (VerilatedVpioVar* const memberp
|
||||||
|
= _vl_vpi_handle_dotted_indexed_member_by_name(scopeAndName)) {
|
||||||
|
return memberp->castVpiHandle();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!varp) return nullptr;
|
if (!varp) return nullptr;
|
||||||
|
|
@ -2501,6 +2782,11 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
||||||
vpiHandle resultHandle;
|
vpiHandle resultHandle;
|
||||||
if (varp->isParam()) {
|
if (varp->isParam()) {
|
||||||
resultHandle = (new VerilatedVpioParam{varp, scopep})->castVpiHandle();
|
resultHandle = (new VerilatedVpioParam{varp, scopep})->castVpiHandle();
|
||||||
|
} else if (!fullnameOverride.empty()) {
|
||||||
|
resultHandle
|
||||||
|
= (new VerilatedVpioVar{varp, scopep, varp->datap(),
|
||||||
|
_vl_vpi_member_local_name(varp->name()), fullnameOverride})
|
||||||
|
->castVpiHandle();
|
||||||
} else {
|
} else {
|
||||||
resultHandle = (new VerilatedVpioVar{varp, scopep})->castVpiHandle();
|
resultHandle = (new VerilatedVpioVar{varp, scopep})->castVpiHandle();
|
||||||
}
|
}
|
||||||
|
|
@ -2642,6 +2928,11 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
||||||
if (vop) return ((new VerilatedVpioRegIter{vop})->castVpiHandle());
|
if (vop) return ((new VerilatedVpioRegIter{vop})->castVpiHandle());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
case vpiMember: {
|
||||||
|
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||||
|
if (!vop || !vop->isStructOrUnion()) return nullptr;
|
||||||
|
return ((new VerilatedVpioMemberIter{vop})->castVpiHandle());
|
||||||
|
}
|
||||||
case vpiParameter: {
|
case vpiParameter: {
|
||||||
const VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object);
|
const VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object);
|
||||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||||
|
|
@ -2734,6 +3025,11 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) {
|
||||||
if (VL_UNLIKELY(!vop)) return vpiUndefined;
|
if (VL_UNLIKELY(!vop)) return vpiUndefined;
|
||||||
return vop->varp()->isSigned();
|
return vop->varp()->isSigned();
|
||||||
}
|
}
|
||||||
|
case vpiPacked: {
|
||||||
|
const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
|
||||||
|
if (VL_LIKELY(vop && vop->isStructOrUnion())) return 0;
|
||||||
|
[[fallthrough]];
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported property %s, nothing will be returned",
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported property %s, nothing will be returned",
|
||||||
__func__, VerilatedVpiError::strFromVpiProp(property));
|
__func__, VerilatedVpiError::strFromVpiProp(property));
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,10 @@
|
||||||
breathe==4.36.0
|
breathe==4.36.0
|
||||||
compiledb==0.10.7
|
compiledb==0.10.7
|
||||||
distro==1.9.0
|
distro==1.9.0
|
||||||
|
docstrfmt==2.2.0
|
||||||
gersemi==0.23.1
|
gersemi==0.23.1
|
||||||
mbake==1.4.3
|
mbake==1.4.3
|
||||||
|
mdformat==1.0.0
|
||||||
mypy==1.19.0
|
mypy==1.19.0
|
||||||
pylint==3.0.2
|
pylint==3.0.2
|
||||||
ruff==0.14.8
|
ruff==0.14.8
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,241 @@
|
||||||
|
<!-- DESCRIPTION: Verilator: src/ guidelines for AI coding agents
|
||||||
|
SPDX-FileCopyrightText: 2026-2026 Wilson Snyder
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -->
|
||||||
|
|
||||||
|
# src/ -- Verilator compiler sources
|
||||||
|
|
||||||
|
Covers all C++ under `src/`, including astgen inputs and the parser/lexer
|
||||||
|
(`verilog.y`, `verilog.l`). Read the repository-root [AGENTS.md](../AGENTS.md)
|
||||||
|
first. This file has two parts: **Orientation** explains the AST and pass model;
|
||||||
|
**Before you open a PR** is the style and correctness checklist.
|
||||||
|
|
||||||
|
______________________________________________________________________
|
||||||
|
|
||||||
|
# Orientation: the AST and the visitor model
|
||||||
|
|
||||||
|
- **Everything is an `AstNode`.** Each construct is an `Ast*` subclass (`AstAdd`,
|
||||||
|
`AstVar`, `AstIf`). The design under analysis is one tree, with statement lists
|
||||||
|
threaded by sibling `nextp()` links.
|
||||||
|
- **Children sit in numbered slots `op1p()`..`op4p()`, accessed by name.** Use the
|
||||||
|
named accessors (`lhsp()`, `condp()`, `thensp()`), not the raw slots -- the
|
||||||
|
numbering is an implementation detail.
|
||||||
|
- **`astgen` generates node boilerplate.** Declare children and cross-node
|
||||||
|
pointers with `@astgen op` / `@astgen ptr` annotations in the `V3AstNode*.h`
|
||||||
|
headers; it emits accessors, clone, and broken-check code. Do not hand-write
|
||||||
|
what astgen can generate.
|
||||||
|
- **A pass is a visitor.** Convention: a class with a private constructor and a
|
||||||
|
static `apply()` entry point, named after its file (`TimingSuspendableVisitor`
|
||||||
|
in `V3Timing.cpp`). It walks the tree through `visit(AstFoo*)` handlers and
|
||||||
|
`iterateChildren()`. To understand a pass, read its top-of-file comment first --
|
||||||
|
every `.cpp` opens with one describing the algorithm.
|
||||||
|
- **Scratch state lives on nodes.** Passes stash data in `user1p()`..`user5p()`
|
||||||
|
(and `user1()`..`user5()`), claimed for the pass lifetime with a `VNUser*InUse`
|
||||||
|
guard. Save and restore visitor members across recursion with `VL_RESTORER`.
|
||||||
|
- **Three downcasts, three null behaviors:** `VN_IS` returns bool, `VN_CAST`
|
||||||
|
returns nullptr on mismatch, `VN_AS` asserts the type. `V3Broken` re-validates
|
||||||
|
tree invariants between passes, so trust resolved pointers (`dtypep()`,
|
||||||
|
`varp()`) instead of adding defensive null checks for impossible cases.
|
||||||
|
- `docs/internals.rst` is the authoritative reference for the AST, the pass list,
|
||||||
|
and node lifetime.
|
||||||
|
|
||||||
|
______________________________________________________________________
|
||||||
|
|
||||||
|
# Before you open a PR
|
||||||
|
|
||||||
|
## Code style
|
||||||
|
|
||||||
|
- Mark every variable, parameter, pointer, and member function `const` where possible.
|
||||||
|
- Pointer variables take a `p` suffix and pointer locals are doubly const where
|
||||||
|
possible: `AstVar* const varp`; non-pointers never use the `p` suffix.
|
||||||
|
- Do not use `auto` except for iterators or genuinely unwieldy types.
|
||||||
|
- Use pre-increment (`++i`) unless you specifically need post-increment's old value.
|
||||||
|
- Brace-initialize node and struct construction: `new AstIf{fl, condp, thenp, elsep}`.
|
||||||
|
- Never use C-style casts; instead use `static_cast<T>` for non-AST types and
|
||||||
|
`VN_AS`/`VN_CAST` for AST downcasts.
|
||||||
|
- `static constexpr` for compile-time constants, not `#define` or file-scope const.
|
||||||
|
- Mark every `class`/`struct` `final` or `VL_NOT_FINAL` -- a distribution test
|
||||||
|
scans all definitions.
|
||||||
|
- Keep functions under roughly 100-150 lines; thread shared state through a
|
||||||
|
context struct rather than long parameter lists.
|
||||||
|
- Keep headers lean: move implementation to `.cpp`; convert large lambdas into
|
||||||
|
named member functions -- lambdas are opaque in stack traces and block reuse.
|
||||||
|
- Start every new `.cpp` with a top-of-file comment explaining the algorithm.
|
||||||
|
- Comments are capitalized sentences written for an unknown future reader, without
|
||||||
|
"I"/"we"/"our"; remove commented-out code -- version control preserves history.
|
||||||
|
- No `using namespace`; prefix non-namespaced symbols with `VL`/`Vl`.
|
||||||
|
- Prefer semantic predicates over enum comparisons: `varp->isClassMember()`, not
|
||||||
|
`varp->varType() == VVarType::MEMBER`.
|
||||||
|
- `new*` functions return a `new` object; `make*` functions do something more
|
||||||
|
complex -- pick the prefix accordingly.
|
||||||
|
- Name compiler-created temporaries with a `__V` prefix plus a context suffix
|
||||||
|
(`__VInside`, `__VCase`); runtime utility functions use a `vl_` prefix.
|
||||||
|
- Use `VL_*` bit/word macros from `verilatedos.h` (`VL_WORDS_I`, `VL_MASK_I`); do
|
||||||
|
not include `<cstdint>` directly.
|
||||||
|
- Replace magic numbers with named `static constexpr` constants.
|
||||||
|
|
||||||
|
## AST construction and manipulation
|
||||||
|
|
||||||
|
- Build logic as AST nodes, never as raw C text in `AstCStmt` -- later passes
|
||||||
|
(V3Name, `--protect`) rename AST identifiers but cannot see into raw strings.
|
||||||
|
|
||||||
|
- Know the cast forms (above) and never pair `VN_IS` with `VN_AS` on the same
|
||||||
|
node -- use a single `VN_CAST`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// BAD: redundant double check
|
||||||
|
if (VN_IS(nodep, VarRef)) { AstVarRef* const refp = VN_AS(nodep, VarRef); }
|
||||||
|
// GOOD: single conditional cast
|
||||||
|
if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
- Use `UASSERT_OBJ(cond, nodep, "...")` over `UASSERT` when a node is in scope;
|
||||||
|
use `v3fatalSrc("...")` for unreachable paths, never a silent `if (!ptr) return;`.
|
||||||
|
|
||||||
|
- Use `VL_DO_DANGLING(pushDeletep(nodep), nodep)` instead of `deleteTree()` in
|
||||||
|
visitors -- deferred deletion is safe against re-entry and unlinking order.
|
||||||
|
`deleteTree()` is only for fresh nodes that never entered the tree.
|
||||||
|
|
||||||
|
- Every new AST member needs both `dump()` and `dumpJson()` support -- never wrap
|
||||||
|
these in `LCOV_EXCL`; cover them by adding a construct to `t_debug_emitv.v`.
|
||||||
|
Override `isSame()` to include any new semantically meaningful field.
|
||||||
|
|
||||||
|
- Pointers to nodes outside op1p-op4p require a `broken()` override and
|
||||||
|
`cloneRelink()` support -- avoid storing out-of-tree node pointers when possible.
|
||||||
|
|
||||||
|
- Never allocate AstNode objects on the stack or by value -- always pointers.
|
||||||
|
|
||||||
|
- Prefer a new `visit()` in an existing visitor over `nodep->foreach(...)` --
|
||||||
|
better for runtime, and handles diverse node types better. Prefer named
|
||||||
|
accessors over `op1p()`..`op4p()`, and verify traversal order is preserved
|
||||||
|
when converting manual iteration.
|
||||||
|
|
||||||
|
- Prefer `AstForeach` over generating unrolled loop bodies -- constant-size code
|
||||||
|
instead of O(N); wrap the body in `AstBegin` for scope isolation.
|
||||||
|
|
||||||
|
- Always `skipRefp()` when comparing or resolving dtypes -- missing it breaks
|
||||||
|
typedef support; prove the paths with typedef tests.
|
||||||
|
|
||||||
|
- Use `num().isOpaque()` rather than `isDouble() || isString()` when guarding
|
||||||
|
V3Number comparisons against non-integer types.
|
||||||
|
|
||||||
|
- Use `FileLine::operatorCompare` for source-position ordering -- never hand-roll
|
||||||
|
filename/lineno comparisons.
|
||||||
|
|
||||||
|
- Identify compiler-generated constructs by an attribute flag on the node (with
|
||||||
|
dump support), never by name-pattern matching -- magic names break with escaped
|
||||||
|
identifiers.
|
||||||
|
|
||||||
|
- Use `V3Number` arithmetic for `AstConst` values wider than 32 bits -- `1 << i`
|
||||||
|
silently overflows at `i >= 32`.
|
||||||
|
|
||||||
|
- Use `VMemberMap`/`findMember()` for name lookups in structs, classes, modules,
|
||||||
|
and packages -- O(1) versus quadratic linear scans.
|
||||||
|
|
||||||
|
- Never emit raw source filenames or identifiers in generated code -- pass them
|
||||||
|
through `protect()`/`putsQuoted` so `--protect` does not leak source.
|
||||||
|
|
||||||
|
## Visitors and passes
|
||||||
|
|
||||||
|
- `VL_RESTORER` on every visitor member a `visit()` modifies before iterating
|
||||||
|
children -- even when nesting "cannot happen" today.
|
||||||
|
- Every pass using `userNp()` needs a `VNUserNInUse` guard, and the header
|
||||||
|
documents which user fields it uses.
|
||||||
|
- Use `iterateAndNextNull()` rather than `iterate()` -- the null-safe form
|
||||||
|
prevents copy-paste errors during refactors.
|
||||||
|
- Derive read-only visitors from `VNVisitorConst` with `iterateChildrenConst`.
|
||||||
|
- Reset per-module visitor state in `visit(AstNodeModule*)`, including numeric ID
|
||||||
|
counters, to keep generated names stable.
|
||||||
|
- Capture first-occurrence module state inside the node's own `visit()` handler,
|
||||||
|
not via a `foreach` pre-scan from `visit(AstNodeModule)` -- source order already
|
||||||
|
matches IEEE declaration-before-use.
|
||||||
|
- Avoid `backp()` -- it returns parent or prior sibling depending on position and
|
||||||
|
causes O(n^2) hunts; build maps or capture context during forward traversal.
|
||||||
|
- When raw node pointers key a map or set, erase entries when the node is deleted
|
||||||
|
-- allocators reuse addresses, so stale entries alias new nodes.
|
||||||
|
- Derive graph-shaped passes from V3Graph (`V3GraphVertex`/`V3GraphEdge`) -- it
|
||||||
|
gives dump, color, rank, topological sort, and reachability for free.
|
||||||
|
- When a change outgrows local rewrites, create a dedicated pass instead of
|
||||||
|
growing an existing one.
|
||||||
|
- State explicitly how side effects are preserved in optimizations involving
|
||||||
|
purity, expression lifting, or simplification.
|
||||||
|
|
||||||
|
## Errors and warnings
|
||||||
|
|
||||||
|
(See the root checklist for choosing the diagnostic API and its required test.)
|
||||||
|
|
||||||
|
- Append `nodep->prettyNameQ()` for user-facing names; use `name()` only in
|
||||||
|
debug/UINFO output. Enclose specific values in single quotes: `'value'`.
|
||||||
|
- End messages with periods, never exclamation marks; do not write "Error:" in the
|
||||||
|
text -- the macro prints the prefix.
|
||||||
|
- State what was attempted and what was found: "Instance attempts to connect to
|
||||||
|
'PARAM' as a parameter, but it is a variable". Add a `warnMore()` suggestion
|
||||||
|
where possible.
|
||||||
|
- Name warning codes object-first and short (`ASCRANGE`, not `RANGEASC`); rename
|
||||||
|
via `renamedTo()` so old suppressions keep working.
|
||||||
|
- Set warning suppression on `AstVar`, not `AstVarRef` -- VarRefs get recreated
|
||||||
|
and lose `warnIsOff`.
|
||||||
|
- "Unsupported:" messages describe the specific unsupported context, not just the
|
||||||
|
construct name -- each message must be distinct.
|
||||||
|
- When replacing or refactoring a pass, keep existing user-facing error strings --
|
||||||
|
`.out` goldens and documentation depend on the wording.
|
||||||
|
|
||||||
|
## Performance and memory
|
||||||
|
|
||||||
|
- O(n^2) is never acceptable -- build maps for batch lookups; any quadratic loop
|
||||||
|
needs explicit justification in a comment.
|
||||||
|
- Prefer `std::map` for per-module structures (many small instances); use
|
||||||
|
`unordered_map` only for one-per-netlist data, and never let `unordered_*`
|
||||||
|
iteration order reach generated output.
|
||||||
|
- Prefer `emplace` over `insert` and check the returned `.second` instead of a
|
||||||
|
separate `find()`. `reserve()` strings and vectors when the size is estimable.
|
||||||
|
- Add no new static or global mutable data -- statics are being eliminated for
|
||||||
|
future parallelism.
|
||||||
|
- Use Verilator's fixed-width data types for model data (`CData`/`SData`/`IData`/
|
||||||
|
`QData`/`VlWide`), not `size_t`. Process wide data word-by-word
|
||||||
|
(`VL_ZERO_W`, `VL_MEMCPY_W`), never bit-by-bit.
|
||||||
|
- No exceptions in verilated runtime code; do string parsing at verilation time,
|
||||||
|
never during simulation.
|
||||||
|
- Wrap unlikely hot-path branches in `VL_UNLIKELY`/`VL_LIKELY`.
|
||||||
|
- Count what every new pass does via V3Stats -- stats become deterministic
|
||||||
|
regression anchors.
|
||||||
|
|
||||||
|
## Thread safety
|
||||||
|
|
||||||
|
- Annotate with the hierarchy `VL_PURE` > `VL_MT_SAFE` > `VL_MT_STABLE`: PURE has
|
||||||
|
no side effects and calls only PURE; MT_SAFE is safe under locks; MT_STABLE is
|
||||||
|
safe only while tree topology is stable. Annotations must match the
|
||||||
|
implementation.
|
||||||
|
- Never include `verilated.h` in the compiler itself -- use `verilatedos.h`.
|
||||||
|
- Annotate mutex-protected members with `VL_GUARDED_BY` and document acquisition
|
||||||
|
ordering. `++` on shared state and container `empty()` are not thread-safe.
|
||||||
|
|
||||||
|
## Parser and lexer (verilog.y, verilog.l)
|
||||||
|
|
||||||
|
- Preserve IEEE Appendix A BNF comments (`// IEEE: {rule}`); comment explicitly
|
||||||
|
when accepting syntax beyond IEEE as an extension.
|
||||||
|
- The parser only builds AST nodes -- defer semantic validation, `VN_IS` checks,
|
||||||
|
and context-dependent logic to V3LinkParse/V3Width and later passes.
|
||||||
|
- Represent hierarchical paths as structured nodes (`AstDot`/parse-ref chains via
|
||||||
|
`idDotted`), never concatenated strings -- preserves per-segment FileLine.
|
||||||
|
- Prefer tightening a grammar rule's operand type over a runtime cast-chain guard
|
||||||
|
in a later visitor -- illegal operands then fail with a clean syntax error.
|
||||||
|
- Solve ambiguities with token-pipeline look-ahead (`tokenPipeScan*`) rather than
|
||||||
|
limiting grammar rules; mark unsupported rules with `//UNSUP`.
|
||||||
|
- Sort token declarations alphabetically by string literal; sort `yD_*`
|
||||||
|
productions by token name.
|
||||||
|
- Add a test for every `|` alternative and optional clause of a new or changed
|
||||||
|
grammar rule -- untested alternatives are where parse regressions hide.
|
||||||
|
|
||||||
|
## File-specific rules
|
||||||
|
|
||||||
|
| File | Rule |
|
||||||
|
|---|---|
|
||||||
|
| `src/V3Options.cpp` | Chain `.notForRerun()` onto `DECL_OPTION()` for options that do not affect semantic output |
|
||||||
|
| `src/V3Ast.cpp` | For composite types (queues, dynamic arrays) use `computeCastableImp()` on subtypes -- shallow `width()`/`similarDType()` checks miss nested incompatibility |
|
||||||
|
| `src/V3AstNode*.h` | Every node class gets a what-construct comment and every member a semantic-purpose comment; put enum type definitions in `V3AstAttr.h` |
|
||||||
|
| `src/V3AstNodeExpr.h` | `CCast` is only for basic C types (char/short/int/QData) -- never 4-state logic or structs |
|
||||||
|
| `src/V3AstNodeOther.h` | `cloneRelink` must propagate all stateful flags (e.g. `maybePointedTo`) and update internal references |
|
||||||
|
| `src/V3Const.cpp` | Check `keepIfEmpty` before removing empty functions -- flagged functions must survive for codegen/side effects |
|
||||||
|
| `src/V3Coverage.cpp` | Instrumentation contexts are opt-in (allowlist), never blocklist -- blocklists silently break when new contexts appear |
|
||||||
|
| `src/V3Inline.cpp` | Preserve `VarXRef::varp()` during passes -- pin-reconnection needs it before V3LinkDot re-resolves |
|
||||||
|
| `src/V3Sched*.cpp` | Every change needs a test proving necessity; isolate unrelated scheduler changes into separate PRs -- high-risk area |
|
||||||
|
|
@ -51,6 +51,7 @@ set(HEADERS
|
||||||
V3AstNodeExpr.h
|
V3AstNodeExpr.h
|
||||||
V3AstNodeOther.h
|
V3AstNodeOther.h
|
||||||
V3AstNodeStmt.h
|
V3AstNodeStmt.h
|
||||||
|
V3AstPatterns.h
|
||||||
V3AstUserAllocator.h
|
V3AstUserAllocator.h
|
||||||
V3Begin.h
|
V3Begin.h
|
||||||
V3Branch.h
|
V3Branch.h
|
||||||
|
|
@ -175,7 +176,6 @@ set(HEADERS
|
||||||
V3Simulate.h
|
V3Simulate.h
|
||||||
V3Slice.h
|
V3Slice.h
|
||||||
V3Split.h
|
V3Split.h
|
||||||
V3SplitAs.h
|
|
||||||
V3SplitVar.h
|
V3SplitVar.h
|
||||||
V3StackCount.h
|
V3StackCount.h
|
||||||
V3Stats.h
|
V3Stats.h
|
||||||
|
|
@ -183,7 +183,6 @@ set(HEADERS
|
||||||
V3String.h
|
V3String.h
|
||||||
V3Subst.h
|
V3Subst.h
|
||||||
V3SymTable.h
|
V3SymTable.h
|
||||||
V3TSP.h
|
|
||||||
V3Table.h
|
V3Table.h
|
||||||
V3Task.h
|
V3Task.h
|
||||||
V3ThreadPool.h
|
V3ThreadPool.h
|
||||||
|
|
@ -203,7 +202,6 @@ set(HEADERS
|
||||||
V3WidthCommit.h
|
V3WidthCommit.h
|
||||||
V3WidthRemove.h
|
V3WidthRemove.h
|
||||||
VlcBucket.h
|
VlcBucket.h
|
||||||
VlcCovergroup.h
|
|
||||||
VlcOptions.h
|
VlcOptions.h
|
||||||
VlcPoint.h
|
VlcPoint.h
|
||||||
VlcSource.h
|
VlcSource.h
|
||||||
|
|
@ -253,7 +251,6 @@ set(COMMON_SOURCES
|
||||||
V3DfgDataType.cpp
|
V3DfgDataType.cpp
|
||||||
V3DfgDecomposition.cpp
|
V3DfgDecomposition.cpp
|
||||||
V3DfgDfgToAst.cpp
|
V3DfgDfgToAst.cpp
|
||||||
V3DfgDumpPatterns.cpp
|
|
||||||
V3DfgOptimizer.cpp
|
V3DfgOptimizer.cpp
|
||||||
V3DfgPasses.cpp
|
V3DfgPasses.cpp
|
||||||
V3DfgPeephole.cpp
|
V3DfgPeephole.cpp
|
||||||
|
|
@ -330,6 +327,7 @@ set(COMMON_SOURCES
|
||||||
V3ParseGrammar.cpp
|
V3ParseGrammar.cpp
|
||||||
V3ParseImp.cpp
|
V3ParseImp.cpp
|
||||||
V3ParseLex.cpp
|
V3ParseLex.cpp
|
||||||
|
V3PatternStats.cpp
|
||||||
V3PreProc.cpp
|
V3PreProc.cpp
|
||||||
V3PreShell.cpp
|
V3PreShell.cpp
|
||||||
V3Premit.cpp
|
V3Premit.cpp
|
||||||
|
|
@ -351,14 +349,12 @@ set(COMMON_SOURCES
|
||||||
V3Scoreboard.cpp
|
V3Scoreboard.cpp
|
||||||
V3Slice.cpp
|
V3Slice.cpp
|
||||||
V3Split.cpp
|
V3Split.cpp
|
||||||
V3SplitAs.cpp
|
|
||||||
V3SplitVar.cpp
|
V3SplitVar.cpp
|
||||||
V3StackCount.cpp
|
V3StackCount.cpp
|
||||||
V3Stats.cpp
|
V3Stats.cpp
|
||||||
V3StatsReport.cpp
|
V3StatsReport.cpp
|
||||||
V3String.cpp
|
V3String.cpp
|
||||||
V3Subst.cpp
|
V3Subst.cpp
|
||||||
V3TSP.cpp
|
|
||||||
V3Table.cpp
|
V3Table.cpp
|
||||||
V3Task.cpp
|
V3Task.cpp
|
||||||
V3ThreadPool.cpp
|
V3ThreadPool.cpp
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,6 @@ RAW_OBJS_PCH_ASTNOMT = \
|
||||||
V3DfgDataType.o \
|
V3DfgDataType.o \
|
||||||
V3DfgDecomposition.o \
|
V3DfgDecomposition.o \
|
||||||
V3DfgDfgToAst.o \
|
V3DfgDfgToAst.o \
|
||||||
V3DfgDumpPatterns.o \
|
|
||||||
V3DfgOptimizer.o \
|
V3DfgOptimizer.o \
|
||||||
V3DfgPasses.o \
|
V3DfgPasses.o \
|
||||||
V3DfgPeephole.o \
|
V3DfgPeephole.o \
|
||||||
|
|
@ -314,6 +313,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
||||||
V3OrderProcessDomains.o \
|
V3OrderProcessDomains.o \
|
||||||
V3OrderSerial.o \
|
V3OrderSerial.o \
|
||||||
V3Param.o \
|
V3Param.o \
|
||||||
|
V3PatternStats.o \
|
||||||
V3Premit.o \
|
V3Premit.o \
|
||||||
V3ProtectLib.o \
|
V3ProtectLib.o \
|
||||||
V3RandSequence.o \
|
V3RandSequence.o \
|
||||||
|
|
@ -333,11 +333,9 @@ RAW_OBJS_PCH_ASTNOMT = \
|
||||||
V3Scoreboard.o \
|
V3Scoreboard.o \
|
||||||
V3Slice.o \
|
V3Slice.o \
|
||||||
V3Split.o \
|
V3Split.o \
|
||||||
V3SplitAs.o \
|
|
||||||
V3SplitVar.o \
|
V3SplitVar.o \
|
||||||
V3StackCount.o \
|
V3StackCount.o \
|
||||||
V3Subst.o \
|
V3Subst.o \
|
||||||
V3TSP.o \
|
|
||||||
V3Table.o \
|
V3Table.o \
|
||||||
V3Task.o \
|
V3Task.o \
|
||||||
V3Timing.o \
|
V3Timing.o \
|
||||||
|
|
|
||||||
|
|
@ -351,7 +351,7 @@ public:
|
||||||
|
|
||||||
class ActiveDlyVisitor final : public VNVisitor {
|
class ActiveDlyVisitor final : public VNVisitor {
|
||||||
public:
|
public:
|
||||||
enum CheckType : uint8_t { CT_SEQ, CT_COMB, CT_INITIAL, CT_SUSPENDABLE };
|
enum CheckType : uint8_t { CT_COMB, CT_FINAL };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
|
|
@ -359,15 +359,9 @@ private:
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstAssignDly* nodep) override {
|
void visit(AstAssignDly* nodep) override {
|
||||||
// Non-blocking assignments are OK in sequential processes
|
|
||||||
if (m_check == CT_SEQ || m_check == CT_SUSPENDABLE) return;
|
|
||||||
|
|
||||||
// Issue appropriate warning
|
// Issue appropriate warning
|
||||||
if (m_check == CT_INITIAL) {
|
if (m_check == CT_FINAL) {
|
||||||
nodep->v3warn(INITIALDLY,
|
nodep->v3warn(FINALDLY, "Non-blocking assignment '<=' in final block");
|
||||||
"Non-blocking assignment '<=' in initial/final block\n"
|
|
||||||
<< nodep->warnMore()
|
|
||||||
<< "... This will be executed as a blocking assignment '='!");
|
|
||||||
} else {
|
} else {
|
||||||
nodep->v3warn(COMBDLY,
|
nodep->v3warn(COMBDLY,
|
||||||
"Non-blocking assignment '<=' in combinational logic process\n"
|
"Non-blocking assignment '<=' in combinational logic process\n"
|
||||||
|
|
@ -465,11 +459,7 @@ class ActiveVisitor final : public VNVisitor {
|
||||||
wantactivep->addStmtsp(nodep);
|
wantactivep->addStmtsp(nodep);
|
||||||
|
|
||||||
// Warn and convert any delayed assignments
|
// Warn and convert any delayed assignments
|
||||||
{
|
if (!m_clockedProcess) ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_COMB};
|
||||||
ActiveDlyVisitor{nodep, !m_clockedProcess ? ActiveDlyVisitor::CT_COMB
|
|
||||||
: oldsentreep ? ActiveDlyVisitor::CT_SEQ
|
|
||||||
: ActiveDlyVisitor::CT_SUSPENDABLE};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete sensitivity list
|
// Delete sensitivity list
|
||||||
if (oldsentreep) VL_DO_DANGLING(oldsentreep->deleteTree(), oldsentreep);
|
if (oldsentreep) VL_DO_DANGLING(oldsentreep->deleteTree(), oldsentreep);
|
||||||
|
|
@ -509,17 +499,11 @@ class ActiveVisitor final : public VNVisitor {
|
||||||
|
|
||||||
void visit(AstInitialStatic* nodep) override { moveUnderSpecial<AstSenItem::Static>(nodep); }
|
void visit(AstInitialStatic* nodep) override { moveUnderSpecial<AstSenItem::Static>(nodep); }
|
||||||
void visit(AstInitial* nodep) override {
|
void visit(AstInitial* nodep) override {
|
||||||
const bool timedInitial
|
|
||||||
= v3Global.opt.timing().isSetTrue() && nodep->exists([](const AstNode* const subp) {
|
|
||||||
return VN_IS(subp, Delay) || VN_IS(subp, EventControl);
|
|
||||||
});
|
|
||||||
const ActiveDlyVisitor dlyvisitor{nodep, timedInitial ? ActiveDlyVisitor::CT_SUSPENDABLE
|
|
||||||
: ActiveDlyVisitor::CT_INITIAL};
|
|
||||||
visitSenItems(nodep);
|
visitSenItems(nodep);
|
||||||
moveUnderSpecial<AstSenItem::Initial>(nodep);
|
moveUnderSpecial<AstSenItem::Initial>(nodep);
|
||||||
}
|
}
|
||||||
void visit(AstFinal* nodep) override {
|
void visit(AstFinal* nodep) override {
|
||||||
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
|
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_FINAL};
|
||||||
moveUnderSpecial<AstSenItem::Final>(nodep);
|
moveUnderSpecial<AstSenItem::Final>(nodep);
|
||||||
}
|
}
|
||||||
void visit(AstCoverToggle* nodep) override { moveUnderSpecial<AstSenItem::Combo>(nodep); }
|
void visit(AstCoverToggle* nodep) override { moveUnderSpecial<AstSenItem::Combo>(nodep); }
|
||||||
|
|
|
||||||
363
src/V3Assert.cpp
363
src/V3Assert.cpp
|
|
@ -20,9 +20,83 @@
|
||||||
|
|
||||||
#include "V3AstUserAllocator.h"
|
#include "V3AstUserAllocator.h"
|
||||||
#include "V3Stats.h"
|
#include "V3Stats.h"
|
||||||
|
#include "V3UniqueNames.h"
|
||||||
|
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class DefaultDisableLocalVisitor final : public VNVisitor {
|
||||||
|
// STATE
|
||||||
|
AstNode* m_scopep = nullptr;
|
||||||
|
|
||||||
|
// VISITORS
|
||||||
|
void visit(AstNodeModule* nodep) override {
|
||||||
|
VL_RESTORER(m_scopep);
|
||||||
|
m_scopep = nodep;
|
||||||
|
nodep->defaultDisablep(nullptr);
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstGenBlock* nodep) override {
|
||||||
|
VL_RESTORER(m_scopep);
|
||||||
|
m_scopep = nodep;
|
||||||
|
nodep->defaultDisablep(nullptr);
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstDefaultDisable* nodep) override {
|
||||||
|
UASSERT_OBJ(nodep, m_scopep,
|
||||||
|
"default disable iff must be inside a module or generate block");
|
||||||
|
AstDefaultDisable* defaultp = nullptr;
|
||||||
|
if (const AstNodeModule* const modp = VN_CAST(m_scopep, NodeModule)) {
|
||||||
|
defaultp = modp->defaultDisablep();
|
||||||
|
} else {
|
||||||
|
defaultp = VN_AS(m_scopep, GenBlock)->defaultDisablep();
|
||||||
|
}
|
||||||
|
if (VL_UNLIKELY(defaultp)) {
|
||||||
|
nodep->v3error("Only one 'default disable iff' allowed per "
|
||||||
|
<< (VN_IS(m_scopep, NodeModule) ? "module" : "generate block")
|
||||||
|
<< " (IEEE 1800-2023 16.15)");
|
||||||
|
} else if (AstNodeModule* const modp = VN_CAST(m_scopep, NodeModule)) {
|
||||||
|
modp->defaultDisablep(nodep);
|
||||||
|
} else {
|
||||||
|
VN_AS(m_scopep, GenBlock)->defaultDisablep(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DefaultDisableLocalVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class DefaultDisablePropagateVisitor final : public VNVisitor {
|
||||||
|
// STATE
|
||||||
|
AstDefaultDisable* m_defaultDisablep = nullptr;
|
||||||
|
|
||||||
|
// VISITORS
|
||||||
|
void visit(AstNodeModule* nodep) override {
|
||||||
|
VL_RESTORER(m_defaultDisablep);
|
||||||
|
m_defaultDisablep = nodep->defaultDisablep();
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstGenBlock* nodep) override {
|
||||||
|
VL_RESTORER(m_defaultDisablep);
|
||||||
|
if (!nodep->defaultDisablep()) nodep->defaultDisablep(m_defaultDisablep);
|
||||||
|
m_defaultDisablep = nodep->defaultDisablep();
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DefaultDisablePropagateVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void V3AssertCommon::collectDefaultDisable(AstNetlist* nodep) {
|
||||||
|
{ DefaultDisableLocalVisitor{nodep}; }
|
||||||
|
{ DefaultDisablePropagateVisitor{nodep}; }
|
||||||
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// AssertDeFutureVisitor
|
// AssertDeFutureVisitor
|
||||||
// If any AstFuture, then move all non-future varrefs to be one cycle behind,
|
// If any AstFuture, then move all non-future varrefs to be one cycle behind,
|
||||||
|
|
@ -153,12 +227,26 @@ class AssertVisitor final : public VNVisitor {
|
||||||
bool m_inRestrict = false; // True inside restrict assertion
|
bool m_inRestrict = false; // True inside restrict assertion
|
||||||
AstNode* m_passsp = nullptr; // Current pass statement
|
AstNode* m_passsp = nullptr; // Current pass statement
|
||||||
AstNode* m_failsp = nullptr; // Current fail statement
|
AstNode* m_failsp = nullptr; // Current fail statement
|
||||||
|
AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion
|
||||||
AstFinal* m_finalp = nullptr; // Current final block
|
AstFinal* m_finalp = nullptr; // Current final block
|
||||||
|
VDouble0 m_statLiftedCaseExprs; // Count of purified case expressions
|
||||||
|
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||||
|
V3UniqueNames m_caseTempNames{"__VCase"};
|
||||||
// Map from (expression, senTree) to AstAlways that computes delayed values of the expression
|
// Map from (expression, senTree) to AstAlways that computes delayed values of the expression
|
||||||
std::unordered_map<VNRef<AstNodeExpr>, std::unordered_map<VNRef<AstSenTree>, AstAlways*>>
|
std::unordered_map<VNRef<AstNodeExpr>, std::unordered_map<VNRef<AstSenTree>, AstAlways*>>
|
||||||
m_modExpr2Sen2DelayedAlwaysp;
|
m_modExpr2Sen2DelayedAlwaysp;
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
static string assertCtlGetCall(const char* query, VAssertType type,
|
||||||
|
VAssertDirectiveType directiveType) {
|
||||||
|
return "vlSymsp->_vm_contextp__->assertCtlGet(VerilatedAssertCtlQuery::"s + query + ", "s
|
||||||
|
+ std::to_string(type) + ", "s + std::to_string(directiveType) + ")"s;
|
||||||
|
}
|
||||||
|
static const char* assertPassOnQuery(bool vacuous) {
|
||||||
|
static constexpr const char* queries[2]
|
||||||
|
= {"ASSERT_CTL_PASS_ON_NONVACUOUS", "ASSERT_CTL_PASS_ON_VACUOUS"};
|
||||||
|
return queries[vacuous];
|
||||||
|
}
|
||||||
static AstNodeExpr* assertOnCond(FileLine* fl, VAssertType type,
|
static AstNodeExpr* assertOnCond(FileLine* fl, VAssertType type,
|
||||||
VAssertDirectiveType directiveType) {
|
VAssertDirectiveType directiveType) {
|
||||||
// cppcheck-suppress missingReturn
|
// cppcheck-suppress missingReturn
|
||||||
|
|
@ -178,9 +266,7 @@ class AssertVisitor final : public VNVisitor {
|
||||||
case VAssertDirectiveType::ASSUME: {
|
case VAssertDirectiveType::ASSUME: {
|
||||||
if (v3Global.opt.assertOn()) {
|
if (v3Global.opt.assertOn()) {
|
||||||
return new AstCExpr{fl, AstCExpr::Pure{},
|
return new AstCExpr{fl, AstCExpr::Pure{},
|
||||||
"vlSymsp->_vm_contextp__->assertOnGet("s + std::to_string(type)
|
assertCtlGetCall("ASSERT_CTL_ON", type, directiveType), 1};
|
||||||
+ ", "s + std::to_string(directiveType) + ")"s,
|
|
||||||
1};
|
|
||||||
}
|
}
|
||||||
return new AstConst{fl, AstConst::BitFalse{}};
|
return new AstConst{fl, AstConst::BitFalse{}};
|
||||||
}
|
}
|
||||||
|
|
@ -196,6 +282,27 @@ class AssertVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
VL_UNREACHABLE;
|
VL_UNREACHABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isControlled(VAssertDirectiveType directiveType) {
|
||||||
|
return (static_cast<int>(directiveType)
|
||||||
|
& (static_cast<int>(VAssertDirectiveType::ASSERT)
|
||||||
|
| static_cast<int>(VAssertDirectiveType::COVER)
|
||||||
|
| static_cast<int>(VAssertDirectiveType::ASSUME)));
|
||||||
|
}
|
||||||
|
static AstNodeExpr* assertPassOnCond(FileLine* fl, VAssertType type,
|
||||||
|
VAssertDirectiveType directiveType, bool vacuous) {
|
||||||
|
if (!isControlled(directiveType)) return new AstConst{fl, AstConst::BitTrue{}};
|
||||||
|
if (!v3Global.opt.assertOn()) return new AstConst{fl, AstConst::BitFalse{}};
|
||||||
|
return new AstCExpr{fl, AstCExpr::Pure{},
|
||||||
|
assertCtlGetCall(assertPassOnQuery(vacuous), type, directiveType), 1};
|
||||||
|
}
|
||||||
|
static AstNodeExpr* assertFailOnCond(FileLine* fl, VAssertType type,
|
||||||
|
VAssertDirectiveType directiveType) {
|
||||||
|
if (!isControlled(directiveType)) return new AstConst{fl, AstConst::BitTrue{}};
|
||||||
|
if (!v3Global.opt.assertOn()) return new AstConst{fl, AstConst::BitFalse{}};
|
||||||
|
return new AstCExpr{fl, AstCExpr::Pure{},
|
||||||
|
assertCtlGetCall("ASSERT_CTL_FAIL_ON", type, directiveType), 1};
|
||||||
|
}
|
||||||
string assertDisplayMessage(const AstNode* nodep, const string& prefix, const string& message,
|
string assertDisplayMessage(const AstNode* nodep, const string& prefix, const string& message,
|
||||||
VDisplayType severity) {
|
VDisplayType severity) {
|
||||||
if (severity == VDisplayType::DT_ERROR || severity == VDisplayType::DT_FATAL) {
|
if (severity == VDisplayType::DT_ERROR || severity == VDisplayType::DT_FATAL) {
|
||||||
|
|
@ -207,36 +314,6 @@ class AssertVisitor final : public VNVisitor {
|
||||||
+ cvtToStr(nodep->fileline()->lineno()) + ": %m" + ((message != "") ? ": " : "")
|
+ cvtToStr(nodep->fileline()->lineno()) + ": %m" + ((message != "") ? ": " : "")
|
||||||
+ message + "\n");
|
+ message + "\n");
|
||||||
}
|
}
|
||||||
static bool resolveAssertType(AstAssertCtl* nodep) {
|
|
||||||
if (!nodep->assertTypesp()) {
|
|
||||||
nodep->ctlAssertTypes(VAssertType{ALL_ASSERT_TYPES});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (const AstConst* const assertTypesp = VN_CAST(nodep->assertTypesp(), Const)) {
|
|
||||||
nodep->ctlAssertTypes(VAssertType{assertTypesp->toSInt()});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
static bool resolveControlType(AstAssertCtl* nodep) {
|
|
||||||
if (const AstConst* const constp = VN_CAST(nodep->controlTypep(), Const)) {
|
|
||||||
nodep->ctlType(constp->toSInt());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
static bool resolveDirectiveType(AstAssertCtl* nodep) {
|
|
||||||
if (!nodep->directiveTypesp()) {
|
|
||||||
nodep->ctlDirectiveTypes(VAssertDirectiveType::ASSERT | VAssertDirectiveType::ASSUME
|
|
||||||
| VAssertDirectiveType::COVER);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (const AstConst* const directiveTypesp = VN_CAST(nodep->directiveTypesp(), Const)) {
|
|
||||||
nodep->ctlDirectiveTypes(VAssertDirectiveType{directiveTypesp->toSInt()});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
|
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
|
||||||
nodep->fmtp()->text(
|
nodep->fmtp()->text(
|
||||||
assertDisplayMessage(nodep, prefix, nodep->fmtp()->text(), nodep->displayType()));
|
assertDisplayMessage(nodep, prefix, nodep->fmtp()->text(), nodep->displayType()));
|
||||||
|
|
@ -278,8 +355,8 @@ class AssertVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
static AstIf* newIfAssertOn(AstNode* bodyp, VAssertDirectiveType directiveType,
|
static AstIf* newIfAssertOn(AstNode* bodyp, VAssertDirectiveType directiveType,
|
||||||
VAssertType type = VAssertType::INTERNAL) {
|
VAssertType type = VAssertType::INTERNAL) {
|
||||||
// Add a internal if to check assertions are on.
|
// Add an internal if to check assertions are on.
|
||||||
// Don't make this a AND term, as it's unlikely to need to test this.
|
// Don't make this an AND term, as it's unlikely to need to test this.
|
||||||
FileLine* const fl = bodyp->fileline();
|
FileLine* const fl = bodyp->fileline();
|
||||||
|
|
||||||
AstNodeExpr* const condp = assertOnCond(fl, type, directiveType);
|
AstNodeExpr* const condp = assertOnCond(fl, type, directiveType);
|
||||||
|
|
@ -288,6 +365,30 @@ class AssertVisitor final : public VNVisitor {
|
||||||
newp->user2(true); // Mark as an assertOn() check
|
newp->user2(true); // Mark as an assertOn() check
|
||||||
return newp;
|
return newp;
|
||||||
}
|
}
|
||||||
|
static AstNodeStmt* newIfAssertPassOn(AstNode* bodyp, VAssertDirectiveType directiveType,
|
||||||
|
VAssertType type, bool vacuous) {
|
||||||
|
// Add an internal if to check assertion passOn is enabled.
|
||||||
|
// Don't make this an AND term, as it's unlikely to need to test this.
|
||||||
|
FileLine* const fl = bodyp->fileline();
|
||||||
|
AstNodeExpr* const condp = assertPassOnCond(fl, type, directiveType, vacuous);
|
||||||
|
AstNodeIf* const newp = new AstIf{fl, condp, bodyp};
|
||||||
|
newp->isBoundsCheck(true); // To avoid LATCH warning
|
||||||
|
newp->user1(true); // Don't assert/cover this if
|
||||||
|
newp->user2(true); // Mark as an assertOn() check
|
||||||
|
return newp;
|
||||||
|
}
|
||||||
|
static AstNodeStmt* newIfAssertFailOn(AstNode* bodyp, VAssertDirectiveType directiveType,
|
||||||
|
VAssertType type) {
|
||||||
|
// Add an internal if to check assertion failOn is enabled.
|
||||||
|
// Don't make this an AND term, as it's unlikely to need to test this.
|
||||||
|
FileLine* const fl = bodyp->fileline();
|
||||||
|
AstNodeExpr* const condp = assertFailOnCond(fl, type, directiveType);
|
||||||
|
AstNodeIf* const newp = new AstIf{fl, condp, bodyp};
|
||||||
|
newp->isBoundsCheck(true); // To avoid LATCH warning
|
||||||
|
newp->user1(true); // Don't assert/cover this if
|
||||||
|
newp->user2(true); // Mark as an assertOn() check
|
||||||
|
return newp;
|
||||||
|
}
|
||||||
|
|
||||||
static AstIf* assertCond(const AstNodeCoverOrAssert* nodep, AstNodeExpr* propp,
|
static AstIf* assertCond(const AstNodeCoverOrAssert* nodep, AstNodeExpr* propp,
|
||||||
AstNode* passsp, AstNode* failsp) {
|
AstNode* passsp, AstNode* failsp) {
|
||||||
|
|
@ -444,6 +545,7 @@ class AssertVisitor final : public VNVisitor {
|
||||||
if (failsp) failsp->unlinkFrBackWithNext();
|
if (failsp) failsp->unlinkFrBackWithNext();
|
||||||
|
|
||||||
bool selfDestruct = false;
|
bool selfDestruct = false;
|
||||||
|
bool passspGated = false;
|
||||||
if (const AstCover* const snodep = VN_CAST(nodep, Cover)) {
|
if (const AstCover* const snodep = VN_CAST(nodep, Cover)) {
|
||||||
++m_statCover;
|
++m_statCover;
|
||||||
if (!v3Global.opt.coverageUser()) {
|
if (!v3Global.opt.coverageUser()) {
|
||||||
|
|
@ -455,6 +557,9 @@ class AssertVisitor final : public VNVisitor {
|
||||||
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
||||||
if (message != "") covincp->declp()->comment(message);
|
if (message != "") covincp->declp()->comment(message);
|
||||||
if (passsp) {
|
if (passsp) {
|
||||||
|
passsp = newIfAssertPassOn(passsp, nodep->directive(), nodep->userType(),
|
||||||
|
/*vacuous=*/false);
|
||||||
|
passspGated = true;
|
||||||
passsp = AstNode::addNext<AstNode, AstNode>(covincp, passsp);
|
passsp = AstNode::addNext<AstNode, AstNode>(covincp, passsp);
|
||||||
} else {
|
} else {
|
||||||
passsp = covincp;
|
passsp = covincp;
|
||||||
|
|
@ -475,8 +580,10 @@ class AssertVisitor final : public VNVisitor {
|
||||||
|
|
||||||
VL_RESTORER(m_passsp);
|
VL_RESTORER(m_passsp);
|
||||||
VL_RESTORER(m_failsp);
|
VL_RESTORER(m_failsp);
|
||||||
|
VL_RESTORER(m_assertp);
|
||||||
m_passsp = passsp;
|
m_passsp = passsp;
|
||||||
m_failsp = failsp;
|
m_failsp = failsp;
|
||||||
|
m_assertp = nodep;
|
||||||
iterate(nodep->propp());
|
iterate(nodep->propp());
|
||||||
|
|
||||||
AstNode* propExprp;
|
AstNode* propExprp;
|
||||||
|
|
@ -488,6 +595,15 @@ class AssertVisitor final : public VNVisitor {
|
||||||
propExprp = nodep->propp()->unlinkFrBack();
|
propExprp = nodep->propp()->unlinkFrBack();
|
||||||
}
|
}
|
||||||
FileLine* const flp = nodep->fileline();
|
FileLine* const flp = nodep->fileline();
|
||||||
|
bool passspAlreadyGated = false;
|
||||||
|
if (passsp && VN_IS(passsp, If)) passspAlreadyGated = VN_AS(passsp, If)->user1();
|
||||||
|
if (passsp && !passspGated && !passspAlreadyGated && !VN_IS(propExprp, PExpr)) {
|
||||||
|
passsp = newIfAssertPassOn(passsp, nodep->directive(), nodep->userType(),
|
||||||
|
/*vacuous=*/false);
|
||||||
|
}
|
||||||
|
if (failsp && !VN_IS(propExprp, PExpr)) {
|
||||||
|
failsp = newIfAssertFailOn(failsp, nodep->directive(), nodep->userType());
|
||||||
|
}
|
||||||
AstNode* bodysp = assertBody(nodep, propExprp, passsp, failsp);
|
AstNode* bodysp = assertBody(nodep, propExprp, passsp, failsp);
|
||||||
if (disablep) bodysp = new AstIf{flp, new AstLogNot{flp, disablep}, bodysp};
|
if (disablep) bodysp = new AstIf{flp, new AstLogNot{flp, disablep}, bodysp};
|
||||||
// Add assertOn check last, for better combining
|
// Add assertOn check last, for better combining
|
||||||
|
|
@ -582,8 +698,36 @@ class AssertVisitor final : public VNVisitor {
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|
||||||
|
if (nodep->user2()) {
|
||||||
|
// Combine consecutive assertOn checks if possible
|
||||||
|
if (AstIf* const backp = VN_CAST(nodep->backp(), If)) {
|
||||||
|
if (backp->nextp() == nodep //
|
||||||
|
&& backp->user2() //
|
||||||
|
&& backp->condp()->sameTree(nodep->condp())) {
|
||||||
|
++m_statAssertOnCombined;
|
||||||
|
backp->addThensp(nodep->thensp()->unlinkFrBackWithNext());
|
||||||
|
nodep->unlinkFrBack();
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Combine nested assertOn checks if possible
|
||||||
|
if (nodep->thensp() && !nodep->thensp()->nextp() && isEmptyStmt(nodep->elsesp())) {
|
||||||
|
AstIf* const checkp = VN_CAST(nodep->thensp(), If);
|
||||||
|
if (checkp //
|
||||||
|
&& checkp->user2() //
|
||||||
|
&& checkp->condp()->sameTree(nodep->condp())) {
|
||||||
|
++m_statAssertOnCombined;
|
||||||
|
nodep->addThensp(checkp->thensp()->unlinkFrBackWithNext());
|
||||||
|
VL_DO_DANGLING(pushDeletep(checkp->unlinkFrBack()), checkp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swap assertOn check with single statement 'if' statement to bubble up for combining
|
// Swap assertOn check with single statement 'if' statement to bubble up for combining
|
||||||
|
|
@ -611,24 +755,32 @@ class AssertVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine consecutive assertOn checks if possible
|
|
||||||
if (nodep->user2()) {
|
|
||||||
if (AstIf* const backp = VN_CAST(nodep->backp(), If)) {
|
|
||||||
if (backp->nextp() == nodep //
|
|
||||||
&& backp->user2() //
|
|
||||||
&& backp->condp()->sameTree(nodep->condp())) {
|
|
||||||
++m_statAssertOnCombined;
|
|
||||||
backp->addThensp(nodep->thensp()->unlinkFrBackWithNext());
|
|
||||||
nodep->unlinkFrBack();
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//========== Case assertions
|
//========== Case assertions
|
||||||
void visit(AstCase* nodep) override {
|
void visit(AstCase* nodep) override {
|
||||||
|
// Introduce temporary variable for AstCase if needed - it is done here and not in V3Case
|
||||||
|
// because this phase is before V3Scope and V3Case is not. Doing it before V3Scope ensures
|
||||||
|
// that V3Scope will take care of a scope creation
|
||||||
|
// We also need to do it before V3Begin, co that pragmas like `unique0` also work correctly
|
||||||
|
if (!nodep->exprp()->isPure()) {
|
||||||
|
++m_statLiftedCaseExprs;
|
||||||
|
FileLine* const fl = nodep->exprp()->fileline();
|
||||||
|
AstVar* const varp = new AstVar{fl, VVarType::BLOCKTEMP, m_caseTempNames.get(nodep),
|
||||||
|
nodep->exprp()->dtypep()};
|
||||||
|
AstNodeExpr* const origp = nodep->exprp()->unlinkFrBack();
|
||||||
|
nodep->addHereThisAsNext(
|
||||||
|
new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, origp});
|
||||||
|
nodep->exprp(new AstVarRef{fl, varp, VAccess::READ});
|
||||||
|
if (m_ftaskp) {
|
||||||
|
varp->funcLocal(true);
|
||||||
|
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||||
|
m_ftaskp->stmtsp()->addHereThisAsNext(varp);
|
||||||
|
} else {
|
||||||
|
m_modp->stmtsp()->addHereThisAsNext(varp);
|
||||||
|
}
|
||||||
|
VIsCached::clearCacheTree();
|
||||||
|
}
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (!nodep->user1SetOnce()) {
|
if (!nodep->user1SetOnce()) {
|
||||||
bool has_default = false;
|
bool has_default = false;
|
||||||
|
|
@ -807,8 +959,11 @@ class AssertVisitor final : public VNVisitor {
|
||||||
if (nodep->pass() && m_passsp) {
|
if (nodep->pass() && m_passsp) {
|
||||||
// Cover adds COVERINC by AstNode::addNext, thus need to clone next too.
|
// Cover adds COVERINC by AstNode::addNext, thus need to clone next too.
|
||||||
stmtsp = m_passsp->cloneTree(true);
|
stmtsp = m_passsp->cloneTree(true);
|
||||||
|
stmtsp = newIfAssertPassOn(stmtsp, m_assertp->directive(), m_assertp->userType(),
|
||||||
|
nodep->vacuous());
|
||||||
} else if (!nodep->pass() && m_failsp) {
|
} else if (!nodep->pass() && m_failsp) {
|
||||||
stmtsp = m_failsp->cloneTree(true);
|
stmtsp = m_failsp->cloneTree(true);
|
||||||
|
stmtsp = newIfAssertFailOn(stmtsp, m_assertp->directive(), m_assertp->userType());
|
||||||
}
|
}
|
||||||
if (stmtsp) {
|
if (stmtsp) {
|
||||||
stmtsp->foreachAndNext([](AstNodeVarRef* const refp) {
|
stmtsp->foreachAndNext([](AstNodeVarRef* const refp) {
|
||||||
|
|
@ -914,34 +1069,51 @@ class AssertVisitor final : public VNVisitor {
|
||||||
visitAssertionIterate(nodep, nodep->failsp());
|
visitAssertionIterate(nodep, nodep->failsp());
|
||||||
}
|
}
|
||||||
void visit(AstAssertCtl* nodep) override {
|
void visit(AstAssertCtl* nodep) override {
|
||||||
if (VN_IS(m_modp, Class) || VN_IS(m_modp, Iface)) {
|
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: assertcontrols in classes or interfaces");
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|
||||||
if (!resolveAssertType(nodep)) {
|
bool assertTypeConst = true;
|
||||||
nodep->v3warn(E_UNSUPPORTED,
|
if (!nodep->assertTypesp()) {
|
||||||
"Unsupported: non-constant assert assertion-type expression");
|
nodep->ctlAssertTypes(VAssertType{ALL_ASSERT_TYPES});
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
} else if (const AstConst* const assertTypesp = VN_CAST(nodep->assertTypesp(), Const)) {
|
||||||
|
nodep->ctlAssertTypes(VAssertType{assertTypesp->toSInt()});
|
||||||
|
} else {
|
||||||
|
assertTypeConst = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool controlTypeConst = false;
|
||||||
|
if (const AstConst* const constp = VN_CAST(nodep->controlTypep(), Const)) {
|
||||||
|
nodep->ctlType(constp->toSInt());
|
||||||
|
controlTypeConst = true;
|
||||||
|
}
|
||||||
|
if (controlTypeConst
|
||||||
|
&& (nodep->ctlType() < VAssertCtlType::LOCK
|
||||||
|
|| nodep->ctlType() > VAssertCtlType::VACUOUS_OFF)) {
|
||||||
|
nodep->unlinkFrBack();
|
||||||
|
nodep->v3error("Bad $assertcontrol control_type '"
|
||||||
|
<< cvtToStr(static_cast<int>(nodep->ctlType()))
|
||||||
|
<< "' (IEEE 1800-2023 Table 20-5)");
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (nodep->ctlAssertTypes() != ALL_ASSERT_TYPES
|
if (assertTypeConst && nodep->ctlAssertTypes() != ALL_ASSERT_TYPES
|
||||||
&& nodep->ctlAssertTypes().containsAny(VAssertType::EXPECT | VAssertType::UNIQUE
|
&& nodep->ctlAssertTypes().containsAny(VAssertType::UNIQUE | VAssertType::UNIQUE0
|
||||||
| VAssertType::UNIQUE0
|
|
||||||
| VAssertType::PRIORITY)) {
|
| VAssertType::PRIORITY)) {
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: assert control assertion_type");
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: assert control assertion_type");
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!resolveControlType(nodep)) {
|
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: non-const assert control type expression");
|
bool directiveTypeConst = true;
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
if (!nodep->directiveTypesp()) {
|
||||||
return;
|
nodep->ctlDirectiveTypes(VAssertDirectiveType::ASSERT | VAssertDirectiveType::ASSUME
|
||||||
|
| VAssertDirectiveType::COVER);
|
||||||
|
} else if (const AstConst* const directiveTypesp
|
||||||
|
= VN_CAST(nodep->directiveTypesp(), Const)) {
|
||||||
|
nodep->ctlDirectiveTypes(VAssertDirectiveType{directiveTypesp->toSInt()});
|
||||||
|
} else {
|
||||||
|
directiveTypeConst = false;
|
||||||
}
|
}
|
||||||
if (!resolveDirectiveType(nodep)) {
|
if (!directiveTypeConst) {
|
||||||
nodep->v3warn(E_UNSUPPORTED,
|
nodep->v3warn(E_UNSUPPORTED,
|
||||||
"Unsupported: non-const assert directive type expression");
|
"Unsupported: non-const assert directive type expression");
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
|
|
@ -949,43 +1121,18 @@ class AssertVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
switch (nodep->ctlType()) {
|
UINFO(9, "Generating assertctl for a module: " << m_modp);
|
||||||
case VAssertCtlType::ON:
|
AstCStmt* const newp = new AstCStmt{fl};
|
||||||
UINFO(9, "Generating assertctl for a module: " << m_modp);
|
newp->add("vlSymsp->_vm_contextp__->assertCtl(");
|
||||||
nodep->replaceWith(
|
newp->add(nodep->controlTypep()->unlinkFrBack());
|
||||||
new AstCStmt{fl, "vlSymsp->_vm_contextp__->assertOnSet("s
|
newp->add(", ");
|
||||||
+ std::to_string(nodep->ctlAssertTypes()) + ", "s
|
if (nodep->assertTypesp()) {
|
||||||
+ std::to_string(nodep->ctlDirectiveTypes()) + ");\n"s});
|
newp->add(nodep->assertTypesp()->unlinkFrBack());
|
||||||
break;
|
} else {
|
||||||
case VAssertCtlType::OFF:
|
newp->add(std::to_string(ALL_ASSERT_TYPES));
|
||||||
case VAssertCtlType::KILL: {
|
|
||||||
UINFO(9, "Generating assertctl for a module: " << m_modp);
|
|
||||||
nodep->replaceWith(
|
|
||||||
new AstCStmt{fl, "vlSymsp->_vm_contextp__->assertOnClear("s
|
|
||||||
+ std::to_string(nodep->ctlAssertTypes()) + " ,"s
|
|
||||||
+ std::to_string(nodep->ctlDirectiveTypes()) + ");\n"s});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VAssertCtlType::LOCK:
|
|
||||||
case VAssertCtlType::UNLOCK:
|
|
||||||
case VAssertCtlType::PASS_ON:
|
|
||||||
case VAssertCtlType::PASS_OFF:
|
|
||||||
case VAssertCtlType::FAIL_ON:
|
|
||||||
case VAssertCtlType::FAIL_OFF:
|
|
||||||
case VAssertCtlType::NONVACUOUS_ON:
|
|
||||||
case VAssertCtlType::VACUOUS_OFF: {
|
|
||||||
nodep->unlinkFrBack();
|
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: $assertcontrol control_type '" << cvtToStr(
|
|
||||||
static_cast<int>(nodep->ctlType())) << "'");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
nodep->unlinkFrBack();
|
|
||||||
nodep->v3warn(EC_ERROR, "Bad $assertcontrol control_type '"
|
|
||||||
<< cvtToStr(static_cast<int>(nodep->ctlType()))
|
|
||||||
<< "' (IEEE 1800-2023 Table 20-5)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
newp->add(", " + std::to_string(nodep->ctlDirectiveTypes()) + ");\n");
|
||||||
|
nodep->replaceWith(newp);
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
}
|
}
|
||||||
void visit(AstAssertIntrinsic* nodep) override { //
|
void visit(AstAssertIntrinsic* nodep) override { //
|
||||||
|
|
@ -1006,11 +1153,12 @@ class AssertVisitor final : public VNVisitor {
|
||||||
VL_RESTORER(m_modp);
|
VL_RESTORER(m_modp);
|
||||||
VL_RESTORER(m_modPastNum);
|
VL_RESTORER(m_modPastNum);
|
||||||
VL_RESTORER(m_modStrobeNum);
|
VL_RESTORER(m_modStrobeNum);
|
||||||
VL_RESTORER(m_modExpr2Sen2DelayedAlwaysp);
|
VL_RESTORER(m_finalp);
|
||||||
|
VL_RESTORER_CLEAR(m_modExpr2Sen2DelayedAlwaysp);
|
||||||
m_modp = nodep;
|
m_modp = nodep;
|
||||||
m_modPastNum = 0;
|
m_modPastNum = 0;
|
||||||
m_modStrobeNum = 0;
|
m_modStrobeNum = 0;
|
||||||
m_modExpr2Sen2DelayedAlwaysp.clear();
|
m_finalp = nullptr;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
void visit(AstNodeProcedure* nodep) override {
|
void visit(AstNodeProcedure* nodep) override {
|
||||||
|
|
@ -1057,6 +1205,9 @@ public:
|
||||||
V3Stats::addStat("Assertions, $past variables", m_statPastVars);
|
V3Stats::addStat("Assertions, $past variables", m_statPastVars);
|
||||||
V3Stats::addStat("Assertions, assertOn checks combined", m_statAssertOnCombined);
|
V3Stats::addStat("Assertions, assertOn checks combined", m_statAssertOnCombined);
|
||||||
V3Stats::addStat("Assertions, assertOn checks hoisted", m_statAssertOnHoisted);
|
V3Stats::addStat("Assertions, assertOn checks hoisted", m_statAssertOnHoisted);
|
||||||
|
V3Stats::addStat("Assertions, lifted impure case expressions", m_statLiftedCaseExprs);
|
||||||
|
// Rewrites can change purity, e.g. by compiling out assertion statements with --no-assert
|
||||||
|
VIsCached::clearCacheTree();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,11 @@
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
class V3AssertCommon final {
|
||||||
|
public:
|
||||||
|
static void collectDefaultDisable(AstNetlist* nodep) VL_MT_DISABLED;
|
||||||
|
};
|
||||||
|
|
||||||
class V3Assert final {
|
class V3Assert final {
|
||||||
public:
|
public:
|
||||||
static void assertAll(AstNetlist* nodep) VL_MT_DISABLED;
|
static void assertAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "V3AssertPre.h"
|
#include "V3AssertPre.h"
|
||||||
|
|
||||||
|
#include "V3Assert.h"
|
||||||
#include "V3Const.h"
|
#include "V3Const.h"
|
||||||
#include "V3Task.h"
|
#include "V3Task.h"
|
||||||
#include "V3UniqueNames.h"
|
#include "V3UniqueNames.h"
|
||||||
|
|
@ -60,6 +61,7 @@ private:
|
||||||
AstNodeExpr* m_disablep = nullptr; // Last disable
|
AstNodeExpr* m_disablep = nullptr; // Last disable
|
||||||
AstIf* m_disableSeqIfp = nullptr; // Used for handling disable iff in sequences
|
AstIf* m_disableSeqIfp = nullptr; // Used for handling disable iff in sequences
|
||||||
AstPExpr* m_pexprp = nullptr; // Last AstPExpr
|
AstPExpr* m_pexprp = nullptr; // Last AstPExpr
|
||||||
|
bool m_underCover = false; // True if the enclosing assertion is a cover
|
||||||
// Other:
|
// Other:
|
||||||
V3UniqueNames m_cycleDlyNames{"__VcycleDly"}; // Cycle delay counter name generator
|
V3UniqueNames m_cycleDlyNames{"__VcycleDly"}; // Cycle delay counter name generator
|
||||||
V3UniqueNames m_consRepNames{"__VconsRep"}; // Consecutive repetition counter name generator
|
V3UniqueNames m_consRepNames{"__VconsRep"}; // Consecutive repetition counter name generator
|
||||||
|
|
@ -91,7 +93,10 @@ private:
|
||||||
fromAlways = true;
|
fromAlways = true;
|
||||||
}
|
}
|
||||||
if (!senip) {
|
if (!senip) {
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Unclocked assertion");
|
nodep->v3error("Concurrent assertion has no clock (IEEE 1800-2023 16.16)\n"
|
||||||
|
<< nodep->warnMore()
|
||||||
|
<< "... Suggest provide a clocking event, a default"
|
||||||
|
" clocking, or a clocked procedural context");
|
||||||
newp = new AstSenTree{nodep->fileline(), nullptr};
|
newp = new AstSenTree{nodep->fileline(), nullptr};
|
||||||
} else {
|
} else {
|
||||||
if (cassertp && fromAlways) cassertp->senFromAlways(true);
|
if (cassertp && fromAlways) cassertp->senFromAlways(true);
|
||||||
|
|
@ -1281,7 +1286,10 @@ private:
|
||||||
// Don't iterate pexprp here -- it was already iterated when created
|
// Don't iterate pexprp here -- it was already iterated when created
|
||||||
// (in visit(AstSExpr*)), so delays and disable iff are already processed.
|
// (in visit(AstSExpr*)), so delays and disable iff are already processed.
|
||||||
} else if (nodep->isOverlapped()) {
|
} else if (nodep->isOverlapped()) {
|
||||||
nodep->replaceWith(new AstLogOr{flp, new AstLogNot{flp, lhsp}, rhsp});
|
AstNodeExpr* const exprp
|
||||||
|
= m_underCover ? static_cast<AstNodeExpr*>(new AstLogAnd{flp, lhsp, rhsp})
|
||||||
|
: new AstLogOr{flp, new AstLogNot{flp, lhsp}, rhsp};
|
||||||
|
nodep->replaceWith(exprp);
|
||||||
} else {
|
} else {
|
||||||
if (m_disablep) {
|
if (m_disablep) {
|
||||||
lhsp = new AstAnd{flp, new AstNot{flp, m_disablep->cloneTreePure(false)}, lhsp};
|
lhsp = new AstAnd{flp, new AstNot{flp, m_disablep->cloneTreePure(false)}, lhsp};
|
||||||
|
|
@ -1290,7 +1298,9 @@ private:
|
||||||
AstPast* const pastp = new AstPast{flp, lhsp};
|
AstPast* const pastp = new AstPast{flp, lhsp};
|
||||||
pastp->dtypeFrom(lhsp);
|
pastp->dtypeFrom(lhsp);
|
||||||
pastp->sentreep(newSenTree(nodep));
|
pastp->sentreep(newSenTree(nodep));
|
||||||
AstNodeExpr* const exprp = new AstOr{flp, new AstNot{flp, pastp}, rhsp};
|
AstNodeExpr* const exprp
|
||||||
|
= m_underCover ? static_cast<AstNodeExpr*>(new AstAnd{flp, pastp, rhsp})
|
||||||
|
: new AstOr{flp, new AstNot{flp, pastp}, rhsp};
|
||||||
exprp->dtypeSetBit();
|
exprp->dtypeSetBit();
|
||||||
nodep->replaceWith(exprp);
|
nodep->replaceWith(exprp);
|
||||||
}
|
}
|
||||||
|
|
@ -1438,12 +1448,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(AstDefaultDisable* nodep) override {
|
void visit(AstDefaultDisable* nodep) override {
|
||||||
if (m_defaultDisablep) {
|
|
||||||
nodep->v3error("Only one 'default disable iff' allowed per module"
|
|
||||||
" (IEEE 1800-2023 16.15)");
|
|
||||||
} else {
|
|
||||||
m_defaultDisablep = nodep;
|
|
||||||
}
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
}
|
}
|
||||||
void visit(AstInferredDisable* nodep) override {
|
void visit(AstInferredDisable* nodep) override {
|
||||||
|
|
@ -1474,6 +1478,10 @@ private:
|
||||||
nodep->propp(new AstSampled{nodep->fileline(), nodep->propp()->unlinkFrBack(),
|
nodep->propp(new AstSampled{nodep->fileline(), nodep->propp()->unlinkFrBack(),
|
||||||
propDtp->dtypep()});
|
propDtp->dtypep()});
|
||||||
}
|
}
|
||||||
|
// cover counts non-vacuous matches only (IEEE 1800-2023 16.15.2), so an
|
||||||
|
// implication antecedent must hold; assert passes vacuously instead.
|
||||||
|
VL_RESTORER(m_underCover);
|
||||||
|
m_underCover = VN_IS(nodep->backp(), Cover);
|
||||||
iterate(nodep->propp());
|
iterate(nodep->propp());
|
||||||
}
|
}
|
||||||
void visit(AstPExpr* nodep) override {
|
void visit(AstPExpr* nodep) override {
|
||||||
|
|
@ -1565,10 +1573,15 @@ private:
|
||||||
VL_RESTORER(m_modp);
|
VL_RESTORER(m_modp);
|
||||||
m_defaultClockingp = nullptr;
|
m_defaultClockingp = nullptr;
|
||||||
m_defaultClkEvtVarp = nullptr;
|
m_defaultClkEvtVarp = nullptr;
|
||||||
m_defaultDisablep = nullptr;
|
m_defaultDisablep = nodep->defaultDisablep();
|
||||||
m_modp = nodep;
|
m_modp = nodep;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
|
void visit(AstGenBlock* nodep) override {
|
||||||
|
VL_RESTORER(m_defaultDisablep);
|
||||||
|
m_defaultDisablep = nodep->defaultDisablep();
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
void visit(AstProperty* nodep) override {
|
void visit(AstProperty* nodep) override {
|
||||||
// The body will be visited when will be substituted in place of property reference
|
// The body will be visited when will be substituted in place of property reference
|
||||||
// (AstFuncRef)
|
// (AstFuncRef)
|
||||||
|
|
|
||||||
150
src/V3Ast.cpp
150
src/V3Ast.cpp
|
|
@ -1745,6 +1745,156 @@ AstNodeDType* AstNode::getCommonClassTypep(AstNode* node1p, AstNode* node2p) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
// Renders the canonical pattern S-expression for a single AstNode
|
||||||
|
|
||||||
|
class VNPatternString final {
|
||||||
|
std::ostream& m_os;
|
||||||
|
|
||||||
|
std::map<std::string, std::string> m_internedConsts; // Interned constants
|
||||||
|
std::map<int, std::string> m_internedWordWidths; // Interned widths
|
||||||
|
std::map<int, std::string> m_internedWideWidths; // Interned widths
|
||||||
|
|
||||||
|
// Whether to dump the widhtMin as well
|
||||||
|
const bool m_dumpWidthMin = v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH;
|
||||||
|
|
||||||
|
static std::string toLetters(size_t value, bool lowerCase = false) {
|
||||||
|
const char base = lowerCase ? 'a' : 'A';
|
||||||
|
std::string s;
|
||||||
|
do { s += static_cast<char>(base + value % 26); } while (value /= 26);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& internConst(const AstConst& nodep) {
|
||||||
|
const auto pair = m_internedConsts.emplace(nodep.num().ascii(false), "");
|
||||||
|
if (pair.second) pair.first->second += toLetters(m_internedConsts.size() - 1);
|
||||||
|
return pair.first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& internWordWidth(int value) {
|
||||||
|
const auto pair = m_internedWordWidths.emplace(value, "");
|
||||||
|
if (pair.second) pair.first->second += toLetters(m_internedWordWidths.size() - 1, true);
|
||||||
|
return pair.first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& internWideWidth(int value) {
|
||||||
|
const auto pair = m_internedWideWidths.emplace(value, "");
|
||||||
|
if (pair.second) pair.first->second += toLetters(m_internedWideWidths.size() - 1);
|
||||||
|
return pair.first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// True if the node has no operands (e.g. a VarRef or Const)
|
||||||
|
static bool isLeaf(const AstNode* nodep) {
|
||||||
|
const VNTypeInfo& typeInfo = VNType::typeInfo(nodep->type());
|
||||||
|
for (const VNTypeInfo::OpEn& opType : typeInfo.m_opType) {
|
||||||
|
if (opType != VNTypeInfo::OP_UNUSED) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render operand, return true if not unused
|
||||||
|
void renderOperand(VNTypeInfo::OpEn opType, const AstNode* const opp, uint32_t depth) {
|
||||||
|
switch (opType) {
|
||||||
|
case VNTypeInfo::OP_UNUSED: //
|
||||||
|
break;
|
||||||
|
case VNTypeInfo::OP_USED: //
|
||||||
|
m_os << ' ';
|
||||||
|
render(opp, depth);
|
||||||
|
break;
|
||||||
|
case VNTypeInfo::OP_LIST:
|
||||||
|
m_os << " [";
|
||||||
|
for (const AstNode* nodep = opp; nodep; nodep = nodep->nextp()) {
|
||||||
|
if (nodep != opp) m_os << ", ";
|
||||||
|
render(opp, depth);
|
||||||
|
}
|
||||||
|
m_os << ']';
|
||||||
|
break;
|
||||||
|
case VNTypeInfo::OP_OPTIONAL:
|
||||||
|
if (opp) {
|
||||||
|
m_os << " ";
|
||||||
|
render(opp, depth);
|
||||||
|
} else {
|
||||||
|
m_os << " nil";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the node into the stream.
|
||||||
|
void render(const AstNode* nodep, uint32_t depth) {
|
||||||
|
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
|
||||||
|
// Base case 1: constant
|
||||||
|
if (constp->isZero()) {
|
||||||
|
m_os << "(CONST ZERO)";
|
||||||
|
} else if (constp->isEqAllOnes()) {
|
||||||
|
m_os << "(CONST ONES)";
|
||||||
|
} else {
|
||||||
|
m_os << "(CONST #" << internConst(*constp) << ')';
|
||||||
|
}
|
||||||
|
} else if (isLeaf(nodep)) {
|
||||||
|
// Base case 2: expression with no operands (e.g. a variable reference)
|
||||||
|
m_os << '(' << nodep->typeName() << ')';
|
||||||
|
} else if (depth == 0) {
|
||||||
|
// Base case 3: deep expression
|
||||||
|
m_os << '_';
|
||||||
|
} else {
|
||||||
|
// Recursively print an S-expression for the expression
|
||||||
|
m_os << '(';
|
||||||
|
// Name
|
||||||
|
m_os << nodep->typeName();
|
||||||
|
// Operands
|
||||||
|
const VNTypeInfo& typeInfo = VNType::typeInfo(nodep->type());
|
||||||
|
renderOperand(typeInfo.m_opType[0], nodep->op1p(), depth - 1);
|
||||||
|
renderOperand(typeInfo.m_opType[1], nodep->op2p(), depth - 1);
|
||||||
|
renderOperand(typeInfo.m_opType[2], nodep->op3p(), depth - 1);
|
||||||
|
renderOperand(typeInfo.m_opType[3], nodep->op4p(), depth - 1);
|
||||||
|
// S-expression end
|
||||||
|
m_os << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annotate type
|
||||||
|
m_os << ':';
|
||||||
|
const AstNodeDType* const dtypep = nodep->dtypep() ? nodep->dtypep()->skipRefp() : nullptr;
|
||||||
|
if (!dtypep) {
|
||||||
|
m_os << '?';
|
||||||
|
} else if (dtypep->isCompound() || VN_IS(dtypep, UnpackArrayDType)) {
|
||||||
|
dtypep->dumpSmall(m_os);
|
||||||
|
} else {
|
||||||
|
const int width = nodep->width();
|
||||||
|
if (width == 1) {
|
||||||
|
m_os << '1';
|
||||||
|
} else if (width <= VL_QUADSIZE) {
|
||||||
|
m_os << internWordWidth(width);
|
||||||
|
} else {
|
||||||
|
m_os << internWideWidth(width);
|
||||||
|
}
|
||||||
|
if (m_dumpWidthMin) {
|
||||||
|
m_os << '/';
|
||||||
|
const int widthMin = nodep->widthMin();
|
||||||
|
if (widthMin == 1) {
|
||||||
|
m_os << '1';
|
||||||
|
} else if (widthMin <= VL_QUADSIZE) {
|
||||||
|
m_os << internWordWidth(widthMin);
|
||||||
|
} else {
|
||||||
|
m_os << internWideWidth(widthMin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
VNPatternString(std::ostream& os, const AstNode* nodep, uint32_t depth)
|
||||||
|
: m_os{os} {
|
||||||
|
render(nodep, depth);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string AstNodeExpr::patternString(uint32_t depth) const {
|
||||||
|
std::ostringstream oss;
|
||||||
|
VNPatternString{oss, this, depth};
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// VNDeleter
|
// VNDeleter
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -342,7 +342,6 @@ public:
|
||||||
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
|
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
|
||||||
VAR_PUBLIC_FLAT_RD, // V3LinkParse moves to AstVar::sigPublic
|
VAR_PUBLIC_FLAT_RD, // V3LinkParse moves to AstVar::sigPublic
|
||||||
VAR_PUBLIC_FLAT_RW, // V3LinkParse moves to AstVar::sigPublic
|
VAR_PUBLIC_FLAT_RW, // V3LinkParse moves to AstVar::sigPublic
|
||||||
VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign
|
|
||||||
VAR_SC_BIGUINT, // V3LinkParse moves to AstVar::attrScBigUint
|
VAR_SC_BIGUINT, // V3LinkParse moves to AstVar::attrScBigUint
|
||||||
VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv
|
VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv
|
||||||
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
|
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
|
||||||
|
|
@ -364,7 +363,7 @@ public:
|
||||||
"TYPEID", "TYPENAME",
|
"TYPEID", "TYPENAME",
|
||||||
"VAR_BASE", "VAR_FORCEABLE", "VAR_FSM_ARC_INCLUDE_COND", "VAR_FSM_RESET_ARC",
|
"VAR_BASE", "VAR_FORCEABLE", "VAR_FSM_ARC_INCLUDE_COND", "VAR_FSM_RESET_ARC",
|
||||||
"VAR_FSM_STATE", "VAR_PORT_DTYPE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
|
"VAR_FSM_STATE", "VAR_PORT_DTYPE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
|
||||||
"VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW", "VAR_ISOLATE_ASSIGNMENTS",
|
"VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
|
||||||
"VAR_SC_BIGUINT", "VAR_SC_BV", "VAR_SFORMAT", "VAR_SPLIT_VAR"
|
"VAR_SC_BIGUINT", "VAR_SC_BV", "VAR_SFORMAT", "VAR_SPLIT_VAR"
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
@ -1191,6 +1190,19 @@ public:
|
||||||
= {"user", "array", "auto", "ignore", "illegal", "default", "wildcard", "transition"};
|
= {"user", "array", "auto", "ignore", "illegal", "default", "wildcard", "transition"};
|
||||||
return names[m_e];
|
return names[m_e];
|
||||||
}
|
}
|
||||||
|
// VlCovBinKind enumerator naming the bin's set
|
||||||
|
const char* binSetEnum() const {
|
||||||
|
switch (m_e) {
|
||||||
|
case BINS_IGNORE: return "VlCovBinKind::KIND_IGNORE";
|
||||||
|
case BINS_ILLEGAL: return "VlCovBinKind::KIND_ILLEGAL";
|
||||||
|
case BINS_DEFAULT: return "VlCovBinKind::KIND_DEFAULT";
|
||||||
|
default: return "VlCovBinKind::KIND_NORMAL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Normal bins (feed coverage) are anything but ignore/illegal/default
|
||||||
|
bool binIsNormal() const {
|
||||||
|
return m_e != BINS_IGNORE && m_e != BINS_ILLEGAL && m_e != BINS_DEFAULT;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
constexpr bool operator==(const VCoverBinsType& lhs, VCoverBinsType::en rhs) {
|
constexpr bool operator==(const VCoverBinsType& lhs, VCoverBinsType::en rhs) {
|
||||||
return lhs.m_e == rhs;
|
return lhs.m_e == rhs;
|
||||||
|
|
@ -1416,6 +1428,7 @@ public:
|
||||||
ET_EVENT, // VlEventBase::isFired
|
ET_EVENT, // VlEventBase::isFired
|
||||||
// Involving an expression
|
// Involving an expression
|
||||||
ET_TRUE,
|
ET_TRUE,
|
||||||
|
ET_INITIAL_NBA, // Event that is fired initially and never again
|
||||||
//
|
//
|
||||||
ET_COMBO, // Sensitive to all combo inputs to this block
|
ET_COMBO, // Sensitive to all combo inputs to this block
|
||||||
ET_COMBO_STAR, // Sensitive to all combo inputs to this block (from .*)
|
ET_COMBO_STAR, // Sensitive to all combo inputs to this block (from .*)
|
||||||
|
|
@ -1434,6 +1447,7 @@ public:
|
||||||
true, // ET_NEGEDGE
|
true, // ET_NEGEDGE
|
||||||
true, // ET_EVENT
|
true, // ET_EVENT
|
||||||
true, // ET_TRUE
|
true, // ET_TRUE
|
||||||
|
true, // ET_INITIAL_NBA
|
||||||
|
|
||||||
false, // ET_COMBO
|
false, // ET_COMBO
|
||||||
false, // ET_COMBO_STAR
|
false, // ET_COMBO_STAR
|
||||||
|
|
@ -1457,14 +1471,14 @@ public:
|
||||||
}
|
}
|
||||||
const char* ascii() const {
|
const char* ascii() const {
|
||||||
static const char* const names[]
|
static const char* const names[]
|
||||||
= {"CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE", "COMBO",
|
= {"CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE", "ET_INITIAL_NBA",
|
||||||
"COMBO_STAR", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"};
|
"COMBO", "COMBO_STAR", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"};
|
||||||
return names[m_e];
|
return names[m_e];
|
||||||
}
|
}
|
||||||
const char* verilogKwd() const {
|
const char* verilogKwd() const {
|
||||||
static const char* const names[]
|
static const char* const names[] = {
|
||||||
= {"[changed]", "edge", "posedge", "negedge", "[event]", "[true]", "*",
|
"[changed]", "edge", "posedge", "negedge", "[event]", "[true]", "[initial_nba]",
|
||||||
"*", "[hybrid]", "[static]", "[initial]", "[final]", "[never]"};
|
"*", "*", "[hybrid]", "[static]", "[initial]", "[final]", "[never]"};
|
||||||
return names[m_e];
|
return names[m_e];
|
||||||
}
|
}
|
||||||
// Return true iff this and the other have mutually exclusive transitions
|
// Return true iff this and the other have mutually exclusive transitions
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,13 @@ bool AstVar::sameNode(const AstNode* samep) const {
|
||||||
return m_name == asamep->m_name && varType() == asamep->varType();
|
return m_name == asamep->m_name && varType() == asamep->varType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstMatchMasked::AstMatchMasked(FileLine* fl, AstNodeExpr* lhsp, AstVarScope* matchp)
|
||||||
|
: ASTGEN_SUPER_MatchMasked(fl) {
|
||||||
|
this->lhsp(lhsp);
|
||||||
|
this->matchp(new AstVarRef{fl, matchp, VAccess::READ});
|
||||||
|
dtypeSetUInt32();
|
||||||
|
}
|
||||||
|
|
||||||
AstVarRef::AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access)
|
AstVarRef::AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access)
|
||||||
: ASTGEN_SUPER_VarRef(fl, varp, access) {
|
: ASTGEN_SUPER_VarRef(fl, varp, access) {
|
||||||
if (v3Global.assertDTypesResolved()) {
|
if (v3Global.assertDTypesResolved()) {
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,11 @@ public:
|
||||||
void generic(bool flag) { m_generic = flag; }
|
void generic(bool flag) { m_generic = flag; }
|
||||||
std::pair<uint32_t, uint32_t> dimensions(bool includeBasic) const;
|
std::pair<uint32_t, uint32_t> dimensions(bool includeBasic) const;
|
||||||
uint32_t arrayUnpackedElements() const; // 1, or total multiplication of all dimensions
|
uint32_t arrayUnpackedElements() const; // 1, or total multiplication of all dimensions
|
||||||
|
// Fixed aggregate streaming properties
|
||||||
|
bool isStreamableFixedAggregate() const;
|
||||||
|
bool containsUnpackedStruct() const;
|
||||||
|
int widthStream() const;
|
||||||
|
string vlEnumType() const; // Return VerilatedVarType: VLVT_UINT32, etc
|
||||||
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" : isDouble() ? "D" : isQuad() ? "Q" : "I");
|
return (isString() ? "N" : isWide() ? "W" : isDouble() ? "D" : isQuad() ? "Q" : "I");
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,9 @@ public:
|
||||||
// Returns an error message if widthMin() is not correct otherwise returns nullptr like
|
// Returns an error message if widthMin() is not correct otherwise returns nullptr like
|
||||||
// broken()
|
// broken()
|
||||||
virtual const char* widthMismatch() const VL_MT_STABLE { return nullptr; }
|
virtual const char* widthMismatch() const VL_MT_STABLE { return nullptr; }
|
||||||
|
|
||||||
|
// S-expression inspired dump of node and operands for debugging
|
||||||
|
std::string patternString(uint32_t depth = 0) const;
|
||||||
};
|
};
|
||||||
class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr {
|
class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr {
|
||||||
// Binary expression
|
// Binary expression
|
||||||
|
|
@ -1855,6 +1858,22 @@ public:
|
||||||
bool index() const { return m_index; }
|
bool index() const { return m_index; }
|
||||||
bool isExprCoverageEligible() const override { return false; }
|
bool isExprCoverageEligible() const override { return false; }
|
||||||
};
|
};
|
||||||
|
class AstMatchMasked final : public AstNodeExpr {
|
||||||
|
// This is a non-source construct, created internally to represent
|
||||||
|
// some case statements. It is a '(mask & _) == bits' matching loop
|
||||||
|
// where {mask, bits} pairs are packed into a single wide 'matchp',
|
||||||
|
// and the result is the index of the first matching entry.
|
||||||
|
// See VL_DECODER_* runtime functions.
|
||||||
|
// @astgen op1 := lhsp : AstNodeExpr
|
||||||
|
// @astgen op2 := matchp : AstVarRef
|
||||||
|
public:
|
||||||
|
inline AstMatchMasked(FileLine* fl, AstNodeExpr* lhsp, AstVarScope* matchp);
|
||||||
|
ASTGEN_MEMBERS_AstMatchMasked;
|
||||||
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||||
|
string emitC() override { return "VL_MATCHMASKED_%lq(%lw, %li, %ri)"; }
|
||||||
|
bool cleanOut() const override { return true; }
|
||||||
|
static uint32_t fold(const V3Number& lhs, AstVar* matchVarp);
|
||||||
|
};
|
||||||
class AstMatches final : public AstNodeExpr {
|
class AstMatches final : public AstNodeExpr {
|
||||||
// "matches" operator: "expr matches pattern"
|
// "matches" operator: "expr matches pattern"
|
||||||
// @astgen op1 := lhsp : AstNodeExpr // Expression to match
|
// @astgen op1 := lhsp : AstNodeExpr // Expression to match
|
||||||
|
|
@ -2225,6 +2244,23 @@ public:
|
||||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||||
bool isSystemFunc() const override { return true; }
|
bool isSystemFunc() const override { return true; }
|
||||||
};
|
};
|
||||||
|
class AstSClocked final : public AstNodeExpr {
|
||||||
|
// Sequence expression with an explicit leading clocking event
|
||||||
|
// IEEE 1800-2023 16.7: sequence_expr ::= clocking_event sequence_expr
|
||||||
|
// The clocking event is hoisted to the enclosing assertion clock by V3AssertNfa.
|
||||||
|
// @astgen op1 := sensesp : AstSenItem
|
||||||
|
// @astgen op2 := exprp : AstNodeExpr
|
||||||
|
public:
|
||||||
|
AstSClocked(FileLine* fl, AstSenItem* sensesp, AstNodeExpr* exprp)
|
||||||
|
: ASTGEN_SUPER_SClocked(fl) {
|
||||||
|
this->sensesp(sensesp);
|
||||||
|
this->exprp(exprp);
|
||||||
|
}
|
||||||
|
ASTGEN_MEMBERS_AstSClocked;
|
||||||
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||||
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||||
|
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
|
||||||
|
};
|
||||||
class AstSConsRep final : public AstNodeExpr {
|
class AstSConsRep final : public AstNodeExpr {
|
||||||
// Consecutive repetition [*N], [*N:M], [+], [*] (IEEE 1800-2023 16.9.2)
|
// Consecutive repetition [*N], [*N:M], [+], [*] (IEEE 1800-2023 16.9.2)
|
||||||
// op1 := exprp -- the repeated expression
|
// op1 := exprp -- the repeated expression
|
||||||
|
|
@ -5701,6 +5737,22 @@ public:
|
||||||
void dump(std::ostream& str) const override;
|
void dump(std::ostream& str) const override;
|
||||||
void dumpJson(std::ostream& str) const override;
|
void dumpJson(std::ostream& str) const override;
|
||||||
};
|
};
|
||||||
|
class AstMostSetBitP1 final : public AstNodeUniop {
|
||||||
|
// Most-significant set bit plus one (bit-width); 0 if value is zero
|
||||||
|
public:
|
||||||
|
AstMostSetBitP1(FileLine* fl, AstNodeExpr* lhsp)
|
||||||
|
: ASTGEN_SUPER_MostSetBitP1(fl, lhsp) {
|
||||||
|
dtypeSetInteger2State();
|
||||||
|
}
|
||||||
|
ASTGEN_MEMBERS_AstMostSetBitP1;
|
||||||
|
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opMostSetBitP1(lhs); }
|
||||||
|
string emitVerilog() override { return "%f$mostsetbitp1(%l)"; }
|
||||||
|
string emitC() override { return "VL_MOSTSETBITP1_%lq(%lW, %P, %li)"; }
|
||||||
|
bool cleanOut() const override { return true; }
|
||||||
|
bool cleanLhs() const override { return true; }
|
||||||
|
bool sizeMattersLhs() const override { return false; }
|
||||||
|
int instrCount() const override { return widthInstrs() * 16; }
|
||||||
|
};
|
||||||
class AstNToI final : public AstNodeUniop {
|
class AstNToI final : public AstNodeUniop {
|
||||||
// String to any-size integral
|
// String to any-size integral
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,6 @@ class AstNodeFTask VL_NOT_FINAL : public AstNode {
|
||||||
string m_ifacePortName; // Interface port name for out-of-block definition (IEEE 25.8)
|
string m_ifacePortName; // Interface port name for out-of-block definition (IEEE 25.8)
|
||||||
uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees
|
uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees
|
||||||
bool m_taskPublic : 1; // Public task
|
bool m_taskPublic : 1; // Public task
|
||||||
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
|
|
||||||
bool m_classMethod : 1; // Class method
|
bool m_classMethod : 1; // Class method
|
||||||
bool m_didProto : 1; // Did prototype processing
|
bool m_didProto : 1; // Did prototype processing
|
||||||
bool m_prototype : 1; // Just a prototype
|
bool m_prototype : 1; // Just a prototype
|
||||||
|
|
@ -130,7 +129,6 @@ protected:
|
||||||
: AstNode{t, fl}
|
: AstNode{t, fl}
|
||||||
, m_name{name}
|
, m_name{name}
|
||||||
, m_taskPublic{false}
|
, m_taskPublic{false}
|
||||||
, m_attrIsolateAssign{false}
|
|
||||||
, m_classMethod{false}
|
, m_classMethod{false}
|
||||||
, m_didProto{false}
|
, m_didProto{false}
|
||||||
, m_prototype{false}
|
, m_prototype{false}
|
||||||
|
|
@ -179,8 +177,6 @@ public:
|
||||||
uint64_t dpiOpenParent() const { return m_dpiOpenParent; }
|
uint64_t dpiOpenParent() const { return m_dpiOpenParent; }
|
||||||
bool taskPublic() const { return m_taskPublic; }
|
bool taskPublic() const { return m_taskPublic; }
|
||||||
void taskPublic(bool flag) { m_taskPublic = flag; }
|
void taskPublic(bool flag) { m_taskPublic = flag; }
|
||||||
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
|
||||||
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
|
||||||
bool classMethod() const { return m_classMethod; }
|
bool classMethod() const { return m_classMethod; }
|
||||||
void classMethod(bool flag) { m_classMethod = flag; }
|
void classMethod(bool flag) { m_classMethod = flag; }
|
||||||
bool didProto() const { return m_didProto; }
|
bool didProto() const { return m_didProto; }
|
||||||
|
|
@ -301,6 +297,7 @@ class AstNodeModule VL_NOT_FINAL : public AstNode {
|
||||||
VLifetime m_lifetime; // Lifetime
|
VLifetime m_lifetime; // Lifetime
|
||||||
VTimescale m_timeunit; // Global time unit
|
VTimescale m_timeunit; // Global time unit
|
||||||
VOptionBool m_unconnectedDrive; // State of `unconnected_drive
|
VOptionBool m_unconnectedDrive; // State of `unconnected_drive
|
||||||
|
AstDefaultDisable* m_defaultDisablep = nullptr; // Default disable iff in this scope
|
||||||
|
|
||||||
bool m_modPublic : 1; // Module has public references
|
bool m_modPublic : 1; // Module has public references
|
||||||
bool m_modTrace : 1; // Tracing this module
|
bool m_modTrace : 1; // Tracing this module
|
||||||
|
|
@ -351,6 +348,8 @@ public:
|
||||||
string origName() const override { return m_origName; }
|
string origName() const override { return m_origName; }
|
||||||
string someInstanceName() const VL_MT_SAFE { return m_someInstanceName; }
|
string someInstanceName() const VL_MT_SAFE { return m_someInstanceName; }
|
||||||
void someInstanceName(const string& name) { m_someInstanceName = name; }
|
void someInstanceName(const string& name) { m_someInstanceName = name; }
|
||||||
|
AstDefaultDisable* defaultDisablep() const { return m_defaultDisablep; }
|
||||||
|
void defaultDisablep(AstDefaultDisable* nodep) { m_defaultDisablep = nodep; }
|
||||||
bool inLibrary() const { return m_inLibrary; }
|
bool inLibrary() const { return m_inLibrary; }
|
||||||
void inLibrary(bool flag) { m_inLibrary = flag; }
|
void inLibrary(bool flag) { m_inLibrary = flag; }
|
||||||
void depth(int value) { m_depth = value; }
|
void depth(int value) { m_depth = value; }
|
||||||
|
|
@ -1001,6 +1000,8 @@ public:
|
||||||
// this matters, the caller must handle the dtype difference as appropriate. If 'mergeDType' is
|
// this matters, the caller must handle the dtype difference as appropriate. If 'mergeDType' is
|
||||||
// false, the returned VarScope will have _->dtypep()->sameTree(initp->dtypep()) return true.
|
// false, the returned VarScope will have _->dtypep()->sameTree(initp->dtypep()) return true.
|
||||||
AstVarScope* findConst(AstConst* initp, bool mergeDType);
|
AstVarScope* findConst(AstConst* initp, bool mergeDType);
|
||||||
|
// Rebuild hashes and missing variable scopes after potential removals
|
||||||
|
void rebuildVarScopesAndCache();
|
||||||
};
|
};
|
||||||
class AstConstraint final : public AstNode {
|
class AstConstraint final : public AstNode {
|
||||||
// Constraint
|
// Constraint
|
||||||
|
|
@ -1184,12 +1185,21 @@ public:
|
||||||
};
|
};
|
||||||
class AstCoverpointRef final : public AstNode {
|
class AstCoverpointRef final : public AstNode {
|
||||||
// Reference to a coverpoint used in a cross
|
// Reference to a coverpoint used in a cross
|
||||||
const string m_name; // coverpoint name
|
// @astgen op1 := exprp : Optional[AstNodeExpr] // Non-standard: hierarchical/dotted
|
||||||
|
// // reference (implicit coverpoint), e.g.
|
||||||
|
// // 'cross a.b'; nullptr for a plain coverpoint
|
||||||
|
// // name. An AstDot at parse time, resolved
|
||||||
|
// // by the time V3Covergroup runs.
|
||||||
|
const string m_name; // coverpoint name; empty when exprp() carries a hierarchical reference
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstCoverpointRef(FileLine* fl, const string& name)
|
AstCoverpointRef(FileLine* fl, const string& name)
|
||||||
: ASTGEN_SUPER_CoverpointRef(fl)
|
: ASTGEN_SUPER_CoverpointRef(fl)
|
||||||
, m_name{name} {}
|
, m_name{name} {}
|
||||||
|
AstCoverpointRef(FileLine* fl, AstNodeExpr* exprp)
|
||||||
|
: ASTGEN_SUPER_CoverpointRef(fl) {
|
||||||
|
this->exprp(exprp);
|
||||||
|
}
|
||||||
ASTGEN_MEMBERS_AstCoverpointRef;
|
ASTGEN_MEMBERS_AstCoverpointRef;
|
||||||
void dump(std::ostream& str) const override;
|
void dump(std::ostream& str) const override;
|
||||||
void dumpJson(std::ostream& str) const override;
|
void dumpJson(std::ostream& str) const override;
|
||||||
|
|
@ -1752,6 +1762,7 @@ public:
|
||||||
class Combo {}; // for constructor type-overload selection
|
class Combo {}; // for constructor type-overload selection
|
||||||
class Static {}; // for constructor type-overload selection
|
class Static {}; // for constructor type-overload selection
|
||||||
class Initial {}; // for constructor type-overload selection
|
class Initial {}; // for constructor type-overload selection
|
||||||
|
class InitialNBA {}; // for constructor type-overload selection
|
||||||
class Final {}; // for constructor type-overload selection
|
class Final {}; // for constructor type-overload selection
|
||||||
class Never {}; // for constructor type-overload selection
|
class Never {}; // for constructor type-overload selection
|
||||||
AstSenItem(FileLine* fl, VEdgeType edgeType, AstNodeExpr* senp, AstNodeExpr* condp = nullptr)
|
AstSenItem(FileLine* fl, VEdgeType edgeType, AstNodeExpr* senp, AstNodeExpr* condp = nullptr)
|
||||||
|
|
@ -1769,6 +1780,9 @@ public:
|
||||||
AstSenItem(FileLine* fl, Initial)
|
AstSenItem(FileLine* fl, Initial)
|
||||||
: ASTGEN_SUPER_SenItem(fl)
|
: ASTGEN_SUPER_SenItem(fl)
|
||||||
, m_edgeType{VEdgeType::ET_INITIAL} {}
|
, m_edgeType{VEdgeType::ET_INITIAL} {}
|
||||||
|
AstSenItem(FileLine* fl, InitialNBA)
|
||||||
|
: ASTGEN_SUPER_SenItem(fl)
|
||||||
|
, m_edgeType{VEdgeType::ET_INITIAL_NBA} {}
|
||||||
AstSenItem(FileLine* fl, Final)
|
AstSenItem(FileLine* fl, Final)
|
||||||
: ASTGEN_SUPER_SenItem(fl)
|
: ASTGEN_SUPER_SenItem(fl)
|
||||||
, m_edgeType{VEdgeType::ET_FINAL} {}
|
, m_edgeType{VEdgeType::ET_FINAL} {}
|
||||||
|
|
@ -2131,15 +2145,16 @@ class AstVar final : public AstNode {
|
||||||
bool m_funcReturn : 1; // Return variable for a function
|
bool m_funcReturn : 1; // Return variable for a function
|
||||||
bool m_attrScBv : 1; // User force bit vector attribute
|
bool m_attrScBv : 1; // User force bit vector attribute
|
||||||
bool m_attrScBigUint : 1; // User force sc_biguint attribute
|
bool m_attrScBigUint : 1; // User force sc_biguint attribute
|
||||||
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
|
|
||||||
bool m_attrSFormat : 1; // User sformat attribute
|
bool m_attrSFormat : 1; // User sformat attribute
|
||||||
bool m_attrSplitVar : 1; // declared with split_var metacomment
|
bool m_attrSplitVar : 1; // declared with split_var metacomment
|
||||||
bool m_attrFsmState : 1; // declared with fsm_state metacomment
|
bool m_attrFsmState : 1; // declared with fsm_state metacomment
|
||||||
bool m_attrFsmRegisterWrapper : 1; // connected to an fsm_register_wrapper instance
|
bool m_attrFsmRegisterWrapper : 1; // connected to an fsm_register_wrapper instance
|
||||||
bool m_attrFsmResetArc : 1; // declared with fsm_reset_arc metacomment
|
bool m_attrFsmResetArc : 1; // declared with fsm_reset_arc metacomment
|
||||||
bool m_attrFsmArcInclCond : 1; // declared with fsm_arc_include_cond metacomment
|
bool m_attrFsmArcInclCond : 1; // declared with fsm_arc_include_cond metacomment
|
||||||
|
bool m_constPoolEntry : 1; // Constant pool variable
|
||||||
bool m_fileDescr : 1; // File descriptor
|
bool m_fileDescr : 1; // File descriptor
|
||||||
bool m_gotNansiType : 1; // Linker saw Non-ANSI type declaration
|
bool m_gotNansiType : 1; // Linker saw Non-ANSI type declaration
|
||||||
|
bool m_icoMaybeWritten : 1; // Design might write this input signal - for ico change detect
|
||||||
bool m_isConst : 1; // Table contains constant data
|
bool m_isConst : 1; // Table contains constant data
|
||||||
bool m_isContinuously : 1; // Ever assigned continuously (for force/release)
|
bool m_isContinuously : 1; // Ever assigned continuously (for force/release)
|
||||||
bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier
|
bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier
|
||||||
|
|
@ -2194,15 +2209,16 @@ class AstVar final : public AstNode {
|
||||||
m_funcReturn = false;
|
m_funcReturn = false;
|
||||||
m_attrScBv = false;
|
m_attrScBv = false;
|
||||||
m_attrScBigUint = false;
|
m_attrScBigUint = false;
|
||||||
m_attrIsolateAssign = false;
|
|
||||||
m_attrSFormat = false;
|
m_attrSFormat = false;
|
||||||
m_attrSplitVar = false;
|
m_attrSplitVar = false;
|
||||||
m_attrFsmState = false;
|
m_attrFsmState = false;
|
||||||
m_attrFsmRegisterWrapper = false;
|
m_attrFsmRegisterWrapper = false;
|
||||||
m_attrFsmResetArc = false;
|
m_attrFsmResetArc = false;
|
||||||
m_attrFsmArcInclCond = false;
|
m_attrFsmArcInclCond = false;
|
||||||
|
m_constPoolEntry = false;
|
||||||
m_fileDescr = false;
|
m_fileDescr = false;
|
||||||
m_gotNansiType = false;
|
m_gotNansiType = false;
|
||||||
|
m_icoMaybeWritten = false;
|
||||||
m_isConst = false;
|
m_isConst = false;
|
||||||
m_isContinuously = false;
|
m_isContinuously = false;
|
||||||
m_hasStrengthAssignment = false;
|
m_hasStrengthAssignment = false;
|
||||||
|
|
@ -2343,13 +2359,14 @@ public:
|
||||||
void attrFileDescr(bool flag) { m_fileDescr = flag; }
|
void attrFileDescr(bool flag) { m_fileDescr = flag; }
|
||||||
void attrScBv(bool flag) { m_attrScBv = flag; }
|
void attrScBv(bool flag) { m_attrScBv = flag; }
|
||||||
void attrScBigUint(bool flag) { m_attrScBigUint = flag; }
|
void attrScBigUint(bool flag) { m_attrScBigUint = flag; }
|
||||||
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
|
||||||
void attrSFormat(bool flag) { m_attrSFormat = flag; }
|
void attrSFormat(bool flag) { m_attrSFormat = flag; }
|
||||||
void attrSplitVar(bool flag) { m_attrSplitVar = flag; }
|
void attrSplitVar(bool flag) { m_attrSplitVar = flag; }
|
||||||
void attrFsmState(bool flag) { m_attrFsmState = flag; }
|
void attrFsmState(bool flag) { m_attrFsmState = flag; }
|
||||||
void attrFsmRegisterWrapper(bool flag) { m_attrFsmRegisterWrapper = flag; }
|
void attrFsmRegisterWrapper(bool flag) { m_attrFsmRegisterWrapper = flag; }
|
||||||
void attrFsmResetArc(bool flag) { m_attrFsmResetArc = flag; }
|
void attrFsmResetArc(bool flag) { m_attrFsmResetArc = flag; }
|
||||||
void attrFsmArcInclCond(bool flag) { m_attrFsmArcInclCond = flag; }
|
void attrFsmArcInclCond(bool flag) { m_attrFsmArcInclCond = flag; }
|
||||||
|
bool constPoolEntry() const { return m_constPoolEntry; }
|
||||||
|
void setConstPoolEntry() { m_constPoolEntry = true; }
|
||||||
void rand(const VRandAttr flag) { m_rand = flag; }
|
void rand(const VRandAttr flag) { m_rand = flag; }
|
||||||
void usedParam(bool flag) { m_usedParam = flag; }
|
void usedParam(bool flag) { m_usedParam = flag; }
|
||||||
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
|
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
|
||||||
|
|
@ -2383,6 +2400,8 @@ public:
|
||||||
void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; }
|
void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; }
|
||||||
bool hasUserInit() const { return m_hasUserInit; }
|
bool hasUserInit() const { return m_hasUserInit; }
|
||||||
void hasUserInit(bool flag) { m_hasUserInit = flag; }
|
void hasUserInit(bool flag) { m_hasUserInit = flag; }
|
||||||
|
void icoMaybeWritten(bool flag) { m_icoMaybeWritten = flag; }
|
||||||
|
bool icoMaybeWritten() const { return m_icoMaybeWritten; }
|
||||||
bool isDpiOpenArray() const VL_MT_SAFE { return m_isDpiOpenArray; }
|
bool isDpiOpenArray() const VL_MT_SAFE { return m_isDpiOpenArray; }
|
||||||
void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; }
|
void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; }
|
||||||
bool isHideLocal() const { return m_isHideLocal; }
|
bool isHideLocal() const { return m_isHideLocal; }
|
||||||
|
|
@ -2462,12 +2481,6 @@ public:
|
||||||
bool isWor() const { return varType().isWor(); }
|
bool isWor() const { return varType().isWor(); }
|
||||||
bool isWiredNet() const { return varType().isWiredNet(); }
|
bool isWiredNet() const { return varType().isWiredNet(); }
|
||||||
bool isTemp() const { return varType().isTemp(); }
|
bool isTemp() const { return varType().isTemp(); }
|
||||||
bool isToggleCoverable() const {
|
|
||||||
return ((isIO() || isSignal())
|
|
||||||
&& (isIO() || isBitLogic())
|
|
||||||
// Wrapper would otherwise duplicate wrapped module's coverage
|
|
||||||
&& !isSc() && !isPrimaryIO() && !isConst() && !isDouble() && !isString());
|
|
||||||
}
|
|
||||||
bool isClassMember() const { return varType() == VVarType::MEMBER; }
|
bool isClassMember() const { return varType() == VVarType::MEMBER; }
|
||||||
bool isVirtIface() const {
|
bool isVirtIface() const {
|
||||||
if (AstIfaceRefDType* const dtp = VN_CAST(dtypep(), IfaceRefDType)) {
|
if (AstIfaceRefDType* const dtp = VN_CAST(dtypep(), IfaceRefDType)) {
|
||||||
|
|
@ -2519,7 +2532,6 @@ public:
|
||||||
bool attrFsmRegisterWrapper() const { return m_attrFsmRegisterWrapper; }
|
bool attrFsmRegisterWrapper() const { return m_attrFsmRegisterWrapper; }
|
||||||
bool attrFsmResetArc() const { return m_attrFsmResetArc; }
|
bool attrFsmResetArc() const { return m_attrFsmResetArc; }
|
||||||
bool attrFsmArcInclCond() const { return m_attrFsmArcInclCond; }
|
bool attrFsmArcInclCond() const { return m_attrFsmArcInclCond; }
|
||||||
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
|
||||||
AstIface* sensIfacep() const { return m_sensIfacep; }
|
AstIface* sensIfacep() const { return m_sensIfacep; }
|
||||||
VRandAttr rand() const { return m_rand; }
|
VRandAttr rand() const { return m_rand; }
|
||||||
string verilogKwd() const override;
|
string verilogKwd() const override;
|
||||||
|
|
@ -2531,7 +2543,6 @@ public:
|
||||||
// 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
|
||||||
if (fromp->attrFileDescr()) attrFileDescr(true);
|
if (fromp->attrFileDescr()) attrFileDescr(true);
|
||||||
if (fromp->attrIsolateAssign()) attrIsolateAssign(true);
|
|
||||||
if (fromp->isContinuously()) isContinuously(true);
|
if (fromp->isContinuously()) isContinuously(true);
|
||||||
}
|
}
|
||||||
void propagateWrapAttrFrom(const AstVar* fromp) {
|
void propagateWrapAttrFrom(const AstVar* fromp) {
|
||||||
|
|
@ -2810,6 +2821,7 @@ class AstGenBlock final : public AstNodeGen {
|
||||||
std::string m_name; // Name of block
|
std::string m_name; // Name of block
|
||||||
const bool m_unnamed; // Originally unnamed (name change does not affect this)
|
const bool m_unnamed; // Originally unnamed (name change does not affect this)
|
||||||
const bool m_implied; // Not inserted by user
|
const bool m_implied; // Not inserted by user
|
||||||
|
AstDefaultDisable* m_defaultDisablep = nullptr; // Default disable iff in this scope
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstGenBlock(FileLine* fl, const string& name, AstNode* itemsp, bool implied)
|
AstGenBlock(FileLine* fl, const string& name, AstNode* itemsp, bool implied)
|
||||||
|
|
@ -2826,6 +2838,8 @@ public:
|
||||||
void name(const std::string& name) override { m_name = name; }
|
void name(const std::string& name) override { m_name = name; }
|
||||||
bool unnamed() const { return m_unnamed; }
|
bool unnamed() const { return m_unnamed; }
|
||||||
bool implied() const { return m_implied; }
|
bool implied() const { return m_implied; }
|
||||||
|
AstDefaultDisable* defaultDisablep() const { return m_defaultDisablep; }
|
||||||
|
void defaultDisablep(AstDefaultDisable* nodep) { m_defaultDisablep = nodep; }
|
||||||
};
|
};
|
||||||
class AstGenCase final : public AstNodeGen {
|
class AstGenCase final : public AstNodeGen {
|
||||||
// Generate 'case'
|
// Generate 'case'
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
ASTGEN_MEMBERS_AstNodeAssign;
|
ASTGEN_MEMBERS_AstNodeAssign;
|
||||||
// Clone single node, just get same type back.
|
// Clone single node, just get same type back.
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
virtual AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) = 0;
|
virtual AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) = 0;
|
||||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||||
virtual bool cleanRhs() const { return true; }
|
virtual bool cleanRhs() const { return true; }
|
||||||
|
|
@ -941,13 +942,16 @@ public:
|
||||||
class AstPExprClause final : public AstNodeStmt {
|
class AstPExprClause final : public AstNodeStmt {
|
||||||
const bool m_pass; // True if will be replaced by passing assertion clause, false for
|
const bool m_pass; // True if will be replaced by passing assertion clause, false for
|
||||||
// assertion failure clause
|
// assertion failure clause
|
||||||
|
const bool m_vacuous; // True if pass is vacuous
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ASTGEN_MEMBERS_AstPExprClause;
|
ASTGEN_MEMBERS_AstPExprClause;
|
||||||
explicit AstPExprClause(FileLine* fl, bool pass = true)
|
explicit AstPExprClause(FileLine* fl, bool pass = true, bool vacuous = false)
|
||||||
: ASTGEN_SUPER_PExprClause(fl)
|
: ASTGEN_SUPER_PExprClause(fl)
|
||||||
, m_pass{pass} {}
|
, m_pass{pass}
|
||||||
|
, m_vacuous{vacuous} {}
|
||||||
bool pass() const { return m_pass; }
|
bool pass() const { return m_pass; }
|
||||||
|
bool vacuous() const { return m_vacuous; }
|
||||||
};
|
};
|
||||||
class AstPrintTimeScale final : public AstNodeStmt {
|
class AstPrintTimeScale final : public AstNodeStmt {
|
||||||
// Parents: stmtlist
|
// Parents: stmtlist
|
||||||
|
|
@ -1606,12 +1610,18 @@ public:
|
||||||
};
|
};
|
||||||
class AstCover final : public AstNodeCoverOrAssert {
|
class AstCover final : public AstNodeCoverOrAssert {
|
||||||
// @astgen op3 := coverincsp: List[AstNode] // Coverage node
|
// @astgen op3 := coverincsp: List[AstNode] // Coverage node
|
||||||
|
bool m_isCoverSeq = false; // 'cover sequence' (IEEE 1800-2023 16.14.3): fires per
|
||||||
|
// end-of-match, not per property success
|
||||||
public:
|
public:
|
||||||
ASTGEN_MEMBERS_AstCover;
|
ASTGEN_MEMBERS_AstCover;
|
||||||
AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, VAssertType type,
|
AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, VAssertType type,
|
||||||
const string& name = "")
|
const string& name = "")
|
||||||
: ASTGEN_SUPER_Cover(fl, propp, stmtsp, type, VAssertDirectiveType::COVER, name) {}
|
: ASTGEN_SUPER_Cover(fl, propp, stmtsp, type, VAssertDirectiveType::COVER, name) {}
|
||||||
string verilogKwd() const override { return "cover"; }
|
string verilogKwd() const override { return "cover"; }
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
|
bool isCoverSeq() const { return m_isCoverSeq; }
|
||||||
|
void isCoverSeq(bool flag) { m_isCoverSeq = flag; }
|
||||||
};
|
};
|
||||||
class AstRestrict final : public AstNodeCoverOrAssert {
|
class AstRestrict final : public AstNodeCoverOrAssert {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue