Merge remote-tracking branch 'upstream/master' into fix/7792-disable-midwindow
This commit is contained in:
commit
b5a68cf315
|
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
# DESCRIPTION: Github actions composite action
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
name: Artifact cache
|
||||
description: >-
|
||||
Cache a directory across workflow runs using a GitHub Actions artifact instead
|
||||
of actions/cache (useful where artifacts are preferable, e.g. no 10 GB limit
|
||||
on public repos). The base 'key' is scoped automatically: per pull request
|
||||
(<key>-pr-<N>) or per branch (<key>-branch-<name>), and on a PR restore falls
|
||||
back to the target branch's cache. Call once with mode=restore before the work
|
||||
and once with mode=save after, passing the same 'key' and 'path'.
|
||||
|
||||
Branch-scoped restores are provenance-checked (the artifact must come from a
|
||||
same-repo push to that branch) - artifact names are a global, unauthenticated
|
||||
namespace, so otherwise a fork PR could forge one.
|
||||
|
||||
mode=restore calls the GitHub API via 'gh', so the caller's job must grant
|
||||
'actions: read'.
|
||||
|
||||
inputs:
|
||||
mode:
|
||||
description: "'restore' or 'save'"
|
||||
required: true
|
||||
path:
|
||||
description: "Directory to cache (archived on save, extracted into on restore)"
|
||||
required: true
|
||||
key:
|
||||
description: "Base artifact name; scoped per PR/branch automatically"
|
||||
required: true
|
||||
retention-days:
|
||||
description: "Artifact retention in days (mode=save)"
|
||||
required: false
|
||||
default: '3'
|
||||
token:
|
||||
description: "Token for the GitHub API (mode=restore); defaults to the job's GITHUB_TOKEN"
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
outputs:
|
||||
key:
|
||||
description: "Echoes the input 'key', so a later save can reuse it without repeating the expression"
|
||||
value: ${{ inputs.key }}
|
||||
cache-hit:
|
||||
description: "'true' if an artifact was restored (mode=restore)"
|
||||
value: ${{ steps.restore.outputs.cache-hit }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Check mode
|
||||
shell: bash
|
||||
env:
|
||||
MODE: ${{ inputs.mode }}
|
||||
run: |
|
||||
case "$MODE" in
|
||||
restore|save) ;;
|
||||
*) echo "::error::artifact-cache: 'mode' must be 'restore' or 'save' (got '$MODE')"; exit 1 ;;
|
||||
esac
|
||||
|
||||
# Scope the base key: <key>-pr-<N> for pull requests (with the target branch
|
||||
# as fallback), else <key>-branch-<name>. Refs come via env, not ${{ }}
|
||||
# interpolation, so a branch name with shell metacharacters can't inject.
|
||||
- name: Compute artifact name
|
||||
id: name
|
||||
shell: bash
|
||||
env:
|
||||
BASE_KEY: ${{ inputs.key }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
BASE_REF: ${{ github.event.pull_request.base.ref }}
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sanitize() { printf '%s' "$1" | tr '/' '-'; } # artifact names cannot contain '/'
|
||||
if [ "$EVENT_NAME" = pull_request ]; then
|
||||
{
|
||||
echo "primary=${BASE_KEY}-pr-${PR_NUMBER}"
|
||||
echo "primary-branch="
|
||||
echo "fallback=${BASE_KEY}-branch-$(sanitize "$BASE_REF")"
|
||||
echo "fallback-branch=$BASE_REF"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
{
|
||||
echo "primary=${BASE_KEY}-branch-$(sanitize "$REF_NAME")"
|
||||
echo "primary-branch=$REF_NAME"
|
||||
echo "fallback="
|
||||
echo "fallback-branch="
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Restore artifact cache
|
||||
id: restore
|
||||
if: ${{ inputs.mode == 'restore' }}
|
||||
continue-on-error: true # a cold start is fine; a restore failure must not fail the caller
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ inputs.token || github.token }}
|
||||
CACHE_PATH: ${{ inputs.path }}
|
||||
PRIMARY: ${{ steps.name.outputs.primary }}
|
||||
PRIMARY_BRANCH: ${{ steps.name.outputs.primary-branch }}
|
||||
FALLBACK: ${{ steps.name.outputs.fallback }}
|
||||
FALLBACK_BRANCH: ${{ steps.name.outputs.fallback-branch }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "$CACHE_PATH"
|
||||
# Newest non-expired artifact named $1 (empty if none). With a non-empty
|
||||
# $2 (branch), require provenance: a same-repo run (head_repository_id ==
|
||||
# repository_id) whose head branch is $2, so a fork cannot forge it.
|
||||
newest_run_id() {
|
||||
want="$1" br="$2" gh api \
|
||||
"/repos/$GITHUB_REPOSITORY/actions/artifacts?name=$1&per_page=100" \
|
||||
--jq '.artifacts[]
|
||||
| select(.expired == false and .name == env.want)
|
||||
| select(env.br == ""
|
||||
or (.workflow_run.head_branch == env.br
|
||||
and .workflow_run.head_repository_id == .workflow_run.repository_id))
|
||||
| [.created_at, (.workflow_run.id | tostring)] | @tsv' \
|
||||
| sort | tail -n1 | cut -f2
|
||||
}
|
||||
restore() { # $1=name $2=branch(empty ok); returns 0 on a successful restore
|
||||
local name="$1" br="$2" rid tarball
|
||||
[ -n "$name" ] || return 1
|
||||
rid="$(newest_run_id "$name" "$br")" || return 1
|
||||
[ -n "$rid" ] || return 1
|
||||
echo "Restoring '$CACHE_PATH' from artifact '$name' (run $rid)"
|
||||
gh run download "$rid" -R "$GITHUB_REPOSITORY" --name "$name" --dir "$RUNNER_TEMP/artifact-cache-dl" || return 1
|
||||
# Each artifact holds a single tarball; match by extension so the inner
|
||||
# filename is not part of the contract.
|
||||
tarball="$(find "$RUNNER_TEMP/artifact-cache-dl" -name '*.tar.zst' -print -quit)"
|
||||
[ -n "$tarball" ] || return 1
|
||||
tar -I zstd -x -f "$tarball" -C "$CACHE_PATH"
|
||||
}
|
||||
if restore "$PRIMARY" "$PRIMARY_BRANCH"; then
|
||||
echo "Restored from primary key"
|
||||
echo "cache-hit=true" >> "$GITHUB_OUTPUT"
|
||||
elif restore "$FALLBACK" "$FALLBACK_BRANCH"; then
|
||||
echo "Restored from fallback key"
|
||||
echo "cache-hit=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "No matching artifact found; starting cold"
|
||||
echo "cache-hit=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Pack artifact cache
|
||||
id: pack
|
||||
if: ${{ inputs.mode == 'save' }}
|
||||
shell: bash
|
||||
env:
|
||||
CACHE_PATH: ${{ inputs.path }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
packdir="$(mktemp -d)" # unique dir so concurrent saves cannot collide
|
||||
tar -I 'zstd -T0' -cf "$packdir/cache.tar.zst" -C "$CACHE_PATH" .
|
||||
echo "tarball=$packdir/cache.tar.zst" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload artifact cache
|
||||
if: ${{ inputs.mode == 'save' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: ${{ steps.name.outputs.primary }}
|
||||
path: ${{ steps.pack.outputs.tarball }}
|
||||
retention-days: ${{ inputs.retention-days }}
|
||||
overwrite: true
|
||||
compression-level: 0 # tarball is already zstd-compressed
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
# DESCRIPTION: Github actions composite action
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
name: Set up Python venv
|
||||
description: >-
|
||||
Restore, create, and optionally save the make-managed Python venv in a GitHub
|
||||
Actions cache. The cache key combines the venv path (venvs are not
|
||||
relocatable), the host OS and version, the Python major.minor version, and
|
||||
the python-dev-requirements.txt hash, so any of those changing invalidates
|
||||
it. Requires the already-configured Verilator tree to be present in 'repo'.
|
||||
|
||||
inputs:
|
||||
repo:
|
||||
description: "Verilator checkout holding the Makefile and .venv"
|
||||
required: false
|
||||
default: repo
|
||||
save:
|
||||
description: "Save the cache on a miss (set true only on trusted branches)"
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Compute Python venv cache key
|
||||
id: cachekey
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.repo }}
|
||||
run: |
|
||||
source ci/ci-common.bash
|
||||
host="${DISTRO_ID:-$HOST_OS}${DISTRO_VERSION:+-$DISTRO_VERSION}"
|
||||
pyver="$(python3 -c 'import sys; print("%d.%d" % sys.version_info[:2])')"
|
||||
reqs="$(sha256sum python-dev-requirements.txt | cut -d' ' -f1)"
|
||||
venv="${PWD#/}/.venv" # absolute venv path (leading '/' trimmed)
|
||||
echo "key=venv-${host}-py${pyver}-${reqs}-${venv//\//-}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore Python venv
|
||||
id: venv
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||
with:
|
||||
path: ${{ inputs.repo }}/.venv
|
||||
key: ${{ steps.cachekey.outputs.key }}
|
||||
|
||||
- name: Create Python venv
|
||||
if: ${{ steps.venv.outputs.cache-hit != 'true' }}
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.repo }}
|
||||
run: make venv
|
||||
|
||||
- name: Save Python venv
|
||||
if: ${{ inputs.save == 'true' && steps.venv.outputs.cache-hit != 'true' }}
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||
with:
|
||||
path: ${{ inputs.repo }}/.venv
|
||||
key: ${{ steps.venv.outputs.cache-primary-key }}
|
||||
|
|
@ -16,6 +16,7 @@ on:
|
|||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -29,272 +30,141 @@ concurrency:
|
|||
jobs:
|
||||
|
||||
build-2604-gcc:
|
||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
||||
name: Build | 26.04 | gcc
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
with:
|
||||
cc: gcc
|
||||
runs-on: ubuntu-26.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-26.04, cc: gcc, asan: 0}
|
||||
|
||||
build-2604-clang:
|
||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
||||
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 }}
|
||||
os: ${{ matrix.os }}
|
||||
os-name: linux
|
||||
cc: ${{ matrix.cc }}
|
||||
dev-asan: ${{ matrix.asan }}
|
||||
dev-gcov: 0
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {os: ubuntu-26.04, cc: clang, asan: 1}
|
||||
|
||||
build-2404-gcc:
|
||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
||||
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: 0}
|
||||
|
||||
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-osx-gcc:
|
||||
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: 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
path: repo
|
||||
- name: Cache $CCACHE_DIR
|
||||
- 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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
path: ${{ github.workspace }}/repo/verilator.zip
|
||||
name: verilator-win.zip
|
||||
|
||||
test-2604-gcc:
|
||||
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
||||
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 }}
|
||||
os: ${{ matrix.os }}
|
||||
cc: ${{ matrix.cc }}
|
||||
reloc: ${{ matrix.reloc }}
|
||||
cc: gcc
|
||||
runs-on: ubuntu-26.04
|
||||
suite: ${{ matrix.suite }}
|
||||
dev-gcov: 0
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Ubuntu 26.04 gcc
|
||||
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: dist-vlt-0}
|
||||
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: dist-vlt-1}
|
||||
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: dist-vlt-2}
|
||||
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: dist-vlt-3}
|
||||
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt-0}
|
||||
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt-1}
|
||||
- {os: ubuntu-26.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-2604-clang:
|
||||
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
||||
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 }}
|
||||
os: ${{ matrix.os }}
|
||||
cc: ${{ matrix.cc }}
|
||||
reloc: ${{ matrix.reloc }}
|
||||
cc: clang
|
||||
runs-on: ubuntu-26.04
|
||||
suite: ${{ matrix.suite }}
|
||||
dev-gcov: 0
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Ubuntu 26.04 clang
|
||||
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: dist-vlt-0}
|
||||
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: dist-vlt-1}
|
||||
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: dist-vlt-2}
|
||||
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: dist-vlt-3}
|
||||
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt-0}
|
||||
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt-1}
|
||||
- {os: ubuntu-26.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-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}
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||
|
||||
lint-py:
|
||||
name: Lint Python
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ on:
|
|||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -38,15 +39,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 +53,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:
|
||||
|
|
@ -121,7 +119,7 @@ jobs:
|
|||
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ jobs:
|
|||
|
||||
- name: Docker meta
|
||||
id: docker_meta
|
||||
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6
|
||||
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # 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@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4
|
||||
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
||||
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Build and Push to Docker
|
||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
|
||||
with:
|
||||
context: ${{ env.build_context }}
|
||||
|
|
|
|||
|
|
@ -11,35 +11,44 @@ on:
|
|||
permissions:
|
||||
contents: write
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: repo
|
||||
|
||||
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
path: repo
|
||||
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
|
||||
git config --global user.email "action@example.com"
|
||||
git config --global user.name "github action"
|
||||
- name: Format code
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
autoconf
|
||||
./configure
|
||||
make venv
|
||||
|
||||
- name: Set up Python venv
|
||||
uses: ./repo/.github/actions/setup-venv
|
||||
with:
|
||||
save: ${{ github.ref == 'refs/heads/master' }}
|
||||
|
||||
- name: Format code
|
||||
run: |
|
||||
source .venv/bin/activate
|
||||
make -j 4 format CLANGFORMAT=clang-format-18
|
||||
git status
|
||||
|
||||
- name: Push
|
||||
run: |-
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
|
|
|
|||
|
|
@ -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,6 +37,10 @@ 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:
|
||||
|
|
@ -58,9 +65,16 @@ 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
|
||||
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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
CACHE_BASE_KEY: build-${{ inputs.runs-on }}-${{ inputs.cc }}${{ inputs.ccwarn && '-ccwarn' || '' }}${{ inputs.dev-asan && '-asan' || '' }}${{ inputs.dev-gcov && '-gcov' || '' }}
|
||||
CCACHE_COMPILERCHECK: content
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||
INSTALL_DIR: ${{ github.workspace }}/install
|
||||
RELOC_DIR: ${{ github.workspace }}/relloc
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -48,26 +58,28 @@ 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)
|
||||
steps:
|
||||
- name: Checkout
|
||||
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: Configure ccache
|
||||
run: |
|
||||
# ccache is unreliable on macOS, and does nothing with 'gcc --coverage'
|
||||
if [ "${{ startsWith(inputs.runs-on, 'macos') }}" = true ] || [ "${{ inputs.dev-gcov }}" = true ]; then
|
||||
echo "CCACHE_DISABLE=1" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Cache $CCACHE_DIR
|
||||
if: ${{ env.CCACHE_DISABLE != '1' }}
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||
|
|
@ -75,25 +87,43 @@ jobs:
|
|||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ inputs.sha }}
|
||||
restore-keys: |
|
||||
${{ env.CACHE_KEY }}-
|
||||
${{ 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
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -7,14 +7,6 @@ name: reusable-lint-py
|
|||
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
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
|
@ -31,19 +23,18 @@ jobs:
|
|||
with:
|
||||
path: repo
|
||||
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install dependencies
|
||||
run: ./ci/ci-install.bash lint-py
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
autoconf
|
||||
./configure --enable-longtests --enable-ccwarn
|
||||
|
||||
- name: Install python dependencies
|
||||
run: |
|
||||
sudo apt install python3-clang || \
|
||||
sudo apt install python3-clang
|
||||
make venv
|
||||
- name: Set up Python venv
|
||||
uses: ./repo/.github/actions/setup-venv
|
||||
with:
|
||||
save: ${{ github.ref == 'refs/heads/master' }}
|
||||
|
||||
- name: Lint
|
||||
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@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # 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: ""
|
||||
|
|
@ -53,8 +53,8 @@ defaults:
|
|||
shell: bash
|
||||
|
||||
env:
|
||||
CCACHE_DIR: ${{ github.workspace }}/ccache
|
||||
CCACHE_MAXSIZE: 512M
|
||||
# RTLMeter measures compile/execute times, so caching must stay off to keep
|
||||
# timings representative; ccache is still on PATH but acts as a pass-through
|
||||
CCACHE_DISABLE: 1
|
||||
|
||||
jobs:
|
||||
|
|
@ -82,14 +82,6 @@ jobs:
|
|||
working-directory: rtlmeter
|
||||
run: make venv
|
||||
|
||||
- name: Use saved ccache
|
||||
if: ${{ env.CCACHE_DISABLE == 0 }}
|
||||
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 }}
|
||||
restore-keys: rtlmeter-run-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.cases }}-${{ inputs.compileArgs }}
|
||||
|
||||
########################################################################
|
||||
# Run with new Verilator
|
||||
########################################################################
|
||||
|
|
@ -101,7 +93,7 @@ jobs:
|
|||
|
||||
- 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
|
||||
|
|
@ -164,7 +156,7 @@ jobs:
|
|||
- 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
|
||||
|
|
|
|||
|
|
@ -11,29 +11,37 @@ 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
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
CCACHE_COMPRESS: 1
|
||||
CCACHE_COMPILERCHECK: content
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||
INSTALL_DIR: ${{ github.workspace }}/install
|
||||
RELOC_DIR: ${{ github.workspace }}/relloc
|
||||
CXX: ${{ inputs.cc == 'clang' && 'clang++' || 'g++' }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -43,15 +51,8 @@ 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 }}
|
||||
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
|
||||
steps:
|
||||
|
||||
- name: Download repository archive
|
||||
|
|
@ -63,32 +64,43 @@ 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@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
||||
- name: Configure ccache
|
||||
run: |
|
||||
# ccache is unreliable on macOS, and does nothing with 'gcc --coverage'
|
||||
if [ "${{ startsWith(inputs.runs-on, 'macos') }}" = true ] || [ "${{ inputs.dev-gcov }}" = true ]; then
|
||||
echo "CCACHE_DISABLE=1" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
# Test-job ccache is stored as an artifact, not actions/cache
|
||||
- name: Restore ccache
|
||||
id: ccache
|
||||
if: ${{ env.CCACHE_DISABLE != '1' }}
|
||||
uses: ./repo/.github/actions/artifact-cache
|
||||
with:
|
||||
mode: restore
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.CACHE_KEY }}-
|
||||
key: ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.suite }}
|
||||
|
||||
- name: Install test dependencies
|
||||
run: |
|
||||
./ci/ci-install.bash
|
||||
make venv
|
||||
./ci/ci-install.bash test
|
||||
|
||||
- name: Set up Python venv
|
||||
uses: ./repo/.github/actions/setup-venv
|
||||
with:
|
||||
save: ${{ github.ref == 'refs/heads/master' }}
|
||||
|
||||
- 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 }}
|
||||
|
|
@ -104,6 +116,16 @@ jobs:
|
|||
path: ${{ github.workspace }}/repo/obj_coverage/verilator-${{ inputs.suite }}.info
|
||||
name: code-coverage-${{ inputs.suite }}
|
||||
|
||||
- name: Save ccache
|
||||
if: ${{ env.CCACHE_DISABLE != '1' && !cancelled() }}
|
||||
uses: ./repo/.github/actions/artifact-cache
|
||||
with:
|
||||
mode: save
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ steps.ccache.outputs.key }}
|
||||
# Keep master's cache around longer; PR/branch caches churn faster
|
||||
retention-days: ${{ github.ref == 'refs/heads/master' && 7 || 3 }}
|
||||
|
||||
- name: Fail job if a test failed
|
||||
if: ${{ steps.run-test.outcome == 'failure' && !cancelled() }}
|
||||
run: |-
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
#!/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 --enable-light-debug"
|
||||
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
|
||||
BUILD_START=$SECONDS
|
||||
"$MAKE" -j "$NPROC" -k
|
||||
ccache -svv
|
||||
ccache --evict-older-than "$((SECONDS - BUILD_START + 60))s"
|
||||
ccache -svv
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# 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)
|
||||
;;
|
||||
*)
|
||||
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,141 +10,168 @@
|
|||
# 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
|
||||
echo "path-exclude /usr/share/info/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
||||
elif [ "$HOST_OS" = "macOS" ]; then
|
||||
# The macos runner image ships an untrusted third-party tap we don't use;
|
||||
# untap it so brew stops emitting a tap-trust warning. Force + '|| true' since
|
||||
# untap fails if a formula was installed from it, which is harmless here.
|
||||
brew untap --force aws/tap || true
|
||||
fi
|
||||
|
||||
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
|
||||
# Workaround -fsanitize=address crash
|
||||
sudo sysctl -w vm.mmap_rnd_bits=28
|
||||
elif [ "$STAGE" = "lint-py" ]; then
|
||||
# nodist/clang_check_attributes.
|
||||
if [ "$HOST_OS" = "linux" ] && [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||
PACKAGES=(
|
||||
python3-clang # Not run, but importers are linted
|
||||
)
|
||||
sudo apt-get update ||
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes "${PACKAGES[@]}" ||
|
||||
sudo apt-get install --yes "${PACKAGES[@]}"
|
||||
fi
|
||||
else
|
||||
##############################################################################
|
||||
# Unknown build stage
|
||||
fatal "Unknown CI_BUILD_STAGE_NAME: '$CI_BUILD_STAGE_NAME'"
|
||||
fatal "Unknown stage '$STAGE' (expected 'build', 'test' or 'lint-py')"
|
||||
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,169 @@
|
|||
#!/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 (wipes most of it); 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, but keep the CI infrastructure
|
||||
find . -mindepth 1 -maxdepth 1 ! -name .github ! -name ci -exec rm -rf {} +
|
||||
ls -la .
|
||||
fi
|
||||
|
||||
# Run the specified suite
|
||||
ccache -z
|
||||
TEST_START=$SECONDS
|
||||
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
|
||||
ccache --evict-older-than "$((SECONDS - TEST_START + 60))s"
|
||||
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
|
||||
|
|
|
|||
37
configure.ac
37
configure.ac
|
|
@ -129,6 +129,21 @@ AC_ARG_ENABLE([dev-gcov],
|
|||
AC_SUBST(CFG_WITH_DEV_GCOV)
|
||||
AC_MSG_RESULT($CFG_WITH_DEV_GCOV)
|
||||
|
||||
# Flag to reduce the debug info in the debug executable to minimize its size
|
||||
AC_MSG_CHECKING(whether to reduce debug info in the debug executable)
|
||||
AC_ARG_ENABLE([light-debug],
|
||||
[AS_HELP_STRING([--enable-light-debug],
|
||||
[Reduce the amount of debug information in the debug
|
||||
Verilator executable to minimize its size. Enable
|
||||
slight optimization. Enough for backtraces only.])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_LIGHT_DEBUG=yes ;;
|
||||
no) CFG_WITH_LIGHT_DEBUG=no ;;
|
||||
*) AC_MSG_ERROR([bad value '${enableval}' for --enable-light-debug]) ;;
|
||||
esac],
|
||||
CFG_WITH_LIGHT_DEBUG=no)
|
||||
AC_MSG_RESULT($CFG_WITH_LIGHT_DEBUG)
|
||||
|
||||
# Special Substitutions - CFG_WITH_DEFENV
|
||||
AC_MSG_CHECKING(whether to use hardcoded paths)
|
||||
AC_ARG_ENABLE([defenv],
|
||||
|
|
@ -518,15 +533,27 @@ _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-unused)
|
|||
AC_SUBST(CFG_CXXFLAGS_PARSER)
|
||||
|
||||
# Flags for compiling the debug version of Verilator (in addition to above CFG_CXXFLAGS_SRC)
|
||||
if test "$CFG_WITH_DEV_GCOV" = "no"; then # Do not optimize for the coverage build
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-Og)
|
||||
if test "$CFG_WITH_LIGHT_DEBUG" = "yes"; then
|
||||
# Slight optimization and minimal compressed debug info. This is enough for
|
||||
# --gdb/--gdbbt backtraces, but omits the bulk of the debug info, which
|
||||
# significantly reduces object file sizes. For CI or release builds.
|
||||
if test "$CFG_WITH_DEV_GCOV" = "no"; then # Do not optimize for the coverage build
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-Og)
|
||||
fi
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-ggdb1)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-fdebug-info-for-profiling) # For fully-qualified names with clang
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-gz)
|
||||
else
|
||||
# Full debug: no optimization, full debug info, for development.
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-O0)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-ggdb)
|
||||
fi
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-ggdb)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-gz)
|
||||
AC_SUBST(CFG_CXXFLAGS_DBG)
|
||||
|
||||
# Flags for linking the debug version of Verilator (in addition to above CFG_LDFLAGS_SRC)
|
||||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_DBG,-gz)
|
||||
if test "$CFG_WITH_LIGHT_DEBUG" = "yes"; then
|
||||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_DBG,-gz)
|
||||
fi
|
||||
AC_SUBST(CFG_LDFLAGS_DBG)
|
||||
|
||||
# Flags for compiling the optimized version of Verilator (in addition to above CFG_CXXFLAGS_SRC)
|
||||
|
|
|
|||
|
|
@ -33,4 +33,4 @@ sphinxcontrib-spelling==8.0.2
|
|||
yamlfix==1.19.1
|
||||
yapf==0.43.0
|
||||
|
||||
git+https://github.com/antmicro/astsee.git
|
||||
git+https://github.com/antmicro/astsee.git@222480a8ec13b312809ea4acc08c81b4c0f4da2f
|
||||
|
|
|
|||
|
|
@ -90,6 +90,58 @@ public:
|
|||
explicit DefaultDisablePropagateVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
};
|
||||
|
||||
// Lower a sequence used as an event control ('@seq', IEEE 1800-2023 9.4.2.4) into a
|
||||
// synthesized event fired by an internal 'cover sequence' on each end-of-match
|
||||
class SeqEventLowerVisitor final : public VNVisitor {
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
V3UniqueNames m_names{"__VseqEvent"}; // Synthesized event names
|
||||
|
||||
// VISITORS
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
m_modp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstSenItem* nodep) override {
|
||||
AstFuncRef* const funcrefp = VN_CAST(nodep->sensp(), FuncRef);
|
||||
if (funcrefp && VN_IS(funcrefp->taskp(), Sequence)) {
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstVar* const eventp = new AstVar{flp, VVarType::MODULETEMP, m_names.get(nodep),
|
||||
m_modp->findBasicDType(VBasicDTypeKwd::EVENT)};
|
||||
eventp->lifetime(VLifetime::STATIC_EXPLICIT);
|
||||
m_modp->addStmtsp(eventp);
|
||||
v3Global.setHasEvents();
|
||||
funcrefp->unlinkFrBack();
|
||||
nodep->sensp(new AstVarRef{flp, eventp, VAccess::READ});
|
||||
const bool automaticActual = funcrefp->exists([](const AstNodeVarRef* refp) {
|
||||
return refp->varp() && refp->varp()->lifetime().isAutomatic();
|
||||
});
|
||||
if (automaticActual) {
|
||||
nodep->v3error("Arguments to a sequence used as an event control must be"
|
||||
" static (IEEE 1800-2023 9.4.2.4)");
|
||||
VN_AS(funcrefp->taskp(), Sequence)->isReferenced(false);
|
||||
VL_DO_DANGLING(pushDeletep(funcrefp), funcrefp);
|
||||
return;
|
||||
}
|
||||
AstFireEvent* const firep
|
||||
= new AstFireEvent{flp, new AstVarRef{flp, eventp, VAccess::WRITE}, false};
|
||||
AstCover* const coverp
|
||||
= new AstCover{flp, new AstPropSpec{flp, nullptr, nullptr, funcrefp}, firep,
|
||||
VAssertType::CONCURRENT};
|
||||
coverp->isCoverSeq(true);
|
||||
coverp->isSeqEvent(true);
|
||||
m_modp->addStmtsp(coverp);
|
||||
return;
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
explicit SeqEventLowerVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void V3AssertCommon::collectDefaultDisable(AstNetlist* nodep) {
|
||||
|
|
@ -97,6 +149,11 @@ void V3AssertCommon::collectDefaultDisable(AstNetlist* nodep) {
|
|||
{ DefaultDisablePropagateVisitor{nodep}; }
|
||||
}
|
||||
|
||||
void V3AssertCommon::lowerSequenceEvents(AstNetlist* nodep) {
|
||||
{ SeqEventLowerVisitor{nodep}; }
|
||||
V3Global::dumpCheckGlobalTree("assertseqevent", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// AssertDeFutureVisitor
|
||||
// If any AstFuture, then move all non-future varrefs to be one cycle behind,
|
||||
|
|
@ -546,14 +603,19 @@ class AssertVisitor final : public VNVisitor {
|
|||
|
||||
bool selfDestruct = false;
|
||||
bool passspGated = false;
|
||||
if (const AstCover* const snodep = VN_CAST(nodep, Cover)) {
|
||||
const AstCover* const coverp = VN_CAST(nodep, Cover);
|
||||
// A sequence event control is not an assertion directive; no assertion control
|
||||
const bool seqEvent = coverp && coverp->isSeqEvent();
|
||||
if (coverp) {
|
||||
++m_statCover;
|
||||
if (!v3Global.opt.coverageUser()) {
|
||||
if (seqEvent) {
|
||||
// Keep the event-fire action, with no coverage bucket
|
||||
} else if (!v3Global.opt.coverageUser()) {
|
||||
selfDestruct = true;
|
||||
} else {
|
||||
// V3Coverage assigned us a bucket to increment.
|
||||
AstCoverInc* const covincp = VN_AS(snodep->coverincsp(), CoverInc);
|
||||
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
|
||||
AstCoverInc* const covincp = VN_AS(coverp->coverincsp(), CoverInc);
|
||||
UASSERT_OBJ(covincp, coverp, "Missing AstCoverInc under assertion");
|
||||
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
||||
if (message != "") covincp->declp()->comment(message);
|
||||
if (passsp) {
|
||||
|
|
@ -597,7 +659,8 @@ class AssertVisitor final : public VNVisitor {
|
|||
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)) {
|
||||
if (passsp && !passspGated && !passspAlreadyGated && !VN_IS(propExprp, PExpr)
|
||||
&& !seqEvent) {
|
||||
passsp = newIfAssertPassOn(passsp, nodep->directive(), nodep->userType(),
|
||||
/*vacuous=*/false);
|
||||
}
|
||||
|
|
@ -607,7 +670,7 @@ class AssertVisitor final : public VNVisitor {
|
|||
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
|
||||
bodysp = newIfAssertOn(bodysp, nodep->directive(), nodep->userType());
|
||||
if (!seqEvent) bodysp = newIfAssertOn(bodysp, nodep->directive(), nodep->userType());
|
||||
if (sentreep) bodysp = new AstAlways{flp, VAlwaysKwd::ALWAYS, sentreep, bodysp};
|
||||
|
||||
if (passsp && !passsp->backp()) VL_DO_DANGLING(pushDeletep(passsp), passsp);
|
||||
|
|
@ -1153,12 +1216,11 @@ 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
class V3AssertCommon final {
|
||||
public:
|
||||
static void collectDefaultDisable(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
static void lowerSequenceEvents(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
class V3Assert final {
|
||||
|
|
|
|||
|
|
@ -291,6 +291,8 @@ class SvaNfaBuilder final {
|
|||
// not just the first. Builder builds parallel-branch (no first-match-wins)
|
||||
// topology when true. Default false preserves cover_property semantics.
|
||||
bool m_isCoverSeq = false;
|
||||
// Unsupported endpoint topology must reject, not ignore, or the wait hangs
|
||||
bool m_isSeqEvent = false;
|
||||
|
||||
struct RangeDelayRejectInfo final {
|
||||
SvaStateVertex* startp = nullptr;
|
||||
|
|
@ -298,6 +300,15 @@ class SvaNfaBuilder final {
|
|||
int rhsLen = 0;
|
||||
};
|
||||
|
||||
void warnEndpointUnsupported(FileLine* flp, const string& what) const {
|
||||
if (m_isSeqEvent) {
|
||||
flp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: sequence used as an event control with " << what);
|
||||
} else {
|
||||
flp->v3warn(COVERIGN, "Ignoring unsupported: cover sequence with " << what);
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeExpr* throughoutCond(AstNodeExpr* baseCondp, FileLine* flp) {
|
||||
if (m_throughoutStack.empty()) return baseCondp;
|
||||
// AND all throughout conditions (supports nesting)
|
||||
|
|
@ -465,8 +476,8 @@ class SvaNfaBuilder final {
|
|||
AstVar* tryHoistSampled(AstNodeExpr* exprp, FileLine* flp, int cloneCount) {
|
||||
constexpr int kHoistThreshold = 2;
|
||||
if (cloneCount < kHoistThreshold) return nullptr;
|
||||
AstVar* const tempVarp = new AstVar{flp, VVarType::MODULETEMP, m_propTempNames.get(exprp),
|
||||
m_modp->findBitDType()};
|
||||
AstVar* const tempVarp
|
||||
= new AstVar{flp, VVarType::MODULETEMP, m_propTempNames.get(exprp), exprp->dtypep()};
|
||||
m_modp->addStmtsp(tempVarp);
|
||||
AstAssign* const assignp = new AstAssign{flp, new AstVarRef{flp, tempVarp, VAccess::WRITE},
|
||||
sampled(exprp->cloneTreePure(false))};
|
||||
|
|
@ -578,8 +589,7 @@ class SvaNfaBuilder final {
|
|||
// overlapping ends and the nested-sequence merge collapses them, so
|
||||
// reject those for a cover sequence rather than under-count.
|
||||
if (m_isCoverSeq && (range > kChainLimit || VN_IS(rhsExprp, SExpr))) {
|
||||
flp->v3warn(COVERIGN,
|
||||
"Ignoring unsupported: cover sequence with this ranged cycle delay");
|
||||
warnEndpointUnsupported(flp, "this ranged cycle delay");
|
||||
outErrorEmitted = true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -885,8 +895,7 @@ class SvaNfaBuilder final {
|
|||
// terminal, so a cover sequence would under-count. Reject the ranged form
|
||||
// (the single-count b[->N] has one end and is enumerated correctly).
|
||||
if (m_isCoverSeq && hasMax && maxN > minN) {
|
||||
flp->v3warn(COVERIGN,
|
||||
"Ignoring unsupported: cover sequence with a ranged goto repetition");
|
||||
warnEndpointUnsupported(flp, "a ranged goto repetition");
|
||||
return BuildResult::failWithError();
|
||||
}
|
||||
|
||||
|
|
@ -950,8 +959,7 @@ class SvaNfaBuilder final {
|
|||
// than under-count. Plain boolean disjunction has one end per cycle and
|
||||
// is handled by the OR-fold.
|
||||
if (m_isCoverSeq && (lhs.termVertexp != entryVtxp || rhs.termVertexp != entryVtxp)) {
|
||||
flp->v3warn(COVERIGN,
|
||||
"Ignoring unsupported: cover sequence with a sequence operand of 'or'");
|
||||
warnEndpointUnsupported(flp, "a sequence operand of 'or'");
|
||||
return BuildResult::failWithError();
|
||||
}
|
||||
SvaStateVertex* const mergeVtxp = scopedCreateVertex();
|
||||
|
|
@ -1446,11 +1454,12 @@ class SvaNfaBuilder final {
|
|||
|
||||
public:
|
||||
SvaNfaBuilder(SvaGraph& graph, AstNodeModule* modp, V3UniqueNames& propTempNames,
|
||||
bool isCoverSeq = false)
|
||||
bool isCoverSeq = false, bool isSeqEvent = false)
|
||||
: m_graph{graph}
|
||||
, m_modp{modp}
|
||||
, m_propTempNames{propTempNames}
|
||||
, m_isCoverSeq{isCoverSeq} {}
|
||||
, m_isCoverSeq{isCoverSeq}
|
||||
, m_isSeqEvent{isSeqEvent} {}
|
||||
|
||||
// Reset scope between antecedent and consequent: liveness must not leak.
|
||||
void resetScope() {
|
||||
|
|
@ -3054,11 +3063,17 @@ class AssertNfaVisitor final : public VNVisitor {
|
|||
bool senTreeOwned = false; // True if we created senTreep locally
|
||||
AstPropSpec* const propSpecp = VN_CAST(assertp->propp(), PropSpec);
|
||||
UASSERT_OBJ(propSpecp, assertp, "Concurrent assertion must have PropSpec");
|
||||
AstCover* const coverp = VN_CAST(assertp, Cover);
|
||||
const bool isCover = coverp != nullptr;
|
||||
const bool isCoverSeq = coverp && coverp->isCoverSeq();
|
||||
// A sequence event control is not an assertion directive; no default
|
||||
// disable iff, no assertion control
|
||||
const bool isSeqEvent = coverp && coverp->isSeqEvent();
|
||||
// Inherit module defaults (IEEE 14.12, 16.15) when assertion has none.
|
||||
if (!propSpecp->sensesp() && m_defaultClockingp) {
|
||||
propSpecp->sensesp(m_defaultClockingp->sensesp()->cloneTree(true));
|
||||
}
|
||||
if (!propSpecp->disablep() && m_defaultDisablep) {
|
||||
if (!propSpecp->disablep() && m_defaultDisablep && !isSeqEvent) {
|
||||
propSpecp->disablep(m_defaultDisablep->condp()->cloneTreePure(true));
|
||||
}
|
||||
if (!senTreep && propSpecp->sensesp()) {
|
||||
|
|
@ -3070,12 +3085,9 @@ class AssertNfaVisitor final : public VNVisitor {
|
|||
if (!senTreep) return;
|
||||
|
||||
FileLine* const flp = assertp->fileline();
|
||||
const bool isCover = VN_IS(assertp, Cover);
|
||||
AstCover* const coverp = VN_CAST(assertp, Cover);
|
||||
const bool isCoverSeq = coverp && coverp->isCoverSeq();
|
||||
|
||||
SvaGraph graph;
|
||||
SvaNfaBuilder builder{graph, m_modp, m_propTempNames, isCoverSeq};
|
||||
SvaNfaBuilder builder{graph, m_modp, m_propTempNames, isCoverSeq, isSeqEvent};
|
||||
|
||||
const BuildResult result = buildAssertionGraph(builder, graph, seqBodyp, parts, flp);
|
||||
if (result.valid()) wireMatchAndMidSources(graph, result, flp);
|
||||
|
|
@ -3117,13 +3129,16 @@ class AssertNfaVisitor final : public VNVisitor {
|
|||
std::vector<AstNodeExpr*> perMidSrcs;
|
||||
|
||||
AstNodeExpr* const alwaysTriggerp
|
||||
= assertOnCond(flp, assertp->userType(), assertp->directive());
|
||||
= isSeqEvent ? new AstConst{flp, AstConst::BitTrue{}}
|
||||
: assertOnCond(flp, assertp->userType(), assertp->directive());
|
||||
AstNodeExpr* const outputExprp = m_loweringp->lower(
|
||||
flp, graph, alwaysTriggerp, senTreep, result.finalCondp, isCover,
|
||||
disableExprp ? disableExprp->cloneTreePure(false) : nullptr, negated,
|
||||
needMatch ? &matchExprp : nullptr, disableCntVarp, snapshotVarp,
|
||||
needPerSrcFail ? &requiredStepSrcs : nullptr, isCoverSeq ? &perMidSrcs : nullptr,
|
||||
assertp->userType(), assertp->directive());
|
||||
isSeqEvent ? VAssertType{VAssertType::INTERNAL} : assertp->userType(),
|
||||
isSeqEvent ? VAssertDirectiveType{VAssertDirectiveType::INTERNAL}
|
||||
: assertp->directive());
|
||||
|
||||
AstSenTree* const perSrcSenTreep
|
||||
= (requiredStepSrcs.size() >= 2) ? senTreep->cloneTree(false) : nullptr;
|
||||
|
|
|
|||
|
|
@ -1466,7 +1466,9 @@ private:
|
|||
iterateAndNextNull(nodep->sensesp());
|
||||
if (m_senip && m_senip != nodep->sensesp())
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion");
|
||||
if (!nodep->disablep() && m_defaultDisablep) {
|
||||
const AstCover* const coverp = VN_CAST(nodep->backp(), Cover);
|
||||
const bool seqEvent = coverp && coverp->isSeqEvent();
|
||||
if (!nodep->disablep() && m_defaultDisablep && !seqEvent) {
|
||||
nodep->disablep(m_defaultDisablep->condp()->cloneTreePure(true));
|
||||
}
|
||||
m_disablep = nodep->disablep();
|
||||
|
|
|
|||
|
|
@ -1612,6 +1612,8 @@ 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
|
||||
bool m_isSeqEvent = false; // Synthesized for a sequence used as an event control
|
||||
// (IEEE 1800-2023 9.4.2.4)
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstCover;
|
||||
AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, VAssertType type,
|
||||
|
|
@ -1622,6 +1624,8 @@ public:
|
|||
void dumpJson(std::ostream& str) const override;
|
||||
bool isCoverSeq() const { return m_isCoverSeq; }
|
||||
void isCoverSeq(bool flag) { m_isCoverSeq = flag; }
|
||||
bool isSeqEvent() const { return m_isSeqEvent; }
|
||||
void isSeqEvent(bool flag) { m_isSeqEvent = flag; }
|
||||
};
|
||||
class AstRestrict final : public AstNodeCoverOrAssert {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -2241,9 +2241,11 @@ void AstNodeCoverOrAssert::dumpJson(std::ostream& str) const {
|
|||
void AstCover::dump(std::ostream& str) const {
|
||||
this->AstNodeCoverOrAssert::dump(str);
|
||||
if (isCoverSeq()) str << " [COVERSEQ]";
|
||||
if (isSeqEvent()) str << " [SEQEVENT]";
|
||||
}
|
||||
void AstCover::dumpJson(std::ostream& str) const {
|
||||
dumpJsonBoolFuncIf(str, isCoverSeq);
|
||||
dumpJsonBoolFuncIf(str, isSeqEvent);
|
||||
this->AstNodeCoverOrAssert::dumpJson(str);
|
||||
}
|
||||
void AstClocking::dump(std::ostream& str) const {
|
||||
|
|
|
|||
|
|
@ -137,12 +137,9 @@ class BeginVisitor final : public VNVisitor {
|
|||
UINFO(8, " rename to " << nodep->name());
|
||||
m_statep->userMarkChanged(nodep);
|
||||
}
|
||||
VL_RESTORER(m_displayScope);
|
||||
VL_RESTORER(m_namedScope);
|
||||
VL_RESTORER(m_unnamedScope);
|
||||
m_displayScope = "";
|
||||
m_namedScope = "";
|
||||
m_unnamedScope = "";
|
||||
VL_RESTORER_CLEAR(m_displayScope);
|
||||
VL_RESTORER_CLEAR(m_namedScope);
|
||||
VL_RESTORER_CLEAR(m_unnamedScope);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstNodeProcedure* nodep) override {
|
||||
|
|
@ -163,14 +160,13 @@ class BeginVisitor final : public VNVisitor {
|
|||
// naming; so that any begin's inside the function will rename
|
||||
// inside the function.
|
||||
// Process children
|
||||
VL_RESTORER(m_displayScope);
|
||||
VL_RESTORER_COPY(m_displayScope);
|
||||
VL_RESTORER(m_ftaskp);
|
||||
VL_RESTORER(m_liftedp);
|
||||
VL_RESTORER(m_namedScope);
|
||||
VL_RESTORER(m_unnamedScope);
|
||||
VL_RESTORER_CLEAR(m_namedScope);
|
||||
VL_RESTORER_CLEAR(m_unnamedScope);
|
||||
m_displayScope = dot(m_displayScope, nodep->name());
|
||||
m_namedScope = "";
|
||||
m_unnamedScope = "";
|
||||
|
||||
m_ftaskp = nodep;
|
||||
m_liftedp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -191,9 +187,9 @@ class BeginVisitor final : public VNVisitor {
|
|||
void visit(AstGenBlock* nodep) override {
|
||||
// GenBlocks were only useful in variable creation, change names and delete
|
||||
UINFO(8, " " << nodep);
|
||||
VL_RESTORER(m_displayScope);
|
||||
VL_RESTORER(m_namedScope);
|
||||
VL_RESTORER(m_unnamedScope);
|
||||
VL_RESTORER_COPY(m_displayScope);
|
||||
VL_RESTORER_COPY(m_namedScope);
|
||||
VL_RESTORER_COPY(m_unnamedScope);
|
||||
UASSERT_OBJ(!m_keepBegins, nodep, "Should be able to eliminate all AstGenBlock");
|
||||
dotNames(nodep->name(), nodep->fileline(), "__BEGIN__");
|
||||
iterateAndNextNull(nodep->itemsp());
|
||||
|
|
@ -227,9 +223,9 @@ class BeginVisitor final : public VNVisitor {
|
|||
void visit(AstBegin* nodep) override {
|
||||
// Begin blocks were only useful in variable creation, change names and delete
|
||||
UINFO(8, " " << nodep);
|
||||
VL_RESTORER(m_displayScope);
|
||||
VL_RESTORER(m_namedScope);
|
||||
VL_RESTORER(m_unnamedScope);
|
||||
VL_RESTORER_COPY(m_displayScope);
|
||||
VL_RESTORER_COPY(m_namedScope);
|
||||
VL_RESTORER_COPY(m_unnamedScope);
|
||||
{
|
||||
VL_RESTORER(m_keepBegins);
|
||||
m_keepBegins = false;
|
||||
|
|
@ -261,9 +257,9 @@ class BeginVisitor final : public VNVisitor {
|
|||
void visit(AstNodeBlock* nodep) override {
|
||||
// Begin/Fork blocks were only useful in variable creation, change names and delete
|
||||
UINFO(8, " " << nodep);
|
||||
VL_RESTORER(m_displayScope);
|
||||
VL_RESTORER(m_namedScope);
|
||||
VL_RESTORER(m_unnamedScope);
|
||||
VL_RESTORER_COPY(m_displayScope);
|
||||
VL_RESTORER_COPY(m_namedScope);
|
||||
VL_RESTORER_COPY(m_unnamedScope);
|
||||
{
|
||||
VL_RESTORER(m_keepBegins);
|
||||
m_keepBegins = VN_IS(nodep, Fork);
|
||||
|
|
|
|||
|
|
@ -252,18 +252,15 @@ private:
|
|||
void visit(AstScope* nodep) override {
|
||||
VL_RESTORER(m_inScope);
|
||||
m_inScope = true;
|
||||
VL_RESTORER(m_cFuncNames);
|
||||
m_cFuncNames.clear();
|
||||
VL_RESTORER_CLEAR(m_cFuncNames);
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_cFuncNames);
|
||||
m_cFuncNames.clear();
|
||||
VL_RESTORER_CLEAR(m_cFuncNames);
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
void visit(AstNodeUOrStructDType* nodep) override {
|
||||
VL_RESTORER(m_cFuncNames);
|
||||
m_cFuncNames.clear();
|
||||
VL_RESTORER_CLEAR(m_cFuncNames);
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ class ClassVisitor final : public VNVisitor {
|
|||
classScopep->aboveScopep(), classScopep->aboveCellp()};
|
||||
packagep->addStmtsp(scopep);
|
||||
// Iterate
|
||||
VL_RESTORER(m_prefix);
|
||||
VL_RESTORER_CLEAR(m_prefix);
|
||||
VL_RESTORER(m_classPackagep);
|
||||
VL_RESTORER(m_classScopep);
|
||||
VL_RESTORER(m_packageScopep);
|
||||
|
|
@ -129,7 +129,7 @@ class ClassVisitor final : public VNVisitor {
|
|||
void visit(AstNodeModule* nodep) override {
|
||||
// Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule)
|
||||
// Classes are always under a Package (perhaps $unit) or a module
|
||||
VL_RESTORER(m_prefix);
|
||||
VL_RESTORER_CLEAR(m_prefix);
|
||||
VL_RESTORER(m_modp);
|
||||
m_modp = nodep;
|
||||
m_prefix = nodep->name() + "__03a__03a"; // ::
|
||||
|
|
|
|||
|
|
@ -279,8 +279,8 @@ class CoverageVisitor final : public VNVisitor {
|
|||
const AstNodeModule* const origModp = m_modp;
|
||||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_state);
|
||||
VL_RESTORER(m_exprTempNames);
|
||||
VL_RESTORER(m_funcTemps);
|
||||
VL_RESTORER_COPY(m_exprTempNames);
|
||||
VL_RESTORER_COPY(m_funcTemps);
|
||||
createHandle(nodep);
|
||||
m_modp = nodep;
|
||||
m_state.m_inModOff = false; // Haven't made top shell, so tops are real tops
|
||||
|
|
@ -294,8 +294,8 @@ class CoverageVisitor final : public VNVisitor {
|
|||
void visit(AstClass* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_state);
|
||||
VL_RESTORER(m_exprTempNames);
|
||||
VL_RESTORER(m_funcTemps);
|
||||
VL_RESTORER_COPY(m_exprTempNames);
|
||||
VL_RESTORER_COPY(m_funcTemps);
|
||||
createHandle(nodep);
|
||||
m_modp = nodep;
|
||||
// Covergroup declarations are not executable statements; suppress line/expr/toggle
|
||||
|
|
@ -356,8 +356,8 @@ class CoverageVisitor final : public VNVisitor {
|
|||
|
||||
void visit(AstNodeFTask* nodep) override {
|
||||
VL_RESTORER(m_ftaskp);
|
||||
VL_RESTORER(m_exprTempNames);
|
||||
VL_RESTORER(m_funcTemps);
|
||||
VL_RESTORER_COPY(m_exprTempNames);
|
||||
VL_RESTORER_COPY(m_funcTemps);
|
||||
m_ftaskp = nodep;
|
||||
if (!nodep->dpiImport()) iterateProcedure(nodep);
|
||||
}
|
||||
|
|
@ -762,7 +762,7 @@ class CoverageVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstGenBlock* nodep) override {
|
||||
// Similar to AstBegin
|
||||
VL_RESTORER(m_beginHier);
|
||||
VL_RESTORER_COPY(m_beginHier);
|
||||
if (nodep->name() != "") {
|
||||
m_beginHier = m_beginHier + (m_beginHier != "" ? "__DOT__" : "") + nodep->name();
|
||||
}
|
||||
|
|
@ -776,7 +776,7 @@ class CoverageVisitor final : public VNVisitor {
|
|||
// generate blocks; each point should get separate consideration.
|
||||
// (Currently ignored for line coverage, since any generate iteration
|
||||
// covers the code in that line.)
|
||||
VL_RESTORER(m_beginHier);
|
||||
VL_RESTORER_COPY(m_beginHier);
|
||||
VL_RESTORER(m_inToggleOff);
|
||||
VL_RESTORER(m_exprStmtsp);
|
||||
m_exprStmtsp = nodep;
|
||||
|
|
@ -874,7 +874,7 @@ class CoverageVisitor final : public VNVisitor {
|
|||
UASSERT_OBJ(m_exprs.empty(), nodep, "unexpected expression coverage garbage");
|
||||
VL_RESTORER(m_seeking);
|
||||
VL_RESTORER(m_objective);
|
||||
VL_RESTORER(m_exprs);
|
||||
VL_RESTORER_CLEAR(m_exprs); // Already asserted above it's empty.
|
||||
|
||||
m_seeking = SEEKING;
|
||||
m_objective = false;
|
||||
|
|
|
|||
|
|
@ -1727,15 +1727,12 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
|||
VL_RESTORER(m_covergroupp);
|
||||
VL_RESTORER(m_sampleFuncp);
|
||||
VL_RESTORER(m_constructorp);
|
||||
VL_RESTORER(m_coverpoints);
|
||||
VL_RESTORER(m_coverpointMap);
|
||||
VL_RESTORER(m_coverCrosses);
|
||||
VL_RESTORER_CLEAR(m_coverpoints);
|
||||
VL_RESTORER_CLEAR(m_coverpointMap);
|
||||
VL_RESTORER_CLEAR(m_coverCrosses);
|
||||
m_covergroupp = nodep;
|
||||
m_sampleFuncp = nullptr;
|
||||
m_constructorp = nullptr;
|
||||
m_coverpoints.clear();
|
||||
m_coverpointMap.clear();
|
||||
m_coverCrosses.clear();
|
||||
|
||||
// Extract and store the clocking event from AstCovergroup node
|
||||
// The parser creates this node to preserve the event information
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ class TraceDriver final : public DfgVisitor {
|
|||
uint64_t m_component = 0;
|
||||
uint32_t m_lsb = 0; // LSB to extract from the currently visited Vertex
|
||||
uint32_t m_msb = 0; // MSB to extract from the currently visited Vertex
|
||||
std::vector<uint32_t> m_idxs; // Indices to extract from the currently visited Vertex
|
||||
// Result of tracing the currently visited Vertex. Use SET_RESULT below!
|
||||
DfgVertex* m_resp = nullptr;
|
||||
DfgVertex* m_defaultp = nullptr; // When tracing a variable, this is its 'defaultp', if any
|
||||
|
|
@ -228,8 +229,7 @@ class TraceDriver final : public DfgVisitor {
|
|||
return varp;
|
||||
}
|
||||
|
||||
// Continue tracing drivers of the given vertex, at the given LSB.
|
||||
// Every visitor should call this to continue the traversal.
|
||||
// Trace drivers of the given packed vertex, at the given bit range.
|
||||
DfgVertex* trace(DfgVertex* const vtxp, const uint32_t msb, const uint32_t lsb) {
|
||||
UASSERT_OBJ(vtxp->isPacked(), vtxp, "Can only trace packed type vertices");
|
||||
UASSERT_OBJ(vtxp->size() > msb, vtxp, "Traced Vertex too narrow");
|
||||
|
|
@ -271,6 +271,7 @@ class TraceDriver final : public DfgVisitor {
|
|||
// Otherwise visit the vertex to trace it
|
||||
VL_RESTORER(m_msb);
|
||||
VL_RESTORER(m_lsb);
|
||||
VL_RESTORER_CLEAR(m_idxs);
|
||||
VL_RESTORER(m_resp);
|
||||
m_msb = msb;
|
||||
m_lsb = lsb;
|
||||
|
|
@ -285,6 +286,40 @@ class TraceDriver final : public DfgVisitor {
|
|||
return respr;
|
||||
}
|
||||
|
||||
// Trace drivers of the given array vertex, at the current m_idxs, m_msb, m_lsb.
|
||||
DfgVertex* traceSameIdx(DfgVertex* const vtxp) {
|
||||
UASSERT_OBJ(vtxp->isArray(), vtxp, "Should be an array vertex");
|
||||
UASSERT_OBJ(!m_idxs.empty(), vtxp, "Should have a pending index");
|
||||
VL_RESTORER(m_resp);
|
||||
m_resp = nullptr;
|
||||
iterate(vtxp); // Resolve the element, the array visitors set 'm_resp'
|
||||
UASSERT_OBJ(m_resp, vtxp, "Tracing driver failed for " << vtxp->typeName());
|
||||
UASSERT_OBJ(m_resp->width() == (m_msb - m_lsb + 1), vtxp, "Wrong result width");
|
||||
return m_resp;
|
||||
}
|
||||
|
||||
// Trace drivers of the given array vertex, pushing the given index, at current m_msb, m_lsb.
|
||||
DfgVertex* tracePushIdx(DfgVertex* const vtxp, const uint32_t idx) {
|
||||
const size_t nIdxs = m_idxs.size();
|
||||
m_idxs.push_back(idx);
|
||||
DfgVertex* const resp = traceSameIdx(vtxp);
|
||||
m_idxs.pop_back();
|
||||
UASSERT_OBJ(m_idxs.size() == nIdxs, vtxp, "Index stack size mismatch");
|
||||
return resp;
|
||||
}
|
||||
|
||||
// Trace drivers of the given vertex, popping the innermost index, at current m_msb, m_lsb.
|
||||
DfgVertex* tracePopIdx(DfgVertex* const vtxp) {
|
||||
UASSERT_OBJ(!m_idxs.empty(), vtxp, "Should have a pending index");
|
||||
const size_t nIdxs = m_idxs.size();
|
||||
const uint32_t idx = m_idxs.back();
|
||||
m_idxs.pop_back();
|
||||
DfgVertex* const resp = m_idxs.empty() ? trace(vtxp, m_msb, m_lsb) : traceSameIdx(vtxp);
|
||||
m_idxs.push_back(idx);
|
||||
UASSERT_OBJ(m_idxs.size() == nIdxs, vtxp, "Index stack size mismatch");
|
||||
return resp;
|
||||
}
|
||||
|
||||
template <typename Vertex>
|
||||
Vertex* traceBitwiseBinary(Vertex* vtxp) {
|
||||
static_assert(std::is_base_of<DfgVertexBinary, Vertex>::value,
|
||||
|
|
@ -388,25 +423,26 @@ class TraceDriver final : public DfgVisitor {
|
|||
|
||||
// Gather terms
|
||||
std::vector<DfgVertex*> termps;
|
||||
uint32_t lsb = m_lsb;
|
||||
for (const Driver& driver : drivers) {
|
||||
// Driver is below the searched LSB, move on
|
||||
if (m_lsb > driver.m_msb) continue;
|
||||
if (lsb > driver.m_msb) continue;
|
||||
// Driver is above the searched MSB, done
|
||||
if (driver.m_lsb > m_msb) break;
|
||||
// Gap below this driver, trace default to fill it
|
||||
if (driver.m_lsb > m_lsb) {
|
||||
if (driver.m_lsb > lsb) {
|
||||
UASSERT_OBJ(m_defaultp, vtxp, "Should have a default driver if needs tracing");
|
||||
termps.emplace_back(trace(m_defaultp, driver.m_lsb - 1, m_lsb));
|
||||
m_lsb = driver.m_lsb;
|
||||
termps.emplace_back(trace(m_defaultp, driver.m_lsb - 1, lsb));
|
||||
lsb = driver.m_lsb;
|
||||
}
|
||||
// Driver covers searched range, pick the needed/available bits
|
||||
const uint32_t lim = std::min(m_msb, driver.m_msb);
|
||||
termps.emplace_back(trace(driver.m_vtxp, lim - driver.m_lsb, m_lsb - driver.m_lsb));
|
||||
m_lsb = lim + 1;
|
||||
termps.emplace_back(trace(driver.m_vtxp, lim - driver.m_lsb, lsb - driver.m_lsb));
|
||||
lsb = lim + 1;
|
||||
}
|
||||
if (m_msb >= m_lsb) {
|
||||
if (m_msb >= lsb) {
|
||||
UASSERT_OBJ(m_defaultp, vtxp, "Should have a default driver if needs tracing");
|
||||
termps.emplace_back(trace(m_defaultp, m_msb, m_lsb));
|
||||
termps.emplace_back(trace(m_defaultp, m_msb, lsb));
|
||||
}
|
||||
|
||||
// The earlier cheks cover the case when either a whole driver or the default covers
|
||||
|
|
@ -425,46 +461,58 @@ class TraceDriver final : public DfgVisitor {
|
|||
SET_RESULT(resp);
|
||||
}
|
||||
|
||||
void visit(DfgVarPacked* vtxp) override {
|
||||
UASSERT_OBJ(!vtxp->isVolatile(), vtxp, "Should not trace through volatile VarPacked");
|
||||
void visit(DfgSpliceArray* vtxp) override {
|
||||
// Explicit per-element driver (a UnitArray wrapping the element value)
|
||||
if (DfgVertex* const driverp = vtxp->driverAt(m_idxs.back())) {
|
||||
// Consume this index, then trace the element value
|
||||
SET_RESULT(tracePopIdx(driverp->as<DfgUnitArray>()->srcp()));
|
||||
return;
|
||||
}
|
||||
// TODO: this is unreachable, as syntheis can't create it today.
|
||||
// // Element not driven explicitly, so it comes from the default array. Keep the
|
||||
// // index pending (the default is the whole array, indexed the same way) and
|
||||
// // continue tracing it.
|
||||
// UASSERT_OBJ(m_defaultp, vtxp, "Independent array element should have a driver or
|
||||
// default"); SET RESULT(traceSameIdx(m_defaultp));
|
||||
}
|
||||
|
||||
void visit(DfgVertexVar* vtxp) override {
|
||||
UASSERT_OBJ(!vtxp->isVolatile(), vtxp, "Should not trace through volatile variable");
|
||||
VL_RESTORER(m_defaultp);
|
||||
m_defaultp = vtxp->defaultp();
|
||||
SET_RESULT(trace(vtxp->srcp(), m_msb, m_lsb));
|
||||
DfgVertex* const drvp = vtxp->srcp() ? vtxp->srcp() : m_defaultp;
|
||||
UASSERT_OBJ(drvp, vtxp, "Should not have to trace undriven variable");
|
||||
// Packed variable: trace the driver. Array variable: continue navigating it at
|
||||
// the pending element (both at the same bit range).
|
||||
SET_RESULT(m_idxs.empty() ? trace(drvp, m_msb, m_lsb) : traceSameIdx(drvp));
|
||||
}
|
||||
|
||||
void visit(DfgArraySel* vtxp) override {
|
||||
// From a variable
|
||||
const DfgVarArray* varp = vtxp->fromp()->cast<DfgVarArray>();
|
||||
if (!varp) return;
|
||||
|
||||
// If index is not constant, independence was proven only if the 'fromp' is
|
||||
// independent, so no need to trace that
|
||||
if (!vtxp->bitp()->is<DfgConst>()) {
|
||||
DfgArraySel* const resp = make<DfgArraySel>(vtxp, vtxp->width());
|
||||
resp->fromp(vtxp->fromp());
|
||||
resp->bitp(trace(vtxp->bitp(), vtxp->bitp()->width() - 1, 0));
|
||||
DfgSel* const selp = make<DfgSel>(vtxp, m_msb - m_lsb + 1);
|
||||
selp->fromp(resp);
|
||||
selp->lsb(m_lsb);
|
||||
SET_RESULT(selp);
|
||||
// If constant index, push it and trace the selected element through the array
|
||||
// structure of 'fromp'. This handles arbitrarily nested (multi-dimensional)
|
||||
// arrays, as each nested ArraySel pushes a further index.
|
||||
if (const DfgConst* const idxp = vtxp->bitp()->cast<DfgConst>()) {
|
||||
SET_RESULT(tracePushIdx(vtxp->fromp(), idxp->toU32()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Trace the relevant driver based on the static index
|
||||
const DfgConst* const idxp = vtxp->bitp()->as<DfgConst>();
|
||||
UASSERT_OBJ(!varp->isVolatile(), vtxp, "Should not trace through volatile VarArray");
|
||||
// Skip through intermediate variables
|
||||
while (varp->srcp() && varp->srcp()->is<DfgVarArray>()) {
|
||||
varp = varp->srcp()->as<DfgVarArray>();
|
||||
UASSERT_OBJ(!varp->isVolatile(), vtxp, "Should not trace through volatile VarArray");
|
||||
}
|
||||
// Find driver
|
||||
const DfgVertex* srcp = varp->srcp();
|
||||
if (const DfgSpliceArray* const splicep = srcp->cast<DfgSpliceArray>()) {
|
||||
srcp = splicep->driverAt(idxp->toSizeT());
|
||||
}
|
||||
// Trace the driver, which at this point must be a UnitArray
|
||||
SET_RESULT(trace(srcp->as<DfgUnitArray>()->srcp(), m_msb, m_lsb));
|
||||
// If index is not constant, independence was proven only if the 'fromp' is
|
||||
// independent, so no need to trace that, just reference it with the traced
|
||||
// index. This only happens at the packed ArraySel leaf.
|
||||
UASSERT_OBJ(m_idxs.empty(), vtxp, "Non-constant index below an outer array index");
|
||||
DfgArraySel* const resp = make<DfgArraySel>(vtxp, vtxp->width());
|
||||
resp->fromp(vtxp->fromp());
|
||||
resp->bitp(trace(vtxp->bitp(), vtxp->bitp()->width() - 1, 0));
|
||||
DfgSel* const selp = make<DfgSel>(vtxp, m_msb - m_lsb + 1);
|
||||
selp->fromp(resp);
|
||||
selp->lsb(m_lsb);
|
||||
SET_RESULT(selp);
|
||||
}
|
||||
|
||||
void visit(DfgUnitArray* vtxp) override {
|
||||
// Single-element array adapter, the pending index must be 0, unwrap the element
|
||||
UASSERT_OBJ(m_idxs.back() == 0, vtxp, "UnitArray element index should be 0");
|
||||
SET_RESULT(tracePopIdx(vtxp->srcp()));
|
||||
}
|
||||
|
||||
void visit(DfgConcat* vtxp) override {
|
||||
|
|
@ -710,7 +758,7 @@ class TraceDriver final : public DfgVisitor {
|
|||
DfgSel* const selp = make<DfgSel>(vtxp, m_msb - m_lsb + 1);
|
||||
selp->fromp(resp);
|
||||
selp->lsb(m_lsb);
|
||||
SET_RESULT(resp);
|
||||
SET_RESULT(selp);
|
||||
}
|
||||
|
||||
#undef SET_RESULT
|
||||
|
|
@ -741,6 +789,142 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// A bit mask for each bit in a value, which can be either packed or aggregate type
|
||||
class BitMask final {
|
||||
// TYPES
|
||||
const DfgDataType& m_dtype;
|
||||
union {
|
||||
V3Number m_num; // The bits, if packed
|
||||
std::vector<BitMask> m_sub; // The per element masks, if aggregate
|
||||
};
|
||||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
BitMask(FileLine* flp, const DfgDataType& dtype)
|
||||
: m_dtype{dtype} {
|
||||
UASSERT_OBJ(!m_dtype.isNull(), flp, "Expected non-null data type");
|
||||
if (m_dtype.isPacked()) {
|
||||
new (&m_num) V3Number{flp, static_cast<int>(m_dtype.size()), 0};
|
||||
} else {
|
||||
new (&m_sub) std::vector<BitMask>{};
|
||||
m_sub.reserve(m_dtype.size());
|
||||
for (uint32_t i = 0; i < m_dtype.size(); ++i)
|
||||
m_sub.emplace_back(flp, m_dtype.elemDtype());
|
||||
}
|
||||
}
|
||||
BitMask(const DfgVertex& vtx)
|
||||
: BitMask{vtx.fileline(), vtx.dtype()} {}
|
||||
BitMask(const BitMask& other)
|
||||
: m_dtype{other.m_dtype} {
|
||||
if (m_dtype.isPacked()) {
|
||||
new (&m_num) V3Number{other.m_num};
|
||||
} else {
|
||||
new (&m_sub) std::vector<BitMask>{other.m_sub};
|
||||
}
|
||||
}
|
||||
BitMask& operator=(const BitMask& other) {
|
||||
if (this != &other) {
|
||||
UASSERT(m_dtype == other.m_dtype, "Expected same data type");
|
||||
if (other.m_dtype.isPacked()) {
|
||||
m_num = other.m_num;
|
||||
} else {
|
||||
m_sub = other.m_sub;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
~BitMask() {
|
||||
if (m_dtype.isPacked()) {
|
||||
m_num.~V3Number();
|
||||
} else {
|
||||
m_sub.~vector<BitMask>();
|
||||
}
|
||||
}
|
||||
|
||||
// METHODS
|
||||
V3Number& num() {
|
||||
UASSERT(m_dtype.isPacked(), "Expected packed data type");
|
||||
return m_num;
|
||||
}
|
||||
const V3Number& num() const {
|
||||
UASSERT(m_dtype.isPacked(), "Expected packed data type");
|
||||
return m_num;
|
||||
}
|
||||
std::vector<BitMask>& sub() {
|
||||
UASSERT(m_dtype.isArray(), "Expected array data type");
|
||||
return m_sub;
|
||||
}
|
||||
|
||||
bool isZero() const {
|
||||
if (m_dtype.isPacked()) return m_num.isEqZero();
|
||||
|
||||
for (const BitMask& sub : m_sub) {
|
||||
if (!sub.isZero()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool isOnes() const {
|
||||
if (m_dtype.isPacked()) return m_num.isEqAllOnes();
|
||||
|
||||
for (const BitMask& sub : m_sub) {
|
||||
if (!sub.isOnes()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void setZero() {
|
||||
if (m_dtype.isPacked()) {
|
||||
m_num.setAllBits0();
|
||||
} else {
|
||||
for (BitMask& sub : m_sub) sub.setZero();
|
||||
}
|
||||
}
|
||||
void setOnes() {
|
||||
if (m_dtype.isPacked()) {
|
||||
m_num.setAllBits1();
|
||||
} else {
|
||||
for (BitMask& sub : m_sub) sub.setOnes();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const BitMask& other) const {
|
||||
UASSERT(m_dtype == other.m_dtype, "Expected same data type");
|
||||
if (m_dtype.isPacked()) return m_num.isCaseEq(other.m_num);
|
||||
return m_sub == other.m_sub;
|
||||
}
|
||||
bool operator!=(const BitMask& other) const { return !(*this == other); }
|
||||
|
||||
// 'this' has a clear bit where 'that' has a set bit, that is,
|
||||
// 'this' has a proper subset of bits set compared to 'that'.
|
||||
bool isContractionOf(const BitMask& that) const {
|
||||
UASSERT(m_dtype == that.m_dtype, "Expected same data type");
|
||||
if (m_dtype.isPacked()) {
|
||||
const size_t words = VL_WORDS_I(m_dtype.size());
|
||||
for (size_t i = 0; i < words; ++i) {
|
||||
if (~m_num.edataWord(i) & that.m_num.edataWord(i)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UASSERT(m_dtype.isArray(), "Expected array data type");
|
||||
for (size_t i = 0; i < m_sub.size(); ++i) {
|
||||
if (m_sub[i].isContractionOf(that.m_sub[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
if (m_dtype.isPacked()) return "0x" + m_num.displayed(m_num.fileline(), "%x");
|
||||
std::string result;
|
||||
result += "{";
|
||||
for (const BitMask& sub : m_sub) {
|
||||
if (&sub != &m_sub.front()) result += ", ";
|
||||
result += sub.toString();
|
||||
}
|
||||
result += "}";
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class IndependentBits final : public DfgVisitor {
|
||||
// TYPES
|
||||
struct VertexState final {
|
||||
|
|
@ -751,7 +935,7 @@ class IndependentBits final : public DfgVisitor {
|
|||
// STATE
|
||||
const SccInfo& m_sccInfo; // The SccInfo instance
|
||||
// Vertex to current bit mask map. The mask is set for the bits that are independent of the SCC
|
||||
std::unordered_map<const DfgVertex*, V3Number> m_vtxp2Mask;
|
||||
std::unordered_map<const DfgVertex*, BitMask> m_vtxp2Mask;
|
||||
// Work list for the traversal (min-queue of vertex RPO numbers)
|
||||
std::priority_queue<size_t, std::vector<size_t>, std::greater<size_t>> m_workQueue;
|
||||
std::unordered_map<const DfgVertex*, VertexState> m_vtxp2State; // State of each vertex
|
||||
|
|
@ -761,21 +945,13 @@ class IndependentBits final : public DfgVisitor {
|
|||
#endif
|
||||
|
||||
// METHODS
|
||||
// Predicate to check if a vertex should be analysed directly
|
||||
bool handledDirectly(const DfgVertex& vtx) const {
|
||||
if (!vtx.isPacked()) return false;
|
||||
if (vtx.is<DfgSplicePacked>()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Retrieve the mask for the given vertex (create it with value 0 if needed)
|
||||
V3Number& mask(const DfgVertex& vtx) {
|
||||
UASSERT_OBJ(handledDirectly(vtx), &vtx, "Vertex should not be handled direclty");
|
||||
// Look up (or create) mask for 'vtxp'
|
||||
BitMask& mask(const DfgVertex& vtx) {
|
||||
// Look up (or create) mask for 'vtx'
|
||||
return m_vtxp2Mask
|
||||
.emplace(std::piecewise_construct, //
|
||||
std::forward_as_tuple(&vtx), //
|
||||
std::forward_as_tuple(vtx.fileline(), static_cast<int>(vtx.width()), 0)) //
|
||||
std::forward_as_tuple(&vtx), std::forward_as_tuple(vtx))
|
||||
.first->second;
|
||||
}
|
||||
|
||||
|
|
@ -784,7 +960,7 @@ class IndependentBits final : public DfgVisitor {
|
|||
// TODO: Use C++20 std::source_location instead of a macro
|
||||
#ifdef VL_DEBUG
|
||||
#define MASK(vtxp) \
|
||||
([this](const DfgVertex& vtx) -> V3Number& { \
|
||||
([this](const DfgVertex& vtx) -> BitMask& { \
|
||||
if (VL_UNLIKELY(m_lineCoverageFile.is_open())) m_lineCoverageFile << __LINE__ << '\n'; \
|
||||
return mask(vtx); \
|
||||
}(*vtxp))
|
||||
|
|
@ -810,13 +986,24 @@ class IndependentBits final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
void propagateFromDriver(V3Number& m, const DfgVertex* srcp) {
|
||||
void propagateFromDriver(BitMask& m, const DfgVertex* srcp) {
|
||||
// If there is no driver, we are done
|
||||
if (!srcp) return;
|
||||
// If it is driven by a splice, we need to combine the masks of the drivers
|
||||
if (const DfgSplicePacked* const splicep = srcp->cast<DfgSplicePacked>()) {
|
||||
splicep->foreachDriver([&](const DfgVertex& src, uint32_t lo) {
|
||||
m.opSelInto(MASK(&src), lo, src.width());
|
||||
m.num().opSelInto(MASK(&src).num(), lo, src.width());
|
||||
return false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (const DfgSpliceArray* const splicep = srcp->cast<DfgSpliceArray>()) {
|
||||
splicep->foreachDriver([&](const DfgVertex& src, uint32_t lo) {
|
||||
if (const DfgUnitArray* const uap = src.cast<DfgUnitArray>()) {
|
||||
m.sub().at(lo) = MASK(uap->srcp());
|
||||
} else {
|
||||
// m.sub().at(lo) = Can't happen MASK(&src);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return;
|
||||
|
|
@ -827,15 +1014,15 @@ class IndependentBits final : public DfgVisitor {
|
|||
|
||||
// VISITORS
|
||||
void visit(DfgVertex* vtxp) override { // LCOV_EXCL_START
|
||||
UASSERT_OBJ(handledDirectly(*vtxp), vtxp, "Vertex should be handled direclty");
|
||||
UINFO(9, "IndependentBits - Unhandled vertex type: " << vtxp->typeName());
|
||||
// Conservative assumption about all bits being dependent prevails
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
void visit(DfgVarPacked* vtxp) override {
|
||||
void visit(DfgVertexVar* vtxp) override {
|
||||
// We cannot trace through a volatile variable, so pretend all bits are dependent
|
||||
if (vtxp->isVolatile()) return;
|
||||
V3Number& m = MASK(vtxp);
|
||||
|
||||
BitMask& m = MASK(vtxp);
|
||||
DfgVertex* const srcp = vtxp->srcp();
|
||||
DfgVertex* const defaultp = vtxp->defaultp();
|
||||
// If there is a default driver, we start from that
|
||||
|
|
@ -844,81 +1031,62 @@ class IndependentBits final : public DfgVisitor {
|
|||
propagateFromDriver(m, srcp);
|
||||
}
|
||||
|
||||
void visit(DfgArraySel* vtxp) override {
|
||||
// From a variable
|
||||
const DfgVarArray* varp = vtxp->fromp()->cast<DfgVarArray>();
|
||||
if (!varp) return;
|
||||
void visit(DfgVertexSplice* vtxp) override {
|
||||
propagateFromDriver(MASK(vtxp), vtxp); // Needed to continue traversal
|
||||
}
|
||||
|
||||
// If index is not constant, independent only if the variable index
|
||||
// is indenpendent and the array is independent. We don't track arrays,
|
||||
// so we will assume an array is only independent if it has no drivers
|
||||
// in the graph. TODO: could check all drivers.
|
||||
if (!vtxp->bitp()->is<DfgConst>()) {
|
||||
if (MASK(vtxp->bitp()).isEqAllOnes() && !varp->srcp() && !varp->defaultp()) {
|
||||
MASK(vtxp).setAllBits1();
|
||||
}
|
||||
void visit(DfgUnitArray* vtxp) override { MASK(vtxp).sub().at(0) = MASK(vtxp->srcp()); }
|
||||
|
||||
void visit(DfgArraySel* vtxp) override {
|
||||
DfgVertex* const fromp = vtxp->fromp();
|
||||
|
||||
// If constant index, copy mask of relevant element
|
||||
if (const DfgConst* const idxp = vtxp->bitp()->cast<DfgConst>()) {
|
||||
MASK(vtxp) = MASK(vtxp->fromp()).sub().at(idxp->toSizeT());
|
||||
return;
|
||||
}
|
||||
|
||||
// Trace the relevant driver based on the static index
|
||||
const DfgConst* const idxp = vtxp->bitp()->as<DfgConst>();
|
||||
// We cannot trace through a volatile variable, so pretend all bits are dependent
|
||||
if (varp->isVolatile()) return;
|
||||
// Skip through intermediate variables
|
||||
while (varp->srcp() && varp->srcp()->is<DfgVarArray>()) {
|
||||
varp = varp->srcp()->as<DfgVarArray>();
|
||||
if (varp->isVolatile()) return;
|
||||
}
|
||||
// Find driver
|
||||
const DfgVertex* srcp = varp->srcp();
|
||||
if (!srcp) return;
|
||||
if (const DfgSpliceArray* const splicep = srcp->cast<DfgSpliceArray>()) {
|
||||
srcp = splicep->driverAt(idxp->toSizeT());
|
||||
if (!srcp) return;
|
||||
}
|
||||
const DfgUnitArray* uap = srcp->cast<DfgUnitArray>();
|
||||
if (!uap) return;
|
||||
srcp = uap->srcp();
|
||||
// Propagate from driver
|
||||
propagateFromDriver(MASK(vtxp), srcp);
|
||||
// If index is not constant, independent only if the index is indenpendent, and the array
|
||||
// is independent. TODO: could relax by '&' reducing, not sure if worth it.
|
||||
if (MASK(vtxp->bitp()).isOnes() && MASK(fromp).isOnes()) MASK(vtxp).setOnes();
|
||||
}
|
||||
|
||||
void visit(DfgConcat* vtxp) override {
|
||||
const DfgVertex* const rhsp = vtxp->rhsp();
|
||||
const DfgVertex* const lhsp = vtxp->lhsp();
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opSelInto(MASK(rhsp), 0, rhsp->width());
|
||||
m.opSelInto(MASK(lhsp), rhsp->width(), lhsp->width());
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m.opSelInto(MASK(rhsp).num(), 0, rhsp->width());
|
||||
m.opSelInto(MASK(lhsp).num(), rhsp->width(), lhsp->width());
|
||||
}
|
||||
|
||||
void visit(DfgRep* vtxp) override {
|
||||
const uint32_t count = vtxp->count();
|
||||
const DfgVertex* const srcp = vtxp->srcp();
|
||||
const uint32_t sWidth = srcp->width();
|
||||
V3Number& vMask = MASK(vtxp);
|
||||
V3Number& sMask = MASK(srcp);
|
||||
V3Number& vMask = MASK(vtxp).num();
|
||||
V3Number& sMask = MASK(srcp).num();
|
||||
for (uint32_t i = 0; i < count; ++i) vMask.opSelInto(sMask, i * sWidth, sWidth);
|
||||
}
|
||||
|
||||
void visit(DfgSel* vtxp) override {
|
||||
const uint32_t lsb = vtxp->lsb();
|
||||
const uint32_t msb = lsb + vtxp->width() - 1;
|
||||
MASK(vtxp).opSel(MASK(vtxp->fromp()), msb, lsb);
|
||||
MASK(vtxp).num().opSel(MASK(vtxp->fromp()).num(), msb, lsb);
|
||||
}
|
||||
|
||||
void visit(DfgExtend* vtxp) override {
|
||||
const DfgVertex* const srcp = vtxp->srcp();
|
||||
const uint32_t sWidth = srcp->width();
|
||||
V3Number& s = MASK(srcp);
|
||||
V3Number& m = MASK(vtxp);
|
||||
V3Number& s = MASK(srcp).num();
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m.opSelInto(s, 0, sWidth);
|
||||
m.opSetRange(sWidth, vtxp->width() - sWidth, '1');
|
||||
}
|
||||
void visit(DfgExtendS* vtxp) override {
|
||||
const DfgVertex* const srcp = vtxp->srcp();
|
||||
const uint32_t sWidth = srcp->width();
|
||||
V3Number& s = MASK(srcp);
|
||||
V3Number& m = MASK(vtxp);
|
||||
V3Number& s = MASK(srcp).num();
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m.opSelInto(s, 0, sWidth);
|
||||
m.opSetRange(sWidth, vtxp->width() - sWidth, s.bitIs0(sWidth - 1) ? '0' : '1');
|
||||
}
|
||||
|
|
@ -928,71 +1096,62 @@ class IndependentBits final : public DfgVisitor {
|
|||
}
|
||||
|
||||
void visit(DfgAnd* vtxp) override { //
|
||||
MASK(vtxp).opAnd(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
|
||||
MASK(vtxp).num().opAnd(MASK(vtxp->lhsp()).num(), MASK(vtxp->rhsp()).num());
|
||||
}
|
||||
void visit(DfgOr* vtxp) override { //
|
||||
MASK(vtxp).opAnd(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
|
||||
MASK(vtxp).num().opAnd(MASK(vtxp->lhsp()).num(), MASK(vtxp->rhsp()).num());
|
||||
}
|
||||
void visit(DfgXor* vtxp) override { //
|
||||
MASK(vtxp).opAnd(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
|
||||
MASK(vtxp).num().opAnd(MASK(vtxp->lhsp()).num(), MASK(vtxp->rhsp()).num());
|
||||
}
|
||||
|
||||
void visit(DfgAdd* vtxp) override {
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opAnd(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m.opAnd(MASK(vtxp->lhsp()).num(), MASK(vtxp->rhsp()).num());
|
||||
floodTowardsMsb(m);
|
||||
}
|
||||
void visit(DfgSub* vtxp) override { // Same as Add: 2's complement (a - b) == (a + ~b + 1)
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opAnd(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m.opAnd(MASK(vtxp->lhsp()).num(), MASK(vtxp->rhsp()).num());
|
||||
floodTowardsMsb(m);
|
||||
}
|
||||
|
||||
void visit(DfgRedAnd* vtxp) override { //
|
||||
if (MASK(vtxp->lhsp()).isEqAllOnes()) { //
|
||||
MASK(vtxp).setAllBits1();
|
||||
}
|
||||
void visit(DfgRedAnd* vtxp) override {
|
||||
const bool independent = MASK(vtxp->lhsp()).isOnes();
|
||||
if (independent) MASK(vtxp).setOnes();
|
||||
}
|
||||
void visit(DfgRedOr* vtxp) override { //
|
||||
if (MASK(vtxp->lhsp()).isEqAllOnes()) { //
|
||||
MASK(vtxp).setAllBits1();
|
||||
}
|
||||
void visit(DfgRedOr* vtxp) override {
|
||||
const bool independent = MASK(vtxp->lhsp()).isOnes();
|
||||
if (independent) MASK(vtxp).setOnes();
|
||||
}
|
||||
void visit(DfgRedXor* vtxp) override { //
|
||||
if (MASK(vtxp->lhsp()).isEqAllOnes()) { //
|
||||
MASK(vtxp).setAllBits1();
|
||||
}
|
||||
void visit(DfgRedXor* vtxp) override {
|
||||
const bool independent = MASK(vtxp->lhsp()).isOnes();
|
||||
if (independent) MASK(vtxp).setOnes();
|
||||
}
|
||||
|
||||
void visit(DfgEq* vtxp) override {
|
||||
const bool independent
|
||||
= MASK(vtxp->lhsp()).isEqAllOnes() && MASK(vtxp->rhsp()).isEqAllOnes();
|
||||
MASK(vtxp).setBit(0, independent ? '1' : '0');
|
||||
const bool independent = MASK(vtxp->lhsp()).isOnes() && MASK(vtxp->rhsp()).isOnes();
|
||||
if (independent) MASK(vtxp).setOnes();
|
||||
}
|
||||
void visit(DfgNeq* vtxp) override {
|
||||
const bool independent
|
||||
= MASK(vtxp->lhsp()).isEqAllOnes() && MASK(vtxp->rhsp()).isEqAllOnes();
|
||||
MASK(vtxp).setBit(0, independent ? '1' : '0');
|
||||
const bool independent = MASK(vtxp->lhsp()).isOnes() && MASK(vtxp->rhsp()).isOnes();
|
||||
if (independent) MASK(vtxp).setOnes();
|
||||
}
|
||||
void visit(DfgLt* vtxp) override {
|
||||
const bool independent
|
||||
= MASK(vtxp->lhsp()).isEqAllOnes() && MASK(vtxp->rhsp()).isEqAllOnes();
|
||||
MASK(vtxp).setBit(0, independent ? '1' : '0');
|
||||
const bool independent = MASK(vtxp->lhsp()).isOnes() && MASK(vtxp->rhsp()).isOnes();
|
||||
if (independent) MASK(vtxp).setOnes();
|
||||
}
|
||||
void visit(DfgLte* vtxp) override {
|
||||
const bool independent
|
||||
= MASK(vtxp->lhsp()).isEqAllOnes() && MASK(vtxp->rhsp()).isEqAllOnes();
|
||||
MASK(vtxp).setBit(0, independent ? '1' : '0');
|
||||
const bool independent = MASK(vtxp->lhsp()).isOnes() && MASK(vtxp->rhsp()).isOnes();
|
||||
if (independent) MASK(vtxp).setOnes();
|
||||
}
|
||||
void visit(DfgGt* vtxp) override {
|
||||
const bool independent
|
||||
= MASK(vtxp->lhsp()).isEqAllOnes() && MASK(vtxp->rhsp()).isEqAllOnes();
|
||||
MASK(vtxp).setBit(0, independent ? '1' : '0');
|
||||
const bool independent = MASK(vtxp->lhsp()).isOnes() && MASK(vtxp->rhsp()).isOnes();
|
||||
if (independent) MASK(vtxp).setOnes();
|
||||
}
|
||||
void visit(DfgGte* vtxp) override {
|
||||
const bool independent
|
||||
= MASK(vtxp->lhsp()).isEqAllOnes() && MASK(vtxp->rhsp()).isEqAllOnes();
|
||||
MASK(vtxp).setBit(0, independent ? '1' : '0');
|
||||
const bool independent = MASK(vtxp->lhsp()).isOnes() && MASK(vtxp->rhsp()).isOnes();
|
||||
if (independent) MASK(vtxp).setOnes();
|
||||
}
|
||||
|
||||
void visit(DfgShiftRS* vtxp) override {
|
||||
|
|
@ -1004,14 +1163,10 @@ class IndependentBits final : public DfgVisitor {
|
|||
if (DfgConst* const rConstp = rhsp->cast<DfgConst>()) {
|
||||
const uint32_t shiftAmount = rConstp->toU32();
|
||||
if (shiftAmount >= width) {
|
||||
if (MASK(lhsp).bitIs0(width - 1)) {
|
||||
MASK(vtxp).setAllBits0();
|
||||
} else {
|
||||
MASK(vtxp).setAllBits1();
|
||||
}
|
||||
if (MASK(lhsp).num().bitIs1(width - 1)) { MASK(vtxp).setOnes(); }
|
||||
} else {
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opShiftRS(MASK(lhsp), rConstp->num(), width);
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m.opShiftRS(MASK(lhsp).num(), rConstp->num(), width);
|
||||
m.opSetRange(width - shiftAmount, shiftAmount, '1');
|
||||
}
|
||||
return;
|
||||
|
|
@ -1020,9 +1175,9 @@ class IndependentBits final : public DfgVisitor {
|
|||
// Otherwise, as the shift amount is non-negative, all independent
|
||||
// and consecutive top bits in the lhs yield an independent result
|
||||
// if the shift amount is independent.
|
||||
if (MASK(rhsp).isEqAllOnes()) {
|
||||
V3Number& m = MASK(vtxp);
|
||||
m = MASK(lhsp);
|
||||
if (MASK(rhsp).isOnes()) {
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m = MASK(lhsp).num();
|
||||
floodTowardsLsb(m);
|
||||
}
|
||||
}
|
||||
|
|
@ -1036,10 +1191,10 @@ class IndependentBits final : public DfgVisitor {
|
|||
if (DfgConst* const rConstp = rhsp->cast<DfgConst>()) {
|
||||
const uint32_t shiftAmount = rConstp->toU32();
|
||||
if (shiftAmount >= width) {
|
||||
MASK(vtxp).setAllBits1();
|
||||
MASK(vtxp).setOnes();
|
||||
} else {
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opShiftR(MASK(lhsp), rConstp->num());
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m.opShiftR(MASK(lhsp).num(), rConstp->num());
|
||||
m.opSetRange(width - shiftAmount, shiftAmount, '1');
|
||||
}
|
||||
return;
|
||||
|
|
@ -1048,9 +1203,9 @@ class IndependentBits final : public DfgVisitor {
|
|||
// Otherwise, as the shift amount is non-negative, all independent
|
||||
// and consecutive top bits in the lhs yield an independent result
|
||||
// if the shift amount is independent.
|
||||
if (MASK(rhsp).isEqAllOnes()) {
|
||||
V3Number& m = MASK(vtxp);
|
||||
m = MASK(lhsp);
|
||||
if (MASK(rhsp).isOnes()) {
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m = MASK(lhsp).num();
|
||||
floodTowardsLsb(m);
|
||||
}
|
||||
}
|
||||
|
|
@ -1064,10 +1219,10 @@ class IndependentBits final : public DfgVisitor {
|
|||
if (DfgConst* const rConstp = rhsp->cast<DfgConst>()) {
|
||||
const uint32_t shiftAmount = rConstp->toU32();
|
||||
if (shiftAmount >= width) {
|
||||
MASK(vtxp).setAllBits1();
|
||||
MASK(vtxp).setOnes();
|
||||
} else {
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opShiftL(MASK(lhsp), rConstp->num());
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m.opShiftL(MASK(lhsp).num(), rConstp->num());
|
||||
m.opSetRange(0, shiftAmount, '1');
|
||||
}
|
||||
return;
|
||||
|
|
@ -1076,23 +1231,21 @@ class IndependentBits final : public DfgVisitor {
|
|||
// Otherwise, as the shift amount is non-negative, all independent
|
||||
// and consecutive bottom bits in the lhs yield an independent result
|
||||
// if the shift amount is independent.
|
||||
if (MASK(rhsp).isEqAllOnes()) {
|
||||
V3Number& m = MASK(vtxp);
|
||||
m = MASK(lhsp);
|
||||
if (MASK(rhsp).isOnes()) {
|
||||
V3Number& m = MASK(vtxp).num();
|
||||
m = MASK(lhsp).num();
|
||||
floodTowardsMsb(m);
|
||||
}
|
||||
}
|
||||
|
||||
void visit(DfgCond* vtxp) override {
|
||||
if (MASK(vtxp->condp()).isEqAllOnes()) {
|
||||
MASK(vtxp).opAnd(MASK(vtxp->thenp()), MASK(vtxp->elsep()));
|
||||
if (MASK(vtxp->condp()).isOnes()) {
|
||||
MASK(vtxp).num().opAnd(MASK(vtxp->thenp()).num(), MASK(vtxp->elsep()).num());
|
||||
}
|
||||
}
|
||||
|
||||
void visit(DfgMatchMasked* vtxp) override {
|
||||
if (MASK(vtxp->lhsp()).isEqAllOnes() && MASK(vtxp->matchp()).isEqAllOnes()) { //
|
||||
MASK(vtxp).setAllBits1();
|
||||
}
|
||||
if (MASK(vtxp->lhsp()).isOnes() && MASK(vtxp->matchp()).isOnes()) { MASK(vtxp).setOnes(); }
|
||||
}
|
||||
|
||||
#undef MASK
|
||||
|
|
@ -1102,11 +1255,6 @@ class IndependentBits final : public DfgVisitor {
|
|||
vtx.foreachSink([&](DfgVertex& sink) {
|
||||
// Ignore if sink is not part of an SCC, already has all bits marked independent
|
||||
if (!m_sccInfo.get(sink)) return false;
|
||||
// If a vertex is not handled directly, recursively enqueue its sinks instead
|
||||
if (!handledDirectly(sink)) {
|
||||
enqueueSinks(sink);
|
||||
return false;
|
||||
}
|
||||
// Otherwise just enqueue it
|
||||
VertexState& state = m_vtxp2State.at(&sink);
|
||||
if (!state.m_isOnWorkList) {
|
||||
|
|
@ -1169,18 +1317,15 @@ class IndependentBits final : public DfgVisitor {
|
|||
// always assign constants bits, which are always independent (eg Extend/Shift)
|
||||
// Enqueue sinks of all SCC vertices that have at least one independent bit
|
||||
for (DfgVertex* const vtxp : rpoEnumeration) {
|
||||
if (!handledDirectly(*vtxp)) continue;
|
||||
if (m_sccInfo.get(*vtxp)) continue;
|
||||
mask(*vtxp).setAllBits1();
|
||||
mask(*vtxp).setOnes();
|
||||
}
|
||||
for (DfgVertex* const vtxp : rpoEnumeration) {
|
||||
if (!handledDirectly(*vtxp)) continue;
|
||||
if (!m_sccInfo.get(*vtxp)) continue;
|
||||
iterate(vtxp);
|
||||
UINFO(9, "Initial independent bits of "
|
||||
<< vtxp << " " << vtxp->typeName()
|
||||
<< " are: " << mask(*vtxp).displayed(vtxp->fileline(), "%b"));
|
||||
if (!mask(*vtxp).isEqZero()) enqueueSinks(*vtxp);
|
||||
UINFO(9, "Initial independent bits of " << vtxp << " " << vtxp->typeName()
|
||||
<< " are: " << mask(*vtxp).toString());
|
||||
if (!mask(*vtxp).isZero()) enqueueSinks(*vtxp);
|
||||
}
|
||||
|
||||
// Propagate independent bits until no more changes are made
|
||||
|
|
@ -1191,13 +1336,11 @@ class IndependentBits final : public DfgVisitor {
|
|||
m_vtxp2State.at(currp).m_isOnWorkList = false;
|
||||
// Should not enqueue vertices that are not in an SCC
|
||||
UASSERT_OBJ(m_sccInfo.get(*currp), currp, "Vertex should be in an SCC");
|
||||
// Should only enqueue packed vertices
|
||||
UASSERT_OBJ(handledDirectly(*currp), currp, "Vertex should be handled directly");
|
||||
|
||||
// Grab current mask of item
|
||||
const V3Number& currMask = mask(*currp);
|
||||
const BitMask& currMask = mask(*currp);
|
||||
// Remember current mask so we can check if it changed
|
||||
const V3Number prevMask = currMask;
|
||||
const BitMask prevMask = currMask;
|
||||
|
||||
UINFO(9, "Analyzing independent bits of " << currp << " " << currp->typeName());
|
||||
|
||||
|
|
@ -1205,19 +1348,16 @@ class IndependentBits final : public DfgVisitor {
|
|||
iterate(currp);
|
||||
|
||||
// If mask changed, enqueue sinks
|
||||
if (!prevMask.isCaseEq(currMask)) {
|
||||
if (prevMask != currMask) {
|
||||
UINFO(9, "Independent bits of " //
|
||||
<< currp << " " << currp->typeName() << " changed" //
|
||||
<< "\n form: " << prevMask.displayed(currp->fileline(), "%b")
|
||||
<< "\n to: " << currMask.displayed(currp->fileline(), "%b"));
|
||||
<< "\n form: " << prevMask.toString()
|
||||
<< "\n to: " << currMask.toString());
|
||||
enqueueSinks(*currp);
|
||||
// Check the mask only ever expands (no bit goes 1 -> 0)
|
||||
if (VL_UNLIKELY(v3Global.opt.debugCheck())) {
|
||||
V3Number notCurr{currMask};
|
||||
notCurr.opNot(currMask);
|
||||
V3Number prevAndNotCurr{currMask};
|
||||
prevAndNotCurr.opAnd(prevMask, notCurr);
|
||||
UASSERT_OBJ(prevAndNotCurr.isEqZero(), currp, "Mask should only expand");
|
||||
UASSERT_OBJ(!currMask.isContractionOf(prevMask), currp,
|
||||
"Mask should only expand");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1228,8 +1368,8 @@ public:
|
|||
// returns a map from vertices to a bit mask, where a bit in the mask is
|
||||
// set if the corresponding bit in that vertex is known to be independent
|
||||
// of the values of vertices in the same SCC as the vertex resides in.
|
||||
static std::unordered_map<const DfgVertex*, V3Number> apply(DfgGraph& dfg,
|
||||
const SccInfo& sccInfo) {
|
||||
static std::unordered_map<const DfgVertex*, BitMask> apply(DfgGraph& dfg,
|
||||
const SccInfo& sccInfo) {
|
||||
return std::move(IndependentBits{dfg, sccInfo}.m_vtxp2Mask);
|
||||
}
|
||||
};
|
||||
|
|
@ -1239,21 +1379,21 @@ class FixUp final {
|
|||
SccInfo& m_sccInfo; // The SccInfo instance
|
||||
TraceDriver m_traceDriver{m_dfg, m_sccInfo};
|
||||
// The independent bits map
|
||||
const std::unordered_map<const DfgVertex*, V3Number> m_independentBits
|
||||
const std::unordered_map<const DfgVertex*, BitMask> m_independentBits
|
||||
= IndependentBits::apply(m_dfg, m_sccInfo);
|
||||
size_t m_nImprovements = 0; // Number of improvements mde
|
||||
size_t m_nImprovements = 0; // Number of improvements made
|
||||
|
||||
// Returns a bitmask set if that bit of 'vtx' is used (has a sink)
|
||||
static V3Number computeUsedBits(DfgVertex& vtx) {
|
||||
V3Number result{vtx.fileline(), static_cast<int>(vtx.width()), 0};
|
||||
static BitMask computeUsedBits(DfgVertex& vtx) {
|
||||
BitMask result{vtx};
|
||||
vtx.foreachSink([&result](DfgVertex& sink) {
|
||||
// If used via a Sel, mark the selected bits used
|
||||
if (const DfgSel* const selp = sink.cast<DfgSel>()) {
|
||||
result.opSetRange(selp->lsb(), selp->width(), '1');
|
||||
result.num().opSetRange(selp->lsb(), selp->width(), '1');
|
||||
return false;
|
||||
}
|
||||
// Used without a Sel, so all bits are used
|
||||
result.setAllBits1();
|
||||
result.setOnes();
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
|
|
@ -1306,20 +1446,18 @@ class FixUp final {
|
|||
UASSERT_OBJ(!vtx.is<DfgSplicePacked>(), &vtx, "Should not be a splice");
|
||||
|
||||
// Get which bits of 'vtxp' are independent of the SCCs
|
||||
const V3Number& indpBits = m_independentBits.at(&vtx);
|
||||
UINFO(9, "Independent bits of '" << debugStr(vtx) << "' are "
|
||||
<< indpBits.displayed(vtx.fileline(), "%b"));
|
||||
const BitMask& indpBits = m_independentBits.at(&vtx);
|
||||
UINFO(9, "Independent bits of '" << debugStr(vtx) << "' are " << indpBits.toString());
|
||||
// Can't do anything if all bits are dependent
|
||||
if (indpBits.isEqZero()) return;
|
||||
if (indpBits.isZero()) return;
|
||||
|
||||
// Figure out which bits of 'vtxp' are used
|
||||
const V3Number usedBits = computeUsedBits(vtx);
|
||||
UINFO(9, "Used bits of '" << debugStr(vtx) << "' are "
|
||||
<< usedBits.displayed(vtx.fileline(), "%b"));
|
||||
const BitMask usedBits = computeUsedBits(vtx);
|
||||
UINFO(9, "Used bits of '" << debugStr(vtx) << "' are " << usedBits.toString());
|
||||
|
||||
// Nothing to do if no used bits are independen (all used bits are dependent)
|
||||
V3Number usedAndIndependent{vtx.fileline(), static_cast<int>(vtx.width()), 0};
|
||||
usedAndIndependent.opAnd(usedBits, indpBits);
|
||||
usedAndIndependent.opAnd(usedBits.num(), indpBits.num());
|
||||
if (usedAndIndependent.isEqZero()) return;
|
||||
|
||||
// We are computing the terms to concatenate and replace 'vtxp' with
|
||||
|
|
@ -1328,14 +1466,14 @@ class FixUp final {
|
|||
// Iterate through consecutive used/unused ranges
|
||||
FileLine* const flp = vtx.fileline();
|
||||
const uint32_t width = vtx.width();
|
||||
bool isUsed = usedBits.bitIs1(0); // Is current range used
|
||||
bool isUsed = usedBits.num().bitIs1(0); // Is current range used
|
||||
uint32_t lsb = 0; // LSB of current range
|
||||
for (uint32_t msb = 0; msb < width; ++msb) {
|
||||
const bool endRange = msb == width - 1 || isUsed != usedBits.bitIs1(msb + 1);
|
||||
const bool endRange = msb == width - 1 || isUsed != usedBits.num().bitIs1(msb + 1);
|
||||
if (!endRange) continue;
|
||||
if (isUsed) {
|
||||
// The range is used, compute the replacement terms
|
||||
gatherTerms(termps, vtx, indpBits, msb, lsb);
|
||||
gatherTerms(termps, vtx, indpBits.num(), msb, lsb);
|
||||
} else {
|
||||
// The range is not used, just use constant 0 as a placeholder
|
||||
DfgConst* const constp = new DfgConst{m_dfg, flp, msb - lsb + 1, 0};
|
||||
|
|
|
|||
|
|
@ -78,7 +78,13 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) {
|
|||
&& !vVtxp->hasExtWrRefs() //
|
||||
&& !vVtxp->hasModWrRefs();
|
||||
VL_DO_DANGLING(vVtxp->unlinkDelete(dfg), vVtxp);
|
||||
if (srcp) VL_DO_DANGLING(srcp->unlinkDelete(dfg), srcp);
|
||||
if (srcp) {
|
||||
srcp->foreachSource([&](DfgVertex& src) {
|
||||
src.as<DfgLogic>()->setDrivesUnusedVars();
|
||||
return false;
|
||||
});
|
||||
VL_DO_DANGLING(srcp->unlinkDelete(dfg), srcp);
|
||||
}
|
||||
if (delAst) {
|
||||
VL_DO_DANGLING(vscp->unlinkFrBack()->deleteTree(), vscp);
|
||||
++ctx.m_varsDeleted;
|
||||
|
|
|
|||
|
|
@ -2005,6 +2005,11 @@ static void dfgSelectLogicForSynthesis(DfgGraph& dfg) {
|
|||
for (DfgVertex& vtx : dfg.opVertices()) {
|
||||
DfgLogic* const logicp = vtx.cast<DfgLogic>();
|
||||
if (!logicp) continue;
|
||||
// If drives an unused variable, synthesize it so the partial logic can be removed
|
||||
if (logicp->drivesUnusedVars()) {
|
||||
worklist.push_front(*logicp);
|
||||
continue;
|
||||
}
|
||||
// Blocks corresponding to continuous assignments
|
||||
if (logicp->nodep()->keyword() == VAlwaysKwd::CONT_ASSIGN) {
|
||||
worklist.push_front(*logicp);
|
||||
|
|
@ -2016,10 +2021,8 @@ static void dfgSelectLogicForSynthesis(DfgGraph& dfg) {
|
|||
worklist.push_front(*logicp);
|
||||
continue;
|
||||
}
|
||||
// Simple blocks driving exactly 1 variable, e.g if (rst) a = b else a = c;
|
||||
if (!logicp->hasMultipleSinks() && cfg.nBlocks() <= 4 && cfg.nEdges() <= 4) {
|
||||
worklist.push_front(*logicp);
|
||||
}
|
||||
// Blocks driving exactly 1 variable
|
||||
if (!logicp->hasMultipleSinks()) worklist.push_front(*logicp);
|
||||
}
|
||||
|
||||
// Now expand to cover all logic driving the same set of variables and mark
|
||||
|
|
|
|||
|
|
@ -512,6 +512,7 @@ class DfgLogic final : public DfgVertexVariadic {
|
|||
AstScope* const m_scopep; // The AstScope m_nodep is under, iff scoped
|
||||
const std::unique_ptr<CfgGraph> m_cfgp;
|
||||
std::vector<DfgVertex*> m_synth; // Vertices this logic was synthesized into
|
||||
bool m_drivesUnusedVars = false; // Logic drives unused variables
|
||||
bool m_selectedForSynthesis = false; // Logic selected for synthesis
|
||||
bool m_nonSynthesizable = false; // Logic is not synthesizeable (by DfgSynthesis)
|
||||
bool m_reverted = false; // Logic was synthesized (in part if non-synthesizable) then reverted
|
||||
|
|
@ -538,6 +539,8 @@ public:
|
|||
const CfgGraph& cfg() const { return *m_cfgp; }
|
||||
std::vector<DfgVertex*>& synth() { return m_synth; }
|
||||
const std::vector<DfgVertex*>& synth() const { return m_synth; }
|
||||
bool drivesUnusedVars() const { return m_drivesUnusedVars; }
|
||||
void setDrivesUnusedVars() { m_drivesUnusedVars = true; }
|
||||
bool selectedForSynthesis() const { return m_selectedForSynthesis; }
|
||||
void setSelectedForSynthesis() { m_selectedForSynthesis = true; }
|
||||
bool nonSynthesizable() const { return m_nonSynthesizable; }
|
||||
|
|
|
|||
|
|
@ -1050,8 +1050,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
if (nodep->packed()) puts("packed ");
|
||||
{
|
||||
puts("{\n");
|
||||
VL_RESTORER(m_packedps);
|
||||
m_packedps.clear();
|
||||
VL_RESTORER_CLEAR(m_packedps);
|
||||
for (AstMemberDType* itemp = nodep->membersp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
iterateConst(itemp);
|
||||
|
|
|
|||
|
|
@ -561,10 +561,9 @@ class ForkVisitor final : public VNVisitor {
|
|||
// replace body with a call to that task. Returns true iff wrapped.
|
||||
bool taskify(AstBegin* beginp) {
|
||||
// Visit statement to gather variables (And recursively process)
|
||||
VL_RESTORER(m_forkLocalsp);
|
||||
VL_RESTORER_CLEAR(m_forkLocalsp);
|
||||
VL_RESTORER(m_capturedVarsp);
|
||||
VL_RESTORER(m_capturedArgsp);
|
||||
m_forkLocalsp.clear();
|
||||
m_capturedVarsp = nullptr;
|
||||
m_capturedArgsp = nullptr;
|
||||
iterate(beginp);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
|
|
@ -44,27 +45,90 @@ class V3ThreadPool;
|
|||
//======================================================================
|
||||
// Restorer
|
||||
|
||||
/// Save a given variable's value on the stack, restoring it at end-of-scope.
|
||||
// Object must be named, or it will not persist until end-of-scope.
|
||||
// Constructor needs () or GCC 4.8 false warning.
|
||||
#define VL_RESTORER(var) const VRestorer<typename std::decay_t<decltype(var)>> restorer_##var(var);
|
||||
/// Get the copy of the variable previously saved by VL_RESTORER()
|
||||
// For all flavours, 'var' must be a named scalar variable (simple identifier).
|
||||
|
||||
// Copy given variable's value on the stack, copy saved value back at end-of-scope.
|
||||
// Only usable for trivially copyable types; use VL_RESTORER_COPY/VL_RESTORER_CLEAR for
|
||||
// non-trivially copyable types, which are more efficient.
|
||||
#define VL_RESTORER(var) \
|
||||
const VRestorerTrivial<typename std::decay_t<decltype(var)>> restorer_##var(var);
|
||||
|
||||
// This is the equivalent of VL_RESTORER for non-trivially copyable types. Still more efficient
|
||||
// than VL_RESTORER as uses move to restore.
|
||||
#define VL_RESTORER_COPY(var) \
|
||||
const VRestorerCopy<typename std::decay_t<decltype(var)>> restorer_##var(var);
|
||||
|
||||
// Swap 'var' with a no-args constructed object of the same type, effectively clearing it, then
|
||||
// swap back at end-of-scope. No copying involved. Use this e.g. for std containers where they
|
||||
// would be .clear()'d right after the VL_RESTORER instance.
|
||||
#define VL_RESTORER_CLEAR(var) \
|
||||
const VRestorerClear<typename std::decay_t<decltype(var)>> restorer_##var(var);
|
||||
|
||||
// Get const reference to the saved copy
|
||||
#define VL_RESTORER_PREV(var) restorer_##var.saved()
|
||||
|
||||
// Object used by VL_RESTORER. This object must be an auto variable, not
|
||||
// allocated on the heap or otherwise.
|
||||
// Implementation of VL_RESTORER
|
||||
template <typename T>
|
||||
class VRestorer final {
|
||||
class VRestorerTrivial final {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Use VL_RESTORER_{COPY,CLEAR} for non trivially copyable types");
|
||||
T& m_ref; // Reference to object we're saving and restoring
|
||||
const T m_saved; // Value saved, for later restore
|
||||
|
||||
public:
|
||||
explicit VRestorer(T& permr)
|
||||
: m_ref{permr}
|
||||
, m_saved{permr} {}
|
||||
~VRestorer() { m_ref = m_saved; }
|
||||
explicit VRestorerTrivial(T& val)
|
||||
: m_ref{val}
|
||||
, m_saved{val} {}
|
||||
~VRestorerTrivial() { m_ref = m_saved; }
|
||||
VL_UNCOPYABLE(VRestorerTrivial);
|
||||
// Must be stack allocated
|
||||
void* operator new(size_t) = delete;
|
||||
void operator delete(void*) = delete;
|
||||
|
||||
const T& saved() const { return m_saved; }
|
||||
};
|
||||
|
||||
// Implementation of VL_RESTORER_COPY
|
||||
template <typename T>
|
||||
class VRestorerCopy final {
|
||||
static_assert(!std::is_trivially_copyable<T>::value,
|
||||
"Use VL_RESTORER for trivially copyable types");
|
||||
T& m_ref; // Reference to object we're saving and restoring
|
||||
T m_saved; // Value saved, for later restore
|
||||
|
||||
public:
|
||||
explicit VRestorerCopy(T& val)
|
||||
: m_ref{val}
|
||||
, m_saved{val} {}
|
||||
~VRestorerCopy() { m_ref = std::move(m_saved); }
|
||||
VL_UNCOPYABLE(VRestorerCopy);
|
||||
// Must be stack allocated
|
||||
void* operator new(size_t) = delete;
|
||||
void operator delete(void*) = delete;
|
||||
|
||||
const T& saved() const { return m_saved; }
|
||||
};
|
||||
|
||||
// Implementation of VL_RESTORER_CLEAR.
|
||||
template <typename T>
|
||||
class VRestorerClear final {
|
||||
static_assert(!std::is_trivially_copyable<T>::value,
|
||||
"Use VL_RESTORER for trivially copyable types");
|
||||
T& m_ref; // Reference to object we're saving and restoring
|
||||
T m_saved{}; // Owns the swapped-out value; starts empty
|
||||
|
||||
public:
|
||||
explicit VRestorerClear(T& val)
|
||||
: m_ref{val} {
|
||||
std::swap(m_ref, m_saved);
|
||||
}
|
||||
~VRestorerClear() { std::swap(m_ref, m_saved); }
|
||||
VL_UNCOPYABLE(VRestorerClear);
|
||||
// Must be stack allocated
|
||||
void* operator new(size_t) = delete;
|
||||
void operator delete(void*) = delete;
|
||||
|
||||
const T& saved() const { return m_saved; }
|
||||
VL_UNCOPYABLE(VRestorer);
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
|
|
@ -331,12 +331,9 @@ class HierBlockUsageCollectVisitor final : public VNVisitorConst {
|
|||
}
|
||||
|
||||
// This is a hierarchical block, gather parts
|
||||
VL_RESTORER(m_params);
|
||||
VL_RESTORER(m_typeParams);
|
||||
VL_RESTORER(m_childrenp);
|
||||
m_params.clear();
|
||||
m_typeParams.clear();
|
||||
m_childrenp.clear();
|
||||
VL_RESTORER_CLEAR(m_params);
|
||||
VL_RESTORER_CLEAR(m_typeParams);
|
||||
VL_RESTORER_CLEAR(m_childrenp);
|
||||
iterateChildrenConst(nodep);
|
||||
// Create the graph vertex for this hier block
|
||||
V3HierBlock* const blockp = new V3HierBlock{m_graphp, nodep, m_params, m_typeParams};
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class InlineIntfRefVisitor final : public VNVisitor {
|
|||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override { iterateChildren(nodep->topModulep()); }
|
||||
void visit(AstCell* nodep) override {
|
||||
VL_RESTORER(m_scope);
|
||||
VL_RESTORER_COPY(m_scope);
|
||||
if (m_scope.empty()) {
|
||||
m_scope = nodep->name();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ class LibMapVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
void visit(AstLibrary* nodep) override {
|
||||
VL_RESTORER(m_lib);
|
||||
VL_RESTORER(m_rel);
|
||||
VL_RESTORER_CLEAR(m_lib);
|
||||
VL_RESTORER_CLEAR(m_rel);
|
||||
m_lib = nodep->name();
|
||||
m_rel = V3Os::filenameDir(nodep->fileline()->filename());
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -157,11 +157,11 @@ class LinkConfigsVisitor final : public VNVisitor {
|
|||
m_isDefault = true;
|
||||
iterateAndNextNull(nodep->usep());
|
||||
} else if (nodep->isCell()) {
|
||||
VL_RESTORER(m_cell);
|
||||
VL_RESTORER_CLEAR(m_cell);
|
||||
m_cell = nodep->cellp()->name();
|
||||
iterateAndNextNull(nodep->usep());
|
||||
} else {
|
||||
VL_RESTORER(m_hierInst);
|
||||
VL_RESTORER_COPY(m_hierInst);
|
||||
{
|
||||
VL_RESTORER(m_dotp);
|
||||
m_dotp = VN_AS(nodep->cellp(), Dot);
|
||||
|
|
|
|||
|
|
@ -1259,7 +1259,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
const bool standalonePkg
|
||||
= !m_modSymp && (m_statep->forPrearray() && VN_IS(nodep, Package));
|
||||
const bool doit = (m_modSymp || standalonePkg);
|
||||
VL_RESTORER(m_scope);
|
||||
VL_RESTORER_COPY(m_scope);
|
||||
VL_RESTORER(m_classOrPackagep);
|
||||
VL_RESTORER(m_modSymp);
|
||||
VL_RESTORER(m_curSymp);
|
||||
|
|
@ -1335,7 +1335,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
void visit(AstClass* nodep) override { // FindVisitor::
|
||||
UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit");
|
||||
UINFO(8, " " << nodep);
|
||||
VL_RESTORER(m_scope);
|
||||
VL_RESTORER_COPY(m_scope);
|
||||
VL_RESTORER(m_classOrPackagep);
|
||||
VL_RESTORER(m_modSymp);
|
||||
VL_RESTORER(m_curSymp);
|
||||
|
|
@ -1384,7 +1384,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
if (nodep->recursive() && m_inRecursion) return;
|
||||
iterateChildren(nodep);
|
||||
// Recurse in, preserving state
|
||||
VL_RESTORER(m_scope);
|
||||
VL_RESTORER_COPY(m_scope);
|
||||
VL_RESTORER(m_modSymp);
|
||||
VL_RESTORER(m_curSymp);
|
||||
VL_RESTORER(m_paramNum);
|
||||
|
|
@ -3584,7 +3584,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
|
||||
void symIterateChildren(AstNode* nodep, VSymEnt* symp) {
|
||||
// Iterate children, changing to given context, with restore to old context
|
||||
VL_RESTORER(m_ds);
|
||||
VL_RESTORER_COPY(m_ds);
|
||||
VL_RESTORER(m_curSymp);
|
||||
m_curSymp = symp;
|
||||
m_ds.init(m_curSymp);
|
||||
|
|
@ -3592,7 +3592,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
}
|
||||
void symIterateNull(AstNode* nodep, VSymEnt* symp) {
|
||||
// Iterate node, changing to given context, with restore to old context
|
||||
VL_RESTORER(m_ds);
|
||||
VL_RESTORER_COPY(m_ds);
|
||||
VL_RESTORER(m_curSymp);
|
||||
m_curSymp = symp;
|
||||
m_ds.init(m_curSymp);
|
||||
|
|
@ -3805,10 +3805,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
LINKDOT_VISIT_START();
|
||||
UINFO(5, indent() << "visit " << nodep);
|
||||
checkNoDot(nodep);
|
||||
VL_RESTORER(m_usedPins);
|
||||
VL_RESTORER(m_usedDefParamPins);
|
||||
m_usedPins.clear();
|
||||
m_usedDefParamPins.clear();
|
||||
VL_RESTORER_CLEAR(m_usedPins);
|
||||
VL_RESTORER_CLEAR(m_usedDefParamPins);
|
||||
UASSERT_OBJ(nodep->modp(), nodep,
|
||||
"Instance has unlinked module"); // V3LinkCell should have errored out
|
||||
VL_RESTORER(m_cellp);
|
||||
|
|
@ -3845,10 +3843,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
LINKDOT_VISIT_START();
|
||||
UINFO(5, indent() << "visit " << nodep);
|
||||
// Can be under dot if called as package::class and that class resolves, so no checkNoDot
|
||||
VL_RESTORER(m_usedPins);
|
||||
VL_RESTORER(m_usedDefParamPins);
|
||||
m_usedPins.clear();
|
||||
m_usedDefParamPins.clear();
|
||||
VL_RESTORER_CLEAR(m_usedPins);
|
||||
VL_RESTORER_CLEAR(m_usedDefParamPins);
|
||||
UASSERT_OBJ(nodep->classp(), nodep, "ClassRef has unlinked class");
|
||||
UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp() || V3Error::errorCount(), nodep,
|
||||
"class reference parameter not removed by V3Param");
|
||||
|
|
@ -4753,14 +4749,12 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
LINKDOT_VISIT_START();
|
||||
UINFO(8, indent() << "visit " << nodep);
|
||||
UINFO(9, indent() << m_ds.ascii());
|
||||
VL_RESTORER(m_usedPins);
|
||||
VL_RESTORER(m_usedDefParamPins);
|
||||
m_usedPins.clear();
|
||||
m_usedDefParamPins.clear();
|
||||
VL_RESTORER_CLEAR(m_usedPins);
|
||||
VL_RESTORER_CLEAR(m_usedDefParamPins);
|
||||
UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp(), nodep,
|
||||
"class reference parameter not removed by V3Param");
|
||||
{
|
||||
VL_RESTORER(m_ds);
|
||||
VL_RESTORER_COPY(m_ds);
|
||||
VL_RESTORER(m_pinSymp);
|
||||
|
||||
if (!nodep->classOrPackageSkipp() && nodep->name() != "local::") {
|
||||
|
|
@ -4834,7 +4828,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
VL_RESTORER(m_curSymp);
|
||||
VL_RESTORER(m_ds);
|
||||
VL_RESTORER_COPY(m_ds);
|
||||
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -5054,7 +5048,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
// Created here so should already be resolved.
|
||||
LINKDOT_VISIT_START();
|
||||
UINFO(5, indent() << "visit " << nodep);
|
||||
VL_RESTORER(m_ds);
|
||||
VL_RESTORER_COPY(m_ds);
|
||||
VL_RESTORER(m_randSymp);
|
||||
VL_RESTORER(m_randMethodCallp);
|
||||
{
|
||||
|
|
@ -5509,7 +5503,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
checkNoDot(nodep);
|
||||
{
|
||||
VL_RESTORER(m_curSymp);
|
||||
VL_RESTORER(m_ds);
|
||||
VL_RESTORER_COPY(m_ds);
|
||||
if (nodep->name() != "") {
|
||||
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||
UINFO(5, indent() << "cur=se" << cvtToHex(m_curSymp));
|
||||
|
|
@ -5524,7 +5518,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
checkNoDot(nodep);
|
||||
{
|
||||
VL_RESTORER(m_curSymp);
|
||||
VL_RESTORER(m_ds);
|
||||
VL_RESTORER_COPY(m_ds);
|
||||
if (nodep->name() != "") {
|
||||
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||
UINFO(5, indent() << "cur=se" << cvtToHex(m_curSymp));
|
||||
|
|
@ -5643,7 +5637,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
checkNoDot(nodep);
|
||||
VL_RESTORER(m_curSymp);
|
||||
VL_RESTORER(m_currentWithp);
|
||||
VL_RESTORER(m_restrictedNamesUsed);
|
||||
VL_RESTORER_COPY(m_restrictedNamesUsed);
|
||||
{
|
||||
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||
m_currentWithp = nodep;
|
||||
|
|
@ -5813,7 +5807,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
VL_RESTORER(m_curSymp);
|
||||
VL_RESTORER(m_modSymp);
|
||||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_ifClassImpNames);
|
||||
VL_RESTORER_COPY(m_ifClassImpNames);
|
||||
VL_RESTORER(m_insideClassExtParam);
|
||||
{
|
||||
m_ds.init(m_curSymp);
|
||||
|
|
@ -6169,7 +6163,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
void visit(AstDisable* nodep) override {
|
||||
LINKDOT_VISIT_START();
|
||||
checkNoDot(nodep);
|
||||
VL_RESTORER(m_ds);
|
||||
VL_RESTORER_COPY(m_ds);
|
||||
m_ds.init(m_curSymp);
|
||||
m_ds.m_dotPos = DP_FIRST;
|
||||
m_ds.m_disablep = nodep;
|
||||
|
|
@ -6249,10 +6243,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
UASSERT_OBJ(ifacep, nodep, "Port parameters of AstIfaceRefDType without ifacep()");
|
||||
if (ifacep->dead()) return;
|
||||
checkNoDot(nodep);
|
||||
VL_RESTORER(m_usedPins);
|
||||
VL_RESTORER(m_usedDefParamPins);
|
||||
m_usedPins.clear();
|
||||
m_usedDefParamPins.clear();
|
||||
VL_RESTORER_CLEAR(m_usedPins);
|
||||
VL_RESTORER_CLEAR(m_usedDefParamPins);
|
||||
VL_RESTORER(m_pinSymp);
|
||||
m_pinSymp = m_statep->getNodeSym(ifacep);
|
||||
iterateAndNextNull(nodep->paramsp());
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
<< nodep->verilogKwd() << "'");
|
||||
}
|
||||
|
||||
VL_RESTORER(m_portDups);
|
||||
VL_RESTORER_COPY(m_portDups);
|
||||
collectPorts(nodep->stmtsp());
|
||||
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -763,12 +763,12 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
VL_RESTORER(m_genblkAbove);
|
||||
VL_RESTORER(m_genblkNum);
|
||||
VL_RESTORER(m_beginDepth);
|
||||
VL_RESTORER(m_implTypedef);
|
||||
VL_RESTORER(m_lifetime);
|
||||
VL_RESTORER(m_lifetimeAllowed);
|
||||
VL_RESTORER(m_moduleWithGenericIface);
|
||||
VL_RESTORER(m_randSequenceNum);
|
||||
VL_RESTORER(m_valueModp);
|
||||
VL_RESTORER_CLEAR(m_implTypedef);
|
||||
|
||||
// Module: Create sim table for entire module and iterate
|
||||
cleanFileline(nodep);
|
||||
|
|
@ -780,7 +780,6 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
m_genblkAbove = 0;
|
||||
m_genblkNum = 0;
|
||||
m_beginDepth = 0;
|
||||
m_implTypedef.clear();
|
||||
m_valueModp = nodep;
|
||||
m_lifetime = nodep->lifetime().makeImplicit();
|
||||
m_lifetimeAllowed = VN_IS(nodep, Class);
|
||||
|
|
@ -797,7 +796,7 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
"Verilator top-level internals");
|
||||
}
|
||||
|
||||
VL_RESTORER(m_portDups);
|
||||
VL_RESTORER_COPY(m_portDups);
|
||||
collectPorts(nodep->stmtsp());
|
||||
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class LinkWithVisitor final : public VNVisitor {
|
|||
|
||||
// STATE
|
||||
// Below state needs to be preserved between each module call.
|
||||
string m_randcIllegalWhy; // Why randc illegal
|
||||
const char* m_randcIllegalWhyp = nullptr; // Why randc illegal
|
||||
AstNode* m_randcIllegalp = nullptr; // Node causing randc illegal
|
||||
AstNodeExpr* m_currentRandomizeSelectp = nullptr; // fromp() of current `randomize()` call
|
||||
bool m_inRandomizeWith = false; // If in randomize() with (and no other with afterwards)
|
||||
|
|
@ -49,24 +49,24 @@ class LinkWithVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstConstraintBefore* nodep) override {
|
||||
VL_RESTORER(m_randcIllegalWhy);
|
||||
VL_RESTORER(m_randcIllegalWhyp);
|
||||
VL_RESTORER(m_randcIllegalp);
|
||||
m_randcIllegalWhy = "'solve before' (IEEE 1800-2023 18.5.9)";
|
||||
m_randcIllegalWhyp = "'solve before' (IEEE 1800-2023 18.5.9)";
|
||||
m_randcIllegalp = nodep;
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstDist* nodep) override {
|
||||
VL_RESTORER(m_randcIllegalWhy);
|
||||
VL_RESTORER(m_randcIllegalWhyp);
|
||||
VL_RESTORER(m_randcIllegalp);
|
||||
m_randcIllegalWhy = "'constraint dist' (IEEE 1800-2023 18.5.3)";
|
||||
m_randcIllegalWhyp = "'constraint dist' (IEEE 1800-2023 18.5.3)";
|
||||
m_randcIllegalp = nodep;
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstConstraintExpr* nodep) override {
|
||||
VL_RESTORER(m_randcIllegalWhy);
|
||||
VL_RESTORER(m_randcIllegalWhyp);
|
||||
VL_RESTORER(m_randcIllegalp);
|
||||
if (nodep->isSoft()) {
|
||||
m_randcIllegalWhy = "'constraint soft' (IEEE 1800-2023 18.5.13.1)";
|
||||
m_randcIllegalWhyp = "'constraint soft' (IEEE 1800-2023 18.5.13.1)";
|
||||
m_randcIllegalp = nodep;
|
||||
}
|
||||
iterateChildrenConst(nodep);
|
||||
|
|
@ -76,7 +76,7 @@ class LinkWithVisitor final : public VNVisitor {
|
|||
if (nodep->varp()) { // Else due to dead code, might not have var pointer
|
||||
if (nodep->varp()->isRandC() && m_randcIllegalp) {
|
||||
nodep->v3error("Randc variables not allowed in "
|
||||
<< m_randcIllegalWhy << '\n'
|
||||
<< m_randcIllegalWhyp << '\n'
|
||||
<< nodep->warnContextPrimary() << '\n'
|
||||
<< m_randcIllegalp->warnOther()
|
||||
<< "... Location of restricting expression\n"
|
||||
|
|
|
|||
|
|
@ -2571,11 +2571,9 @@ class ParamVisitor final : public VNVisitor {
|
|||
// Iterate the body
|
||||
{
|
||||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_ifacePortNames);
|
||||
VL_RESTORER(m_ifaceInstCells);
|
||||
VL_RESTORER_CLEAR(m_ifacePortNames);
|
||||
VL_RESTORER_CLEAR(m_ifaceInstCells);
|
||||
m_modp = modp;
|
||||
m_ifacePortNames.clear();
|
||||
m_ifaceInstCells.clear();
|
||||
iterateChildren(modp);
|
||||
}
|
||||
}
|
||||
|
|
@ -3241,7 +3239,7 @@ class ParamVisitor final : public VNVisitor {
|
|||
// Note this clears nodep->genforp(), so begin is no longer special
|
||||
}
|
||||
} else {
|
||||
VL_RESTORER(m_generateHierName);
|
||||
VL_RESTORER_COPY(m_generateHierName);
|
||||
m_generateHierName += "." + nodep->prettyName();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ class RandSequenceVisitor final : public VNVisitor {
|
|||
m_modp->addStmtsp(taskp);
|
||||
|
||||
// Create local (not output) break variable
|
||||
VL_RESTORER(m_localizeRemaps);
|
||||
VL_RESTORER_COPY(m_localizeRemaps);
|
||||
AstVar* breakVarp = newBreakVar(nodep->fileline(), false);
|
||||
taskp->addStmtsp(breakVarp);
|
||||
|
||||
|
|
@ -417,9 +417,9 @@ class RandSequenceVisitor final : public VNVisitor {
|
|||
m_rsp = nodep;
|
||||
VL_RESTORER(m_startProdp);
|
||||
|
||||
VL_RESTORER(m_localizes);
|
||||
VL_RESTORER(m_localizeNames);
|
||||
VL_RESTORER(m_localizeRemaps);
|
||||
VL_RESTORER_COPY(m_localizes);
|
||||
VL_RESTORER_COPY(m_localizeNames);
|
||||
VL_RESTORER_COPY(m_localizeRemaps);
|
||||
findLocalizes(nodep);
|
||||
|
||||
// Find first production
|
||||
|
|
@ -482,7 +482,7 @@ class RandSequenceVisitor final : public VNVisitor {
|
|||
// TODO we could do this only if break exists in the downstream production,
|
||||
// but as-is we'll optimize it away in most cases anyways
|
||||
VL_RESTORER(m_breakVarp);
|
||||
VL_RESTORER(m_localizeRemaps);
|
||||
VL_RESTORER_COPY(m_localizeRemaps);
|
||||
m_breakVarp = newBreakVar(nodep->fileline(), true);
|
||||
m_prodFuncp->addStmtsp(m_breakVarp);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3AstUserAllocator.h"
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3Sched.h"
|
||||
|
||||
|
|
@ -179,7 +180,8 @@ AstCCall* TimingKit::createReady(AstNetlist* const netlistp) {
|
|||
|
||||
class AwaitVisitor final : public VNVisitor {
|
||||
// NODE STATE
|
||||
// AstSenTree::user1() -> bool. Set true if the sentree has been visited.
|
||||
// AstSenTree::user1() -> bool. Set true if the sentree has been visited.
|
||||
// AstCFunc::user1() -> AstUser1Allocator. See alocator below
|
||||
const VNUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
|
|
@ -193,6 +195,34 @@ class AwaitVisitor final : public VNVisitor {
|
|||
std::set<AstSenTree*> m_processDomains; // Sentrees from the current process
|
||||
// Variables written by suspendable processes
|
||||
std::vector<AstVarScope*> m_writtenBySuspendable;
|
||||
struct CFuncCache final {
|
||||
std::set<AstSenTree*> m_processDomains; // What shall be added to m_processDomains
|
||||
std::vector<AstVarScope*>
|
||||
m_writtenBySuspendable; // What shall be added to m_writtenBySuspendable
|
||||
enum State : uint8_t {
|
||||
UNINITIALIZED = 0, // Not initialized members are empty
|
||||
VISITING, // Visiting - needed for breaking recursion
|
||||
INITIALIZED, // Members contains correct values
|
||||
} m_state // Current state of Cache
|
||||
= UNINITIALIZED;
|
||||
};
|
||||
// Caches how visiting the function with given value of m_gatherVars changes
|
||||
// m_processDomains and m_writtenBySuspendable - only accessed from visit(AstCFunc* nodep)
|
||||
AstUser1Allocator<AstCFunc, std::array<CFuncCache, 2>> m_cfuncsCache;
|
||||
// Count uses of not inlined writes to signals in suspendables
|
||||
VDouble0 m_notInlinedWritesInSuspendableUsage;
|
||||
// Set containing information whether an AstCFunc was hit (called) recursively
|
||||
// This is needed to know whether cache is complete. E.g.:
|
||||
// A->B->C->B
|
||||
// Callstack:
|
||||
// visit(A) -> Ok go to successors
|
||||
// visit(B) -> Ok go to successors
|
||||
// visit(C) -> Ok go to successors
|
||||
// visit(B) -> Already visiting B
|
||||
// visit(C) -> Cache must not be created since it is not complete - A was not visited
|
||||
// visit(B) -> Cache may be created since all successors have been transitionally visited
|
||||
// visit(A) -> Cache may be created since all successors have been transitionally visited
|
||||
std::array<std::unordered_set<const AstCFunc*>, 2> m_hitVisiting;
|
||||
|
||||
// METHODS
|
||||
// Add arguments to a resume() call based on arguments in the suspending call
|
||||
|
|
@ -267,6 +297,7 @@ class AwaitVisitor final : public VNVisitor {
|
|||
if (!sentreep->user1SetOnce()) createResumeActive(nodep);
|
||||
if (m_inProcess) m_processDomains.insert(sentreep);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
if (m_gatherVars && nodep->access().isWriteOrRW() && !nodep->varp()->ignoreSchedWrite()
|
||||
|
|
@ -274,6 +305,59 @@ class AwaitVisitor final : public VNVisitor {
|
|||
m_writtenBySuspendable.push_back(nodep->varScopep());
|
||||
}
|
||||
}
|
||||
void visit(AstNodeCCall* const nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// We need to visit bodies of non-inlined functions
|
||||
iterate(nodep->funcp());
|
||||
}
|
||||
void visit(AstCFunc* nodep) override {
|
||||
UASSERT_OBJ(!m_gatherVars || m_inProcess, nodep,
|
||||
"Variables shall be gathered only inside processes");
|
||||
// Cache key does not depends on a m_inProcess variable since it is forced to be true
|
||||
const size_t cacheKey = static_cast<size_t>(m_gatherVars);
|
||||
CFuncCache& value = m_cfuncsCache(nodep)[cacheKey];
|
||||
{
|
||||
VL_RESTORER(m_inProcess);
|
||||
// Force m_inProcess since visiting a tree with !m_inProcess does not change the
|
||||
// m_writtenBySuspendable and m_processDomains (so it would be a bit of a dry run).
|
||||
// However, we must visit children since there might be an AstCAwait which is modified
|
||||
// in its visit() but since the function does not depend on a state of m_inProcess (nor
|
||||
// anything that may be affected by changing the state of m_inProcess) we may force the
|
||||
// variable, visit children and gather cache for m_inProcess && !m_gatherVars
|
||||
m_inProcess = true;
|
||||
switch (value.m_state) {
|
||||
case CFuncCache::UNINITIALIZED: {
|
||||
// Save current state
|
||||
VL_RESTORER_CLEAR(m_processDomains);
|
||||
VL_RESTORER_CLEAR(m_writtenBySuspendable);
|
||||
|
||||
// Visit
|
||||
value.m_state = CFuncCache::VISITING;
|
||||
iterateChildren(nodep);
|
||||
m_hitVisiting[cacheKey].erase(nodep);
|
||||
value.m_state = m_hitVisiting[cacheKey].empty() ? CFuncCache::INITIALIZED
|
||||
: CFuncCache::UNINITIALIZED;
|
||||
|
||||
// Save a cache
|
||||
std::swap(m_processDomains, value.m_processDomains);
|
||||
std::swap(m_writtenBySuspendable, value.m_writtenBySuspendable);
|
||||
} break;
|
||||
case CFuncCache::VISITING:
|
||||
m_hitVisiting[cacheKey].insert(nodep);
|
||||
return; // Break recursion
|
||||
case CFuncCache::INITIALIZED: break;
|
||||
}
|
||||
}
|
||||
if (m_inProcess) {
|
||||
// Add cached values to the visitor state if the m_inProcess was initially true - when
|
||||
// it is false none of these variable shall be modified
|
||||
m_writtenBySuspendable.insert(m_writtenBySuspendable.end(),
|
||||
value.m_writtenBySuspendable.begin(),
|
||||
value.m_writtenBySuspendable.end());
|
||||
m_notInlinedWritesInSuspendableUsage += value.m_writtenBySuspendable.size();
|
||||
m_processDomains.insert(value.m_processDomains.begin(), value.m_processDomains.end());
|
||||
}
|
||||
}
|
||||
void visit(AstExprStmt* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
//--------------------
|
||||
|
|
@ -289,7 +373,10 @@ public:
|
|||
, m_externalDomains{externalDomains} {
|
||||
iterate(nodep);
|
||||
}
|
||||
~AwaitVisitor() override = default;
|
||||
~AwaitVisitor() override {
|
||||
V3Stats::addStat("Scheduling, count of non-inlined signal writes in suspendables",
|
||||
m_notInlinedWritesInSuspendableUsage);
|
||||
}
|
||||
};
|
||||
|
||||
TimingKit prepareTiming(AstNetlist* const netlistp) {
|
||||
|
|
|
|||
|
|
@ -306,10 +306,9 @@ private:
|
|||
}
|
||||
void visit(AstClass* nodep) override {
|
||||
// Move initial statements into the constructor
|
||||
VL_RESTORER(m_initialps);
|
||||
VL_RESTORER_CLEAR(m_initialps);
|
||||
VL_RESTORER(m_ctorp);
|
||||
VL_RESTORER(m_classp);
|
||||
m_initialps.clear();
|
||||
m_ctorp = nullptr;
|
||||
m_classp = nodep;
|
||||
{ // Find m_initialps, m_ctor
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ class TraceDeclVisitor final : public VNVisitor {
|
|||
AstNodeDType* const skipTypep = nodep->skipRefp();
|
||||
// offset and direction args added in EmitCImp
|
||||
std::string callArgs{"tracep, \"" + VIdProtect::protect(m_traName) + "\""};
|
||||
VL_RESTORER(m_traName);
|
||||
VL_RESTORER_COPY(m_traName);
|
||||
FileLine* const flp = skipTypep->fileline();
|
||||
|
||||
const DtypeFuncKey dtypeKey{skipTypep, m_traVscp->varp()->varType()};
|
||||
|
|
@ -530,7 +530,7 @@ class TraceDeclVisitor final : public VNVisitor {
|
|||
void declUnpackedArray(AstUnpackArrayDType* const nodep, bool newFunc) {
|
||||
string prefixName(newFunc ? "name" : m_traName);
|
||||
|
||||
VL_RESTORER(m_traName);
|
||||
VL_RESTORER_COPY(m_traName);
|
||||
FileLine* const flp = nodep->fileline();
|
||||
|
||||
addToSubFunc(new AstTracePushPrefix{flp, prefixName, VTracePrefixType::ARRAY_UNPACKED,
|
||||
|
|
@ -568,7 +568,7 @@ class TraceDeclVisitor final : public VNVisitor {
|
|||
string prefixName(newFunc ? "name" : m_traName);
|
||||
AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump();
|
||||
|
||||
VL_RESTORER(m_traName);
|
||||
VL_RESTORER_COPY(m_traName);
|
||||
FileLine* const flp = nodep->fileline();
|
||||
|
||||
addToSubFunc(new AstTracePushPrefix{flp, prefixName, VTracePrefixType::ARRAY_PACKED,
|
||||
|
|
@ -918,7 +918,7 @@ class TraceDeclVisitor final : public VNVisitor {
|
|||
return;
|
||||
}
|
||||
|
||||
VL_RESTORER(m_traName);
|
||||
VL_RESTORER_COPY(m_traName);
|
||||
FileLine* const flp = nodep->fileline();
|
||||
|
||||
int nMembers = 0;
|
||||
|
|
|
|||
|
|
@ -2191,8 +2191,8 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_graphing);
|
||||
VL_RESTORER(m_unique);
|
||||
VL_RESTORER(m_lhsmap);
|
||||
VL_RESTORER(m_assigns);
|
||||
VL_RESTORER_CLEAR(m_lhsmap);
|
||||
VL_RESTORER_CLEAR(m_assigns);
|
||||
// Not preserved, needs pointer instead: TristateGraph origTgraph = m_tgraph;
|
||||
UASSERT_OBJ(m_tgraph.empty(), nodep, "Unsupported: NodeModule under NodeModule");
|
||||
|
||||
|
|
@ -2201,8 +2201,6 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
m_tgraph.clearAndCheck();
|
||||
m_unique = 0;
|
||||
m_logicp = nullptr;
|
||||
m_lhsmap.clear();
|
||||
m_assigns.clear();
|
||||
m_modp = nodep;
|
||||
// Walk the graph, finding all variables and tristate constructs
|
||||
m_graphing = true;
|
||||
|
|
|
|||
|
|
@ -56,14 +56,12 @@ class UdpVisitor final : public VNVisitor {
|
|||
VL_RESTORER(m_primp);
|
||||
VL_RESTORER(m_outputInitVerfp);
|
||||
VL_RESTORER(m_isFirstOutput);
|
||||
VL_RESTORER(m_inputVars);
|
||||
VL_RESTORER(m_outputVars);
|
||||
VL_RESTORER_CLEAR(m_inputVars);
|
||||
VL_RESTORER_CLEAR(m_outputVars);
|
||||
m_outputInitVerfp = nullptr;
|
||||
m_primp = nodep;
|
||||
m_isFirstOutput = false;
|
||||
iterateChildren(nodep);
|
||||
m_inputVars.clear();
|
||||
m_outputVars.clear();
|
||||
}
|
||||
void visit(AstVar* nodep) override {
|
||||
// Push the input and output vars for primitive.
|
||||
|
|
|
|||
|
|
@ -731,6 +731,17 @@ class WidthVisitor final : public VNVisitor {
|
|||
iterateCheckBool(nodep, "default disable iff condition", nodep->condp(), BOTH);
|
||||
}
|
||||
void visit(AstDelay* nodep) override {
|
||||
if (nodep->isCycleDelay() && m_underSExpr) {
|
||||
// Fold parameterized SVA cycle-delay bounds
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p());
|
||||
V3Const::constifyParamsNoWarnEdit(nodep->lhsp());
|
||||
if (nodep->rhsp() && !nodep->isUnbounded()) {
|
||||
// Fold parametrized SVA cycle-delay max bound
|
||||
userIterateAndNext(nodep->rhsp(), WidthVP{SELF, BOTH}.p());
|
||||
V3Const::constifyParamsNoWarnEdit(nodep->rhsp());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (AstNodeExpr* const fallDelayp = nodep->fallDelay()) {
|
||||
iterateCheckDelay(nodep, "delay", nodep->lhsp(), BOTH);
|
||||
iterateCheckDelay(nodep, "delay", fallDelayp, BOTH);
|
||||
|
|
@ -7852,7 +7863,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
assertAtStatement(nodep);
|
||||
VL_RESTORER(m_insideTempNames);
|
||||
VL_RESTORER_COPY(m_insideTempNames);
|
||||
if (AstClass* const classp = VN_CAST(nodep, Class)) {
|
||||
visitClass(classp);
|
||||
} else {
|
||||
|
|
@ -9564,9 +9575,11 @@ class WidthVisitor final : public VNVisitor {
|
|||
// No width change on output;... // All below have bool or double outputs
|
||||
switch (nodep->type()) {
|
||||
case VNType::Eq:
|
||||
case VNType::EqCase: newp = new AstEqN{fl, lhsp, rhsp}; break;
|
||||
case VNType::EqCase:
|
||||
case VNType::EqWild: newp = new AstEqN{fl, lhsp, rhsp}; break;
|
||||
case VNType::Neq:
|
||||
case VNType::NeqCase: newp = new AstNeqN{fl, lhsp, rhsp}; break;
|
||||
case VNType::NeqCase:
|
||||
case VNType::NeqWild: newp = new AstNeqN{fl, lhsp, rhsp}; break;
|
||||
case VNType::Gt:
|
||||
case VNType::GtS: newp = new AstGtN{fl, lhsp, rhsp}; break;
|
||||
case VNType::Gte:
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class WidthCommitVisitor final : public VNVisitor {
|
|||
// STATE
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
std::string m_contNba; // In continuous- or non-blocking assignment
|
||||
const char* m_contNbap = nullptr; // In continuous- or non-blocking assignment
|
||||
bool m_contReads = false; // Check read continuous automatic variables
|
||||
bool m_dynsizedelem = false; // Writing dynamically-sized array element, not the array itself
|
||||
VMemberMap m_memberMap; // Member names cached for fast lookup
|
||||
|
|
@ -148,7 +148,7 @@ private:
|
|||
void varLifetimeCheck(AstNode* nodep, AstVar* varp) {
|
||||
// Skip if we are under a member select (lhs of a dot)
|
||||
// We don't care about lifetime of anything else than rhs of a dot
|
||||
if (!m_underSel && !m_contNba.empty()) {
|
||||
if (!m_underSel && m_contNbap) {
|
||||
std::string varType;
|
||||
const AstNodeDType* const varDtp = varp->dtypep()->skipRefp();
|
||||
if (varp->lifetime().isAutomatic() && !VN_IS(varDtp, IfaceRefDType)
|
||||
|
|
@ -162,7 +162,7 @@ private:
|
|||
if (!varType.empty()) {
|
||||
UINFO(1, " Related var dtype: " << varDtp);
|
||||
nodep->v3error(varType
|
||||
<< " variable not allowed in " << m_contNba
|
||||
<< " variable not allowed in " << m_contNbap
|
||||
<< " assignment (IEEE 1800-2023 6.21): " << varp->prettyNameQ());
|
||||
}
|
||||
}
|
||||
|
|
@ -419,9 +419,9 @@ private:
|
|||
void visit(AstAssignCont* nodep) override {
|
||||
iterateAndNextNull(nodep->timingControlp());
|
||||
{
|
||||
VL_RESTORER(m_contNba);
|
||||
VL_RESTORER(m_contNbap);
|
||||
VL_RESTORER(m_contReads);
|
||||
m_contNba = "continuous";
|
||||
m_contNbap = "continuous";
|
||||
m_contReads = true;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
|
|
@ -432,9 +432,9 @@ private:
|
|||
iterateAndNextNull(nodep->timingControlp());
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
{
|
||||
VL_RESTORER(m_contNba);
|
||||
VL_RESTORER(m_contNbap);
|
||||
VL_RESTORER(m_contReads);
|
||||
m_contNba = "nonblocking";
|
||||
m_contNbap = "nonblocking";
|
||||
m_contReads = false;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
}
|
||||
|
|
@ -444,9 +444,9 @@ private:
|
|||
iterateAndNextNull(nodep->timingControlp());
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
{
|
||||
VL_RESTORER(m_contNba);
|
||||
VL_RESTORER(m_contNbap);
|
||||
VL_RESTORER(m_contReads);
|
||||
m_contNba = "continuous";
|
||||
m_contNbap = "continuous";
|
||||
m_contReads = false;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ static void process() {
|
|||
// Assertion insertion
|
||||
// After we've added block coverage, but before other nasty transforms
|
||||
V3AssertCommon::collectDefaultDisable(v3Global.rootp());
|
||||
V3AssertCommon::lowerSequenceEvents(v3Global.rootp());
|
||||
V3AssertNfa::assertNfaAll(v3Global.rootp());
|
||||
// V3AssertProp removed: NFA subsumes multi-cycle property lowering.
|
||||
// Unsupported constructs fall through to V3AssertPre.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile(verilator_flags2=['--timing'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
int unsigned crc = 32'h1;
|
||||
bit a, b, c;
|
||||
bit a1, a2, a3, b1;
|
||||
int cyc;
|
||||
int seq_hits, seq_hits2, ref_hits, one_hits, dc_hits;
|
||||
int rng_hits, rng_ref;
|
||||
|
||||
// verilog_format: off // verible does not support clocking events inside sequence declarations
|
||||
sequence seq;
|
||||
@(posedge clk) a ##1 b ##1 c;
|
||||
endsequence
|
||||
|
||||
sequence seq_one;
|
||||
@(posedge clk) a;
|
||||
endsequence
|
||||
|
||||
sequence seq_rng;
|
||||
@(posedge clk) a ##[1:3] b;
|
||||
endsequence
|
||||
// verilog_format: on
|
||||
|
||||
// seq_dc inherits the default clocking; counts must match seq
|
||||
default clocking @(posedge clk);
|
||||
endclocking
|
||||
|
||||
sequence seq_dc;
|
||||
a ##1 b ##1 c;
|
||||
endsequence
|
||||
|
||||
// ref_hits and rng_ref are independent shift-register oracles;
|
||||
// simultaneous end points resume a blocked waiter once
|
||||
initial forever begin
|
||||
@seq;
|
||||
seq_hits = seq_hits + 1;
|
||||
end
|
||||
initial forever begin
|
||||
@seq;
|
||||
seq_hits2 = seq_hits2 + 1;
|
||||
end
|
||||
initial forever begin
|
||||
@seq_one;
|
||||
one_hits = one_hits + 1;
|
||||
end
|
||||
initial forever begin
|
||||
@seq_dc;
|
||||
dc_hits = dc_hits + 1;
|
||||
end
|
||||
initial forever begin
|
||||
@seq_rng;
|
||||
rng_hits = rng_hits + 1;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (a2 && b1 && c) ref_hits = ref_hits + 1;
|
||||
if (b && (a1 || a2 || a3)) rng_ref = rng_ref + 1;
|
||||
a3 <= a2;
|
||||
a2 <= a1;
|
||||
a1 <= a;
|
||||
b1 <= b;
|
||||
end
|
||||
|
||||
// a/b/c bit spacing exceeds the ##2 window to decorrelate the LFSR taps
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[30:0], crc[31] ^ crc[21] ^ crc[1] ^ crc[0]};
|
||||
a <= crc[0];
|
||||
b <= crc[4];
|
||||
c <= crc[8];
|
||||
if (cyc == 60) $finish;
|
||||
end
|
||||
|
||||
// Counts read in final (Postponed) to avoid same-timestep races.
|
||||
final begin
|
||||
`checkd(seq_hits, 14);
|
||||
`checkd(seq_hits2, 14);
|
||||
`checkd(ref_hits, 14);
|
||||
`checkd(one_hits, 30);
|
||||
`checkd(dc_hits, 14);
|
||||
`checkd(rng_hits, 26);
|
||||
`checkd(rng_ref, 26);
|
||||
$write("*-* All Finished *-*\n");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
%Error: t/t_assert_seq_event_bad.v:19:7: Arguments to a sequence used as an event control must be static (IEEE 1800-2023 9.4.2.4)
|
||||
: ... note: In instance 't'
|
||||
19 | @(s_arg(x));
|
||||
| ^~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(expect_filename=test.golden_filename, verilator_flags2=['--timing'], fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
|
||||
// verilog_format: off
|
||||
sequence s_arg(x);
|
||||
@(posedge clk) x;
|
||||
endsequence
|
||||
// verilog_format: on
|
||||
|
||||
task automatic f;
|
||||
bit x = 1;
|
||||
@(s_arg(x));
|
||||
endtask
|
||||
|
||||
initial f();
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile(verilator_flags2=['--timing'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
int unsigned crc = 32'h1;
|
||||
bit a, b, rst;
|
||||
bit a1;
|
||||
int cyc;
|
||||
int hits, ref_hits, one_hits, one_ref;
|
||||
|
||||
// Neither the default disable iff nor $assertoff may suppress a sequence event control
|
||||
default disable iff (rst);
|
||||
|
||||
// verilog_format: off // verible does not support clocking events inside sequence declarations
|
||||
sequence seq;
|
||||
@(posedge clk) a ##1 b;
|
||||
endsequence
|
||||
|
||||
sequence seq_one;
|
||||
@(posedge clk) 1;
|
||||
endsequence
|
||||
// verilog_format: on
|
||||
|
||||
initial begin
|
||||
$assertoff;
|
||||
#300 $assertkill;
|
||||
end
|
||||
|
||||
initial forever begin
|
||||
@seq;
|
||||
hits = hits + 1;
|
||||
end
|
||||
initial forever begin
|
||||
@seq_one;
|
||||
one_hits = one_hits + 1;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (a1 && b) ref_hits = ref_hits + 1;
|
||||
one_ref = one_ref + 1;
|
||||
a1 <= a;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[30:0], crc[31] ^ crc[21] ^ crc[1] ^ crc[0]};
|
||||
a <= crc[0];
|
||||
b <= crc[4];
|
||||
rst <= crc[2];
|
||||
end
|
||||
|
||||
always @(negedge clk) begin
|
||||
if (cyc == 60) $finish;
|
||||
end
|
||||
|
||||
final begin
|
||||
`checkd(hits, ref_hits);
|
||||
`checkd(one_hits, one_ref);
|
||||
`checkd(hits, 19);
|
||||
`checkd(one_hits, 60);
|
||||
$write("*-* All Finished *-*\n");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
%Error-UNSUPPORTED: t/t_assert_seq_event_unsup.v:18:5: Unsupported: non-edge clocking event on a sequence; use an edge such as @(posedge clk)
|
||||
: ... note: In instance 't'
|
||||
18 | @(g) a ##1 b;
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_assert_seq_event_unsup.v:28:30: Unsupported: sequence used as an event control with a sequence operand of 'or'
|
||||
28 | @(posedge clk) (a ##1 b) or (a ##2 b);
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_assert_seq_event_unsup.v:21:12: Unsupported: sequence referenced outside assertion property
|
||||
: ... note: In instance 't'
|
||||
21 | sequence s_ref;
|
||||
| ^~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(expect_filename=test.golden_filename, verilator_flags2=['--timing'], fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
bit a, b;
|
||||
logic g = 0;
|
||||
|
||||
default clocking @(posedge clk);
|
||||
endclocking
|
||||
|
||||
// verilog_format: off
|
||||
sequence s_nonedge;
|
||||
@(g) a ##1 b;
|
||||
endsequence
|
||||
|
||||
sequence s_ref;
|
||||
@(posedge clk) a;
|
||||
endsequence
|
||||
|
||||
// Legal but its endpoint topology is not buildable, so the wait could never
|
||||
// resume; rejected rather than silently ignored.
|
||||
sequence s_or;
|
||||
@(posedge clk) (a ##1 b) or (a ##2 b);
|
||||
endsequence
|
||||
// verilog_format: on
|
||||
|
||||
// Legal: p is never asserted, so s_ref stays referenced outside any
|
||||
// assertion property, which is not yet supported.
|
||||
property p;
|
||||
s_ref;
|
||||
endproperty
|
||||
|
||||
initial begin
|
||||
@s_nonedge;
|
||||
@s_or;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1318,6 +1318,21 @@ module Vt_debug_emitv_sub;
|
|||
endfunction
|
||||
real r;
|
||||
endmodule
|
||||
module Vt_debug_emitv_seq_event;
|
||||
input logic clk;
|
||||
bit a;
|
||||
bit b;
|
||||
bit c;
|
||||
sequence sq;
|
||||
@(posedge clk) a##1 b##1 c
|
||||
endsequence
|
||||
initial begin
|
||||
begin
|
||||
|
||||
???? // EVENTCONTROL
|
||||
@( sq())end
|
||||
end
|
||||
endmodule
|
||||
package Vt_debug_emitv_p;
|
||||
logic pkgvar;
|
||||
endpackage
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ module t (/*AUTOARG*/
|
|||
endfunction
|
||||
|
||||
sub sub(.*);
|
||||
seq_event seq_event(.*);
|
||||
|
||||
initial begin
|
||||
int other;
|
||||
|
|
@ -443,6 +444,16 @@ module sub(input logic clk);
|
|||
real r;
|
||||
endmodule
|
||||
|
||||
module seq_event(input logic clk);
|
||||
bit a, b, c;
|
||||
sequence sq;
|
||||
@(posedge clk) a ##1 b ##1 c;
|
||||
endsequence
|
||||
initial begin
|
||||
@sq;
|
||||
end
|
||||
endmodule
|
||||
|
||||
package p;
|
||||
logic pkgvar;
|
||||
endpackage
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ test.compile(verilator_flags2=[
|
|||
"--prefix", "Vopt",
|
||||
"-Werror-UNOPTFLAT",
|
||||
"--dumpi-V3DfgBreakCycles", "9", # To fill code coverage
|
||||
"--debugi-V3DfgBreakCycles", "9", # To fill code coverage
|
||||
"--debug", "--debugi", "0", "--dumpi-tree", "0",
|
||||
"-CFLAGS \"-I .. -I ../obj_ref\"",
|
||||
"../obj_ref/Vref__ALL.a",
|
||||
|
|
|
|||
|
|
@ -361,6 +361,19 @@ module t (
|
|||
assign ALWAYS_2 = always_2;
|
||||
// verilator lint_on ALWCOMBORDER
|
||||
|
||||
// verilator lint_off ALWCOMBORDER
|
||||
logic [4:0] always_3;
|
||||
always_comb begin
|
||||
always_3[4] = always_3[0];
|
||||
always_3[0] = rand_a[0];
|
||||
always_3[2] = rand_a[2];
|
||||
always_3[3] = |always_3[2:1];
|
||||
end
|
||||
assign always_3[1] = always_3[0];
|
||||
`signal(ALWAYS_3, 5); // UNOPTFLAT
|
||||
assign ALWAYS_3 = always_3;
|
||||
// verilator lint_on ALWCOMBORDER
|
||||
|
||||
logic [31:0] array_4[3]; // UNOPTFLAT
|
||||
// Input
|
||||
assign array_4[0] = rand_a[31:0];
|
||||
|
|
|
|||
|
|
@ -4,7 +4,16 @@
|
|||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
localparam string AB = "AB";
|
||||
|
||||
bit r;
|
||||
|
||||
initial begin
|
||||
if (('bxz10 ==? 'bxxx0) !== 1) $stop;
|
||||
if (('bxz10 ==? 'bxxx1) !== 0) $stop;
|
||||
|
|
@ -12,6 +21,16 @@ module t;
|
|||
if (('bxz10 !=? 'bxxx1) !== 1) $stop;
|
||||
if (('bxz10 !=? 'bxxx0) !== 0) $stop;
|
||||
if (('bxz10 !=? 'b1xx0) !== 'x) $stop;
|
||||
|
||||
r = (AB ==? "AA");
|
||||
`checkd(r, 0);
|
||||
r = (AB ==? "AB");
|
||||
`checkd(r, 1);
|
||||
r = (AB !=? "AB");
|
||||
`checkd(r, 0);
|
||||
|
||||
// real/shortreal is illegal so not tested here
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
module t (
|
||||
input clk
|
||||
);
|
||||
parameter P = 1;
|
||||
|
||||
integer cyc = 0;
|
||||
reg [63:0] crc = '0;
|
||||
reg [63:0] sum = '0;
|
||||
|
|
@ -64,6 +66,11 @@ module t (
|
|||
assert property (@(posedge clk) disable iff (cyc < 2)
|
||||
a |-> ##[1:3] (a | b | c | d | e));
|
||||
|
||||
// Parameterized range bound
|
||||
assert property (@(posedge clk) disable iff (cyc < 2)
|
||||
a |-> ##[P:P+3] (a | b | c | d | e));
|
||||
assert property (@(posedge clk) ##[P:P+3] 1);
|
||||
|
||||
// ##[2:4] range delay
|
||||
assert property (@(posedge clk) disable iff (cyc < 2)
|
||||
b |-> ##[2:4] (a | b | c | d | e));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=['--binary', '--stats', '-fno-dfg'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.file_grep(test.stats,
|
||||
r'Scheduling, count of non-inlined signal writes in suspendables\s+(\d+)', 7)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0)
|
||||
// verilog_format: off
|
||||
|
||||
package pkg;
|
||||
bit [2:0] y3;
|
||||
endpackage
|
||||
|
||||
module t;
|
||||
bit [2:0] y;
|
||||
bit [2:0] z;
|
||||
assign z[0] = 1'b1;
|
||||
assign z[1] = !(y[0]);
|
||||
assign z[2] = !(|y[1:0]);
|
||||
|
||||
bit [2:0] y2;
|
||||
bit [2:0] z2;
|
||||
assign z2[0] = 1'b1;
|
||||
assign z2[1] = !(y2[0]);
|
||||
assign z2[2] = !(|y2[1:0]);
|
||||
|
||||
import pkg::y3;
|
||||
bit [2:0] z3;
|
||||
assign z3[0] = 1'b1;
|
||||
assign z3[1] = !(y3[0]);
|
||||
assign z3[2] = !(|y3[1:0]);
|
||||
|
||||
bit [2:0] y4;
|
||||
bit [2:0] z4;
|
||||
assign z4[0] = 1'b1;
|
||||
assign z4[1] = !(y4[0]);
|
||||
assign z4[2] = !(|y4[1:0]);
|
||||
class Foo;
|
||||
function automatic int bar();
|
||||
// verilator no_inline_task
|
||||
y2 = 3'b111;
|
||||
y3 = 3'b111;
|
||||
return 1;
|
||||
endfunction
|
||||
task run();
|
||||
y = 3'b111;
|
||||
#1;
|
||||
`checkh(z, 3'b001);
|
||||
`checkh(z2, 3'b001);
|
||||
`checkh(z3, 3'b001);
|
||||
`checkh(z4, 3'b111);
|
||||
endtask
|
||||
task a(bit x = 0);
|
||||
// verilator no_inline_task
|
||||
y4 = ~y4;
|
||||
#1;
|
||||
if (!x) b(!x);
|
||||
endtask
|
||||
task b(bit x = 0);
|
||||
// verilator no_inline_task
|
||||
if (!x) a(!x);
|
||||
endtask
|
||||
endclass
|
||||
initial begin
|
||||
static Foo foo = new;
|
||||
#1;
|
||||
`checkh(z, 3'b111);
|
||||
`checkh(z2, 3'b111);
|
||||
`checkh(z3, 3'b111);
|
||||
`checkh(z4, 3'b111);
|
||||
void'(foo.bar());
|
||||
#1;
|
||||
`checkh(z, 3'b111);
|
||||
`checkh(z2, 3'b001);
|
||||
`checkh(z3, 3'b001);
|
||||
`checkh(z4, 3'b111);
|
||||
foo.run();
|
||||
foo.a();
|
||||
`checkh(z, 3'b001);
|
||||
`checkh(z2, 3'b001);
|
||||
`checkh(z3, 3'b001);
|
||||
`checkh(z4, 3'b001);
|
||||
foo.b();
|
||||
`checkh(z, 3'b001);
|
||||
`checkh(z2, 3'b001);
|
||||
`checkh(z3, 3'b001);
|
||||
`checkh(z4, 3'b111);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
%Error: t/t_sequence_ref_bad.v:14:6: Concurrent assertion has no clock (IEEE 1800-2023 16.16)
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest provide a clocking event, a default clocking, or a clocked procedural context
|
||||
14 | @s_one;
|
||||
| ^~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: Exiting due to
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
%Error-UNSUPPORTED: t/t_sequence_ref_unsup.v:9:12: Unsupported: sequence referenced outside assertion property
|
||||
: ... note: In instance 't'
|
||||
9 | sequence s_one;
|
||||
| ^~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
|
|
@ -78,7 +78,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -171,7 +171,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -247,7 +247,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -278,7 +278,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -339,7 +339,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -463,7 +463,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -498,7 +498,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -581,7 +581,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -676,7 +676,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -711,7 +711,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -794,7 +794,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -831,7 +831,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 0 is active: @([event] t.ec.e)
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -906,7 +906,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -936,7 +936,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -994,7 +994,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1060,7 +1060,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1125,7 +1125,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1152,7 +1152,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1215,7 +1215,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1280,7 +1280,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1320,7 +1320,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdynSched.evaluate())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1371,7 +1371,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1427,7 +1427,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1486,7 +1486,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1541,7 +1541,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1596,7 +1596,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
@ -1649,7 +1649,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdlySched.awaitingCurrentTime())
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
|
|
|
|||
Loading…
Reference in New Issue