merge master and resolve conflicts
This commit is contained in:
commit
7372c1b30b
|
|
@ -28,259 +28,143 @@ concurrency:
|
|||
|
||||
jobs:
|
||||
|
||||
build-2404-gcc:
|
||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
||||
build-2604-gcc:
|
||||
name: Build | 26.04 | gcc
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
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 }}
|
||||
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:
|
||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
||||
name: Build | 24.04 | clang
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
with:
|
||||
cc: clang
|
||||
runs-on: ubuntu-24.04
|
||||
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:
|
||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
||||
name: Build | 22.04 | gcc
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
with:
|
||||
cc: gcc
|
||||
runs-on: ubuntu-22.04
|
||||
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:
|
||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
||||
build-macos-15-clang:
|
||||
name: Build | macos-15 | clang
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
with:
|
||||
cc: clang
|
||||
runs-on: macos-15
|
||||
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:
|
||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
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
|
||||
name: Build | windows-2025-vs2026 | msvc
|
||||
runs-on: windows-2025-vs2026
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
path: repo
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v5
|
||||
- name: Cache win_flex_bison
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: msbuild-msvc-cmake
|
||||
path: ${{ github.workspace }}/win_flex_bison
|
||||
key: win_flex_bison
|
||||
- name: compile
|
||||
env:
|
||||
WIN_FLEX_BISON: ${{ github.workspace }}/.ccache
|
||||
run: ./ci/ci-win-compile.ps1
|
||||
- name: test build
|
||||
run: ./ci/ci-win-test.ps1
|
||||
- name: Zip up repository
|
||||
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
|
||||
- name: Upload zip archive
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: ${{ github.workspace }}/repo/verilator.zip
|
||||
name: verilator-win.zip
|
||||
|
||||
test-2604-gcc:
|
||||
name: Test | 26.04 | gcc | ${{ matrix.suite }}
|
||||
needs: build-2604-gcc
|
||||
uses: ./.github/workflows/reusable-test.yml
|
||||
with:
|
||||
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:
|
||||
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
||||
name: Test | 24.04 | gcc | ${{ matrix.suite }}
|
||||
needs: build-2404-gcc
|
||||
uses: ./.github/workflows/reusable-test.yml
|
||||
with:
|
||||
archive: ${{ needs.build-2404-gcc.outputs.archive }}
|
||||
os: ${{ matrix.os }}
|
||||
cc: ${{ matrix.cc }}
|
||||
reloc: ${{ matrix.reloc }}
|
||||
cc: gcc
|
||||
runs-on: ubuntu-24.04
|
||||
suite: ${{ matrix.suite }}
|
||||
dev-gcov: 0
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Ubuntu 24.04 gcc
|
||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-0}
|
||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-1}
|
||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-2}
|
||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-3}
|
||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-0}
|
||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-1}
|
||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-2}
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||
|
||||
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
|
||||
uses: ./.github/workflows/reusable-test.yml
|
||||
with:
|
||||
archive: ${{ needs.build-2404-clang.outputs.archive }}
|
||||
os: ${{ matrix.os }}
|
||||
cc: ${{ matrix.cc }}
|
||||
reloc: ${{ matrix.reloc }}
|
||||
cc: clang
|
||||
reloc: true # Test with relocated installation
|
||||
runs-on: ubuntu-24.04
|
||||
suite: ${{ matrix.suite }}
|
||||
dev-gcov: 0
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Ubuntu 24.04 clang
|
||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-0}
|
||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-1}
|
||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-2}
|
||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-3}
|
||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-0}
|
||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-1}
|
||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-2}
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||
|
||||
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
|
||||
uses: ./.github/workflows/reusable-test.yml
|
||||
with:
|
||||
archive: ${{ needs.build-2204-gcc.outputs.archive }}
|
||||
os: ${{ matrix.os }}
|
||||
cc: ${{ matrix.cc }}
|
||||
reloc: ${{ matrix.reloc }}
|
||||
cc: gcc
|
||||
runs-on: ubuntu-22.04
|
||||
suite: ${{ matrix.suite }}
|
||||
dev-gcov: 0
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Ubuntu 22.04 gcc
|
||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-0}
|
||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-1}
|
||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-2}
|
||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-3}
|
||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-0}
|
||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-1}
|
||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-2}
|
||||
|
||||
test-2204-clang:
|
||||
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ 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}
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||
|
||||
lint-py:
|
||||
name: Lint Python
|
||||
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"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
- run: test_regress/t/t_dist_contributors.py
|
||||
|
|
|
|||
|
|
@ -38,15 +38,13 @@ jobs:
|
|||
(github.event_name == 'workflow_dispatch')
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
with:
|
||||
cc: gcc
|
||||
dev-gcov: true
|
||||
runs-on: ubuntu-24.04
|
||||
# For pull requests, build the head of the pull request branch, not the
|
||||
# merge commit, otherwise patch coverage would include the changes
|
||||
# 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 }}
|
||||
os: ubuntu-24.04
|
||||
os-name: linux
|
||||
cc: gcc
|
||||
dev-asan: 0
|
||||
dev-gcov: 1
|
||||
|
||||
test:
|
||||
name: Test | ${{ matrix.test }}${{ matrix.num }}
|
||||
|
|
@ -54,11 +52,10 @@ jobs:
|
|||
uses: ./.github/workflows/reusable-test.yml
|
||||
with:
|
||||
archive: ${{ needs.build.outputs.archive }}
|
||||
os: ubuntu-24.04
|
||||
cc: gcc
|
||||
reloc: 0
|
||||
dev-gcov: true
|
||||
runs-on: ubuntu-24.04
|
||||
suite: ${{ matrix.test }}${{ matrix.num }}
|
||||
dev-gcov: 1
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -74,10 +71,10 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
|
||||
- name: Download code coverage data
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
pattern: code-coverage-*
|
||||
path: obj_coverage
|
||||
|
|
@ -90,7 +87,7 @@ jobs:
|
|||
find obj_coverage -type f | paste -sd, | sed "s/^/files=/" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload to codecov.io
|
||||
uses: codecov/codecov-action@v6
|
||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7
|
||||
with:
|
||||
disable_file_fixes: true
|
||||
disable_search: true
|
||||
|
|
@ -114,18 +111,18 @@ jobs:
|
|||
sudo apt install lcov
|
||||
|
||||
- name: Download repository archive
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: ${{ needs.build.outputs.archive }}
|
||||
path: ${{ github.workspace }}
|
||||
|
||||
- name: Unpack repository archive
|
||||
run: |
|
||||
tar -x -z -f ${{ needs.build.outputs.archive }}
|
||||
tar --zstd -x -f ${{ needs.build.outputs.archive }}
|
||||
ls -lsha
|
||||
|
||||
- name: Download code coverage data
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
pattern: code-coverage-*
|
||||
path: repo/obj_coverage
|
||||
|
|
@ -172,14 +169,14 @@ jobs:
|
|||
fi
|
||||
|
||||
- name: Upload report
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: repo/obj_coverage
|
||||
name: coverage-report
|
||||
|
||||
- name: Upload notification
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: repo/notification
|
||||
name: pr-notification
|
||||
|
|
@ -195,9 +192,9 @@ jobs:
|
|||
# Creating issues requires elevated privilege
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
with:
|
||||
app-id: ${{ vars.VERILATOR_CI_ID }}
|
||||
client-id: ${{ vars.VERILATOR_CI_ID }}
|
||||
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
||||
owner: verilator
|
||||
repositories: verilator
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
|
||||
- name: Extract context variables
|
||||
run: |
|
||||
|
|
@ -54,7 +54,7 @@ jobs:
|
|||
|
||||
- name: Docker meta
|
||||
id: docker_meta
|
||||
uses: docker/metadata-action@v6
|
||||
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6
|
||||
with:
|
||||
images: |
|
||||
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
||||
|
|
@ -64,21 +64,21 @@ jobs:
|
|||
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- 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'
|
||||
with:
|
||||
context: ${{ env.build_context }}
|
||||
|
|
|
|||
|
|
@ -15,18 +15,12 @@ jobs:
|
|||
format:
|
||||
runs-on: ubuntu-24.04
|
||||
name: Ubuntu 24.04 | format
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
CI_RUNS_ON: ubuntu-24.04
|
||||
CI_COMMIT: ${{ github.sha }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Install packages for build
|
||||
env:
|
||||
CI_BUILD_STAGE_NAME: build
|
||||
run: |
|
||||
sudo apt install clang-format-18 || \
|
||||
sudo apt install clang-format-18
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ name: Pages
|
|||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
paths: ["ci/**", ".github/workflows"]
|
||||
paths: ["ci/**", ".github/workflows/**"]
|
||||
workflow_dispatch:
|
||||
workflow_run:
|
||||
workflows: ["Code coverage", "RTLMeter"]
|
||||
|
|
@ -22,8 +22,11 @@ permissions:
|
|||
# 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
|
||||
# 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:
|
||||
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
|
||||
|
||||
defaults:
|
||||
|
|
@ -34,11 +37,15 @@ jobs:
|
|||
build:
|
||||
name: Build content
|
||||
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:
|
||||
pr-run-ids: ${{ steps.build.outputs.pr-run-ids }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
- name: Build pages
|
||||
id: build
|
||||
env:
|
||||
|
|
@ -48,7 +55,7 @@ jobs:
|
|||
ls -lsha
|
||||
tree -L 3 pages
|
||||
- name: Upload pages artifact
|
||||
uses: actions/upload-pages-artifact@v5
|
||||
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
|
||||
with:
|
||||
path: pages
|
||||
|
||||
|
|
@ -58,10 +65,17 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
url: ${{ steps.deploy-2.outputs.page_url || steps.deploy-1.outputs.page_url }}
|
||||
steps:
|
||||
# GitHub's Pages backend intermittently fails a deployment mid-sync, retry
|
||||
- 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:
|
||||
name: Notify
|
||||
|
|
@ -70,13 +84,13 @@ jobs:
|
|||
if: ${{ github.repository == 'verilator/verilator' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
# Use the Verilator CI app to post the comment
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
with:
|
||||
app-id: ${{ vars.VERILATOR_CI_ID }}
|
||||
client-id: ${{ vars.VERILATOR_CI_ID }}
|
||||
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
||||
permission-actions: write
|
||||
permission-pull-requests: write
|
||||
|
|
|
|||
|
|
@ -7,37 +7,47 @@ name: reusable-build
|
|||
on:
|
||||
workflow_call:
|
||||
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:
|
||||
description: "Commit SHA to build"
|
||||
required: true
|
||||
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:
|
||||
archive:
|
||||
description: "Name of the built repository archive artifact"
|
||||
description: "Name of the built archive artifact"
|
||||
value: ${{ jobs.build.outputs.archive }}
|
||||
|
||||
env:
|
||||
CI_OS_NAME: ${{ inputs.os-name }}
|
||||
CCACHE_COMPRESS: 1
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||
INSTALL_DIR: ${{ github.workspace }}/install
|
||||
RELOC_DIR: ${{ github.workspace }}/relloc
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -48,27 +58,24 @@ jobs:
|
|||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ${{ inputs.os }}
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
outputs:
|
||||
archive: ${{ steps.create-archive.outputs.archive }}
|
||||
env:
|
||||
CI_BUILD_STAGE_NAME: build
|
||||
CI_DEV_ASAN: ${{ inputs.dev-asan }}
|
||||
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)
|
||||
CACHE_BASE_KEY: build-${{ inputs.runs-on }}-${{ inputs.cc }}
|
||||
CCACHE_MAXSIZE: 1000M
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
path: repo
|
||||
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
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||
with:
|
||||
|
|
@ -78,22 +85,40 @@ jobs:
|
|||
${{ env.CACHE_KEY }}-
|
||||
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
run: ./ci/ci-install.bash 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
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
# Name of the archive must be unique based on the build parameters
|
||||
ARCHIVE=verilator-${{ inputs.sha }}-${{ inputs.os }}-${{ inputs.cc }}-${{ inputs.dev-asan }}-${{ inputs.dev-gcov }}.tar.gz
|
||||
tar --posix -c -z -f $ARCHIVE repo
|
||||
# Archive name, unique per build; flavour tags mark non-default builds
|
||||
ARCHIVE="verilator-${{ inputs.sha }}-${{ inputs.runs-on }}-${{ inputs.cc }}"
|
||||
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"
|
||||
|
||||
- name: Upload repository archive
|
||||
uses: actions/upload-artifact@v7
|
||||
- name: Upload archive
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ 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:
|
||||
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
CI_BUILD_STAGE_NAME: build
|
||||
CI_RUNS_ON: ubuntu-22.04
|
||||
CCACHE_COMPRESS: 1
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||
|
|
@ -27,12 +24,12 @@ jobs:
|
|||
name: Sub-lint | Python
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
path: repo
|
||||
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
run: ./ci/ci-install.bash build
|
||||
|
||||
- name: Configure
|
||||
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
|
||||
required: true
|
||||
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
|
||||
required: true
|
||||
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
|
||||
required: false
|
||||
default: ""
|
||||
|
|
@ -73,7 +73,7 @@ jobs:
|
|||
sudo apt install ccache mold libfl-dev libjemalloc-dev libsystemc-dev
|
||||
|
||||
- name: Checkout RTLMeter
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
repository: "verilator/rtlmeter"
|
||||
path: rtlmeter
|
||||
|
|
@ -84,7 +84,7 @@ jobs:
|
|||
|
||||
- name: Use saved ccache
|
||||
if: ${{ env.CCACHE_DISABLE == 0 }}
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
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
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: ${{ inputs.verilator-archive-new }}
|
||||
|
||||
- name: Unpack Verilator installation archive - new
|
||||
run: |
|
||||
tar -x -z -f ${{ inputs.verilator-archive-new }}
|
||||
tar --zstd -x -f ${{ inputs.verilator-archive-new }}
|
||||
mv install verilator-new
|
||||
|
||||
- name: Compile cases - new
|
||||
|
|
@ -135,7 +135,7 @@ jobs:
|
|||
./rtlmeter report --steps '*' --metrics '*' ../results-${{ steps.results.outputs.hash }}.json
|
||||
|
||||
- name: Upload results - new
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: results-${{ steps.results.outputs.hash }}.json
|
||||
name: rtlmeter-${{ inputs.tag }}-results-${{ steps.results.outputs.hash }}
|
||||
|
|
@ -157,14 +157,14 @@ jobs:
|
|||
|
||||
- name: Download Verilator installation archive - old
|
||||
if: ${{ inputs.verilator-archive-old != '' }}
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: ${{ inputs.verilator-archive-old }}
|
||||
|
||||
- name: Unpack Verilator installation archive - old
|
||||
if: ${{ inputs.verilator-archive-old != '' }}
|
||||
run: |
|
||||
tar -x -z -f ${{ inputs.verilator-archive-old }}
|
||||
tar --zstd -x -f ${{ inputs.verilator-archive-old }}
|
||||
mv install verilator-old
|
||||
|
||||
- name: Compile cases - old
|
||||
|
|
@ -198,7 +198,7 @@ jobs:
|
|||
|
||||
- name: Upload results - old
|
||||
if: ${{ inputs.verilator-archive-old != '' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: reference-${{ steps.results.outputs.hash }}.json
|
||||
name: rtlmeter-${{ inputs.tag }}-reference-${{ steps.results.outputs.hash }}
|
||||
|
|
|
|||
|
|
@ -11,29 +11,33 @@ on:
|
|||
description: "Name of the repository archive artifact from reusable-build"
|
||||
required: true
|
||||
type: string
|
||||
os: # e.g. ubuntu-24.04
|
||||
required: true
|
||||
type: string
|
||||
cc: # gcc or clang
|
||||
required: true
|
||||
type: string
|
||||
reloc: # 0 or 1
|
||||
required: true
|
||||
type: number
|
||||
suite: # e.g. dist-vlt-0
|
||||
cc:
|
||||
description: "Compiler to use: 'gcc' or 'clang'"
|
||||
required: true
|
||||
type: string
|
||||
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
|
||||
type: number
|
||||
type: string
|
||||
suite:
|
||||
description: "Test suite to run, e.g. dist-vlt-0"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
CCACHE_COMPRESS: 1
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||
INSTALL_DIR: ${{ github.workspace }}/install
|
||||
RELOC_DIR: ${{ github.workspace }}/relloc
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -43,19 +47,16 @@ defaults:
|
|||
jobs:
|
||||
|
||||
test:
|
||||
runs-on: ${{ inputs.os }}
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
name: Test
|
||||
env:
|
||||
CI_BUILD_STAGE_NAME: test
|
||||
CI_RUNS_ON: ${{ inputs.os }}
|
||||
CI_RELOC: ${{inputs.reloc }}
|
||||
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)
|
||||
steps:
|
||||
|
||||
- name: Download repository archive
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: ${{ inputs.archive }}
|
||||
path: ${{ github.workspace }}
|
||||
|
|
@ -63,11 +64,11 @@ jobs:
|
|||
- name: Unpack repository archive
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
tar -x -z -f ${{ inputs.archive }}
|
||||
tar --zstd -x -f ${{ inputs.archive }}
|
||||
ls -lsha
|
||||
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
||||
with:
|
||||
|
|
@ -78,17 +79,17 @@ jobs:
|
|||
|
||||
- name: Install test dependencies
|
||||
run: |
|
||||
./ci/ci-install.bash
|
||||
./ci/ci-install.bash test
|
||||
make venv
|
||||
|
||||
- name: Test
|
||||
id: run-test
|
||||
continue-on-error: true
|
||||
env:
|
||||
TESTS: ${{ inputs.suite }}
|
||||
run: |
|
||||
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
|
||||
if: ${{ inputs.dev-gcov }}
|
||||
|
|
@ -99,7 +100,7 @@ jobs:
|
|||
|
||||
- name: Upload code coverage data
|
||||
if: ${{ inputs.dev-gcov }}
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: ${{ github.workspace }}/repo/obj_coverage/verilator-${{ inputs.suite }}.info
|
||||
name: code-coverage-${{ inputs.suite }}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ jobs:
|
|||
cases: ${{ steps.cases.outputs.cases }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
|
||||
- name: Startup
|
||||
id: start
|
||||
|
|
@ -65,39 +65,47 @@ jobs:
|
|||
build-gcc-new:
|
||||
name: Build New Verilator - GCC
|
||||
needs: start
|
||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
with:
|
||||
runs-on: ubuntu-24.04
|
||||
cc: gcc
|
||||
ccwarn: false
|
||||
install: true
|
||||
runs-on: ubuntu-24.04
|
||||
sha: ${{ github.sha }}
|
||||
|
||||
build-clang-new:
|
||||
name: Build New Verilator - Clang
|
||||
needs: start
|
||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
with:
|
||||
runs-on: ubuntu-24.04
|
||||
cc: clang
|
||||
ccwarn: false
|
||||
install: true
|
||||
runs-on: ubuntu-24.04
|
||||
sha: ${{ github.sha }}
|
||||
|
||||
build-gcc-old:
|
||||
name: Build Old Verilator - GCC
|
||||
needs: start
|
||||
if: ${{ needs.start.outputs.old-sha != '' }}
|
||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
with:
|
||||
runs-on: ubuntu-24.04
|
||||
cc: gcc
|
||||
ccwarn: false
|
||||
install: true
|
||||
runs-on: ubuntu-24.04
|
||||
sha: ${{ needs.start.outputs.old-sha }}
|
||||
|
||||
build-clang-old:
|
||||
name: Build Old Verilator - Clang
|
||||
needs: start
|
||||
if: ${{ needs.start.outputs.old-sha != '' }}
|
||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
with:
|
||||
runs-on: ubuntu-24.04
|
||||
cc: clang
|
||||
ccwarn: false
|
||||
install: true
|
||||
runs-on: ubuntu-24.04
|
||||
sha: ${{ needs.start.outputs.old-sha }}
|
||||
|
||||
run-gcc:
|
||||
|
|
@ -208,7 +216,7 @@ jobs:
|
|||
run: echo "tags=$(jq -r 'keys | map(sub("^run-"; "")) | join(" ")' <<< '${{ toJSON(needs) }}')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Checkout RTLMeter
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
repository: "verilator/rtlmeter"
|
||||
path: rtlmeter
|
||||
|
|
@ -232,7 +240,7 @@ jobs:
|
|||
./rtlmeter collate ../all-results-$tag/*.json > ../all-results-$tag.json
|
||||
done
|
||||
- name: Upload combined results
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: all-results-*.json
|
||||
name: all-results
|
||||
|
|
@ -259,7 +267,7 @@ jobs:
|
|||
done
|
||||
- name: Upload reference results
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: all-reference-*.json
|
||||
name: all-reference
|
||||
|
|
@ -278,27 +286,27 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Download combined results
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: all-results
|
||||
path: results
|
||||
- name: Upload published results
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: results/*.json
|
||||
name: published-results
|
||||
# Pushing to verilator/verilator-rtlmeter-results requires elevated permissions
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
with:
|
||||
app-id: ${{ vars.VERILATOR_CI_ID }}
|
||||
client-id: ${{ vars.VERILATOR_CI_ID }}
|
||||
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
||||
owner: verilator
|
||||
repositories: verilator-rtlmeter-results
|
||||
permission-contents: write
|
||||
- name: Checkout verilator-rtlmeter-results
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
repository: "verilator/verilator-rtlmeter-results"
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
|
|
@ -331,7 +339,7 @@ jobs:
|
|||
actions: read
|
||||
steps:
|
||||
- name: Checkout RTLMeter
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
repository: "verilator/rtlmeter"
|
||||
path: rtlmeter
|
||||
|
|
@ -341,7 +349,7 @@ jobs:
|
|||
run: make venv
|
||||
|
||||
- name: Checkout Verilator
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
path: verilator
|
||||
|
||||
|
|
@ -367,13 +375,13 @@ jobs:
|
|||
echo ${{ github.event.number }} > ../notification-artifact/pr-number.txt
|
||||
|
||||
- name: Upload report
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: report-artifact
|
||||
name: rtlmeter-report
|
||||
|
||||
- name: Upload notification
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: notification-artifact
|
||||
name: pr-notification
|
||||
|
|
@ -392,9 +400,9 @@ jobs:
|
|||
# Creating issues requires elevated privilege
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
with:
|
||||
app-id: ${{ vars.VERILATOR_CI_ID }}
|
||||
client-id: ${{ vars.VERILATOR_CI_ID }}
|
||||
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
||||
owner: 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
|
||||
project(
|
||||
Verilator
|
||||
VERSION 5.049
|
||||
VERSION 5.051
|
||||
HOMEPAGE_URL https://verilator.org
|
||||
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!
|
||||
|
||||
|
||||
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:**
|
||||
|
||||
* 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]
|
||||
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 NOTREDOP error on reduction and negation operators (#7417) (#7623) (#7624).
|
||||
* 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]
|
||||
* 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]
|
||||
* 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 weak `until` / `until_with` property operators (#7290) (#7548) (#7685). [Yilou Wang]
|
||||
* 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 calling interface functions without parens (#7584). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* 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 FSM detection in primitive wrappers (#7607). [Yogish Sekhar]
|
||||
* 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 process::self().srand() (#7695). [Igor Zaworski, Antmicro Ltd.]
|
||||
* 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 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.]
|
||||
|
|
@ -71,9 +107,27 @@ Verilator 5.049 devel
|
|||
* Optimize runtime assertOn() checks (#7707). [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 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 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 cross-hierarchy tristate drivers of interface nets (#7339) (#7801). [Yilou Wang]
|
||||
* Fix destructive event state before dynamic waits (#7340). [Nick Brereton]
|
||||
* Fix ALWCOMBORDER on variable ordering (#7350) (#7608). [Cookie]
|
||||
* 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 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 scheduling of virtual interface method writes (#7641). [Artur Bieniek, Antmicro Ltd.]
|
||||
* Fix implicit conversions of VlWide (#7642). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Fix CASEINCOMPLETE to not warn on `unique0 case` (#7647).
|
||||
* 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 parameter read through locally-declared interface instance (#7679). [Nick Brereton]
|
||||
* 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 `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 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 splitting functions containing fork logic (#7717). [Mateusz Gancarz, 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
|
||||
|
|
@ -471,7 +558,7 @@ Verilator 5.044 2026-01-01
|
|||
* Support clocking output delay `1step` (#6681). [Ondrej Ille]
|
||||
* Support parsing of dotted `bins_expression` (#6683). [Pawel Kojma, 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 `rand_mode` in global constraint gathering (#6740) (#6752). [Yilou Wang]
|
||||
* Support reduction or in constraints (#6840). [Pawel Kojma, Antmicro Ltd.]
|
||||
|
|
@ -5665,7 +5752,7 @@ Verilator 3.104 2003-04-30
|
|||
**Major:**
|
||||
|
||||
* 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%
|
||||
|
||||
**Minor:**
|
||||
|
|
|
|||
28
Makefile.in
28
Makefile.in
|
|
@ -495,6 +495,11 @@ MAKE_FILES = \
|
|||
src/Makefile*.in \
|
||||
test_regress/Makefile* \
|
||||
|
||||
# Markdown
|
||||
MD_FILES = \
|
||||
*.md \
|
||||
*/*.md \
|
||||
|
||||
# Perl programs
|
||||
PERL_PROGRAMS = \
|
||||
bin/redirect \
|
||||
|
|
@ -541,6 +546,13 @@ PY_FILES = \
|
|||
# Python files, test_regress tests
|
||||
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 \
|
||||
|
|
@ -553,7 +565,7 @@ YAML_FILES = \
|
|||
# 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_FLAGS = --indent-size 2
|
||||
|
|
@ -590,6 +602,13 @@ format-make mbake:
|
|||
$(MBAKE) --version
|
||||
$(MBAKE) $(MBAKE_FLAGS) $(MAKE_FILES)
|
||||
|
||||
MDFORMAT = mdformat
|
||||
MDFORMAT_FLAGS =
|
||||
|
||||
format-md:
|
||||
$(MDFORMAT) --version
|
||||
$(MDFORMAT) $(MDFORMAT_FLAGS) $(MD_FILES)
|
||||
|
||||
YAPF = yapf
|
||||
YAPF_FLAGS = -i --parallel
|
||||
|
||||
|
|
@ -597,6 +616,13 @@ format-py yapf:
|
|||
$(YAPF) --version
|
||||
$(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_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
|
||||
.. SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
..
|
||||
Github doesn't render images unless absolute URL
|
||||
Do not know of a conditional tag, "only: github" nor "github display" works
|
||||
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| image:: https://img.shields.io/badge/Website-Verilator.org-181717.svg
|
||||
:target: https://verilator.org
|
||||
|
||||
.. |badge2| image:: https://img.shields.io/badge/License-LGPL%20v3-blue.svg
|
||||
:target: https://www.gnu.org/licenses/lgpl-3.0
|
||||
|
||||
.. |badge3| image:: https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg
|
||||
:target: https://opensource.org/licenses/Artistic-2.0
|
||||
|
||||
.. |badge4| image:: https://repology.org/badge/tiny-repos/verilator.svg?header=distro%20packages
|
||||
:target: https://repology.org/project/verilator/versions
|
||||
|
||||
.. |badge5| image:: https://img.shields.io/docker/pulls/verilator/verilator
|
||||
:target: https://hub.docker.com/r/verilator/verilator
|
||||
|
||||
.. |badge7| image:: https://github.com/verilator/verilator/workflows/build/badge.svg
|
||||
: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
|
||||
:target: https://verilator.github.io/verilator-rtlmeter-results
|
||||
|
||||
|
||||
Welcome to Verilator
|
||||
====================
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - **Welcome to Verilator, the fastest Verilog/SystemVerilog simulator.**
|
||||
* Accepts Verilog or SystemVerilog
|
||||
* Performs lint code-quality checks
|
||||
* Compiles into multithreaded C++, or SystemC
|
||||
* Creates JSON to front-end your own tools
|
||||
- - **Welcome to Verilator, the fastest Verilog/SystemVerilog simulator.**
|
||||
- Accepts Verilog or SystemVerilog
|
||||
- Performs lint code-quality checks
|
||||
- Compiles into multithreaded C++, or SystemC
|
||||
- Creates JSON to front-end your own tools
|
||||
- |Logo|
|
||||
* - |verilator multithreaded performance|
|
||||
- - |verilator multithreaded performance|
|
||||
- **Fast**
|
||||
* Outperforms many closed-source commercial simulators
|
||||
* Single- and multithreaded output models
|
||||
* - **Widely Used**
|
||||
* Wide industry and academic deployment
|
||||
* Out-of-the-box support from Arm and RISC-V vendor IP
|
||||
* Over 700 contributors
|
||||
- Outperforms many closed-source commercial simulators
|
||||
- Single- and multithreaded output models
|
||||
- - **Widely Used**
|
||||
- Wide industry and academic deployment
|
||||
- Out-of-the-box support from Arm and RISC-V vendor IP
|
||||
- Over 700 contributors
|
||||
- |verilator usage|
|
||||
* - |verilator community|
|
||||
- - |verilator community|
|
||||
- **Community Driven & Openly Licensed**
|
||||
* Guided by the `CHIPS Alliance`_ and `Linux Foundation`_
|
||||
* Open, and free as in both speech and beer
|
||||
* More simulation for your verification budget
|
||||
* - **Commercial Support Available**
|
||||
* Commercial support contracts
|
||||
* Design support contracts
|
||||
* Enhancement contracts
|
||||
- Guided by the `CHIPS Alliance`_ and `Linux Foundation`_
|
||||
- Open, and free as in both speech and beer
|
||||
- More simulation for your verification budget
|
||||
- - **Commercial Support Available**
|
||||
- Commercial support contracts
|
||||
- Design support contracts
|
||||
- Enhancement contracts
|
||||
- |verilator support|
|
||||
|
||||
|
||||
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
|
||||
simulation, Verilator is the tool for you.
|
||||
|
||||
|
||||
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
|
||||
licenses. Thus, Verilator gives you the best simulation cycles/dollar.
|
||||
|
||||
|
||||
Installation & Documentation
|
||||
============================
|
||||
|
||||
|
|
@ -115,7 +118,6 @@ For more information:
|
|||
|
||||
- `Verilator issues <https://verilator.org/issues>`_
|
||||
|
||||
|
||||
Support
|
||||
=======
|
||||
|
||||
|
|
@ -132,7 +134,6 @@ Verilator also supports and encourages commercial support models and
|
|||
organizations; please see `Verilator Commercial Support
|
||||
<https://verilator.org/verilator_commercial_support>`_.
|
||||
|
||||
|
||||
Related Projects
|
||||
================
|
||||
|
||||
|
|
@ -149,7 +150,6 @@ Related Projects
|
|||
- `Surfer <https://surfer-project.org/>`_ - Web or offline waveform viewer
|
||||
for Verilator traces.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
.. _chips alliance: https://chipsalliance.org
|
||||
|
||||
.. _icarus verilog: https://steveicarus.github.io/iverilog
|
||||
|
||||
.. _linux foundation: https://www.linuxfoundation.org
|
||||
|
||||
.. |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 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 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
|
||||
--dpi-hdr-only Only produce the DPI header 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-dfg Enable dumping DfgGraphs to .dot files
|
||||
--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+V Show verbose version and config
|
||||
+verilator+version Show version and exit
|
||||
+verilator+vpi+<library>[:<bootstrap>] Load VPI shared library
|
||||
+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
|
||||
# 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
|
||||
|
||||
################################################################################
|
||||
|
|
@ -10,30 +10,33 @@
|
|||
# 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 -x
|
||||
|
||||
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."
|
||||
export PERL_LWP_SSL_VERIFY_HOSTNAME=0
|
||||
echo "check_certificate = off" >> ~/.wgetrc
|
||||
|
||||
fatal() {
|
||||
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
|
||||
if [ "$HOST_OS" = "linux" ]; then
|
||||
# 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/man/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
||||
|
|
@ -44,100 +47,100 @@ install-wavediff() {
|
|||
source ci/docker/buildenv/wavetools.conf
|
||||
local _base_url="https://github.com/hudson-trading/wavetools/releases/download/${WAVETOOLS_VERSION}"
|
||||
local _platform
|
||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
||||
if [ "$HOST_OS" = "linux" ]; then
|
||||
_platform="linux-x86_64"
|
||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
||||
elif [ "$HOST_OS" = "macOS" ]; then
|
||||
_platform="macos-arm64"
|
||||
elif [ "$CI_OS_NAME" = "windows" ]; then
|
||||
_platform="windows-x86_64"
|
||||
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
|
||||
fi
|
||||
local _tmpdir
|
||||
_tmpdir=$(mktemp -d)
|
||||
local _archive="wavetools-${WAVETOOLS_VERSION}-${_platform}"
|
||||
if [ "$CI_OS_NAME" = "windows" ]; then
|
||||
wget -q -O "${_tmpdir}/${_archive}.zip" "${_base_url}/${_archive}.zip"
|
||||
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
|
||||
wget -q -O "${_tmpdir}/${_archive}.tar.gz" "${_base_url}/${_archive}.tar.gz"
|
||||
tar -xzf "${_tmpdir}/${_archive}.tar.gz" -C "${_tmpdir}"
|
||||
sudo cp "${_tmpdir}/${_archive}/wavediff" /usr/local/bin/wavediff
|
||||
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
|
||||
# build Verilator
|
||||
|
||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
||||
sudo apt-get update ||
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes ccache help2man libfl-dev ||
|
||||
sudo apt-get install --yes ccache help2man libfl-dev
|
||||
if [[ ! "$CI_RUNS_ON" =~ "ubuntu-22.04" ]]; then
|
||||
# Some conflict of libunwind verison on 22.04, can live without it for now
|
||||
sudo apt-get install --yes libjemalloc-dev ||
|
||||
sudo apt-get install --yes libjemalloc-dev
|
||||
fi
|
||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
||||
if [[ ! "$CI_RUNS_ON" =~ "-riscv" ]]; then
|
||||
sudo apt-get install --yes libsystemc libsystemc-dev ||
|
||||
sudo apt-get install --yes libsystemc libsystemc-dev
|
||||
if [ "$HOST_OS" = "linux" ]; then
|
||||
if [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||
PACKAGES=(
|
||||
bear
|
||||
ccache
|
||||
help2man
|
||||
libfl-dev
|
||||
libsystemc-dev
|
||||
mold
|
||||
)
|
||||
# libunwind conflict on 22.04, can live without libjemalloc there
|
||||
if [ "$DISTRO_VERSION" != "22.04" ]; then
|
||||
PACKAGES+=(libjemalloc-dev)
|
||||
fi
|
||||
sudo apt-get update ||
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes "${PACKAGES[@]}" ||
|
||||
sudo apt-get install --yes "${PACKAGES[@]}"
|
||||
fi
|
||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
||||
sudo apt-get install --yes bear mold ||
|
||||
sudo apt-get install --yes bear mold
|
||||
fi
|
||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
||||
elif [ "$HOST_OS" = "macOS" ]; then
|
||||
PACKAGES=(
|
||||
autoconf
|
||||
bison
|
||||
ccache
|
||||
flex
|
||||
gperftools
|
||||
help2man
|
||||
perl
|
||||
)
|
||||
brew update ||
|
||||
brew update
|
||||
brew install ccache perl gperftools autoconf bison flex help2man ||
|
||||
brew install ccache perl gperftools autoconf bison flex help2man
|
||||
elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
||||
sudo pkg install -y autoconf bison ccache gmake perl5
|
||||
brew install "${PACKAGES[@]}" ||
|
||||
brew install "${PACKAGES[@]}"
|
||||
else
|
||||
fatal "Unknown CI_OS_NAME: '$CI_OS_NAME'"
|
||||
fatal "Unknown HOST_OS: '$HOST_OS'"
|
||||
fi
|
||||
|
||||
if [ -n "$CCACHE_DIR" ]; then
|
||||
mkdir -p "$CCACHE_DIR"
|
||||
fi
|
||||
elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
||||
elif [ "$STAGE" = "test" ]; then
|
||||
##############################################################################
|
||||
# Dependencies of jobs in the 'test' stage, i.e.: packages required to
|
||||
# run the tests
|
||||
|
||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
||||
sudo apt-get update ||
|
||||
sudo apt-get update
|
||||
# libfl-dev needed for internal coverage's test runs
|
||||
sudo apt-get install --yes gdb gtkwave lcov libfl-dev ccache jq z3 ||
|
||||
sudo apt-get install --yes gdb gtkwave lcov libfl-dev ccache jq z3
|
||||
# Required for test_regress/t/t_dist_attributes.py
|
||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
||||
sudo apt-get install --yes python3-clang mold ||
|
||||
sudo apt-get install --yes python3-clang mold
|
||||
if [ "$HOST_OS" = "linux" ]; then
|
||||
if [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||
PACKAGES=(
|
||||
ccache
|
||||
gdb
|
||||
jq
|
||||
lcov
|
||||
libfl-dev
|
||||
libsystemc-dev
|
||||
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
|
||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
||||
if [[ ! "$CI_RUNS_ON" =~ "-riscv" ]]; then
|
||||
sudo apt-get install --yes libsystemc libsystemc-dev ||
|
||||
sudo apt-get install --yes libsystemc libsystemc-dev
|
||||
fi
|
||||
fi
|
||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
||||
elif [ "$HOST_OS" = "macOS" ]; then
|
||||
PACKAGES=(
|
||||
ccache
|
||||
jq
|
||||
perl
|
||||
z3
|
||||
)
|
||||
brew update ||
|
||||
brew update
|
||||
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
|
||||
brew install ccache perl jq z3
|
||||
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
|
||||
brew install "${PACKAGES[@]}" ||
|
||||
brew install "${PACKAGES[@]}"
|
||||
else
|
||||
fatal "Unknown CI_OS_NAME: '$CI_OS_NAME'"
|
||||
fatal "Unknown HOST_OS: '$HOST_OS'"
|
||||
fi
|
||||
# Common installs
|
||||
install-wavediff
|
||||
|
|
@ -146,5 +149,13 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|||
else
|
||||
##############################################################################
|
||||
# Unknown build stage
|
||||
fatal "Unknown CI_BUILD_STAGE_NAME: '$CI_BUILD_STAGE_NAME'"
|
||||
fatal "Unknown stage '$STAGE' (expected 'build' or 'test')"
|
||||
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
|
||||
gh pr comment $(cat ${ARTIFACTS_DIR}/pr-number.txt) --body-file ${ARTIFACTS_DIR}/body.txt
|
||||
|
||||
# Get the artifact ID
|
||||
ARTIFACT_ID=$(gh api "repos/{owner}/{repo}/actions/runs/${RUN_ID}/artifacts" --jq '.artifacts[] | select(.name == "pr-notification") | .id')
|
||||
# Get the artifact IDs. Note there can be more than one artifact named
|
||||
# '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
|
||||
gh api --method DELETE "repos/{owner}/{repo}/actions/artifacts/${ARTIFACT_ID}"
|
||||
# Delete them all, so we only notify once
|
||||
for ARTIFACT_ID in ${ARTIFACT_IDS}; do
|
||||
gh api --method DELETE "repos/{owner}/{repo}/actions/artifacts/${ARTIFACT_ID}"
|
||||
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
|
||||
|
||||
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
|
||||
cd winflexbison
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. --install-prefix $PWD/../../../.ccache
|
||||
cmake --build . --config Release -j 3
|
||||
cmake --install . --prefix $PWD/../../../.ccache
|
||||
cmake .. --install-prefix $env:WIN_FLEX_BISON
|
||||
cmake --build . --config Release -j $NPROC
|
||||
cmake --install . --prefix $env:WIN_FLEX_BISON
|
||||
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
|
||||
cd build
|
||||
cmake .. --install-prefix $PWD/../install
|
||||
cmake --build . --config Release -j 3
|
||||
# Ninja saturates all cores; the MSBuild generator only parallelizes across
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -7,13 +7,17 @@
|
|||
|
||||
Set-PSDebug -Trace 1
|
||||
|
||||
$NPROC = $env:NUMBER_OF_PROCESSORS
|
||||
|
||||
cd install
|
||||
$Env:VERILATOR_ROOT=$PWD
|
||||
cd examples/cmake_tracing_c
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build . --config Release -j 3
|
||||
# /Od skips optimization; this only checks the example verilates and builds, so
|
||||
# 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
|
||||
# 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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
=====================================
|
||||
|
|
|
|||
30
configure.ac
30
configure.ac
|
|
@ -12,7 +12,7 @@
|
|||
# Then 'make maintainer-dist'
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[5.049 devel],
|
||||
AC_INIT([Verilator],[5.051 devel],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
|
||||
|
|
@ -589,6 +589,34 @@ m4_foreach([ldflag], [
|
|||
AC_SUBST(CFG_LDLIBS_THREADS)
|
||||
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
|
||||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -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
|
||||
=========================
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
|||
|
||||
404allen404
|
||||
Adam Bagley
|
||||
Adam Kostrzewski
|
||||
Adrian Sampson
|
||||
Adrien Le Masle
|
||||
أحمد المحمودي (Ahmed El-Mahmoudy)
|
||||
|
|
@ -60,6 +61,7 @@ David Turner
|
|||
Dercury
|
||||
Diego Roux
|
||||
Dominick Grochowina
|
||||
Dragon-Git
|
||||
Don Williamson
|
||||
Drew Ranck
|
||||
Drew Taussig
|
||||
|
|
@ -68,6 +70,7 @@ Edgar E. Iglesias
|
|||
Eric Mejdrich
|
||||
Eric Müller
|
||||
Eric Rippey
|
||||
Eryk Szpotański
|
||||
Eunseo Song
|
||||
Ethan Sifferman
|
||||
Eyck Jentzsch
|
||||
|
|
@ -145,6 +148,7 @@ Jose Loyola
|
|||
Josep Sans
|
||||
Joseph Nwabueze
|
||||
Josh Redford
|
||||
Joshua Leahy
|
||||
Julian Carrier
|
||||
Julian Daube
|
||||
Julie Schwartz
|
||||
|
|
@ -158,6 +162,7 @@ Kefa Chen
|
|||
Keith Colbert
|
||||
Kevin Kiningham
|
||||
Kevin Nygaard
|
||||
Kornel Uriasz
|
||||
Kritik Bhimani
|
||||
Krzysztof Bieganski
|
||||
Krzysztof Boronski
|
||||
|
|
@ -250,10 +255,12 @@ Rowan Goemans
|
|||
Rupert Swarbrick
|
||||
Ryan Ziegler
|
||||
Ryszard Rozak
|
||||
Saksham Gupta
|
||||
Samuel Riedel
|
||||
Sean Cross
|
||||
Sebastien Van Cauwenberghe
|
||||
Secturion
|
||||
Sergey Chusov
|
||||
Sergey Fedorov
|
||||
Sergi Granell
|
||||
Seth Pellegrino
|
||||
|
|
@ -270,12 +277,14 @@ Teng Huang
|
|||
Thomas Aldrian
|
||||
Thomas Brown
|
||||
Thomas Dybdahl Ahle
|
||||
Thomas Santerre
|
||||
Tim Hutt
|
||||
Tim Snyder
|
||||
Tobias Jensen
|
||||
Tobias Rosenkranz
|
||||
Tobias Wölfel
|
||||
Todd Strader
|
||||
Tom Jackson
|
||||
Tom Manner
|
||||
Tomasz Gorochowik
|
||||
Topa Topino
|
||||
|
|
@ -297,6 +306,7 @@ Vito Gamberini
|
|||
Wei-Lun Chiu
|
||||
William D. Jones
|
||||
Wilson Snyder
|
||||
Wolfgang Mayerwieser
|
||||
Xi Zhang
|
||||
Yan Xu
|
||||
Yangyu Chen
|
||||
|
|
@ -326,3 +336,4 @@ Yogish Sekhar
|
|||
Zubin Jain
|
||||
Muzaffer Kal
|
||||
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
|
||||
=======================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
@ -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:
|
||||
|
||||
* 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.
|
||||
|
||||
* 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.
|
||||
|
||||
* 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
|
||||
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
|
||||
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.
|
||||
|
||||
* 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.
|
||||
|
||||
* Accessing any other internal members, including
|
||||
``/* verilator public_flat */`` items requires the following changes:
|
||||
- Accessing any other internal members, including ``/* verilator
|
||||
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
|
||||
``__024`` substring is the Verilator escape sequence for the ``$``
|
||||
character, i.e.: ``rootp`` points to the Verilated SystemVerilog
|
||||
``$root`` scope.
|
||||
|
||||
* Replace ``modelp->internal->member`` references with
|
||||
- Replace ``modelp->internal->member`` references with
|
||||
``modelp->rootp->internal->member`` references, which contain one
|
||||
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
|
||||
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());
|
||||
|
||||
|
|
@ -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
|
||||
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,
|
||||
* ``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
|
||||
``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
|
||||
|
|
@ -86,7 +87,8 @@ Please refer to `sv-bugpoint README
|
|||
<https://github.com/antmicro/sv-bugpoint/blob/main/README.md>`_ for more
|
||||
information on how to use `sv-bugpoint`.
|
||||
|
||||
.. Contributing
|
||||
.. ============
|
||||
..
|
||||
Contributing
|
||||
============
|
||||
|
||||
.. 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
|
||||
|
|
@ -29,10 +30,10 @@ Alliance <https://chipsalliance.org>`_, and `Antmicro Ltd
|
|||
Previous major corporate sponsors of Verilator, by providing significant
|
||||
contributions of time or funds include: Antmicro Ltd., Atmel Corporation,
|
||||
Compaq Corporation, Digital Equipment Corporation, Embecosm Ltd., Fractile
|
||||
Ltd., Hicamp Systems, Intel Corporation, Marvell Inc., Mindspeed Technologies
|
||||
Inc., MicroTune Inc., picoChip Designs Ltd., Sun Microsystems Inc., Nauticus
|
||||
Networks Inc., SiCortex Inc, Shunyao CAD, Tenstorrent USA, Inc. and Western
|
||||
Digital Inc.
|
||||
Ltd., Hicamp Systems, Intel Corporation, Marvell Inc., Mindspeed
|
||||
Technologies Inc., MicroTune Inc., picoChip Designs Ltd., Sun Microsystems
|
||||
Inc., Nauticus Networks Inc., SiCortex Inc, Shunyao CAD, Tenstorrent USA,
|
||||
Inc. and Western Digital Inc.
|
||||
|
||||
The contributors of major functionality are: Jeremy Bennett, Krzysztof
|
||||
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,
|
||||
Vassilis Papaefstathiou, Sanggyu Park, Brad Parker, Risto Pejašinović, Seth
|
||||
Pellegrino, Joel Peltonen, Morten Borup Petersen, Dan Petrisko, Thanh Tung
|
||||
Pham, Wesley Piard, Maciej Piechotka, David Pierce, Cody Piersall,
|
||||
T. Platz, Michael Platzer, Dominic Plunkett, Nolan Poe, Tuomas Poikela,
|
||||
George Polack, David Poole, Michael Popoloski, Roman Popov, Aylon Chaim
|
||||
Porat, Oron Port, Rich Porter, Rick Porter, Stefan Post, Niranjan Prabhu,
|
||||
Damien Pretet, Harald Pretl, Bill Pringlemeir, Usha Priyadharshini, Mark
|
||||
Jackson Pulver, Prateek Puri, Nikolay Puzanov, Han Qi, Jiacheng Qian,
|
||||
Marshal Qiao, Raynard Qiao, Yujia Qiao, Jasen Qin, Frank Qiu, Nandu Raj,
|
||||
Kamil Rakoczy, Danilo Ramos, Drew Ranck, Chris Randall, Anton Rapp, Josh
|
||||
Redford, Odd Magne Reitan, Frédéric Requin, Wajahat Riaz, Dustin Richmond,
|
||||
Samuel Riedel, Alberto Del Rio, Eric Rippey, Narcis Rodas, Oleg Rodionov,
|
||||
Ludwig Rogiers, Paul Rolfe, Michail Rontionov, Arjen Roodselaar, Arthur
|
||||
Rosa, Tobias Rosenkranz, Yernagula Roshit, Diego Roux, Ryszard Rozak, Dan
|
||||
Pham, Wesley Piard, Maciej Piechotka, David Pierce, Cody Piersall, T.
|
||||
Platz, Michael Platzer, Dominic Plunkett, Nolan Poe, Tuomas Poikela, George
|
||||
Polack, David Poole, Michael Popoloski, Roman Popov, Aylon Chaim Porat,
|
||||
Oron Port, Rich Porter, Rick Porter, Stefan Post, Niranjan Prabhu, Damien
|
||||
Pretet, Harald Pretl, Bill Pringlemeir, Usha Priyadharshini, Mark Jackson
|
||||
Pulver, Prateek Puri, Nikolay Puzanov, Han Qi, Jiacheng Qian, Marshal Qiao,
|
||||
Raynard Qiao, Yujia Qiao, Jasen Qin, Frank Qiu, Nandu Raj, Kamil Rakoczy,
|
||||
Danilo Ramos, Drew Ranck, Chris Randall, Anton Rapp, Josh Redford, Odd
|
||||
Magne Reitan, Frédéric Requin, Wajahat Riaz, Dustin Richmond, Samuel
|
||||
Riedel, Alberto Del Rio, Eric Rippey, Narcis Rodas, Oleg Rodionov, Ludwig
|
||||
Rogiers, Paul Rolfe, Michail Rontionov, Arjen Roodselaar, Arthur Rosa,
|
||||
Tobias Rosenkranz, Yernagula Roshit, Diego Roux, Ryszard Rozak, Dan
|
||||
Ruelas-Petrisko, Luca Rufer, Huang Rui, Graham Rushton, Jan Egil Ruud,
|
||||
Denis Rystsov, Pawel Sagan, Robert Sammelson, Adrian Sampson, John
|
||||
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:
|
||||
|
||||
|
|
@ -187,6 +188,10 @@ The grammar of control commands is as follows:
|
|||
|
||||
.. 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
|
||||
should be isolated into new blocks. Same as
|
||||
: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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
============
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
@ -9,10 +10,10 @@ Examples
|
|||
|
||||
This section covers the following examples:
|
||||
|
||||
* :ref:`Example Create-Binary Execution`
|
||||
* :ref:`Example C++ Execution`
|
||||
* :ref:`Example SystemC Execution`
|
||||
* :ref:`Examples in the Distribution`
|
||||
- :ref:`Example Create-Binary Execution`
|
||||
- :ref:`Example C++ Execution`
|
||||
- :ref:`Example SystemC Execution`
|
||||
- :ref:`Examples in the Distribution`
|
||||
|
||||
.. toctree::
|
||||
: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:
|
||||
|
||||
|
|
@ -50,8 +51,8 @@ Options:
|
|||
|
||||
.. option:: +verilator+log+file+<filename>
|
||||
|
||||
Log all stdout and stderr to the specified output filename. If not specified
|
||||
the normal stdout/stderr streams are used.
|
||||
Log all stdout and stderr to the specified output filename. If not specified
|
||||
the normal stdout/stderr streams are used.
|
||||
|
||||
.. option:: +verilator+noassert
|
||||
|
||||
|
|
@ -138,6 +139,20 @@ Options:
|
|||
|
||||
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>
|
||||
|
||||
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
|
||||
|
|
@ -490,6 +491,10 @@ Summary:
|
|||
Rarely needed - for developer use. Enable all dumping in the given
|
||||
source file at level 3.
|
||||
|
||||
.. option:: --dump-ast-patterns
|
||||
|
||||
Rarely needed. Enable dumping AstNodeExpr pattern statistics.
|
||||
|
||||
.. option:: --dump-defines
|
||||
|
||||
With :vlopt:`-E`, suppress normal output, and instead print a list of
|
||||
|
|
@ -657,8 +662,28 @@ Summary:
|
|||
|
||||
.. option:: -fno-assemble
|
||||
|
||||
.. option:: -fno-bit-scan-loops
|
||||
|
||||
Rarely needed. Disable converting bit counting loops into built-in operations.
|
||||
|
||||
.. 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-const
|
||||
|
|
@ -737,12 +762,41 @@ Summary:
|
|||
this is not recommended as may cause additional warnings and ordering
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
Rarely needed. Disable inlining of SystemVerilog functions and tasks.
|
||||
|
||||
.. option:: -fno-inline-funcs-eager
|
||||
|
||||
Rarely needed. Disable eager inlining of SystemVerilog functions and tasks.
|
||||
|
||||
.. option:: -fno-life
|
||||
|
||||
.. option:: -fno-life-post
|
||||
|
|
@ -944,27 +998,21 @@ Summary:
|
|||
|
||||
.. option:: --inline-cfuncs <value>
|
||||
|
||||
Inline small C++ function (internal AstCFunc) calls directly into their
|
||||
callers when the function has at most <value> nodes. This reduces
|
||||
function call overhead when :vlopt:`--output-split-cfuncs` places
|
||||
functions in separate compilation units that the C++ compiler cannot
|
||||
inline.
|
||||
Tune the inlining of small generated C++ function. Functions no bigger than
|
||||
<value> nodes will be inlined if possible. The default is 20.
|
||||
|
||||
Set to 0 to disable this optimization. The default is 20.
|
||||
|
||||
This optimization is automatically disabled when :vlopt:`--prof-cfuncs`
|
||||
or :vlopt:`--trace` is used.
|
||||
See also :vlopt:`--inline-cfuncs-product` and :vlopt:`-fno-inline-cfuncs`.
|
||||
|
||||
.. option:: --inline-cfuncs-product <value>
|
||||
|
||||
Tune the inlining of C++ function (internal AstCFunc) calls for larger
|
||||
functions. When a function is too large to always inline (exceeds
|
||||
:vlopt:`--inline-cfuncs` threshold), it may still be inlined if the
|
||||
function size multiplied by the number of call sites is at most <value>.
|
||||
Tune the inlining of small generated C++ function. If a function's node
|
||||
count multiplied by the number of calls is not bigger than <value>, the
|
||||
function will be inlined if possible.
|
||||
|
||||
This allows functions that are called only once or twice to be inlined
|
||||
even if they exceed the small function threshold. Set to 0 to only inline
|
||||
functions below the :vlopt:`--inline-cfuncs` threshold. The default is 200.
|
||||
This allows functions that are called only once or twice to be inlined even
|
||||
if they exceed the small function threshold. The default is 200.
|
||||
|
||||
See also :vlopt:`--inline-cfuncs` and :vlopt:`-fno-inline-cfuncs`.
|
||||
|
||||
.. 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
|
||||
==================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
===============
|
||||
|
|
|
|||
|
|
@ -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
|
||||
===================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -341,6 +342,10 @@ or "`ifdef`"'s may break other tools.
|
|||
|
||||
.. 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
|
||||
signal in any blocks should be isolated into new blocks. When large
|
||||
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
|
||||
|
|
@ -82,17 +83,17 @@ the licenses for details.
|
|||
|
||||
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
|
||||
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
|
||||
Lesser Public License.
|
||||
|
||||
|
|
@ -384,33 +385,33 @@ example of how to do this.
|
|||
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
|
||||
file is large enough to be split due to the :vlopt:`--output-split`
|
||||
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
|
||||
disabled on these routines. See the OPT_FAST and OPT_SLOW make variables
|
||||
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
|
||||
between identical source builds, even across different users. If ccache
|
||||
was installed when Verilator was built, it is used, or see OBJCACHE
|
||||
environment variable to override this. Also see the
|
||||
: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
|
||||
:option:`/*verilator&32;no_inline_module*/` metacomment to your top-level
|
||||
module. This will decrease the amount of code in the model's Verilated
|
||||
class, improving compile times of any instantiating top-level C++ code,
|
||||
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?
|
||||
|
|
@ -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
|
||||
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.)
|
||||
|
||||
* 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
|
||||
that is instantiated many times; in this case, Verilating one of the
|
||||
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
|
||||
|
|
@ -42,138 +43,141 @@ For --cc/--sc, it creates:
|
|||
|
||||
.. list-table::
|
||||
|
||||
* - *{prefix}*.json
|
||||
- - *{prefix}*.json
|
||||
- JSON build definition compiling (from --make json)
|
||||
* - *{prefix}*.mk
|
||||
- - *{prefix}*.mk
|
||||
- Make include file for compiling (from --make gmake)
|
||||
* - *{prefix}*\ _classes.mk
|
||||
- - *{prefix}*\ _classes.mk
|
||||
- Make include file with class names (from --make gmake)
|
||||
* - *{prefix}*.h
|
||||
- - *{prefix}*.h
|
||||
- Model header
|
||||
* - *{prefix}*.cpp
|
||||
- - *{prefix}*.cpp
|
||||
- Model C++ file
|
||||
* - *{prefix}*\ ___024root.h
|
||||
- - *{prefix}*\ ___024root.h
|
||||
- Top-level internal header file (from SystemVerilog $root)
|
||||
* - *{prefix}*\ ___024root.cpp
|
||||
- - *{prefix}*\ ___024root.cpp
|
||||
- Top-level internal C++ file (from SystemVerilog $root)
|
||||
* - *{prefix}*\ ___024root\ *{__n}*.cpp
|
||||
- - *{prefix}*\ ___024root\ *{__n}*.cpp
|
||||
- Additional top-level internal C++ files
|
||||
* - *{prefix}*\ ___024root__Slow\ *{__n}*.cpp
|
||||
- - *{prefix}*\ ___024root__Slow\ *{__n}*.cpp
|
||||
- Infrequent cold routines
|
||||
* - *{prefix}*\ ___024root__Trace\ *{__n}*.cpp
|
||||
- - *{prefix}*\ ___024root__Trace\ *{__n}*.cpp
|
||||
- Wave file generation code (from --trace-\*)
|
||||
* - *{prefix}*\ ___024root__Trace__Slow\ *{__n}*.cpp
|
||||
- - *{prefix}*\ ___024root__Trace__Slow\ *{__n}*.cpp
|
||||
- Wave file generation code (from --trace-\*)
|
||||
* - *{prefix}*\ __Dpi.h
|
||||
- - *{prefix}*\ __Dpi.h
|
||||
- DPI import and export declarations (from --dpi)
|
||||
* - *{prefix}*\ __Dpi.cpp
|
||||
- - *{prefix}*\ __Dpi.cpp
|
||||
- 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)
|
||||
* - *{prefix}*\ __Inlines.h
|
||||
- - *{prefix}*\ __Inlines.h
|
||||
- Inline support functions
|
||||
* - *{prefix}*\ __Syms.h
|
||||
- - *{prefix}*\ __Syms.h
|
||||
- Global symbol table header
|
||||
* - *{prefix}*\ __Syms.cpp
|
||||
- - *{prefix}*\ __Syms.cpp
|
||||
- Global symbol table C++
|
||||
* - *{prefix}{each_verilog_module}*.h
|
||||
- - *{prefix}{each_verilog_module}*.h
|
||||
- Lower level internal header files
|
||||
* - *{prefix}{each_verilog_module}*.cpp
|
||||
- - *{prefix}{each_verilog_module}*.cpp
|
||||
- Lower level internal C++ files
|
||||
* - *{prefix}{each_verilog_module}{__n}*.cpp
|
||||
- - *{prefix}{each_verilog_module}{__n}*.cpp
|
||||
- Additional lower C++ files
|
||||
|
||||
For --hierarchical mode, it creates:
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - V\ *{hier_block}*\ /
|
||||
- - V\ *{hier_block}*/
|
||||
- Directory to Verilate each hierarchical block (from --hierarchical)
|
||||
* - *{prefix}*\ __hierVer.d
|
||||
- - *{prefix}*\ __hierVer.d
|
||||
- Make dependencies of the top module (from --hierarchical)
|
||||
* - *{prefix}*\ _hier.mk
|
||||
- - *{prefix}*\ _hier.mk
|
||||
- Make file for hierarchical blocks (from --make gmake)
|
||||
* - *{prefix}*\ __hierMkJsonArgs.f
|
||||
- - *{prefix}*\ __hierMkJsonArgs.f
|
||||
- Arguments for hierarchical Verilation (from --make json)
|
||||
* - *{prefix}*\ __hierMkArgs.f
|
||||
- - *{prefix}*\ __hierMkArgs.f
|
||||
- Arguments for hierarchical Verilation (from --make gmake)
|
||||
* - *{prefix}*\ __hierParameters.v
|
||||
- - *{prefix}*\ __hierParameters.v
|
||||
- Module parameters for hierarchical blocks
|
||||
* - *{prefix}*\ __hier.dir
|
||||
- Directory to store .dot, .vpp, .tree of top module (from --hierarchical)
|
||||
- - *{prefix}*\ __hier.dir
|
||||
- Directory to store .dot, .vpp, .tree of top module (from
|
||||
--hierarchical)
|
||||
|
||||
In specific debug and other modes, it also creates:
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - *{prefix}*.sarif
|
||||
- - *{prefix}*.sarif
|
||||
- SARIF diagnostics (from --diagnostics-sarif)
|
||||
* - *{prefix}*.tree.json
|
||||
- - *{prefix}*.tree.json
|
||||
- JSON tree information (from --json-only)
|
||||
* - *{prefix}*.tree.meta.json
|
||||
- - *{prefix}*.tree.meta.json
|
||||
- JSON tree metadata (from --json-only)
|
||||
* - *{prefix}*\ __cdc.txt
|
||||
- - *{prefix}*\ __cdc.txt
|
||||
- Clock Domain Crossing checks (from --cdc)
|
||||
* - *{prefix}*\ __stats.txt
|
||||
- - *{prefix}*\ __stats.txt
|
||||
- Statistics (from --stats)
|
||||
* - *{prefix}*\ __idmap.txt
|
||||
- - *{prefix}*\ __idmap.txt
|
||||
- Symbol demangling (from --protect-ids)
|
||||
* - *{prefix}*\ __ver.d
|
||||
- - *{prefix}*\ __ver.d
|
||||
- Make dependencies (from -MMD)
|
||||
* - *{prefix}*\ __verFiles.dat
|
||||
- - *{prefix}*\ __verFiles.dat
|
||||
- Timestamps (from --skip-identical)
|
||||
* - *{prefix}{misc}*.dot
|
||||
- - *{prefix}{misc}*.dot
|
||||
- Debugging graph files (from --debug)
|
||||
* - *{prefix}{misc}*.tree
|
||||
- - *{prefix}{misc}*.tree
|
||||
- Debugging files (from --debug)
|
||||
* - *{prefix}*\ __inputs.vpp
|
||||
- - *{prefix}*\ __inputs.vpp
|
||||
- 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)
|
||||
|
||||
After running Make, the C++ compiler may produce the following:
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - verilated{misc}*.d
|
||||
- - verilated{misc}*.d
|
||||
- Intermediate dependencies
|
||||
* - verilated{misc}*.o
|
||||
- - verilated{misc}*.o
|
||||
- Intermediate objects
|
||||
* - {mod_prefix}{misc}*.d
|
||||
- - {mod_prefix}{misc}*.d
|
||||
- Intermediate dependencies
|
||||
* - {mod_prefix}{misc}*.o
|
||||
- - {mod_prefix}{misc}*.o
|
||||
- Intermediate objects
|
||||
* - *{prefix}*\
|
||||
- - *{prefix}*\
|
||||
- Final executable (from --exe)
|
||||
* - lib\ *{prefix}*.a
|
||||
- - lib\ *{prefix}*.a
|
||||
- Final archive (default lib mode)
|
||||
* - libverilated.a
|
||||
- - libverilated.a
|
||||
- Runtime for verilated model (default lib mode)
|
||||
* - *{prefix}*\ __ALL.a
|
||||
- - *{prefix}*\ __ALL.a
|
||||
- Library of all Verilated objects
|
||||
* - *{prefix}*\ __ALL.cpp
|
||||
- - *{prefix}*\ __ALL.cpp
|
||||
- Include of all code for single compile
|
||||
* - *{prefix}{misc}*.d
|
||||
- - *{prefix}{misc}*.d
|
||||
- Intermediate dependencies
|
||||
* - *{prefix}{misc}*.o
|
||||
- - *{prefix}{misc}*.o
|
||||
- Intermediate objects
|
||||
|
||||
The Verilated executable may produce the following:
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - coverage.dat
|
||||
- Code coverage output, and default input filename for :command:`verilator_coverage`
|
||||
* - gmon.out
|
||||
- GCC/clang code profiler output, often fed into :command:`verilator_profcfunc`
|
||||
* - profile.vlt
|
||||
- - coverage.dat
|
||||
- Code coverage output, and default input filename for
|
||||
:command:`verilator_coverage`
|
||||
- - gmon.out
|
||||
- GCC/clang code profiler output, often fed into
|
||||
:command:`verilator_profcfunc`
|
||||
- - profile.vlt
|
||||
- --prof-pgo data file for :ref:`Thread PGO`
|
||||
* - profile_exec.dat
|
||||
- - profile_exec.dat
|
||||
- --prof-exec data file for :command:`verilator_gantt`
|
||||
|
||||
Verilator_gantt may produce the following:
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - profile_exec.vcd
|
||||
- - profile_exec.vcd
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
@ -16,16 +17,16 @@ Linux).
|
|||
Quick Install
|
||||
=============
|
||||
|
||||
1. Install Python for your platform from https://www.python.org/downloads/.
|
||||
2. Install CMake for your platform from https://cmake.org/download/ or
|
||||
#. Install Python for your platform from https://www.python.org/downloads/.
|
||||
#. Install CMake for your platform from https://cmake.org/download/ or
|
||||
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
|
||||
choice is Clang, then install https://releases.llvm.org/download.html or
|
||||
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.
|
||||
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
|
||||
the environment variable FLEX_INCLUDE to the directory containing
|
||||
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:
|
||||
|
||||
|
|
@ -384,12 +385,10 @@ the files:
|
|||
|
||||
make install
|
||||
|
||||
|
||||
.. Docker Build Environment
|
||||
|
||||
.. include:: ../../ci/docker/buildenv/README.rst
|
||||
|
||||
|
||||
.. Docker Run Environment
|
||||
|
||||
.. 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
|
||||
|
|
@ -102,11 +103,11 @@ Time
|
|||
|
||||
With :vlopt:`--timing`, all timing controls are supported:
|
||||
|
||||
* delay statements,
|
||||
* event control statements not only at the top of a process,
|
||||
* intra-assignment timing controls,
|
||||
* net delays,
|
||||
* ``wait`` statements,
|
||||
- delay statements,
|
||||
- event control statements not only at the top of a process,
|
||||
- intra-assignment timing controls,
|
||||
- net delays,
|
||||
- ``wait`` statements,
|
||||
|
||||
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`
|
||||
error, except:
|
||||
|
||||
* delay statements - they are ignored (as they are in synthesis), though they
|
||||
do issue a :option:`STMTDLY` warning,
|
||||
* intra-assignment timing controls - they are ignored, though they do issue
|
||||
- delay statements - they are ignored (as they are in synthesis), though
|
||||
they do issue a :option:`STMTDLY` warning,
|
||||
- intra-assignment timing controls - they are ignored, though they do issue
|
||||
an :option:`ASSIGNDLY` warning,
|
||||
* net delays - they are ignored,
|
||||
* event controls at the top of the procedure,
|
||||
- net delays - they are ignored,
|
||||
- event controls at the top of the procedure,
|
||||
|
||||
Forks cause this error as well, except:
|
||||
|
||||
* forks with no statements,
|
||||
* ``fork..join`` or ``fork..join_any`` with one statement,
|
||||
* forks with :vlopt:`--bbox-unsup`.
|
||||
- forks with no statements,
|
||||
- ``fork..join`` or ``fork..join_any`` with one statement,
|
||||
- forks with :vlopt:`--bbox-unsup`.
|
||||
|
||||
If neither :vlopt:`--timing` nor :vlopt:`--no-timing` is specified, all
|
||||
timing controls cause the :option:`NEEDTIMINGOPT` error, except event
|
||||
controls at the top of the process. Forks cause this error as well, except:
|
||||
|
||||
* forks with no statements,
|
||||
* ``fork..join`` or ``fork..join_any`` with one statement,
|
||||
* forks with :vlopt:`--bbox-unsup`.
|
||||
- forks with no statements,
|
||||
- ``fork..join`` or ``fork..join_any`` with one statement,
|
||||
- forks with :vlopt:`--bbox-unsup`.
|
||||
|
||||
Timing controls and forks can also be ignored in specific files or parts of
|
||||
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
|
||||
|
|
@ -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
|
||||
version of this standard.
|
||||
|
||||
.. [#] SystemVerilog is defined by the `Institute of Electrical and
|
||||
Electronics Engineers (IEEE) Standard for SystemVerilog - Unified
|
||||
Hardware Design, Specification, and Verification Language`, Standard
|
||||
1800, released in 2005, 2009, 2012, 2017, and 2023. The Verilator
|
||||
documentation uses the shorthand e.g., "IEEE 1800-2023", to refer to
|
||||
the, e.g., 2023 version of this standard.
|
||||
.. [#] SystemVerilog is defined by the `Institute of Electrical and Electronics
|
||||
Engineers (IEEE) Standard for SystemVerilog - Unified Hardware Design,
|
||||
Specification, and Verification Language`, Standard 1800, released in
|
||||
2005, 2009, 2012, 2017, and 2023. The Verilator documentation uses the
|
||||
shorthand e.g., "IEEE 1800-2023", to refer to the, e.g., 2023 version of
|
||||
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:
|
||||
|
||||
|
|
@ -209,7 +210,8 @@ For simple coverage points, use the ``cover property`` construct:
|
|||
|
||||
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:
|
||||
|
||||
|
|
@ -218,8 +220,8 @@ Covergroup Coverage
|
|||
|
||||
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
|
||||
translate covergroup coverage points the user has inserted manually in
|
||||
SystemVerilog code into the Verilated model. Verilator supports
|
||||
coverpoints with value and transition bins, and cross points.
|
||||
SystemVerilog code into the Verilated model. Verilator supports coverpoints
|
||||
with value and transition bins, and cross points.
|
||||
|
||||
|
||||
.. _fsm coverage:
|
||||
|
|
@ -244,15 +246,15 @@ encodings in these common forms:
|
|||
- Single-process FSMs, whose state dispatch is written as ``case (state)``
|
||||
or as a top-level ``if`` / ``else if`` chain comparing the same state
|
||||
variable against known state values
|
||||
- Two-process and three-block FSMs, where a clocked state register is paired
|
||||
with a combinational next-state block using the same supported
|
||||
- Two-process and three-block FSMs, where a clocked state register is
|
||||
paired with a combinational next-state block using the same supported
|
||||
``case`` or top-level ``if`` / ``else if`` dispatch forms
|
||||
|
||||
Scalar state encodings may be wider than 32 bits. This allows sparse
|
||||
state encodings, such as high-Hamming-distance enum or localparam values,
|
||||
to be preserved in the detected FSM model. Verilator uses the declared
|
||||
enum item name, parameter name, or localparam name as the reported state
|
||||
label where possible.
|
||||
Scalar state encodings may be wider than 32 bits. This allows sparse state
|
||||
encodings, such as high-Hamming-distance enum or localparam values, to be
|
||||
preserved in the detected FSM model. Verilator uses the declared enum item
|
||||
name, parameter name, or localparam name as the reported state label where
|
||||
possible.
|
||||
|
||||
Simple input guards are supported when they appear inside a recognized
|
||||
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 extracted coverage model:
|
||||
|
||||
- ``/*verilator fsm_state*/`` forces the variable to be treated as
|
||||
FSM state.
|
||||
- ``/*verilator fsm_reset_arc*/`` marks reset transitions as
|
||||
user-visible reset arcs instead of defaulting to a hidden reset-only
|
||||
summary.
|
||||
- ``/*verilator fsm_arc_include_cond*/`` keeps conditional branch
|
||||
arcs that would otherwise be skipped by the conservative extractor.
|
||||
- ``/*verilator fsm_state*/`` forces the variable to be treated as FSM
|
||||
state.
|
||||
- ``/*verilator fsm_reset_arc*/`` marks reset transitions as user-visible
|
||||
reset arcs instead of defaulting to a hidden reset-only summary.
|
||||
- ``/*verilator fsm_arc_include_cond*/`` keeps conditional branch arcs that
|
||||
would otherwise be skipped by the conservative extractor.
|
||||
|
||||
State registers may also be wrapped by a transparent instance, for
|
||||
example a project flop wrapper or primitive. Such wrappers must be
|
||||
described explicitly with a VLT command file action before Verilator will
|
||||
use their data, state, clock, or reset connections for FSM extraction:
|
||||
State registers may also be wrapped by a transparent instance, for example
|
||||
a project flop wrapper or primitive. Such wrappers must be described
|
||||
explicitly with a VLT command file action before Verilator will use their
|
||||
data, state, clock, or reset connections for FSM extraction:
|
||||
|
||||
.. 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" \
|
||||
-reset "rst_ni" -reset_value "ResetValue"
|
||||
|
||||
Reset arcs are emitted only when the configured reset port has an
|
||||
inferable edge in the wrapper and the configured reset value parameter is
|
||||
statically resolvable. If reset metadata is incomplete, Verilator warns
|
||||
and may still emit FSM state and transition coverage, but reset arcs are
|
||||
omitted.
|
||||
Reset arcs are emitted only when the configured reset port has an inferable
|
||||
edge in the wrapper and the configured reset value parameter is statically
|
||||
resolvable. If reset metadata is incomplete, Verilator warns and may still
|
||||
emit FSM state and transition coverage, but reset arcs are omitted.
|
||||
|
||||
Reset transitions are included in the collected data either way. By
|
||||
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:
|
||||
|
||||
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
|
||||
: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
|
||||
the filename for the coverage data file to write coverage data to
|
||||
(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:
|
||||
|
||||
* 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\>`.
|
||||
|
||||
* 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
|
||||
Verilator internals document (:file:`docs/internals.rst` in the
|
||||
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
|
||||
the lowest, which means performing them separately and in this order:
|
||||
|
||||
* :ref:`Thread PGO`
|
||||
* :ref:`Compiler PGO`
|
||||
- :ref:`Thread PGO`
|
||||
- :ref:`Compiler PGO`
|
||||
|
||||
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
|
||||
|
|
@ -674,7 +674,7 @@ multithreaded models.
|
|||
Please see the appropriate compiler documentation to use PGO with GCC or
|
||||
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:
|
||||
|
||||
.. 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
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
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
|
||||
|
|
@ -7,21 +8,21 @@ Verilating
|
|||
|
||||
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
|
||||
: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++
|
||||
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.
|
||||
|
||||
* 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.
|
||||
|
||||
* 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
|
||||
useful to feed other tools and to debug how "\`define" statements are
|
||||
expanded.
|
||||
|
|
@ -127,9 +128,9 @@ Usage
|
|||
Users need to mark one or more moderate-size modules as hierarchy block(s).
|
||||
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.
|
||||
|
||||
|
|
@ -145,28 +146,28 @@ Limitations
|
|||
|
||||
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
|
||||
hierarchy block instance can be accessed from the directly enclosing
|
||||
nested hierarchy block, or from the top level non-hierarchical portions
|
||||
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.
|
||||
|
||||
* 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.
|
||||
|
||||
* Delays are not allowed in hierarchy blocks.
|
||||
- Delays are not allowed in hierarchy blocks.
|
||||
|
||||
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.
|
||||
|
||||
* 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.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -882,6 +883,22 @@ List Of Warnings
|
|||
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
|
||||
|
||||
Warns that the same always block contains multiple enum-typed case
|
||||
|
|
@ -1178,7 +1195,7 @@ List Of Warnings
|
|||
|
||||
.. 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
|
||||
``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
|
||||
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
|
||||
clock enables, identified from the reported path going through a clock
|
||||
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:
|
||||
|
||||
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``.
|
||||
|
||||
|
||||
|
|
@ -666,23 +666,23 @@ The second visitor in ``V3Timing.cpp``, ``TimingControlVisitor``, uses the
|
|||
information provided by ``TimingSuspendableVisitor`` and transforms each
|
||||
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
|
||||
corresponding to the sentree referenced by the event control. This
|
||||
sentree is also referenced by the ``AstCAwait`` node, to be used later by
|
||||
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
|
||||
scheduler multiple times: for trigger evaluation, updates, and
|
||||
resumption. The dynamic trigger scheduler is responsible for resuming the
|
||||
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
|
||||
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::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()``:
|
||||
|
||||
* ``_timing_ready()``, which commits all coroutines whose triggers were
|
||||
not set in the current iteration,
|
||||
* ``_timing_resume()``, which calls `resume()` on all trigger and delay
|
||||
- ``_timing_ready()``, which commits all coroutines whose triggers were not
|
||||
set in the current iteration,
|
||||
- ``_timing_resume()``, which calls `resume()` on all trigger and delay
|
||||
schedulers whose triggers were set in the current iteration.
|
||||
|
||||
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
|
||||
Verilator more predictable; this is the reason for introduction of 3rd
|
||||
stage in `VlTriggerScheduler` and thanks to this it is guaranteed that
|
||||
downstream logic will be evaluated before resumption (assuming that the
|
||||
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``;
|
||||
* firing cannot cannot be lost
|
||||
(``test_regress/t/t_event_control_double_lost.v``) - which is possible when
|
||||
triggers are not evaluated right before awaiting.
|
||||
- firing cannot cannot be lost
|
||||
(``test_regress/t/t_event_control_double_lost.v``) - which is possible
|
||||
when triggers are not evaluated right before awaiting.
|
||||
|
||||
All coroutines are committed and resumed in the 'act' eval loop. With
|
||||
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
|
||||
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
|
||||
variables with identical non-empty footprints, emit those groups in deterministic
|
||||
footprint-key order, then emit variables with no footprint information last.
|
||||
variable. The variables in a given module have a set of footprints. We
|
||||
group variables with identical non-empty footprints, emit those groups in
|
||||
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
|
||||
boundary. This avoids false sharing between different macro-task footprints
|
||||
without building a complete pairwise-distance graph over all footprints, which
|
||||
would use excessive memory on very large models.
|
||||
The first emitted variable in each footprint group is aligned to a
|
||||
cache-line boundary. This avoids false sharing between different macro-task
|
||||
footprints without building a complete pairwise-distance graph over all
|
||||
footprints, which would use excessive memory on very large models.
|
||||
|
||||
This is an old idea. Simulators designed at DEC in the early 1990s used
|
||||
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
|
||||
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
|
||||
node is always present, and is a single ``AstNode`` (as opposed to a
|
||||
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.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
to NULL in the constructor, where that node (``AstModule`` visitor) sets
|
||||
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
|
||||
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
|
||||
using the ``user1()`` through ``user4()`` methods, or as a pointer (of
|
||||
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
|
||||
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
|
||||
type ``AstNUser`` that is ignored on most of the visitor functions.
|
||||
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
|
||||
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``)
|
||||
|
||||
* ``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``.
|
||||
* ``jtree $1`` - Pretty print a dump that was previously saved by
|
||||
- ``jtree $1`` - Pretty print a dump that was previously saved by
|
||||
``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.
|
||||
|
||||
* ``jtree 0x55555613dca0`` - Pretty print using address literal (rather
|
||||
- ``jtree 0x55555613dca0`` - Pretty print using address literal (rather
|
||||
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
|
||||
``gdb``'s ``help`` command.
|
||||
|
|
@ -2243,25 +2244,25 @@ Adding 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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
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
|
||||
``test_regress/obj_dir/t_<newtestcase>/*.tree`` file which you can
|
||||
examine to see if the parsing worked. See also the sections above on
|
||||
debugging.
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
.. for github, vim: syntax=reStructuredText
|
||||
.. SPDX-FileCopyrightText: 2025-2026 Wilson Snyder
|
||||
.. SPDX-License-Identifier: CC0-1.0
|
||||
..
|
||||
for github, vim: syntax=reStructuredText
|
||||
SPDX-FileCopyrightText: 2025-2026 Wilson Snyder
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
Security Policy
|
||||
===============
|
||||
|
|
|
|||
|
|
@ -477,6 +477,7 @@ Syms
|
|||
Synopsys
|
||||
SystemC
|
||||
SystemVerilog
|
||||
Szpotanski
|
||||
Takatsukasa
|
||||
Tambe
|
||||
Tarik
|
||||
|
|
@ -537,6 +538,7 @@ Verilog
|
|||
Vighnesh
|
||||
Viktor
|
||||
Vilp
|
||||
VlRNG
|
||||
VlWide
|
||||
Vlip
|
||||
Vm
|
||||
|
|
@ -684,6 +686,7 @@ countones
|
|||
cout
|
||||
covergroup
|
||||
covergroups
|
||||
coverpoint
|
||||
coverpoints
|
||||
cpp
|
||||
cppstyle
|
||||
|
|
@ -861,6 +864,7 @@ hx
|
|||
hyperthreading
|
||||
hyperthreads
|
||||
icecream
|
||||
ico
|
||||
idmap
|
||||
ifdef
|
||||
ifdefed
|
||||
|
|
@ -916,6 +920,7 @@ linters
|
|||
linux
|
||||
liu
|
||||
livelock
|
||||
liveness
|
||||
lldb
|
||||
ln
|
||||
loc
|
||||
|
|
@ -924,6 +929,7 @@ localparams
|
|||
localtime
|
||||
logicals
|
||||
longint
|
||||
lookups
|
||||
lossy
|
||||
lsb
|
||||
lubc
|
||||
|
|
@ -943,6 +949,7 @@ misconnected
|
|||
misconversion
|
||||
misdetecting
|
||||
misoptimized
|
||||
misoptimizing
|
||||
missized
|
||||
mk
|
||||
mno
|
||||
|
|
@ -1204,6 +1211,7 @@ typename
|
|||
uint
|
||||
un
|
||||
unbased
|
||||
unclocked
|
||||
uncomment
|
||||
undef
|
||||
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(); \
|
||||
}
|
||||
|
||||
#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.
|
||||
#if 1
|
||||
# define FST_DCHECK(a) FST_CHECK(a)
|
||||
|
|
|
|||
|
|
@ -335,10 +335,10 @@ public:
|
|||
// Double variables should not use these array-based emitValueChange overloads.
|
||||
// We implement them to satisfy the VairableInfo::dispatchHelper template instantiation.
|
||||
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) {
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ Handle Writer::createVar(
|
|||
// (void)type;
|
||||
// (void)svt;
|
||||
// (void)sdt;
|
||||
// throw std::runtime_error("TODO");
|
||||
// FST_FAIL_STRING("TODO");
|
||||
// return 0;
|
||||
// }
|
||||
// LCOV_EXCL_STOP
|
||||
|
|
@ -353,11 +353,7 @@ void compressUsingZlib(
|
|||
uncompressed_size,
|
||||
level
|
||||
);
|
||||
if (z_status != Z_OK) {
|
||||
throw std::runtime_error(
|
||||
"Failed to compress data with zlib, error code: " + std::to_string(z_status)
|
||||
);
|
||||
}
|
||||
FST_CHECK_EQ(z_status, Z_OK);
|
||||
compressed_data.resize(compressed_bound);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,12 @@
|
|||
# include <unistd.h>
|
||||
# define _VL_HAVE_GETRLIMIT
|
||||
#endif
|
||||
#if VM_VPI
|
||||
# include <cstring>
|
||||
# ifndef _WIN32
|
||||
# include <dlfcn.h> // dlopen
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "verilated_threads.h"
|
||||
// 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
|
||||
|
||||
|
|
@ -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>
|
||||
static size_t _vl_snprintf_string(std::string& str, const char* format,
|
||||
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 {
|
||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
||||
const int randReset = Verilated::threadContextp()->randReset();
|
||||
if (randReset == 0) return 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};
|
||||
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 {
|
||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
||||
const int randReset = Verilated::threadContextp()->randReset();
|
||||
if (randReset == 0) return 0;
|
||||
QData data = ~0ULL;
|
||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
||||
if (randReset != 1) { // if 2, randomize
|
||||
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
||||
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,
|
||||
uint64_t salt) VL_MT_UNSAFE {
|
||||
if (Verilated::threadContextp()->randReset() != 2) { return VL_RAND_RESET_W(obits, outwp); }
|
||||
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = rng.rand64();
|
||||
outwp[VL_WORDS_I(obits) - 1] = rng.rand64() & VL_MASK_E(obits);
|
||||
const int words = VL_WORDS_I(obits);
|
||||
const int randReset = Verilated::threadContextp()->randReset();
|
||||
if (randReset == 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -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 {
|
||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
||||
const int randReset = Verilated::threadContextp()->randReset();
|
||||
if (randReset == 0) return 0;
|
||||
IData data = ~0;
|
||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
||||
data = VL_RANDOM_I();
|
||||
}
|
||||
if (randReset != 1) data = VL_RANDOM_I(); // if 2, randomize
|
||||
data &= VL_MASK_I(obits);
|
||||
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 {
|
||||
// Not inlined to speed up compilation of slowpath code
|
||||
return VL_ZERO_W(obits, outwp);
|
||||
|
|
@ -3028,40 +3085,97 @@ void VerilatedContext::assertOn(bool flag) VL_MT_SAFE {
|
|||
}
|
||||
bool VerilatedContext::assertOnGet(VerilatedAssertType_t type,
|
||||
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE {
|
||||
// Check if selected directive type bit in the assertOn is enabled for assertion type.
|
||||
// Note: it is assumed that this is checked only for one type at the time.
|
||||
|
||||
// Flag unspecified assertion types as disabled.
|
||||
if (type == 0) return false;
|
||||
|
||||
// Get index of 3-bit group guarding assertion type status.
|
||||
// Since the assertOnGet is generated __always__ for a single assert type, we assume that only
|
||||
// a single bit will be set. Thus, ceil log2 will work fine.
|
||||
VL_DEBUG_IFDEF(assert((type & (type - 1)) == 0););
|
||||
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));
|
||||
return assertCtlGet(VerilatedAssertCtlQuery::ASSERT_CTL_ON, type, directive);
|
||||
}
|
||||
uint32_t VerilatedContext::assertOnMask(VerilatedAssertType_t types,
|
||||
VerilatedAssertDirectiveType_t directives) VL_PURE {
|
||||
// Place the directive bits at each selected assertion type's 3-bit group.
|
||||
uint32_t mask = 0;
|
||||
for (int i = 0; i < std::numeric_limits<VerilatedAssertType_t>::digits; ++i) {
|
||||
if (VL_BITISSET_I(types, i)) mask |= directives << (i * ASSERT_DIRECTIVE_TYPE_MASK_WIDTH);
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
void VerilatedContext::assertOnSet(VerilatedAssertType_t types,
|
||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||
// For each assertion type, set directive bits.
|
||||
|
||||
// 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);
|
||||
}
|
||||
m_s.m_assertOn |= assertOnMask(types, directives);
|
||||
}
|
||||
void VerilatedContext::assertOnClear(VerilatedAssertType_t types,
|
||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||
// Iterate through all positions of assertion type bits. If bit for this assertion type is set,
|
||||
// clear 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));
|
||||
m_s.m_assertOn &= ~assertOnMask(types, directives);
|
||||
}
|
||||
void VerilatedContext::assertCtl(uint32_t controlType, VerilatedAssertType_t types,
|
||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||
// 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 {
|
||||
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>.
|
||||
if (u64 == 0) u64 = pickRandomSeed();
|
||||
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") {
|
||||
VerilatedImp::versionDump(); // Someday more info too
|
||||
VL_FATAL_MT("COMMAND_LINE", 0, "",
|
||||
|
|
@ -3893,6 +4018,7 @@ std::unique_ptr<VerilatedTraceConfig> VerilatedModel::traceConfig() const { retu
|
|||
|
||||
// cppcheck-suppress unusedFunction // Used by applications
|
||||
uint32_t VerilatedVarProps::entSize() const VL_MT_SAFE {
|
||||
if (m_entSize) return m_entSize;
|
||||
uint32_t size = 1;
|
||||
switch (vltype()) {
|
||||
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);
|
||||
}
|
||||
|
||||
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*
|
||||
VerilatedScope::forceableVarInsert(const char* namep, void* datap, bool isParam,
|
||||
VerilatedVarType vltype, int vlflags, void* forceReadSignalData,
|
||||
|
|
|
|||
|
|
@ -137,7 +137,9 @@ enum VerilatedVarType : uint8_t {
|
|||
VLVT_UINT64, // AKA QData
|
||||
VLVT_WDATA, // AKA VlWide
|
||||
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 {
|
||||
|
|
@ -154,7 +156,8 @@ enum VerilatedVarFlags : uint32_t {
|
|||
VLVF_CONTINUOUSLY = (1 << 11), // Is continously assigned
|
||||
VLVF_FORCEABLE = (1 << 12), // Forceable
|
||||
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
|
||||
|
|
@ -175,6 +178,15 @@ enum class VerilatedAssertDirectiveType : uint8_t {
|
|||
DIRECTIVE_TYPE_COVER = (1 << 1),
|
||||
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 VerilatedAssertDirectiveType_t = std::underlying_type<VerilatedAssertDirectiveType>::type;
|
||||
|
||||
|
|
@ -356,6 +368,10 @@ private:
|
|||
static constexpr size_t ASSERT_ON_WIDTH
|
||||
= ASSERT_DIRECTIVE_TYPE_MASK_WIDTH * std::numeric_limits<VerilatedAssertType_t>::digits
|
||||
+ 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:
|
||||
// TYPES
|
||||
|
|
@ -375,6 +391,16 @@ protected:
|
|||
// for each VerilatedAssertType we store
|
||||
// 3-bits, one for each directive type. Last
|
||||
// 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_fatalOnError = true; // Fatal on $stop/non-fatal error
|
||||
bool m_fatalOnVpiError = true; // Fatal on vpi error/unsupported
|
||||
|
|
@ -484,6 +510,13 @@ public:
|
|||
/// Clear enabled status for given assertion types
|
||||
void assertOnClear(VerilatedAssertType_t types,
|
||||
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)
|
||||
bool calcUnusedSigs() const VL_MT_SAFE { return m_s.m_calcUnusedSigs; }
|
||||
/// 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;
|
||||
VerilatedVar* varInsert(const char* namep, void* datap, bool isParam, VerilatedVarType vltype,
|
||||
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,
|
||||
VerilatedVarType vltype, int vlflags,
|
||||
void* forceReadSignalData, const char* forceReadSignalName,
|
||||
|
|
@ -1000,6 +1036,9 @@ public:
|
|||
static void scTraceBeforeElaborationError() VL_ATTR_NORETURN VL_MT_SAFE;
|
||||
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
|
||||
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; }
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ CFG_GCH_IF_CLANG = @CFG_GCH_IF_CLANG@
|
|||
CFG_LDFLAGS_VERILATED = @CFG_LDFLAGS_VERILATED@
|
||||
# Linker libraries for multithreading
|
||||
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
|
||||
|
|
@ -93,6 +96,7 @@ VK_CPPFLAGS_ALWAYS += \
|
|||
-DVM_TRACE_FST=$(VM_TRACE_FST) \
|
||||
-DVM_TRACE_VCD=$(VM_TRACE_VCD) \
|
||||
-DVM_TRACE_SAIF=$(VM_TRACE_SAIF) \
|
||||
-DVM_VPI=$(VM_VPI) \
|
||||
$(CFG_CXXFLAGS_NO_UNUSED) \
|
||||
|
||||
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 {
|
||||
private:
|
||||
struct Entry final {
|
||||
int m_lsb; // Inclusive lower bit
|
||||
int m_msb; // Inclusive upper bit
|
||||
int m_lsb; // Inclusive lower bit for scalar path or element index for unpacked
|
||||
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
|
||||
const void* m_rhsDatap; // Pointer to RHS storage
|
||||
|
||||
bool operator<(const Entry& other) const { return m_msb < other.m_msb; }
|
||||
int m_bitLsb = 0;
|
||||
int m_bitMsb = 0;
|
||||
int m_elemWidth = 0;
|
||||
};
|
||||
|
||||
std::vector<Entry> m_entries; // Sorted by msb, non-overlapping
|
||||
|
|
@ -134,6 +135,41 @@ private:
|
|||
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) {
|
||||
assert(width > 0 && width <= VL_QUADSIZE);
|
||||
assert(rhsLsb >= 0);
|
||||
|
|
@ -195,6 +231,22 @@ private:
|
|||
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>
|
||||
typename std::enable_if<VlIsVlWide<T>::value>::type applyEntries(T& val) const {
|
||||
for (const auto& entry : m_entries) {
|
||||
|
|
@ -229,15 +281,19 @@ public:
|
|||
using ElemRef
|
||||
= decltype(VlForceArrayIndexer<T>::elem(result, static_cast<std::size_t>(0)));
|
||||
using Elem = VlForceBaseType<ElemRef>;
|
||||
const int total = static_cast<int>(VlForceArrayIndexer<T>::size);
|
||||
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 endIdx = entry.m_msb;
|
||||
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);
|
||||
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;
|
||||
|
|
@ -250,14 +306,18 @@ public:
|
|||
T readIndex(T origVal, int index) const {
|
||||
if (m_entries.empty()) return origVal;
|
||||
|
||||
const auto it = std::lower_bound(m_entries.begin(), m_entries.end(), index,
|
||||
[](const Entry& e, int idx) { return e.m_msb < idx; });
|
||||
if (it != m_entries.end() && it->m_lsb <= index) {
|
||||
const int rhsIndex = index - it->m_rhsLsb;
|
||||
const T* const rhsBasep = static_cast<const T*>(it->m_rhsDatap);
|
||||
return rhsBasep[rhsIndex];
|
||||
T result = origVal;
|
||||
for (auto it = std::lower_bound(m_entries.begin(), m_entries.end(), index,
|
||||
[](const Entry& e, int idx) { return e.m_msb < idx; });
|
||||
it != m_entries.end() && it->m_lsb <= index; ++it) {
|
||||
if (it->m_elemWidth == 0) {
|
||||
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 {
|
||||
|
|
@ -291,11 +351,28 @@ public:
|
|||
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) {
|
||||
assert(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() {}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
const char* msg) VL_MT_SAFE;
|
||||
|
||||
// clang-format off
|
||||
/// 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;
|
||||
// clang-format on
|
||||
|
||||
/// 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;
|
||||
|
|
@ -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
|
||||
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
|
||||
inline IData VL_RANDOM_I() 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)
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
double VL_ITOR_D_W(int lbits, WDataInP const lwp) 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;
|
||||
}
|
||||
|
||||
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 {
|
||||
// MSB set bit plus one; similar to FLS. 0=value is zero
|
||||
for (int i = words - 1; i >= 0; --i) {
|
||||
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
|
||||
for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) {
|
||||
if (VL_UNLIKELY(VL_BITISSET_E(lwp[i], bit))) return i * VL_EDATASIZE + bit + 1;
|
||||
}
|
||||
// Can't get here - one bit must be set
|
||||
}
|
||||
// Shorter worst case if predict not taken
|
||||
if (VL_UNLIKELY(lwp[i])) return i * VL_EDATASIZE + VL_MOSTSETBITP1_I(lwp[i]);
|
||||
}
|
||||
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) {
|
||||
for (int i = 0; (i < wordsInQ + 1); ++i) { nequal |= (q.at(wordsInQ - i) ^ rwp[i]); }
|
||||
} else if (sizeof(T) == 8) {
|
||||
QData temp = 0;
|
||||
int qSize = q.size() - 1;
|
||||
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]);
|
||||
temp = rwp[i + 1];
|
||||
nequal |= (static_cast<QData>(q.at(qSize - i)) ^ rwp[i]);
|
||||
temp = rwp[i];
|
||||
}
|
||||
}
|
||||
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,
|
||||
WDataInP const rwp) VL_PURE {
|
||||
EData nequal = 0;
|
||||
const int wordsInQ = q.size() * N_Words;
|
||||
if ((q.size() * N_Words) != words) { return false; }
|
||||
int count = 0;
|
||||
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 {
|
||||
to_q.clear();
|
||||
|
||||
VL_CONSTEXPR_CXX17 size_t otherSize = 4 * N_Words;
|
||||
VL_CONSTEXPR_CXX17 size_t sizeOfThis = sizeof(T_Value);
|
||||
T_Value temp = 0;
|
||||
for (auto val : from_q) {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ class VerilatedVarProps VL_NOT_FINAL {
|
|||
const uint32_t m_magic; // Magic number
|
||||
const VerilatedVarType m_vltype; // Data type
|
||||
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_packed; // Packed array ranges
|
||||
VerilatedRange m_packedDpi; // Flattened packed array range
|
||||
|
|
@ -104,10 +105,12 @@ class VerilatedVarProps VL_NOT_FINAL {
|
|||
// CONSTRUCTORS
|
||||
protected:
|
||||
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_vltype{vltype}
|
||||
, m_vlflags{vlflags} {
|
||||
, m_vlflags{vlflags}
|
||||
, m_entSize{entSize} {
|
||||
// Only preallocate the ranges
|
||||
initUnpacked(udims, nullptr);
|
||||
initPacked(pdims, nullptr);
|
||||
|
|
@ -119,12 +122,14 @@ public:
|
|||
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
||||
: m_magic{MAGIC}
|
||||
, 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)
|
||||
: m_magic{MAGIC}
|
||||
, 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);
|
||||
}
|
||||
// With packed
|
||||
|
|
@ -132,14 +137,16 @@ public:
|
|||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pdims, const int* plims)
|
||||
: m_magic{MAGIC}
|
||||
, 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);
|
||||
}
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims,
|
||||
Packed, int pdims, const int* plims)
|
||||
: m_magic{MAGIC}
|
||||
, 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);
|
||||
initPacked(pdims, plims);
|
||||
}
|
||||
|
|
@ -164,6 +171,7 @@ public:
|
|||
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
|
||||
bool isSigned() const { return ((m_vlflags & VLVF_SIGNED) != 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 pdims() const VL_MT_SAFE { return m_packed.size(); }
|
||||
int dims() const VL_MT_SAFE { return pdims() + udims(); }
|
||||
|
|
@ -265,6 +273,8 @@ protected:
|
|||
// CONSTRUCTORS
|
||||
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||
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,
|
||||
VerilatedVarFlags vlflags, int udims, int pdims, bool isParam,
|
||||
std::unique_ptr<const VerilatedForceControlSignals> forceControlSignals);
|
||||
|
|
@ -296,6 +306,13 @@ inline VerilatedVar::VerilatedVar(const char* namep, void* datap, VerilatedVarTy
|
|||
, m_datap{datap}
|
||||
, m_namep{namep}
|
||||
, 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(
|
||||
const char* namep, void* datap, VerilatedVarType vltype, VerilatedVarFlags vlflags, int udims,
|
||||
int pdims, bool isParam,
|
||||
|
|
|
|||
|
|
@ -337,6 +337,7 @@ public:
|
|||
|
||||
~VlProcess() {
|
||||
if (m_parentp) m_parentp->detach(this);
|
||||
if (t_currentp == this) t_currentp = m_parentp.get();
|
||||
}
|
||||
|
||||
void attach(VlProcess* childp) { m_children.insert(childp); }
|
||||
|
|
@ -2069,8 +2070,24 @@ struct VlNull final {
|
|||
operator T*() const {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
|
@ -68,6 +69,25 @@ constexpr unsigned VL_VPI_LINE_SIZE_ = 8192;
|
|||
//======================================================================
|
||||
// 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
|
||||
class VerilatedVpio VL_NOT_FINAL {
|
||||
// CONSTANTS
|
||||
|
|
@ -201,6 +221,9 @@ public:
|
|||
}
|
||||
const VerilatedVar* varp() const { return m_varp; }
|
||||
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).
|
||||
int32_t indexedDim() const { return m_indexedDim; }
|
||||
// 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_bitOffset = 0;
|
||||
int32_t m_partselBits = -1; // Part-select width, -1 means no part-select active
|
||||
std::string m_name;
|
||||
std::string m_fullNameOverride;
|
||||
|
||||
protected:
|
||||
void* m_varDatap = nullptr; // varp()->datap() adjusted for array entries
|
||||
|
|
@ -373,6 +398,17 @@ public:
|
|||
: VerilatedVpioVarBase{varp, scopep} {
|
||||
m_entSize = varp->entSize();
|
||||
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)
|
||||
: VerilatedVpioVarBase{vop} {
|
||||
|
|
@ -380,6 +416,8 @@ public:
|
|||
m_entSize = vop->m_entSize;
|
||||
m_varDatap = vop->m_varDatap;
|
||||
m_index = vop->m_index;
|
||||
m_name = vop->m_name;
|
||||
m_fullNameOverride = vop->m_fullNameOverride;
|
||||
m_partselBits = vop->m_partselBits;
|
||||
m_bitOffset = vop->m_bitOffset;
|
||||
// Not copying m_prevDatap, must be nullptr
|
||||
|
|
@ -395,15 +433,22 @@ public:
|
|||
uint32_t bitOffset() const override { return m_bitOffset; }
|
||||
int32_t partselBits() const { return m_partselBits; }
|
||||
uint32_t bitSize() const {
|
||||
if (isStructOrUnion() && !isIndexedDimUnpacked()) return 0;
|
||||
if (m_partselBits >= 0) return static_cast<uint32_t>(m_partselBits);
|
||||
return VerilatedVpioVarBase::bitSize();
|
||||
}
|
||||
uint32_t size() const override {
|
||||
if (isStructOrUnion() && !isIndexedDimUnpacked()) return 0;
|
||||
if (m_partselBits >= 0) return static_cast<uint32_t>(m_partselBits);
|
||||
return VerilatedVpioVarBase::size();
|
||||
}
|
||||
const VerilatedRange* rangep() const override {
|
||||
if (isStructOrUnion() && !isIndexedDimUnpacked()) return nullptr;
|
||||
return VerilatedVpioVarBase::rangep();
|
||||
}
|
||||
uint32_t entSize() const { return m_entSize; }
|
||||
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].
|
||||
VerilatedVpioVar* withPartSelect(int32_t hi, int32_t lo) const {
|
||||
if (isIndexedDimUnpacked()) return nullptr;
|
||||
|
|
@ -456,22 +501,43 @@ public:
|
|||
|
||||
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;
|
||||
// TODO have V3EmitCSyms.cpp put vpiType directly into constant table
|
||||
switch (varp()->vltype()) {
|
||||
case VLVT_REAL: type = vpiRealVar; 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;
|
||||
}
|
||||
if (isIndexedDimUnpacked()) return vpiRegArray;
|
||||
if (isIndexedDimUnpacked())
|
||||
return isStructOrUnion() && varp()->isNet() ? vpiNetArray : vpiRegArray;
|
||||
return type;
|
||||
}
|
||||
const char* fullname() const override {
|
||||
static thread_local std::string t_out;
|
||||
t_out = std::string{scopep()->name()} + "." + name();
|
||||
for (auto idx : index()) t_out += "[" + std::to_string(idx) + "]";
|
||||
return t_out.c_str();
|
||||
m_fullname = m_fullNameOverride.empty()
|
||||
? std::string{scopep()->name()} + "." + varp()->name()
|
||||
: m_fullNameOverride;
|
||||
for (auto idx : index()) m_fullname += "[" + std::to_string(idx) + "]";
|
||||
return m_fullname.c_str();
|
||||
}
|
||||
void* prevDatap() const { return m_prevDatap; }
|
||||
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 {
|
||||
|
||||
public:
|
||||
explicit VerilatedVpioModule(const VerilatedScope* modulep)
|
||||
: VerilatedVpioScope{modulep} {
|
||||
// Look for '.' not inside escaped identifier
|
||||
const std::string scopename = m_fullname;
|
||||
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;
|
||||
if (VL_UNLIKELY(!_vl_vpi_find_unescaped_dot(m_fullname))) m_toplevel = true;
|
||||
}
|
||||
// cppcheck-suppress duplInheritedMember
|
||||
static VerilatedVpioModule* castp(vpiHandle h) {
|
||||
|
|
@ -1770,6 +1874,8 @@ const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_PURE {
|
|||
};
|
||||
// clang-format on
|
||||
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 >= vpiPackage && vpiVal <= vpiPropFormalDecl)
|
||||
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, vpiStructVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUnionVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUnionNet);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiBitVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassObj);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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 VerilatedScope* scopep;
|
||||
std::string fullnameOverride;
|
||||
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."))) {
|
||||
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;
|
||||
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
|
||||
|
|
@ -2491,8 +2762,18 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
|||
}
|
||||
if (!varp) {
|
||||
scopep = Verilated::threadContextp()->scopeFind(scopename.c_str());
|
||||
if (!scopep) return nullptr;
|
||||
varp = scopep->varFind(basename.c_str());
|
||||
if (scopep) { 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;
|
||||
|
|
@ -2501,6 +2782,11 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
|||
vpiHandle resultHandle;
|
||||
if (varp->isParam()) {
|
||||
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 {
|
||||
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());
|
||||
return nullptr;
|
||||
}
|
||||
case vpiMember: {
|
||||
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||
if (!vop || !vop->isStructOrUnion()) return nullptr;
|
||||
return ((new VerilatedVpioMemberIter{vop})->castVpiHandle());
|
||||
}
|
||||
case vpiParameter: {
|
||||
const VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object);
|
||||
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;
|
||||
return vop->varp()->isSigned();
|
||||
}
|
||||
case vpiPacked: {
|
||||
const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
|
||||
if (VL_LIKELY(vop && vop->isStructOrUnion())) return 0;
|
||||
[[fallthrough]];
|
||||
}
|
||||
default:
|
||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported property %s, nothing will be returned",
|
||||
__func__, VerilatedVpiError::strFromVpiProp(property));
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@
|
|||
breathe==4.36.0
|
||||
compiledb==0.10.7
|
||||
distro==1.9.0
|
||||
docstrfmt==2.2.0
|
||||
gersemi==0.23.1
|
||||
mbake==1.4.3
|
||||
mdformat==1.0.0
|
||||
mypy==1.19.0
|
||||
pylint==3.0.2
|
||||
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
|
||||
V3AstNodeOther.h
|
||||
V3AstNodeStmt.h
|
||||
V3AstPatterns.h
|
||||
V3AstUserAllocator.h
|
||||
V3Begin.h
|
||||
V3Branch.h
|
||||
|
|
@ -175,7 +176,6 @@ set(HEADERS
|
|||
V3Simulate.h
|
||||
V3Slice.h
|
||||
V3Split.h
|
||||
V3SplitAs.h
|
||||
V3SplitVar.h
|
||||
V3StackCount.h
|
||||
V3Stats.h
|
||||
|
|
@ -183,7 +183,6 @@ set(HEADERS
|
|||
V3String.h
|
||||
V3Subst.h
|
||||
V3SymTable.h
|
||||
V3TSP.h
|
||||
V3Table.h
|
||||
V3Task.h
|
||||
V3ThreadPool.h
|
||||
|
|
@ -203,7 +202,6 @@ set(HEADERS
|
|||
V3WidthCommit.h
|
||||
V3WidthRemove.h
|
||||
VlcBucket.h
|
||||
VlcCovergroup.h
|
||||
VlcOptions.h
|
||||
VlcPoint.h
|
||||
VlcSource.h
|
||||
|
|
@ -253,7 +251,6 @@ set(COMMON_SOURCES
|
|||
V3DfgDataType.cpp
|
||||
V3DfgDecomposition.cpp
|
||||
V3DfgDfgToAst.cpp
|
||||
V3DfgDumpPatterns.cpp
|
||||
V3DfgOptimizer.cpp
|
||||
V3DfgPasses.cpp
|
||||
V3DfgPeephole.cpp
|
||||
|
|
@ -330,6 +327,7 @@ set(COMMON_SOURCES
|
|||
V3ParseGrammar.cpp
|
||||
V3ParseImp.cpp
|
||||
V3ParseLex.cpp
|
||||
V3PatternStats.cpp
|
||||
V3PreProc.cpp
|
||||
V3PreShell.cpp
|
||||
V3Premit.cpp
|
||||
|
|
@ -351,14 +349,12 @@ set(COMMON_SOURCES
|
|||
V3Scoreboard.cpp
|
||||
V3Slice.cpp
|
||||
V3Split.cpp
|
||||
V3SplitAs.cpp
|
||||
V3SplitVar.cpp
|
||||
V3StackCount.cpp
|
||||
V3Stats.cpp
|
||||
V3StatsReport.cpp
|
||||
V3String.cpp
|
||||
V3Subst.cpp
|
||||
V3TSP.cpp
|
||||
V3Table.cpp
|
||||
V3Task.cpp
|
||||
V3ThreadPool.cpp
|
||||
|
|
|
|||
|
|
@ -264,7 +264,6 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||
V3DfgDataType.o \
|
||||
V3DfgDecomposition.o \
|
||||
V3DfgDfgToAst.o \
|
||||
V3DfgDumpPatterns.o \
|
||||
V3DfgOptimizer.o \
|
||||
V3DfgPasses.o \
|
||||
V3DfgPeephole.o \
|
||||
|
|
@ -314,6 +313,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||
V3OrderProcessDomains.o \
|
||||
V3OrderSerial.o \
|
||||
V3Param.o \
|
||||
V3PatternStats.o \
|
||||
V3Premit.o \
|
||||
V3ProtectLib.o \
|
||||
V3RandSequence.o \
|
||||
|
|
@ -333,11 +333,9 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||
V3Scoreboard.o \
|
||||
V3Slice.o \
|
||||
V3Split.o \
|
||||
V3SplitAs.o \
|
||||
V3SplitVar.o \
|
||||
V3StackCount.o \
|
||||
V3Subst.o \
|
||||
V3TSP.o \
|
||||
V3Table.o \
|
||||
V3Task.o \
|
||||
V3Timing.o \
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ public:
|
|||
|
||||
class ActiveDlyVisitor final : public VNVisitor {
|
||||
public:
|
||||
enum CheckType : uint8_t { CT_SEQ, CT_COMB, CT_INITIAL, CT_SUSPENDABLE };
|
||||
enum CheckType : uint8_t { CT_COMB, CT_FINAL };
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
|
|
@ -359,15 +359,9 @@ private:
|
|||
|
||||
// VISITORS
|
||||
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
|
||||
if (m_check == CT_INITIAL) {
|
||||
nodep->v3warn(INITIALDLY,
|
||||
"Non-blocking assignment '<=' in initial/final block\n"
|
||||
<< nodep->warnMore()
|
||||
<< "... This will be executed as a blocking assignment '='!");
|
||||
if (m_check == CT_FINAL) {
|
||||
nodep->v3warn(FINALDLY, "Non-blocking assignment '<=' in final block");
|
||||
} else {
|
||||
nodep->v3warn(COMBDLY,
|
||||
"Non-blocking assignment '<=' in combinational logic process\n"
|
||||
|
|
@ -465,11 +459,7 @@ class ActiveVisitor final : public VNVisitor {
|
|||
wantactivep->addStmtsp(nodep);
|
||||
|
||||
// Warn and convert any delayed assignments
|
||||
{
|
||||
ActiveDlyVisitor{nodep, !m_clockedProcess ? ActiveDlyVisitor::CT_COMB
|
||||
: oldsentreep ? ActiveDlyVisitor::CT_SEQ
|
||||
: ActiveDlyVisitor::CT_SUSPENDABLE};
|
||||
}
|
||||
if (!m_clockedProcess) ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_COMB};
|
||||
|
||||
// Delete sensitivity list
|
||||
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(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);
|
||||
moveUnderSpecial<AstSenItem::Initial>(nodep);
|
||||
}
|
||||
void visit(AstFinal* nodep) override {
|
||||
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
|
||||
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_FINAL};
|
||||
moveUnderSpecial<AstSenItem::Final>(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 "V3Stats.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
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
|
||||
// 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
|
||||
AstNode* m_passsp = nullptr; // Current pass statement
|
||||
AstNode* m_failsp = nullptr; // Current fail statement
|
||||
AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion
|
||||
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
|
||||
std::unordered_map<VNRef<AstNodeExpr>, std::unordered_map<VNRef<AstSenTree>, AstAlways*>>
|
||||
m_modExpr2Sen2DelayedAlwaysp;
|
||||
|
||||
// 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,
|
||||
VAssertDirectiveType directiveType) {
|
||||
// cppcheck-suppress missingReturn
|
||||
|
|
@ -178,9 +266,7 @@ class AssertVisitor final : public VNVisitor {
|
|||
case VAssertDirectiveType::ASSUME: {
|
||||
if (v3Global.opt.assertOn()) {
|
||||
return new AstCExpr{fl, AstCExpr::Pure{},
|
||||
"vlSymsp->_vm_contextp__->assertOnGet("s + std::to_string(type)
|
||||
+ ", "s + std::to_string(directiveType) + ")"s,
|
||||
1};
|
||||
assertCtlGetCall("ASSERT_CTL_ON", type, directiveType), 1};
|
||||
}
|
||||
return new AstConst{fl, AstConst::BitFalse{}};
|
||||
}
|
||||
|
|
@ -196,6 +282,27 @@ class AssertVisitor final : public VNVisitor {
|
|||
}
|
||||
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,
|
||||
VDisplayType severity) {
|
||||
if (severity == VDisplayType::DT_ERROR || severity == VDisplayType::DT_FATAL) {
|
||||
|
|
@ -207,36 +314,6 @@ class AssertVisitor final : public VNVisitor {
|
|||
+ cvtToStr(nodep->fileline()->lineno()) + ": %m" + ((message != "") ? ": " : "")
|
||||
+ 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) {
|
||||
nodep->fmtp()->text(
|
||||
assertDisplayMessage(nodep, prefix, nodep->fmtp()->text(), nodep->displayType()));
|
||||
|
|
@ -278,8 +355,8 @@ class AssertVisitor final : public VNVisitor {
|
|||
}
|
||||
static AstIf* newIfAssertOn(AstNode* bodyp, VAssertDirectiveType directiveType,
|
||||
VAssertType type = VAssertType::INTERNAL) {
|
||||
// Add a internal if to check assertions are on.
|
||||
// Don't make this a AND term, as it's unlikely to need to test this.
|
||||
// Add an internal if to check assertions are on.
|
||||
// Don't make this an AND term, as it's unlikely to need to test this.
|
||||
FileLine* const fl = bodyp->fileline();
|
||||
|
||||
AstNodeExpr* const condp = assertOnCond(fl, type, directiveType);
|
||||
|
|
@ -288,6 +365,30 @@ class AssertVisitor final : public VNVisitor {
|
|||
newp->user2(true); // Mark as an assertOn() check
|
||||
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,
|
||||
AstNode* passsp, AstNode* failsp) {
|
||||
|
|
@ -444,6 +545,7 @@ class AssertVisitor final : public VNVisitor {
|
|||
if (failsp) failsp->unlinkFrBackWithNext();
|
||||
|
||||
bool selfDestruct = false;
|
||||
bool passspGated = false;
|
||||
if (const AstCover* const snodep = VN_CAST(nodep, Cover)) {
|
||||
++m_statCover;
|
||||
if (!v3Global.opt.coverageUser()) {
|
||||
|
|
@ -455,6 +557,9 @@ class AssertVisitor final : public VNVisitor {
|
|||
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
||||
if (message != "") covincp->declp()->comment(message);
|
||||
if (passsp) {
|
||||
passsp = newIfAssertPassOn(passsp, nodep->directive(), nodep->userType(),
|
||||
/*vacuous=*/false);
|
||||
passspGated = true;
|
||||
passsp = AstNode::addNext<AstNode, AstNode>(covincp, passsp);
|
||||
} else {
|
||||
passsp = covincp;
|
||||
|
|
@ -475,8 +580,10 @@ class AssertVisitor final : public VNVisitor {
|
|||
|
||||
VL_RESTORER(m_passsp);
|
||||
VL_RESTORER(m_failsp);
|
||||
VL_RESTORER(m_assertp);
|
||||
m_passsp = passsp;
|
||||
m_failsp = failsp;
|
||||
m_assertp = nodep;
|
||||
iterate(nodep->propp());
|
||||
|
||||
AstNode* propExprp;
|
||||
|
|
@ -488,6 +595,15 @@ class AssertVisitor final : public VNVisitor {
|
|||
propExprp = nodep->propp()->unlinkFrBack();
|
||||
}
|
||||
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);
|
||||
if (disablep) bodysp = new AstIf{flp, new AstLogNot{flp, disablep}, bodysp};
|
||||
// Add assertOn check last, for better combining
|
||||
|
|
@ -582,8 +698,36 @@ class AssertVisitor final : public VNVisitor {
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
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
|
||||
|
|
@ -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
|
||||
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);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
bool has_default = false;
|
||||
|
|
@ -807,8 +959,11 @@ class AssertVisitor final : public VNVisitor {
|
|||
if (nodep->pass() && m_passsp) {
|
||||
// Cover adds COVERINC by AstNode::addNext, thus need to clone next too.
|
||||
stmtsp = m_passsp->cloneTree(true);
|
||||
stmtsp = newIfAssertPassOn(stmtsp, m_assertp->directive(), m_assertp->userType(),
|
||||
nodep->vacuous());
|
||||
} else if (!nodep->pass() && m_failsp) {
|
||||
stmtsp = m_failsp->cloneTree(true);
|
||||
stmtsp = newIfAssertFailOn(stmtsp, m_assertp->directive(), m_assertp->userType());
|
||||
}
|
||||
if (stmtsp) {
|
||||
stmtsp->foreachAndNext([](AstNodeVarRef* const refp) {
|
||||
|
|
@ -914,34 +1069,51 @@ class AssertVisitor final : public VNVisitor {
|
|||
visitAssertionIterate(nodep, nodep->failsp());
|
||||
}
|
||||
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);
|
||||
|
||||
if (!resolveAssertType(nodep)) {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: non-constant assert assertion-type expression");
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
bool assertTypeConst = true;
|
||||
if (!nodep->assertTypesp()) {
|
||||
nodep->ctlAssertTypes(VAssertType{ALL_ASSERT_TYPES});
|
||||
} 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;
|
||||
}
|
||||
if (nodep->ctlAssertTypes() != ALL_ASSERT_TYPES
|
||||
&& nodep->ctlAssertTypes().containsAny(VAssertType::EXPECT | VAssertType::UNIQUE
|
||||
| VAssertType::UNIQUE0
|
||||
if (assertTypeConst && nodep->ctlAssertTypes() != ALL_ASSERT_TYPES
|
||||
&& nodep->ctlAssertTypes().containsAny(VAssertType::UNIQUE | VAssertType::UNIQUE0
|
||||
| VAssertType::PRIORITY)) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: assert control assertion_type");
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return;
|
||||
}
|
||||
if (!resolveControlType(nodep)) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: non-const assert control type expression");
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return;
|
||||
|
||||
bool directiveTypeConst = true;
|
||||
if (!nodep->directiveTypesp()) {
|
||||
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,
|
||||
"Unsupported: non-const assert directive type expression");
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
|
|
@ -949,43 +1121,18 @@ class AssertVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
FileLine* const fl = nodep->fileline();
|
||||
switch (nodep->ctlType()) {
|
||||
case VAssertCtlType::ON:
|
||||
UINFO(9, "Generating assertctl for a module: " << m_modp);
|
||||
nodep->replaceWith(
|
||||
new AstCStmt{fl, "vlSymsp->_vm_contextp__->assertOnSet("s
|
||||
+ std::to_string(nodep->ctlAssertTypes()) + ", "s
|
||||
+ std::to_string(nodep->ctlDirectiveTypes()) + ");\n"s});
|
||||
break;
|
||||
case VAssertCtlType::OFF:
|
||||
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)");
|
||||
}
|
||||
UINFO(9, "Generating assertctl for a module: " << m_modp);
|
||||
AstCStmt* const newp = new AstCStmt{fl};
|
||||
newp->add("vlSymsp->_vm_contextp__->assertCtl(");
|
||||
newp->add(nodep->controlTypep()->unlinkFrBack());
|
||||
newp->add(", ");
|
||||
if (nodep->assertTypesp()) {
|
||||
newp->add(nodep->assertTypesp()->unlinkFrBack());
|
||||
} else {
|
||||
newp->add(std::to_string(ALL_ASSERT_TYPES));
|
||||
}
|
||||
newp->add(", " + std::to_string(nodep->ctlDirectiveTypes()) + ");\n");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstAssertIntrinsic* nodep) override { //
|
||||
|
|
@ -1006,11 +1153,12 @@ class AssertVisitor final : public VNVisitor {
|
|||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_modPastNum);
|
||||
VL_RESTORER(m_modStrobeNum);
|
||||
VL_RESTORER(m_modExpr2Sen2DelayedAlwaysp);
|
||||
VL_RESTORER(m_finalp);
|
||||
VL_RESTORER_CLEAR(m_modExpr2Sen2DelayedAlwaysp);
|
||||
m_modp = nodep;
|
||||
m_modPastNum = 0;
|
||||
m_modStrobeNum = 0;
|
||||
m_modExpr2Sen2DelayedAlwaysp.clear();
|
||||
m_finalp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstNodeProcedure* nodep) override {
|
||||
|
|
@ -1057,6 +1205,9 @@ public:
|
|||
V3Stats::addStat("Assertions, $past variables", m_statPastVars);
|
||||
V3Stats::addStat("Assertions, assertOn checks combined", m_statAssertOnCombined);
|
||||
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 {
|
||||
public:
|
||||
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 "V3Assert.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Task.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
|
@ -60,6 +61,7 @@ private:
|
|||
AstNodeExpr* m_disablep = nullptr; // Last disable
|
||||
AstIf* m_disableSeqIfp = nullptr; // Used for handling disable iff in sequences
|
||||
AstPExpr* m_pexprp = nullptr; // Last AstPExpr
|
||||
bool m_underCover = false; // True if the enclosing assertion is a cover
|
||||
// Other:
|
||||
V3UniqueNames m_cycleDlyNames{"__VcycleDly"}; // Cycle delay counter name generator
|
||||
V3UniqueNames m_consRepNames{"__VconsRep"}; // Consecutive repetition counter name generator
|
||||
|
|
@ -91,7 +93,10 @@ private:
|
|||
fromAlways = true;
|
||||
}
|
||||
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};
|
||||
} else {
|
||||
if (cassertp && fromAlways) cassertp->senFromAlways(true);
|
||||
|
|
@ -1281,7 +1286,10 @@ private:
|
|||
// Don't iterate pexprp here -- it was already iterated when created
|
||||
// (in visit(AstSExpr*)), so delays and disable iff are already processed.
|
||||
} 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 {
|
||||
if (m_disablep) {
|
||||
lhsp = new AstAnd{flp, new AstNot{flp, m_disablep->cloneTreePure(false)}, lhsp};
|
||||
|
|
@ -1290,7 +1298,9 @@ private:
|
|||
AstPast* const pastp = new AstPast{flp, lhsp};
|
||||
pastp->dtypeFrom(lhsp);
|
||||
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();
|
||||
nodep->replaceWith(exprp);
|
||||
}
|
||||
|
|
@ -1438,12 +1448,6 @@ private:
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
void visit(AstInferredDisable* nodep) override {
|
||||
|
|
@ -1474,6 +1478,10 @@ private:
|
|||
nodep->propp(new AstSampled{nodep->fileline(), nodep->propp()->unlinkFrBack(),
|
||||
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());
|
||||
}
|
||||
void visit(AstPExpr* nodep) override {
|
||||
|
|
@ -1565,10 +1573,15 @@ private:
|
|||
VL_RESTORER(m_modp);
|
||||
m_defaultClockingp = nullptr;
|
||||
m_defaultClkEvtVarp = nullptr;
|
||||
m_defaultDisablep = nullptr;
|
||||
m_defaultDisablep = nodep->defaultDisablep();
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstGenBlock* nodep) override {
|
||||
VL_RESTORER(m_defaultDisablep);
|
||||
m_defaultDisablep = nodep->defaultDisablep();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstProperty* nodep) override {
|
||||
// The body will be visited when will be substituted in place of property reference
|
||||
// (AstFuncRef)
|
||||
|
|
|
|||
150
src/V3Ast.cpp
150
src/V3Ast.cpp
|
|
@ -1745,6 +1745,156 @@ AstNodeDType* AstNode::getCommonClassTypep(AstNode* node1p, AstNode* node2p) {
|
|||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -342,7 +342,6 @@ public:
|
|||
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
|
||||
VAR_PUBLIC_FLAT_RD, // 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_BV, // V3LinkParse moves to AstVar::attrScBv
|
||||
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
|
||||
|
|
@ -364,7 +363,7 @@ public:
|
|||
"TYPEID", "TYPENAME",
|
||||
"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_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"
|
||||
};
|
||||
// clang-format on
|
||||
|
|
@ -1191,6 +1190,19 @@ public:
|
|||
= {"user", "array", "auto", "ignore", "illegal", "default", "wildcard", "transition"};
|
||||
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) {
|
||||
return lhs.m_e == rhs;
|
||||
|
|
@ -1416,6 +1428,7 @@ public:
|
|||
ET_EVENT, // VlEventBase::isFired
|
||||
// Involving an expression
|
||||
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_STAR, // Sensitive to all combo inputs to this block (from .*)
|
||||
|
|
@ -1434,6 +1447,7 @@ public:
|
|||
true, // ET_NEGEDGE
|
||||
true, // ET_EVENT
|
||||
true, // ET_TRUE
|
||||
true, // ET_INITIAL_NBA
|
||||
|
||||
false, // ET_COMBO
|
||||
false, // ET_COMBO_STAR
|
||||
|
|
@ -1457,14 +1471,14 @@ public:
|
|||
}
|
||||
const char* ascii() const {
|
||||
static const char* const names[]
|
||||
= {"CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE", "COMBO",
|
||||
"COMBO_STAR", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"};
|
||||
= {"CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE", "ET_INITIAL_NBA",
|
||||
"COMBO", "COMBO_STAR", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"};
|
||||
return names[m_e];
|
||||
}
|
||||
const char* verilogKwd() const {
|
||||
static const char* const names[]
|
||||
= {"[changed]", "edge", "posedge", "negedge", "[event]", "[true]", "*",
|
||||
"*", "[hybrid]", "[static]", "[initial]", "[final]", "[never]"};
|
||||
static const char* const names[] = {
|
||||
"[changed]", "edge", "posedge", "negedge", "[event]", "[true]", "[initial_nba]",
|
||||
"*", "*", "[hybrid]", "[static]", "[initial]", "[final]", "[never]"};
|
||||
return names[m_e];
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
|
||||
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)
|
||||
: ASTGEN_SUPER_VarRef(fl, varp, access) {
|
||||
if (v3Global.assertDTypesResolved()) {
|
||||
|
|
|
|||
|
|
@ -170,6 +170,11 @@ public:
|
|||
void generic(bool flag) { m_generic = flag; }
|
||||
std::pair<uint32_t, uint32_t> dimensions(bool includeBasic) const;
|
||||
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; }
|
||||
const char* charIQWN() const {
|
||||
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
|
||||
// broken()
|
||||
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 {
|
||||
// Binary expression
|
||||
|
|
@ -1855,6 +1858,22 @@ public:
|
|||
bool index() const { return m_index; }
|
||||
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 {
|
||||
// "matches" operator: "expr matches pattern"
|
||||
// @astgen op1 := lhsp : AstNodeExpr // Expression to match
|
||||
|
|
@ -2225,6 +2244,23 @@ public:
|
|||
bool sameNode(const AstNode* /*samep*/) 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 {
|
||||
// Consecutive repetition [*N], [*N:M], [+], [*] (IEEE 1800-2023 16.9.2)
|
||||
// op1 := exprp -- the repeated expression
|
||||
|
|
@ -5701,6 +5737,22 @@ public:
|
|||
void dump(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 {
|
||||
// String to any-size integral
|
||||
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)
|
||||
uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees
|
||||
bool m_taskPublic : 1; // Public task
|
||||
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
|
||||
bool m_classMethod : 1; // Class method
|
||||
bool m_didProto : 1; // Did prototype processing
|
||||
bool m_prototype : 1; // Just a prototype
|
||||
|
|
@ -130,7 +129,6 @@ protected:
|
|||
: AstNode{t, fl}
|
||||
, m_name{name}
|
||||
, m_taskPublic{false}
|
||||
, m_attrIsolateAssign{false}
|
||||
, m_classMethod{false}
|
||||
, m_didProto{false}
|
||||
, m_prototype{false}
|
||||
|
|
@ -179,8 +177,6 @@ public:
|
|||
uint64_t dpiOpenParent() const { return m_dpiOpenParent; }
|
||||
bool taskPublic() const { return m_taskPublic; }
|
||||
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; }
|
||||
void classMethod(bool flag) { m_classMethod = flag; }
|
||||
bool didProto() const { return m_didProto; }
|
||||
|
|
@ -301,6 +297,7 @@ class AstNodeModule VL_NOT_FINAL : public AstNode {
|
|||
VLifetime m_lifetime; // Lifetime
|
||||
VTimescale m_timeunit; // Global time unit
|
||||
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_modTrace : 1; // Tracing this module
|
||||
|
|
@ -351,6 +348,8 @@ public:
|
|||
string origName() const override { return m_origName; }
|
||||
string someInstanceName() const VL_MT_SAFE { return m_someInstanceName; }
|
||||
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; }
|
||||
void inLibrary(bool flag) { m_inLibrary = flag; }
|
||||
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
|
||||
// false, the returned VarScope will have _->dtypep()->sameTree(initp->dtypep()) return true.
|
||||
AstVarScope* findConst(AstConst* initp, bool mergeDType);
|
||||
// Rebuild hashes and missing variable scopes after potential removals
|
||||
void rebuildVarScopesAndCache();
|
||||
};
|
||||
class AstConstraint final : public AstNode {
|
||||
// Constraint
|
||||
|
|
@ -1184,12 +1185,21 @@ public:
|
|||
};
|
||||
class AstCoverpointRef final : public AstNode {
|
||||
// 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:
|
||||
AstCoverpointRef(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_CoverpointRef(fl)
|
||||
, m_name{name} {}
|
||||
AstCoverpointRef(FileLine* fl, AstNodeExpr* exprp)
|
||||
: ASTGEN_SUPER_CoverpointRef(fl) {
|
||||
this->exprp(exprp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverpointRef;
|
||||
void dump(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 Static {}; // 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 Never {}; // for constructor type-overload selection
|
||||
AstSenItem(FileLine* fl, VEdgeType edgeType, AstNodeExpr* senp, AstNodeExpr* condp = nullptr)
|
||||
|
|
@ -1769,6 +1780,9 @@ public:
|
|||
AstSenItem(FileLine* fl, Initial)
|
||||
: ASTGEN_SUPER_SenItem(fl)
|
||||
, m_edgeType{VEdgeType::ET_INITIAL} {}
|
||||
AstSenItem(FileLine* fl, InitialNBA)
|
||||
: ASTGEN_SUPER_SenItem(fl)
|
||||
, m_edgeType{VEdgeType::ET_INITIAL_NBA} {}
|
||||
AstSenItem(FileLine* fl, Final)
|
||||
: ASTGEN_SUPER_SenItem(fl)
|
||||
, 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_attrScBv : 1; // User force bit vector 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_attrSplitVar : 1; // declared with split_var metacomment
|
||||
bool m_attrFsmState : 1; // declared with fsm_state metacomment
|
||||
bool m_attrFsmRegisterWrapper : 1; // connected to an fsm_register_wrapper instance
|
||||
bool m_attrFsmResetArc : 1; // declared with fsm_reset_arc 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_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_isContinuously : 1; // Ever assigned continuously (for force/release)
|
||||
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_attrScBv = false;
|
||||
m_attrScBigUint = false;
|
||||
m_attrIsolateAssign = false;
|
||||
m_attrSFormat = false;
|
||||
m_attrSplitVar = false;
|
||||
m_attrFsmState = false;
|
||||
m_attrFsmRegisterWrapper = false;
|
||||
m_attrFsmResetArc = false;
|
||||
m_attrFsmArcInclCond = false;
|
||||
m_constPoolEntry = false;
|
||||
m_fileDescr = false;
|
||||
m_gotNansiType = false;
|
||||
m_icoMaybeWritten = false;
|
||||
m_isConst = false;
|
||||
m_isContinuously = false;
|
||||
m_hasStrengthAssignment = false;
|
||||
|
|
@ -2343,13 +2359,14 @@ public:
|
|||
void attrFileDescr(bool flag) { m_fileDescr = flag; }
|
||||
void attrScBv(bool flag) { m_attrScBv = flag; }
|
||||
void attrScBigUint(bool flag) { m_attrScBigUint = flag; }
|
||||
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
||||
void attrSFormat(bool flag) { m_attrSFormat = flag; }
|
||||
void attrSplitVar(bool flag) { m_attrSplitVar = flag; }
|
||||
void attrFsmState(bool flag) { m_attrFsmState = flag; }
|
||||
void attrFsmRegisterWrapper(bool flag) { m_attrFsmRegisterWrapper = flag; }
|
||||
void attrFsmResetArc(bool flag) { m_attrFsmResetArc = 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 usedParam(bool flag) { m_usedParam = flag; }
|
||||
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
|
||||
|
|
@ -2383,6 +2400,8 @@ public:
|
|||
void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; }
|
||||
bool hasUserInit() const { return m_hasUserInit; }
|
||||
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; }
|
||||
void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; }
|
||||
bool isHideLocal() const { return m_isHideLocal; }
|
||||
|
|
@ -2462,12 +2481,6 @@ public:
|
|||
bool isWor() const { return varType().isWor(); }
|
||||
bool isWiredNet() const { return varType().isWiredNet(); }
|
||||
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 isVirtIface() const {
|
||||
if (AstIfaceRefDType* const dtp = VN_CAST(dtypep(), IfaceRefDType)) {
|
||||
|
|
@ -2519,7 +2532,6 @@ public:
|
|||
bool attrFsmRegisterWrapper() const { return m_attrFsmRegisterWrapper; }
|
||||
bool attrFsmResetArc() const { return m_attrFsmResetArc; }
|
||||
bool attrFsmArcInclCond() const { return m_attrFsmArcInclCond; }
|
||||
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
||||
AstIface* sensIfacep() const { return m_sensIfacep; }
|
||||
VRandAttr rand() const { return m_rand; }
|
||||
string verilogKwd() const override;
|
||||
|
|
@ -2531,7 +2543,6 @@ public:
|
|||
// This is getting connected to fromp; keep attributes
|
||||
// Note the method below too
|
||||
if (fromp->attrFileDescr()) attrFileDescr(true);
|
||||
if (fromp->attrIsolateAssign()) attrIsolateAssign(true);
|
||||
if (fromp->isContinuously()) isContinuously(true);
|
||||
}
|
||||
void propagateWrapAttrFrom(const AstVar* fromp) {
|
||||
|
|
@ -2810,6 +2821,7 @@ class AstGenBlock final : public AstNodeGen {
|
|||
std::string m_name; // Name of block
|
||||
const bool m_unnamed; // Originally unnamed (name change does not affect this)
|
||||
const bool m_implied; // Not inserted by user
|
||||
AstDefaultDisable* m_defaultDisablep = nullptr; // Default disable iff in this scope
|
||||
|
||||
public:
|
||||
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; }
|
||||
bool unnamed() const { return m_unnamed; }
|
||||
bool implied() const { return m_implied; }
|
||||
AstDefaultDisable* defaultDisablep() const { return m_defaultDisablep; }
|
||||
void defaultDisablep(AstDefaultDisable* nodep) { m_defaultDisablep = nodep; }
|
||||
};
|
||||
class AstGenCase final : public AstNodeGen {
|
||||
// Generate 'case'
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ protected:
|
|||
public:
|
||||
ASTGEN_MEMBERS_AstNodeAssign;
|
||||
// Clone single node, just get same type back.
|
||||
void dump(std::ostream& str) const override;
|
||||
virtual AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) = 0;
|
||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||
virtual bool cleanRhs() const { return true; }
|
||||
|
|
@ -941,13 +942,16 @@ public:
|
|||
class AstPExprClause final : public AstNodeStmt {
|
||||
const bool m_pass; // True if will be replaced by passing assertion clause, false for
|
||||
// assertion failure clause
|
||||
const bool m_vacuous; // True if pass is vacuous
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstPExprClause;
|
||||
explicit AstPExprClause(FileLine* fl, bool pass = true)
|
||||
explicit AstPExprClause(FileLine* fl, bool pass = true, bool vacuous = false)
|
||||
: ASTGEN_SUPER_PExprClause(fl)
|
||||
, m_pass{pass} {}
|
||||
, m_pass{pass}
|
||||
, m_vacuous{vacuous} {}
|
||||
bool pass() const { return m_pass; }
|
||||
bool vacuous() const { return m_vacuous; }
|
||||
};
|
||||
class AstPrintTimeScale final : public AstNodeStmt {
|
||||
// Parents: stmtlist
|
||||
|
|
@ -1606,12 +1610,18 @@ public:
|
|||
};
|
||||
class AstCover final : public AstNodeCoverOrAssert {
|
||||
// @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:
|
||||
ASTGEN_MEMBERS_AstCover;
|
||||
AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, VAssertType type,
|
||||
const string& name = "")
|
||||
: ASTGEN_SUPER_Cover(fl, propp, stmtsp, type, VAssertDirectiveType::COVER, name) {}
|
||||
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 {
|
||||
public:
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue