mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 10:03:44 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
983a06a16f | ||
|
|
ea338be98e | ||
|
|
c8a8f02c09 | ||
|
|
b1c06fdb09 | ||
|
|
18095ac924 | ||
|
|
efc390a37d | ||
|
|
228635918e | ||
|
|
c917f04c65 | ||
|
|
c4a4f35ec4 | ||
|
|
e012f7c79d | ||
|
|
80907b1e26 | ||
|
|
a5f4f7eade | ||
|
|
c7aa95439c | ||
|
|
a3932e259b | ||
|
|
e6cee9d54c | ||
|
|
f694e9e1e8 | ||
|
|
667f64813f | ||
|
|
67818a3430 | ||
|
|
1c2fa7234d | ||
|
|
be83d1393d | ||
|
|
9474a01d54 | ||
|
|
c81be029a6 | ||
|
|
3c121c0a2e | ||
|
|
0f96460042 | ||
|
|
648035df72 | ||
|
|
dcf45da1c0 | ||
|
|
d2920a627d | ||
|
|
2954756190 | ||
|
|
c70439961f | ||
|
|
ab20edbbaf | ||
|
|
297713df8b | ||
|
|
6a05cc680b | ||
|
|
50e42bc197 | ||
|
|
c64afda7fc | ||
|
|
1ad9acd22e | ||
|
|
2f856971ed | ||
|
|
8546d5db06 | ||
|
|
59f221986c | ||
|
|
99c6f9ced8 | ||
|
|
7bff0196b1 | ||
|
|
f055eeabe0 | ||
|
|
7f9333723f | ||
|
|
cce0277e1a | ||
|
|
51a2dc3efb | ||
|
|
0dcdea3325 | ||
|
|
1cd2588241 | ||
|
|
087b15bdb3 | ||
|
|
5e4151e3e0 | ||
|
|
b23b53227d | ||
|
|
8cbaf505ee | ||
|
|
0b85b80ece | ||
|
|
821478070d | ||
|
|
69f42ea480 | ||
|
|
f6d56c6440 | ||
|
|
538c6a6b76 | ||
|
|
1c9a9e0cce | ||
|
|
6fc18710bd | ||
|
|
67cbc36ef0 | ||
|
|
2cd0efbc0f | ||
|
|
3c027baa44 | ||
|
|
33ad9d530e | ||
|
|
d0321b8502 | ||
|
|
ee8e2c0e12 | ||
|
|
8fc78e31d7 | ||
|
|
477b48fb3d | ||
|
|
df0d801790 | ||
|
|
d2760be0d4 | ||
|
|
d18bcc2a69 | ||
|
|
8a45a2d46e | ||
|
|
63a59fce22 | ||
|
|
c4b84b20f7 | ||
|
|
d5f7878eb4 | ||
|
|
459711ba71 | ||
|
|
0820506d74 | ||
|
|
063b938f41 | ||
|
|
cb618d6f9c | ||
|
|
4aceba1106 | ||
|
|
d359a9ce3c | ||
|
|
3dbfa7708f | ||
|
|
cda258cbed | ||
|
|
cccf7ef1b3 | ||
|
|
8844593abb | ||
|
|
9badc5485d | ||
|
|
fd319beb8a | ||
|
|
c9e270a9fa | ||
|
|
d1067002da | ||
|
|
a7ecba4f4e | ||
|
|
99c26d3994 | ||
|
|
e656b11cd1 | ||
|
|
f7c087468d | ||
|
|
227e432695 | ||
|
|
38ae4e617d | ||
|
|
e717c513e9 | ||
|
|
f6f6f84047 | ||
|
|
cacadd6c7d | ||
|
|
65094514d6 | ||
|
|
f88b59f39f | ||
|
|
700858c112 | ||
|
|
2ba4bd9211 | ||
|
|
7523a0cd8e | ||
|
|
8c2b7410f0 | ||
|
|
70b5ce802b | ||
|
|
88e87b8abb | ||
|
|
7628a540af | ||
|
|
06ee8b7261 | ||
|
|
f5ae58ddab | ||
|
|
86b7cfb05c | ||
|
|
8a29360ade | ||
|
|
b032379de2 | ||
|
|
ba893abb2c | ||
|
|
94a63dd407 | ||
|
|
d9fb606869 | ||
|
|
8baff6ae33 | ||
|
|
7c6b225b7e | ||
|
|
2a9757bf38 | ||
|
|
74d12c5b5e | ||
|
|
d4a18d4dfb | ||
|
|
96ea587df0 | ||
|
|
2d8d8add42 | ||
|
|
7dcd4e0b65 | ||
|
|
ace84ef2b3 | ||
|
|
a3553e7bee | ||
|
|
e2f7755611 | ||
|
|
d2f62fda93 | ||
|
|
93401038c0 | ||
|
|
3334576b1d | ||
|
|
6d6d15e003 | ||
|
|
d6b206cc7d | ||
|
|
edd4cd4faf | ||
|
|
91216bdac1 | ||
|
|
92300ab675 | ||
|
|
0b50390359 | ||
|
|
621a67e819 | ||
|
|
75a776c516 | ||
|
|
743e0f4a82 | ||
|
|
649598c74c | ||
|
|
0a3657517d | ||
|
|
2957939d4b | ||
|
|
abf199cf0e | ||
|
|
7da43d8302 | ||
|
|
c8853d1507 | ||
|
|
edf43ae76f | ||
|
|
63478f2946 | ||
|
|
95721f5040 | ||
|
|
1397d5d01e | ||
|
|
098f375e9d | ||
|
|
44fe96b2da | ||
|
|
0ebb92da26 | ||
|
|
73bcf5e0db | ||
|
|
e962efca12 | ||
|
|
0b51926fff | ||
|
|
08cd5fe30b | ||
|
|
da0c31926e | ||
|
|
e96cfc5e56 | ||
|
|
2ef131f7ac | ||
|
|
945ea27fec | ||
|
|
490bd38962 | ||
|
|
121fc62aff | ||
|
|
5d888d2ac0 | ||
|
|
38259d11b6 | ||
|
|
86fa00416d | ||
|
|
645b8cdf24 | ||
|
|
dde6aa34ce | ||
|
|
7601011bba | ||
|
|
18844537bd | ||
|
|
7e80ea6577 | ||
|
|
82dab79096 | ||
|
|
1a4bcac666 | ||
|
|
e413e67ab3 | ||
|
|
b1ec180a3b | ||
|
|
1f164d7ee0 | ||
|
|
3fa88ae7f3 | ||
|
|
351d67c81e | ||
|
|
472a131df7 | ||
|
|
e6c613f28d | ||
|
|
e4b6bac50a | ||
|
|
3c4ea47e02 | ||
|
|
5bd8c49448 | ||
|
|
ba8e4f9dec | ||
|
|
15b75c7c68 | ||
|
|
925a6640d1 | ||
|
|
b42d7c2d9e | ||
|
|
d58f512a85 | ||
|
|
1356c15e44 | ||
|
|
3c47e5735a | ||
|
|
0750e18ad0 | ||
|
|
a24dd8b2dc | ||
|
|
2022bacd38 | ||
|
|
29fd2cf90d | ||
|
|
daf5826610 | ||
|
|
66808eec27 | ||
|
|
a3e7f5103d | ||
|
|
7e116ca601 | ||
|
|
56accae45e | ||
|
|
967b1bae57 | ||
|
|
6b3aebfa32 | ||
|
|
704c5a1c96 | ||
|
|
781f6d90bf | ||
|
|
40323cc02c | ||
|
|
9cddf46932 | ||
|
|
589c9b9433 | ||
|
|
99b71a37b7 | ||
|
|
b70696fc0a | ||
|
|
4b770cffb4 | ||
|
|
42e043cb01 | ||
|
|
c5c3c45102 | ||
|
|
c3be3c8050 | ||
|
|
cac2c3df13 | ||
|
|
2e4dbb846c | ||
|
|
b5fa4212b0 | ||
|
|
c23b0ee972 | ||
|
|
48e575b885 | ||
|
|
5fd1c93d43 | ||
|
|
a6f4dd031f | ||
|
|
73b3ca7d2c | ||
|
|
de4de1c3f8 | ||
|
|
f8fb1d6646 | ||
|
|
d2de6b42cf | ||
|
|
370a40348b | ||
|
|
ee152be17b | ||
|
|
a799fedea6 | ||
|
|
8f8b5ade55 | ||
|
|
bb0300f605 | ||
|
|
7d3021c34d | ||
|
|
e0e0fadacc | ||
|
|
f511f6c34d | ||
|
|
0a855fce47 | ||
|
|
f149dd304c | ||
|
|
8113f1df7a | ||
|
|
b34f685f70 | ||
|
|
f22676eea9 | ||
|
|
cdfff86c2d | ||
|
|
176e333774 | ||
|
|
3924fe9c18 | ||
|
|
3813249826 | ||
|
|
185a49e628 | ||
|
|
f7ce38dbc1 | ||
|
|
22050b97a7 | ||
|
|
7e1efe6d76 | ||
|
|
f39c1799d2 | ||
|
|
cf27c63b2d | ||
|
|
796d5174f3 | ||
|
|
cc1b36bafd | ||
|
|
255bcff3ac | ||
|
|
877fc1e812 | ||
|
|
affe4cde57 | ||
|
|
232b2eb04c | ||
|
|
baf012cf6a | ||
|
|
25377b20af | ||
|
|
d9fdc20492 | ||
|
|
5ead758f28 | ||
|
|
34603ebd60 | ||
|
|
3b43b304a3 | ||
|
|
3afb7e1a21 | ||
|
|
e24efae5a0 | ||
|
|
4262aea87c | ||
|
|
dde8de0a0d | ||
|
|
7ca78a75e7 | ||
|
|
ec124a0905 | ||
|
|
ca83bc50bf | ||
|
|
52287c025f | ||
|
|
3c7727a8f4 | ||
|
|
3191d98391 | ||
|
|
3bd04a70bd | ||
|
|
feb2fe0d94 | ||
|
|
b211af9d24 | ||
|
|
9740203485 | ||
|
|
a21bd8a417 | ||
|
|
1d42c45a34 | ||
|
|
38895f8f29 | ||
|
|
f316ec0d66 | ||
|
|
671ff628ff | ||
|
|
c7e8075972 | ||
|
|
646dcd3838 | ||
|
|
93d0443998 | ||
|
|
6c20fdb7bd | ||
|
|
e743838d09 | ||
|
|
f1a8192a36 | ||
|
|
87d77f0133 | ||
|
|
aca58ca90f | ||
|
|
a5f4d40901 | ||
|
|
8ed0acf1ec | ||
|
|
39b646349f | ||
|
|
56b0b679c6 | ||
|
|
6baea8d846 | ||
|
|
fcc7acbfc6 | ||
|
|
bf4c72f93b | ||
|
|
c78a342bdc | ||
|
|
c2ed0aab00 | ||
|
|
5563b3b6f8 | ||
|
|
5750c888a6 | ||
|
|
8b564f509b | ||
|
|
c7c778f109 | ||
|
|
cbd78e689c | ||
|
|
8d0c75171c | ||
|
|
6e06cd18da | ||
|
|
198cce29ba | ||
|
|
a518efbedb | ||
|
|
13236822d3 | ||
|
|
2285e5b6da | ||
|
|
1bab793c75 | ||
|
|
566f4e6efc | ||
|
|
83eb54ec7e | ||
|
|
f82f59a024 | ||
|
|
12fab5d5d7 | ||
|
|
7ece66d06e | ||
|
|
a64234e897 | ||
|
|
58bd13b623 | ||
|
|
b97df914dd | ||
|
|
0e371d6e5c | ||
|
|
1106e89c84 | ||
|
|
506f703da5 | ||
|
|
853ee5df17 | ||
|
|
964474837f | ||
|
|
ce4be92a67 | ||
|
|
3d2421f3bf | ||
|
|
28c006ee8c | ||
|
|
193b1d2c9f | ||
|
|
147fe4ee9f | ||
|
|
c233a39052 | ||
|
|
1264184fbb | ||
|
|
5d1992ef05 | ||
|
|
f4369ed694 | ||
|
|
7e7b6d7fb8 | ||
|
|
d915745073 | ||
|
|
0a9d9db5ae | ||
|
|
318b1c1a34 | ||
|
|
0dc93c1d5c | ||
|
|
ac3f30ed6c | ||
|
|
447ab12cec | ||
|
|
2cb1a8de73 | ||
|
|
1d79f5c59b | ||
|
|
065f36ab56 | ||
|
|
c561fe8baf | ||
|
|
2b4852048d | ||
|
|
0144e3ebec | ||
|
|
d410e551f8 | ||
|
|
344f87abe3 | ||
|
|
57c816f906 | ||
|
|
82e1dbe162 | ||
|
|
e6b0bdd4df | ||
|
|
4f13c4d1bb | ||
|
|
c37ec19751 | ||
|
|
aaaf8e75af | ||
|
|
8cc31c6cf1 | ||
|
|
8468af1a20 | ||
|
|
db39d70c75 | ||
|
|
04fff7ebd8 | ||
|
|
b154af87a1 | ||
|
|
8b7480806a | ||
|
|
e29f5ad559 | ||
|
|
4618fd5a43 | ||
|
|
ed979c6aa1 | ||
|
|
141c5da3f9 | ||
|
|
0185ee5df3 | ||
|
|
27c08a65e1 | ||
|
|
de408a5eb7 | ||
|
|
fa3c072dd1 | ||
|
|
aac4b7090a | ||
|
|
f0d664530d | ||
|
|
702140bf93 | ||
|
|
2075db3db0 | ||
|
|
b7fec513cf | ||
|
|
78e7758022 | ||
|
|
818318ddd5 | ||
|
|
39eea781bc | ||
|
|
c4f7bd6a04 | ||
|
|
dd03d0f3c9 | ||
|
|
369ce6af2c | ||
|
|
f83817510d | ||
|
|
bfcd779cfb | ||
|
|
e69c380205 | ||
|
|
61e14aa827 | ||
|
|
0c6c83e278 | ||
|
|
6f52208b68 |
@@ -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,109 @@
|
|||||||
|
---
|
||||||
|
# DESCRIPTION: Github actions composite action
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
name: Install dependencies
|
||||||
|
description: >-
|
||||||
|
Install the dependencies of a CI stage with 'ci/ci-install.bash', caching the
|
||||||
|
'.deb' files apt downloads for that stage, so a package is fetched from the
|
||||||
|
network at most once per runner image. On hosts that do not use apt this is
|
||||||
|
just the install, there is nothing to cache.
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
repo:
|
||||||
|
description: "Verilator checkout holding the ci/ scripts"
|
||||||
|
required: false
|
||||||
|
default: repo
|
||||||
|
stage:
|
||||||
|
description: "CI stage to install the dependencies of, e.g. 'build'"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Compute apt cache key
|
||||||
|
id: cachekey
|
||||||
|
if: ${{ runner.os == 'Linux' }}
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ inputs.repo }}
|
||||||
|
env:
|
||||||
|
STAGE: ${{ inputs.stage }}
|
||||||
|
run: |
|
||||||
|
source ci/ci-common.bash
|
||||||
|
host="${DISTRO_ID:-$HOST_OS}${DISTRO_VERSION:+-$DISTRO_VERSION}"
|
||||||
|
echo "key=apt-${host}-${STAGE}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Restore apt downloads
|
||||||
|
if: ${{ runner.os == 'Linux' }}
|
||||||
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||||
|
with:
|
||||||
|
path: ${{ runner.temp }}/apt-cache
|
||||||
|
key: ${{ steps.cachekey.outputs.key }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ steps.cachekey.outputs.key }}-
|
||||||
|
|
||||||
|
- name: Seed apt archive from cache
|
||||||
|
if: ${{ runner.os == 'Linux' }}
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
APT_CACHE_DIR: ${{ runner.temp }}/apt-cache
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
# Ask apt where it keeps its downloads, rather than assume
|
||||||
|
eval "$(apt-config shell ARCHIVES Dir::Cache::archives/d)"
|
||||||
|
ARCHIVES=${ARCHIVES%/} # '/d' yields a trailing slash
|
||||||
|
# Wipe the archive first, so that whatever the runner image left behind is not stored
|
||||||
|
sudo apt-get -o DPkg::Lock::Timeout=60 clean
|
||||||
|
# The directory is absent when nothing was restored, e.g. on a cold start
|
||||||
|
if [ -d "$APT_CACHE_DIR" ] &&
|
||||||
|
[ -n "$(find "$APT_CACHE_DIR" -maxdepth 1 -name '*.deb' -print -quit)" ]; then
|
||||||
|
sudo cp "$APT_CACHE_DIR"/*.deb "$ARCHIVES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ inputs.repo }}
|
||||||
|
env:
|
||||||
|
STAGE: ${{ inputs.stage }}
|
||||||
|
run: ./ci/ci-install.bash "$STAGE"
|
||||||
|
|
||||||
|
- name: Collect apt downloads
|
||||||
|
id: collect
|
||||||
|
if: ${{ runner.os == 'Linux' }}
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
APT_CACHE_DIR: ${{ runner.temp }}/apt-cache
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
# Ask apt where it keeps its downloads, rather than assume
|
||||||
|
eval "$(apt-config shell ARCHIVES Dir::Cache::archives/d)"
|
||||||
|
ARCHIVES=${ARCHIVES%/} # '/d' yields a trailing slash
|
||||||
|
# Sorted names of the '.deb' files in a directory, empty if it has none
|
||||||
|
list-debs() {
|
||||||
|
[ -d "$1" ] || return 0
|
||||||
|
find "$1" -maxdepth 1 -name '*.deb' -printf '%f\n' | sort
|
||||||
|
}
|
||||||
|
# Superseded downloads can no longer be fetched, so drop them
|
||||||
|
sudo apt-get -o DPkg::Lock::Timeout=60 autoclean
|
||||||
|
downloaded=$(list-debs "$ARCHIVES")
|
||||||
|
if [ -z "$downloaded" ]; then
|
||||||
|
echo "Apt kept no '.deb' files, nothing to cache"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if [ "$downloaded" = "$(list-debs "$APT_CACHE_DIR")" ]; then
|
||||||
|
echo "Downloads unchanged, keeping the restored cache entry"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
# Mirror the archive, rather than add to it, so that the cache cannot
|
||||||
|
# grow without bound as package versions churn
|
||||||
|
mkdir -p "$APT_CACHE_DIR"
|
||||||
|
rm -f "$APT_CACHE_DIR"/*.deb
|
||||||
|
sudo cp "$ARCHIVES"/*.deb "$APT_CACHE_DIR"
|
||||||
|
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Save apt downloads
|
||||||
|
if: ${{ steps.collect.outputs.changed == 'true' }}
|
||||||
|
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||||
|
with:
|
||||||
|
path: ${{ runner.temp }}/apt-cache
|
||||||
|
key: ${{ steps.cachekey.outputs.key }}-${{ github.run_id }}
|
||||||
@@ -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 }}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
# DESCRIPTION: Github actions composite action
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
name: Upload PR notification
|
||||||
|
description: >-
|
||||||
|
Upload the 'pr-notification' artifact, holding a comment for 'pages.yml' to
|
||||||
|
post on a pull request. The given directory must hold the content of the
|
||||||
|
comment in 'body.txt', and its single line summary in 'hist.txt'.
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
path:
|
||||||
|
description: "Directory holding the notification contents"
|
||||||
|
required: true
|
||||||
|
key:
|
||||||
|
description: "Unique key for combining comments"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Validate
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
NOTIFICATION_DIR: ${{ inputs.path }}
|
||||||
|
EVENT_NAME: ${{ github.event_name }}
|
||||||
|
run: |
|
||||||
|
# The notification is posted on the pull request of the triggering event
|
||||||
|
if [ "${EVENT_NAME}" != "pull_request" ]; then
|
||||||
|
echo "This action can only be used on a 'pull_request' run, but event is '${EVENT_NAME}'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# The content of the comment, and its single line summary
|
||||||
|
for f in body.txt hist.txt; do
|
||||||
|
if [ ! -f "${NOTIFICATION_DIR}/${f}" ]; then
|
||||||
|
echo "No '${f}' in '${NOTIFICATION_DIR}'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Nothing else, so the artifact holds only what this action puts in it
|
||||||
|
EXTRA=$(find "${NOTIFICATION_DIR}" -mindepth 1 -not -name body.txt -not -name hist.txt)
|
||||||
|
if [ -n "${EXTRA}" ]; then
|
||||||
|
echo "Unexpected content in '${NOTIFICATION_DIR}':" >&2
|
||||||
|
echo "${EXTRA}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# 'ci-pages-notify.bash' stashes 'hist.txt' in an HTML comment, and later
|
||||||
|
# shows it in the history of the notifications superseding this one, so
|
||||||
|
# it must be a single line, and must neither open nor close an HTML comment
|
||||||
|
if [ $(wc -l < "${NOTIFICATION_DIR}/hist.txt") -ne 1 ]; then
|
||||||
|
echo "'hist.txt' must hold exactly one line" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if grep -q -e '<!--' -e '-->' "${NOTIFICATION_DIR}/hist.txt"; then
|
||||||
|
echo "'hist.txt' must not contain '<!--' or '-->'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Add metadata
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
NOTIFICATION_DIR: ${{ inputs.path }}
|
||||||
|
NOTIFICATION_KEY: ${{ inputs.key }}
|
||||||
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
|
run: |
|
||||||
|
echo "${NOTIFICATION_KEY}" > "${NOTIFICATION_DIR}/key.txt"
|
||||||
|
echo "${PR_NUMBER}" > "${NOTIFICATION_DIR}/pr-number.txt"
|
||||||
|
ls -lsha "${NOTIFICATION_DIR}"
|
||||||
|
|
||||||
|
- name: Upload notification
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
|
with:
|
||||||
|
path: ${{ inputs.path }}
|
||||||
|
name: pr-notification
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
---
|
---
|
||||||
# DESCRIPTION: Github actions config
|
# DESCRIPTION: Github actions config
|
||||||
# This name is key to badges in README.rst, so we use the name build
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
name: build-test
|
name: Regressions
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -16,6 +15,7 @@ on:
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
actions: read
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -29,272 +29,141 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build-2604-gcc:
|
build-2604-gcc:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
name: Build | 26.04 | gcc
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: gcc
|
||||||
|
runs-on: ubuntu-26.04
|
||||||
sha: ${{ github.sha }}
|
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:
|
build-2604-clang:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
name: Build | 26.04 | clang
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: clang
|
||||||
|
dev-asan: true # Build (and run) with address sanitizer
|
||||||
|
runs-on: ubuntu-26.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: linux
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: ubuntu-26.04, cc: clang, asan: 1}
|
|
||||||
|
|
||||||
build-2404-gcc:
|
build-2404-gcc:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
name: Build | 24.04 | gcc
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: gcc
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: linux
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: ubuntu-24.04, cc: gcc, asan: 0}
|
|
||||||
|
|
||||||
build-2404-clang:
|
build-2404-clang:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
name: Build | 24.04 | clang
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: clang
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: linux
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: ubuntu-24.04, cc: clang, asan: 0}
|
|
||||||
|
|
||||||
build-2204-gcc:
|
build-2204-gcc:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
name: Build | 22.04 | gcc
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: gcc
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: linux
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: ubuntu-22.04, cc: gcc, asan: 0}
|
|
||||||
|
|
||||||
build-osx-gcc:
|
build-macos-15-clang:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
name: Build | macos-15 | clang
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: clang
|
||||||
|
runs-on: macos-15
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: osx
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: macos-15, cc: gcc, asan: 0}
|
|
||||||
|
|
||||||
build-osx-clang:
|
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}${{ matrix.asan && ' | asan' || '' }}
|
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
|
||||||
with:
|
|
||||||
sha: ${{ github.sha }}
|
|
||||||
os: ${{ matrix.os }}
|
|
||||||
os-name: osx
|
|
||||||
cc: ${{ matrix.cc }}
|
|
||||||
dev-asan: ${{ matrix.asan }}
|
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: macos-15, cc: clang, asan: 0}
|
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.cc }}
|
name: Build | windows-2025-vs2026 | msvc
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: windows-2025-vs2026
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- {os: windows-2025-vs2026, cc: msvc}
|
|
||||||
env:
|
|
||||||
CI_OS_NAME: win
|
|
||||||
CCACHE_COMPRESS: 1
|
|
||||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
|
||||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
with:
|
with:
|
||||||
path: repo
|
path: repo
|
||||||
- name: Cache $CCACHE_DIR
|
- name: Cache win_flex_bison
|
||||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||||
with:
|
with:
|
||||||
path: ${{ env.CCACHE_DIR }}
|
path: ${{ github.workspace }}/win_flex_bison
|
||||||
key: msbuild-msvc-cmake
|
key: win_flex_bison
|
||||||
- name: compile
|
- name: compile
|
||||||
env:
|
|
||||||
WIN_FLEX_BISON: ${{ github.workspace }}/.ccache
|
|
||||||
run: ./ci/ci-win-compile.ps1
|
run: ./ci/ci-win-compile.ps1
|
||||||
- name: test build
|
- name: test build
|
||||||
run: ./ci/ci-win-test.ps1
|
run: ./ci/ci-win-test.ps1
|
||||||
- name: Zip up repository
|
|
||||||
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
|
|
||||||
- name: Upload zip archive
|
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
||||||
with:
|
|
||||||
path: ${{ github.workspace }}/repo/verilator.zip
|
|
||||||
name: verilator-win.zip
|
|
||||||
|
|
||||||
test-2604-gcc:
|
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
|
needs: build-2604-gcc
|
||||||
uses: ./.github/workflows/reusable-test.yml
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
with:
|
with:
|
||||||
archive: ${{ needs.build-2604-gcc.outputs.archive }}
|
archive: ${{ needs.build-2604-gcc.outputs.archive }}
|
||||||
os: ${{ matrix.os }}
|
cc: gcc
|
||||||
cc: ${{ matrix.cc }}
|
runs-on: ubuntu-26.04
|
||||||
reloc: ${{ matrix.reloc }}
|
|
||||||
suite: ${{ matrix.suite }}
|
suite: ${{ matrix.suite }}
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||||
# Ubuntu 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}
|
|
||||||
|
|
||||||
test-2604-clang:
|
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
|
needs: build-2604-clang
|
||||||
uses: ./.github/workflows/reusable-test.yml
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
with:
|
with:
|
||||||
archive: ${{ needs.build-2604-clang.outputs.archive }}
|
archive: ${{ needs.build-2604-clang.outputs.archive }}
|
||||||
os: ${{ matrix.os }}
|
cc: clang
|
||||||
cc: ${{ matrix.cc }}
|
runs-on: ubuntu-26.04
|
||||||
reloc: ${{ matrix.reloc }}
|
|
||||||
suite: ${{ matrix.suite }}
|
suite: ${{ matrix.suite }}
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||||
# Ubuntu 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}
|
|
||||||
|
|
||||||
test-2404-gcc:
|
test-2404-gcc:
|
||||||
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
name: Test | 24.04 | gcc | ${{ matrix.suite }}
|
||||||
needs: build-2404-gcc
|
needs: build-2404-gcc
|
||||||
uses: ./.github/workflows/reusable-test.yml
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
with:
|
with:
|
||||||
archive: ${{ needs.build-2404-gcc.outputs.archive }}
|
archive: ${{ needs.build-2404-gcc.outputs.archive }}
|
||||||
os: ${{ matrix.os }}
|
cc: gcc
|
||||||
cc: ${{ matrix.cc }}
|
runs-on: ubuntu-24.04
|
||||||
reloc: ${{ matrix.reloc }}
|
|
||||||
suite: ${{ matrix.suite }}
|
suite: ${{ matrix.suite }}
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||||
# Ubuntu 24.04 gcc
|
|
||||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-0}
|
|
||||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-1}
|
|
||||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-2}
|
|
||||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt-3}
|
|
||||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-0}
|
|
||||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-1}
|
|
||||||
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-2}
|
|
||||||
|
|
||||||
test-2404-clang:
|
test-2404-clang:
|
||||||
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
name: Test | 24.04 | clang | ${{ matrix.suite }}
|
||||||
needs: build-2404-clang
|
needs: build-2404-clang
|
||||||
uses: ./.github/workflows/reusable-test.yml
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
with:
|
with:
|
||||||
archive: ${{ needs.build-2404-clang.outputs.archive }}
|
archive: ${{ needs.build-2404-clang.outputs.archive }}
|
||||||
os: ${{ matrix.os }}
|
cc: clang
|
||||||
cc: ${{ matrix.cc }}
|
reloc: true # Test with relocated installation
|
||||||
reloc: ${{ matrix.reloc }}
|
runs-on: ubuntu-24.04
|
||||||
suite: ${{ matrix.suite }}
|
suite: ${{ matrix.suite }}
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||||
# Ubuntu 24.04 clang
|
|
||||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-0}
|
|
||||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-1}
|
|
||||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-2}
|
|
||||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt-3}
|
|
||||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-0}
|
|
||||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-1}
|
|
||||||
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-2}
|
|
||||||
|
|
||||||
test-2204-gcc:
|
test-2204-gcc:
|
||||||
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
name: Test | 22.04 | gcc | ${{ matrix.suite }}
|
||||||
needs: build-2204-gcc
|
needs: build-2204-gcc
|
||||||
uses: ./.github/workflows/reusable-test.yml
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
with:
|
with:
|
||||||
archive: ${{ needs.build-2204-gcc.outputs.archive }}
|
archive: ${{ needs.build-2204-gcc.outputs.archive }}
|
||||||
os: ${{ matrix.os }}
|
cc: gcc
|
||||||
cc: ${{ matrix.cc }}
|
runs-on: ubuntu-22.04
|
||||||
reloc: ${{ matrix.reloc }}
|
|
||||||
suite: ${{ matrix.suite }}
|
suite: ${{ matrix.suite }}
|
||||||
dev-gcov: 0
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||||
# Ubuntu 22.04 gcc
|
|
||||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-0}
|
|
||||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-1}
|
|
||||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-2}
|
|
||||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt-3}
|
|
||||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-0}
|
|
||||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-1}
|
|
||||||
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-2}
|
|
||||||
|
|
||||||
lint-py:
|
lint-py:
|
||||||
name: Lint Python
|
name: Lint Python
|
||||||
|
|||||||
@@ -16,5 +16,5 @@ jobs:
|
|||||||
name: "'docs/CONTRIBUTORS' was signed"
|
name: "'docs/CONTRIBUTORS' was signed"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
- run: test_regress/t/t_dist_contributors.py
|
- run: test_regress/t/t_dist_contributors.py
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ on:
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
actions: read
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -38,15 +39,13 @@ jobs:
|
|||||||
(github.event_name == 'workflow_dispatch')
|
(github.event_name == 'workflow_dispatch')
|
||||||
uses: ./.github/workflows/reusable-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
|
cc: gcc
|
||||||
|
dev-gcov: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
# For pull requests, build the head of the pull request branch, not the
|
# For pull requests, build the head of the pull request branch, not the
|
||||||
# merge commit, otherwise patch coverage would include the changes
|
# merge commit, otherwise patch coverage would include the changes
|
||||||
# between the root of the pull request and the target branch
|
# between the root of the pull request and the target branch
|
||||||
sha: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
sha: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||||
os: ubuntu-24.04
|
|
||||||
os-name: linux
|
|
||||||
cc: gcc
|
|
||||||
dev-asan: 0
|
|
||||||
dev-gcov: 1
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
name: Test | ${{ matrix.test }}${{ matrix.num }}
|
name: Test | ${{ matrix.test }}${{ matrix.num }}
|
||||||
@@ -54,11 +53,10 @@ jobs:
|
|||||||
uses: ./.github/workflows/reusable-test.yml
|
uses: ./.github/workflows/reusable-test.yml
|
||||||
with:
|
with:
|
||||||
archive: ${{ needs.build.outputs.archive }}
|
archive: ${{ needs.build.outputs.archive }}
|
||||||
os: ubuntu-24.04
|
|
||||||
cc: gcc
|
cc: gcc
|
||||||
reloc: 0
|
dev-gcov: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
suite: ${{ matrix.test }}${{ matrix.num }}
|
suite: ${{ matrix.test }}${{ matrix.num }}
|
||||||
dev-gcov: 1
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -74,7 +72,7 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
|
|
||||||
- name: Download code coverage data
|
- name: Download code coverage data
|
||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
@@ -106,13 +104,6 @@ jobs:
|
|||||||
if: ${{ contains(needs.*.result, 'success') && !cancelled() }}
|
if: ${{ contains(needs.*.result, 'success') && !cancelled() }}
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
echo 'set man-db/auto-update false' | sudo debconf-communicate >/dev/null
|
|
||||||
sudo dpkg-reconfigure man-db
|
|
||||||
sudo apt install lcov || \
|
|
||||||
sudo apt install lcov
|
|
||||||
|
|
||||||
- name: Download repository archive
|
- name: Download repository archive
|
||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
@@ -121,9 +112,14 @@ jobs:
|
|||||||
|
|
||||||
- name: Unpack repository archive
|
- name: Unpack repository archive
|
||||||
run: |
|
run: |
|
||||||
tar -x -z -f ${{ needs.build.outputs.archive }}
|
tar --zstd -x -f ${{ needs.build.outputs.archive }}
|
||||||
ls -lsha
|
ls -lsha
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
uses: ./repo/.github/actions/install-deps
|
||||||
|
with:
|
||||||
|
stage: coverage
|
||||||
|
|
||||||
- name: Download code coverage data
|
- name: Download code coverage data
|
||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
@@ -136,53 +132,30 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: |
|
run: |
|
||||||
ls -lsha obj_coverage
|
ci/ci-coverage-report.bash \
|
||||||
# Combine reports from test jobs
|
${{ github.run_id }} \
|
||||||
nodist/fastcov.py -C obj_coverage/verilator-*.info --lcov -o obj_coverage/verilator.info
|
"${{ github.event_name == 'pull_request' && github.event.number || '' }}" \
|
||||||
# For a PR, report patch coverage against the merge-base between the head of the PR and the target branch
|
"${{ github.event.pull_request.base.sha }}" \
|
||||||
|
"${{ github.event.pull_request.head.sha }}"
|
||||||
|
# Create the report artifact. Note there is no report if the patch is empty.
|
||||||
|
mkdir ../report-artifact
|
||||||
|
[ ! -d obj_coverage/report ] || mv obj_coverage/report ../report-artifact/
|
||||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||||
COVERAGE_BASE=$(git rev-parse --short $(git merge-base ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}))
|
echo ${{ github.event.number }} > ../report-artifact/pr-number.txt
|
||||||
make coverage-report COVERAGE_BASE=${COVERAGE_BASE} |& tee ${{ github.workspace }}/make-coverage-report.log
|
|
||||||
else
|
|
||||||
make coverage-report
|
|
||||||
fi
|
|
||||||
# Remove data files
|
|
||||||
rm -f obj_coverage/verilator*.info
|
|
||||||
# Some extra work for PRs only
|
|
||||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
|
||||||
# Save PR number in report
|
|
||||||
echo ${{ github.event.number }} > obj_coverage/pr-number.txt
|
|
||||||
# Generate notification comment content
|
|
||||||
mkdir -p notification
|
|
||||||
echo ${{ github.event.number }} > notification/pr-number.txt
|
|
||||||
NUM=$(gh run view ${{ github.run_id }} --json number --jq ".number")
|
|
||||||
URL=$(gh run view ${{ github.run_id }} --json url --jq ".url")
|
|
||||||
echo "Patch coverage from PR workflow [#$NUM]($URL) (code coverage of lines changed relative to ${COVERAGE_BASE}):" > notification/body.txt
|
|
||||||
if [[ ! -f obj_coverage/empty-patch ]]; then
|
|
||||||
echo "<pre>" >> notification/body.txt
|
|
||||||
grep -E "(lines|branches)\.*:" ${{ github.workspace }}/make-coverage-report.log | sed "s/\.*:/:/" >> notification/body.txt || true
|
|
||||||
echo "</pre>" >> notification/body.txt
|
|
||||||
echo "Report: [${{ github.run_id }}](https://${{ github.repository_owner }}.github.io/verilator/coverage-reports/${{ github.run_id }}/index.html)" >> notification/body.txt
|
|
||||||
echo "" >> notification/body.txt
|
|
||||||
echo "Please get to 100% line coverage, and understand all branches; see https://github.com/verilator/verilator/blob/master/docs/internals.rst#code-coverage-results" >> notification/body.txt
|
|
||||||
else
|
|
||||||
echo "Patch contains no code changes" >> notification/body.txt
|
|
||||||
fi
|
|
||||||
cat notification/body.txt
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload report
|
- name: Upload report
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: repo/obj_coverage
|
path: report-artifact
|
||||||
name: coverage-report
|
name: coverage-report
|
||||||
|
|
||||||
- name: Upload notification
|
- name: Upload PR notification
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
uses: ./repo/.github/actions/upload-pr-notification
|
||||||
with:
|
with:
|
||||||
path: repo/notification
|
path: repo/notification
|
||||||
name: pr-notification
|
key: coverage
|
||||||
|
|
||||||
# Create GitHub issue for failed scheduled jobs
|
# Create GitHub issue for failed scheduled jobs
|
||||||
# This should always be the last job (we want an issue if anything breaks)
|
# This should always be the last job (we want an issue if anything breaks)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
|
|
||||||
- name: Extract context variables
|
- name: Extract context variables
|
||||||
run: |
|
run: |
|
||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: docker_meta
|
id: docker_meta
|
||||||
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6
|
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
||||||
@@ -64,21 +64,21 @@ jobs:
|
|||||||
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4
|
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4
|
||||||
with:
|
with:
|
||||||
buildkitd-flags: --debug
|
buildkitd-flags: --debug
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||||
|
|
||||||
- name: Build and Push to Docker
|
- name: Build and Push to Docker
|
||||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||||
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
|
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
|
||||||
with:
|
with:
|
||||||
context: ${{ env.build_context }}
|
context: ${{ env.build_context }}
|
||||||
|
|||||||
@@ -11,35 +11,47 @@ on:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: repo
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format:
|
format:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
name: Ubuntu 24.04 | format
|
name: Ubuntu 24.04 | format
|
||||||
env:
|
|
||||||
CI_OS_NAME: linux
|
|
||||||
CI_RUNS_ON: ubuntu-24.04
|
|
||||||
CI_COMMIT: ${{ github.sha }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
with:
|
with:
|
||||||
|
path: repo
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Install packages for build
|
- name: Install packages for build
|
||||||
env:
|
uses: ./repo/.github/actions/install-deps
|
||||||
CI_BUILD_STAGE_NAME: build
|
with:
|
||||||
|
stage: format
|
||||||
|
|
||||||
|
- name: Configure git identity
|
||||||
run: |
|
run: |
|
||||||
sudo apt install clang-format-18 || \
|
|
||||||
sudo apt install clang-format-18
|
|
||||||
git config --global user.email "[email protected]"
|
git config --global user.email "[email protected]"
|
||||||
git config --global user.name "github action"
|
git config --global user.name "github action"
|
||||||
- name: Format code
|
|
||||||
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
autoconf
|
autoconf
|
||||||
./configure
|
./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
|
source .venv/bin/activate
|
||||||
make -j 4 format CLANGFORMAT=clang-format-18
|
make -j 4 format CLANGFORMAT=clang-format-18
|
||||||
git status
|
git status
|
||||||
|
|
||||||
- name: Push
|
- name: Push
|
||||||
run: |-
|
run: |-
|
||||||
if [ -n "$(git status --porcelain)" ]; then
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ name: Pages
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches: [master]
|
||||||
paths: ["ci/**", ".github/workflows"]
|
paths: ["ci/**", ".github/workflows/**"]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ["Code coverage", "RTLMeter"]
|
workflows: ["Code coverage", "RTLMeter"]
|
||||||
@@ -22,8 +22,11 @@ permissions:
|
|||||||
# Allow only one concurrent deployment, skipping runs queued between the run
|
# Allow only one concurrent deployment, skipping runs queued between the run
|
||||||
# in-progress and latest queued. However, do NOT cancel in-progress runs as we
|
# in-progress and latest queued. However, do NOT cancel in-progress runs as we
|
||||||
# want to allow these deployments to complete.
|
# want to allow these deployments to complete.
|
||||||
|
# A skipped-upstream run does no work (see the build job's if:), so put it in its
|
||||||
|
# own throwaway group: otherwise, as the newest queued run, it would cancel a
|
||||||
|
# pending real run and then deploy nothing.
|
||||||
concurrency:
|
concurrency:
|
||||||
group: "pages"
|
group: ${{ (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'skipped') && format('pages-skip-{0}', github.run_id) || 'pages' }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
@@ -34,19 +37,21 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
name: Build content
|
name: Build content
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
# A skipped upstream run (e.g. Code coverage / RTLMeter on a branch push)
|
||||||
|
# still fires workflow_run; don't rebuild and redeploy for it. deploy and
|
||||||
|
# notify need this job, so they cascade-skip too.
|
||||||
|
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion != 'skipped' }}
|
||||||
outputs:
|
outputs:
|
||||||
pr-run-ids: ${{ steps.build.outputs.pr-run-ids }}
|
pr-run-ids: ${{ steps.build.outputs.pr-run-ids }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
- name: Build pages
|
- name: Build pages
|
||||||
id: build
|
id: build
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: |
|
run: |
|
||||||
./ci/ci-pages.bash
|
./ci/ci-pages.bash
|
||||||
ls -lsha
|
|
||||||
tree -L 3 pages
|
|
||||||
- name: Upload pages artifact
|
- name: Upload pages artifact
|
||||||
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
|
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
|
||||||
with:
|
with:
|
||||||
@@ -58,9 +63,16 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
environment:
|
environment:
|
||||||
name: github-pages
|
name: github-pages
|
||||||
url: ${{ steps.deployment.outputs.page_url }}
|
url: ${{ steps.deploy-2.outputs.page_url || steps.deploy-1.outputs.page_url }}
|
||||||
steps:
|
steps:
|
||||||
|
# GitHub's Pages backend intermittently fails a deployment mid-sync, retry
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
|
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
|
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5
|
||||||
|
|
||||||
notify:
|
notify:
|
||||||
@@ -70,7 +82,7 @@ jobs:
|
|||||||
if: ${{ github.repository == 'verilator/verilator' }}
|
if: ${{ github.repository == 'verilator/verilator' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
# Use the Verilator CI app to post the comment
|
# Use the Verilator CI app to post the comment
|
||||||
- name: Generate access token
|
- name: Generate access token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
@@ -83,5 +95,7 @@ jobs:
|
|||||||
- name: Comment on PR
|
- name: Comment on PR
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||||
|
# Slug of the app the above token belongs to, see 'ci-pages-notify.bash'
|
||||||
|
GH_AUTHOR: ${{ steps.generate-token.outputs.app-slug }}
|
||||||
PR_RUN_IDS: ${{ needs.build.outputs.pr-run-ids }}
|
PR_RUN_IDS: ${{ needs.build.outputs.pr-run-ids }}
|
||||||
run: ./ci/ci-pages-notify.bash
|
run: ./ci/ci-pages-notify.bash
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
# Build and push verilator docker image when tags are pushed to the repository.
|
||||||
|
# The following variable(s) must be configured in the github repository:
|
||||||
|
# DOCKER_HUB_NAMESPACE: docker hub namespace.
|
||||||
|
# The following secrets must be configured in the github repository:
|
||||||
|
# DOCKER_HUB_USER: user name for logging into docker hub
|
||||||
|
# DOCKER_HUB_ACCESS_TOKEN: docker hub access token.
|
||||||
|
name: Maintainance - PR conflict check
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
pull_request_target:
|
||||||
|
types: [synchronize]
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
main:
|
||||||
|
runs-on: ubuntu-26.04
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- name: check if prs are dirty
|
||||||
|
uses: eps1lon/actions-label-merge-conflict@0273be72a0bbd58fcd71d0d6c02c209b50d1e5e1 # 3.1.0
|
||||||
|
with:
|
||||||
|
dirtyLabel: "pr-blocked: needs-rebase"
|
||||||
|
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
@@ -7,37 +7,47 @@ name: reusable-build
|
|||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
|
cc:
|
||||||
|
description: "Compiler to use: 'gcc' or 'clang'"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
ccwarn:
|
||||||
|
description: "Build Verilator with warnings treated as errors (--enable-ccwarn)"
|
||||||
|
required: false
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
dev-asan:
|
||||||
|
description: "Build Verilator with the address sanitizer (--enable-dev-asan)"
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
dev-gcov:
|
||||||
|
description: "Build Verilator with gcov instrumentation (--enable-dev-gcov)"
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
install:
|
||||||
|
description: "Archive the Verilator installation, not the repo tree"
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
runs-on:
|
||||||
|
description: "Runner to build on, e.g. ubuntu-24.04"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
sha:
|
sha:
|
||||||
description: "Commit SHA to build"
|
description: "Commit SHA to build"
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
os: # e.g. ubuntu-24.04
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
cc: # 'clang' or 'gcc'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
os-name: # 'linux' or 'osx'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
dev-asan:
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
dev-gcov:
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
outputs:
|
outputs:
|
||||||
archive:
|
archive:
|
||||||
description: "Name of the built repository archive artifact"
|
description: "Name of the built archive artifact"
|
||||||
value: ${{ jobs.build.outputs.archive }}
|
value: ${{ jobs.build.outputs.archive }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CI_OS_NAME: ${{ inputs.os-name }}
|
CACHE_BASE_KEY: build-${{ inputs.runs-on }}-${{ inputs.cc }}${{ inputs.ccwarn && '-ccwarn' || '' }}${{ inputs.dev-asan && '-asan' || '' }}${{ inputs.dev-gcov && '-gcov' || '' }}
|
||||||
CCACHE_COMPRESS: 1
|
CCACHE_COMPILERCHECK: content
|
||||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
|
||||||
INSTALL_DIR: ${{ github.workspace }}/install
|
|
||||||
RELOC_DIR: ${{ github.workspace }}/relloc
|
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -48,26 +58,28 @@ jobs:
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build
|
name: Build
|
||||||
runs-on: ${{ inputs.os }}
|
runs-on: ${{ inputs.runs-on }}
|
||||||
outputs:
|
outputs:
|
||||||
archive: ${{ steps.create-archive.outputs.archive }}
|
archive: ${{ steps.create-archive.outputs.archive }}
|
||||||
env:
|
|
||||||
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:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
with:
|
with:
|
||||||
path: repo
|
path: repo
|
||||||
ref: ${{ inputs.sha }}
|
ref: ${{ inputs.sha }}
|
||||||
fetch-depth: ${{ inputs.dev-gcov && '0' || '1' }} # Coverage flow needs full history
|
# Coverage needs full history; install needs it for the 'git describe'
|
||||||
|
# behind 'verilator --version'
|
||||||
|
fetch-depth: ${{ (inputs.install || inputs.dev-gcov) && '0' || '1' }}
|
||||||
|
|
||||||
|
- name: 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
|
- name: Cache $CCACHE_DIR
|
||||||
|
if: ${{ env.CCACHE_DISABLE != '1' }}
|
||||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
||||||
env:
|
env:
|
||||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||||
@@ -75,25 +87,46 @@ jobs:
|
|||||||
path: ${{ env.CCACHE_DIR }}
|
path: ${{ env.CCACHE_DIR }}
|
||||||
key: ${{ env.CACHE_KEY }}-${{ inputs.sha }}
|
key: ${{ env.CACHE_KEY }}-${{ inputs.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ env.CACHE_KEY }}-
|
${{ env.CACHE_KEY }}
|
||||||
|
|
||||||
- name: Install packages for build
|
- name: Install packages for build
|
||||||
run: ./ci/ci-install.bash
|
uses: ./repo/.github/actions/install-deps
|
||||||
|
with:
|
||||||
|
stage: build
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./ci/ci-script.bash
|
run: |
|
||||||
|
./ci/ci-build.bash \
|
||||||
|
--prefix ${{ github.workspace }}/install \
|
||||||
|
--compiler ${{ inputs.cc }} \
|
||||||
|
--light-debug \
|
||||||
|
${{ inputs.ccwarn && '--ccwarn' || '' }} \
|
||||||
|
${{ inputs.dev-asan && '--asan' || '' }} \
|
||||||
|
${{ inputs.dev-gcov && '--gcov' || '' }}
|
||||||
|
|
||||||
- name: Create repository archive
|
- name: Install
|
||||||
|
if: ${{ inputs.install }}
|
||||||
|
run: make install
|
||||||
|
|
||||||
|
- name: Create archive
|
||||||
id: create-archive
|
id: create-archive
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: |
|
run: |
|
||||||
# Name of the archive must be unique based on the build parameters
|
# Archive name, unique per build; flavour tags mark non-default builds
|
||||||
ARCHIVE=verilator-${{ inputs.sha }}-${{ inputs.os }}-${{ inputs.cc }}-${{ inputs.dev-asan }}-${{ inputs.dev-gcov }}.tar.gz
|
ARCHIVE="verilator-${{ inputs.sha }}-${{ inputs.runs-on }}-${{ inputs.cc }}"
|
||||||
tar --posix -c -z -f $ARCHIVE repo
|
ARCHIVE="$ARCHIVE${{ inputs.ccwarn && '-ccwarn' || '' }}"
|
||||||
|
ARCHIVE="$ARCHIVE${{ inputs.dev-asan && '-asan' || '' }}"
|
||||||
|
ARCHIVE="$ARCHIVE${{ inputs.dev-gcov && '-gcov' || '' }}"
|
||||||
|
ARCHIVE="$ARCHIVE.tar.zst"
|
||||||
|
# zstd compresses faster than gzip and decompresses far faster in the many downstream jobs
|
||||||
|
ZSTD_NBTHREADS=0 tar --posix --zstd -c -f "$ARCHIVE" ${{ inputs.install && 'install' || 'repo' }}
|
||||||
echo "archive=$ARCHIVE" >> "$GITHUB_OUTPUT"
|
echo "archive=$ARCHIVE" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Upload repository archive
|
- name: Upload archive
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
with:
|
with:
|
||||||
path: ${{ github.workspace }}/${{ steps.create-archive.outputs.archive }}
|
path: ${{ github.workspace }}/${{ steps.create-archive.outputs.archive }}
|
||||||
name: ${{ steps.create-archive.outputs.archive }}
|
name: ${{ steps.create-archive.outputs.archive }}
|
||||||
|
overwrite: true
|
||||||
|
# Archive is already zstd-compressed; skip upload-artifact's zip pass
|
||||||
|
compression-level: 0
|
||||||
|
|||||||
@@ -7,14 +7,6 @@ name: reusable-lint-py
|
|||||||
on:
|
on:
|
||||||
workflow_call:
|
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:
|
defaults:
|
||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -27,23 +19,24 @@ jobs:
|
|||||||
name: Sub-lint | Python
|
name: Sub-lint | Python
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
with:
|
with:
|
||||||
path: repo
|
path: repo
|
||||||
|
|
||||||
- name: Install packages for build
|
- name: Install dependencies
|
||||||
run: ./ci/ci-install.bash
|
uses: ./repo/.github/actions/install-deps
|
||||||
|
with:
|
||||||
|
stage: lint-py
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
autoconf
|
autoconf
|
||||||
./configure --enable-longtests --enable-ccwarn
|
./configure --enable-longtests --enable-ccwarn
|
||||||
|
|
||||||
- name: Install python dependencies
|
- name: Set up Python venv
|
||||||
run: |
|
uses: ./repo/.github/actions/setup-venv
|
||||||
sudo apt install python3-clang || \
|
with:
|
||||||
sudo apt install python3-clang
|
save: ${{ github.ref == 'refs/heads/master' }}
|
||||||
make venv
|
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: |-
|
run: |-
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
---
|
|
||||||
# DESCRIPTION: Github actions config
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
|
|
||||||
name: reusable-rtlmeter-build
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
runs-on:
|
|
||||||
description: "Runner to use, e.g.: ubuntu-24.04"
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
cc:
|
|
||||||
description: "Compiler to use: 'gcc' or 'clang'"
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
sha:
|
|
||||||
description: "Git SHA to build"
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
outputs:
|
|
||||||
archive:
|
|
||||||
description: "Name of the built installation archive artifact"
|
|
||||||
value: ${{ jobs.build.outputs.archive }}
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
env:
|
|
||||||
CCACHE_DIR: ${{ github.workspace }}/ccache
|
|
||||||
CCACHE_MAXSIZE: 512M
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build
|
|
||||||
runs-on: ${{ inputs.runs-on }}
|
|
||||||
outputs:
|
|
||||||
archive: ${{ steps.create-archive.outputs.archive }}
|
|
||||||
steps:
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
echo "path-exclude /usr/share/doc/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
|
||||||
echo "path-exclude /usr/share/man/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
|
||||||
echo "path-exclude /usr/share/info/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
|
||||||
sudo apt update || \
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install ccache mold help2man libfl-dev libjemalloc-dev libsystemc-dev || \
|
|
||||||
sudo apt install ccache mold help2man libfl-dev libjemalloc-dev libsystemc-dev
|
|
||||||
|
|
||||||
- name: Use saved ccache
|
|
||||||
uses: actions/cache@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
|
type: string
|
||||||
required: true
|
required: true
|
||||||
verilator-archive-new:
|
verilator-archive-new:
|
||||||
description: "Name of the installation archive artifact from reusable-rtlmeter-build, new version"
|
description: "Name of the installation archive artifact from reusable-build, new version"
|
||||||
type: string
|
type: string
|
||||||
required: true
|
required: true
|
||||||
verilator-archive-old:
|
verilator-archive-old:
|
||||||
description: "Name of the installation archive artifact from reusable-rtlmeter-build, old version"
|
description: "Name of the installation archive artifact from reusable-build, old version"
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
@@ -53,8 +53,8 @@ defaults:
|
|||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CCACHE_DIR: ${{ github.workspace }}/ccache
|
# RTLMeter measures compile/execute times, so caching must stay off to keep
|
||||||
CCACHE_MAXSIZE: 512M
|
# timings representative; ccache is still on PATH but acts as a pass-through
|
||||||
CCACHE_DISABLE: 1
|
CCACHE_DISABLE: 1
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -62,18 +62,21 @@ jobs:
|
|||||||
runs-on: ${{ inputs.runs-on }}
|
runs-on: ${{ inputs.runs-on }}
|
||||||
name: Run
|
name: Run
|
||||||
steps:
|
steps:
|
||||||
|
- name: Checkout Verilator CI scripts
|
||||||
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
|
with:
|
||||||
|
path: repo
|
||||||
|
sparse-checkout: |
|
||||||
|
.github/actions
|
||||||
|
ci
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
uses: ./repo/.github/actions/install-deps
|
||||||
echo "path-exclude /usr/share/doc/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
with:
|
||||||
echo "path-exclude /usr/share/man/*" | sudo tee -a /etc/dpkg/dpkg.cfg.d/01_nodoc
|
stage: rtlmeter-run
|
||||||
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 libfl-dev libjemalloc-dev libsystemc-dev || \
|
|
||||||
sudo apt install ccache mold libfl-dev libjemalloc-dev libsystemc-dev
|
|
||||||
|
|
||||||
- name: Checkout RTLMeter
|
- name: Checkout RTLMeter
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
with:
|
with:
|
||||||
repository: "verilator/rtlmeter"
|
repository: "verilator/rtlmeter"
|
||||||
path: rtlmeter
|
path: rtlmeter
|
||||||
@@ -82,14 +85,6 @@ jobs:
|
|||||||
working-directory: rtlmeter
|
working-directory: rtlmeter
|
||||||
run: make venv
|
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
|
# Run with new Verilator
|
||||||
########################################################################
|
########################################################################
|
||||||
@@ -101,7 +96,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Unpack Verilator installation archive - new
|
- name: Unpack Verilator installation archive - new
|
||||||
run: |
|
run: |
|
||||||
tar -x -z -f ${{ inputs.verilator-archive-new }}
|
tar --zstd -x -f ${{ inputs.verilator-archive-new }}
|
||||||
mv install verilator-new
|
mv install verilator-new
|
||||||
|
|
||||||
- name: Compile cases - new
|
- name: Compile cases - new
|
||||||
@@ -164,7 +159,7 @@ jobs:
|
|||||||
- name: Unpack Verilator installation archive - old
|
- name: Unpack Verilator installation archive - old
|
||||||
if: ${{ inputs.verilator-archive-old != '' }}
|
if: ${{ inputs.verilator-archive-old != '' }}
|
||||||
run: |
|
run: |
|
||||||
tar -x -z -f ${{ inputs.verilator-archive-old }}
|
tar --zstd -x -f ${{ inputs.verilator-archive-old }}
|
||||||
mv install verilator-old
|
mv install verilator-old
|
||||||
|
|
||||||
- name: Compile cases - old
|
- name: Compile cases - old
|
||||||
|
|||||||
@@ -11,29 +11,37 @@ on:
|
|||||||
description: "Name of the repository archive artifact from reusable-build"
|
description: "Name of the repository archive artifact from reusable-build"
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
os: # e.g. ubuntu-24.04
|
cc:
|
||||||
required: true
|
description: "Compiler to use: 'gcc' or 'clang'"
|
||||||
type: string
|
|
||||||
cc: # gcc or clang
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
reloc: # 0 or 1
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
suite: # e.g. dist-vlt-0
|
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
dev-gcov:
|
dev-gcov:
|
||||||
|
description: "Collect gcov coverage data from the test run"
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
reloc:
|
||||||
|
description: "Relocate the installation before testing"
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
runs-on:
|
||||||
|
description: "Runner to test on, e.g. ubuntu-24.04"
|
||||||
required: true
|
required: true
|
||||||
type: number
|
type: string
|
||||||
|
suite:
|
||||||
|
description: "Test suite to run, e.g. dist-vlt-0"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: read
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CI_OS_NAME: linux
|
CCACHE_COMPILERCHECK: content
|
||||||
CCACHE_COMPRESS: 1
|
|
||||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
CXX: ${{ inputs.cc == 'clang' && 'clang++' || 'g++' }}
|
||||||
INSTALL_DIR: ${{ github.workspace }}/install
|
|
||||||
RELOC_DIR: ${{ github.workspace }}/relloc
|
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -43,15 +51,8 @@ defaults:
|
|||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: ${{ inputs.os }}
|
runs-on: ${{ inputs.runs-on }}
|
||||||
name: Test
|
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:
|
steps:
|
||||||
|
|
||||||
- name: Download repository archive
|
- name: Download repository archive
|
||||||
@@ -63,32 +64,44 @@ jobs:
|
|||||||
- name: Unpack repository archive
|
- name: Unpack repository archive
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: |
|
run: |
|
||||||
tar -x -z -f ${{ inputs.archive }}
|
tar --zstd -x -f ${{ inputs.archive }}
|
||||||
ls -lsha
|
ls -lsha
|
||||||
|
|
||||||
- name: Cache $CCACHE_DIR
|
- name: Configure ccache
|
||||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
|
run: |
|
||||||
env:
|
# ccache is unreliable on macOS, and does nothing with 'gcc --coverage'
|
||||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
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:
|
with:
|
||||||
|
mode: restore
|
||||||
path: ${{ env.CCACHE_DIR }}
|
path: ${{ env.CCACHE_DIR }}
|
||||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
key: ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.suite }}
|
||||||
restore-keys: |
|
|
||||||
${{ env.CACHE_KEY }}-
|
|
||||||
|
|
||||||
- name: Install test dependencies
|
- name: Install test dependencies
|
||||||
run: |
|
uses: ./repo/.github/actions/install-deps
|
||||||
./ci/ci-install.bash
|
with:
|
||||||
make venv
|
stage: test
|
||||||
|
|
||||||
|
- name: Set up Python venv
|
||||||
|
uses: ./repo/.github/actions/setup-venv
|
||||||
|
with:
|
||||||
|
save: ${{ github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
id: run-test
|
id: run-test
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
env:
|
|
||||||
TESTS: ${{ inputs.suite }}
|
|
||||||
run: |
|
run: |
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
./ci/ci-script.bash
|
./ci/ci-test.bash \
|
||||||
|
--suite ${{ inputs.suite }} \
|
||||||
|
${{ inputs.reloc && format('--reloc {0}/reloc', github.workspace) || '' }}
|
||||||
|
|
||||||
- name: Combine code coverage data
|
- name: Combine code coverage data
|
||||||
if: ${{ inputs.dev-gcov }}
|
if: ${{ inputs.dev-gcov }}
|
||||||
@@ -104,6 +117,16 @@ jobs:
|
|||||||
path: ${{ github.workspace }}/repo/obj_coverage/verilator-${{ inputs.suite }}.info
|
path: ${{ github.workspace }}/repo/obj_coverage/verilator-${{ inputs.suite }}.info
|
||||||
name: code-coverage-${{ inputs.suite }}
|
name: code-coverage-${{ inputs.suite }}
|
||||||
|
|
||||||
|
- 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
|
- name: Fail job if a test failed
|
||||||
if: ${{ steps.run-test.outcome == 'failure' && !cancelled() }}
|
if: ${{ steps.run-test.outcome == 'failure' && !cancelled() }}
|
||||||
run: |-
|
run: |-
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
cases: ${{ steps.cases.outputs.cases }}
|
cases: ${{ steps.cases.outputs.cases }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
|
|
||||||
- name: Startup
|
- name: Startup
|
||||||
id: start
|
id: start
|
||||||
@@ -65,39 +65,47 @@ jobs:
|
|||||||
build-gcc-new:
|
build-gcc-new:
|
||||||
name: Build New Verilator - GCC
|
name: Build New Verilator - GCC
|
||||||
needs: start
|
needs: start
|
||||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
cc: gcc
|
cc: gcc
|
||||||
|
ccwarn: false
|
||||||
|
install: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
|
|
||||||
build-clang-new:
|
build-clang-new:
|
||||||
name: Build New Verilator - Clang
|
name: Build New Verilator - Clang
|
||||||
needs: start
|
needs: start
|
||||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
cc: clang
|
cc: clang
|
||||||
|
ccwarn: false
|
||||||
|
install: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ github.sha }}
|
sha: ${{ github.sha }}
|
||||||
|
|
||||||
build-gcc-old:
|
build-gcc-old:
|
||||||
name: Build Old Verilator - GCC
|
name: Build Old Verilator - GCC
|
||||||
needs: start
|
needs: start
|
||||||
if: ${{ needs.start.outputs.old-sha != '' }}
|
if: ${{ needs.start.outputs.old-sha != '' }}
|
||||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
cc: gcc
|
cc: gcc
|
||||||
|
ccwarn: false
|
||||||
|
install: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ needs.start.outputs.old-sha }}
|
sha: ${{ needs.start.outputs.old-sha }}
|
||||||
|
|
||||||
build-clang-old:
|
build-clang-old:
|
||||||
name: Build Old Verilator - Clang
|
name: Build Old Verilator - Clang
|
||||||
needs: start
|
needs: start
|
||||||
if: ${{ needs.start.outputs.old-sha != '' }}
|
if: ${{ needs.start.outputs.old-sha != '' }}
|
||||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
uses: ./.github/workflows/reusable-build.yml
|
||||||
with:
|
with:
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
cc: clang
|
cc: clang
|
||||||
|
ccwarn: false
|
||||||
|
install: true
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
sha: ${{ needs.start.outputs.old-sha }}
|
sha: ${{ needs.start.outputs.old-sha }}
|
||||||
|
|
||||||
run-gcc:
|
run-gcc:
|
||||||
@@ -208,7 +216,7 @@ jobs:
|
|||||||
run: echo "tags=$(jq -r 'keys | map(sub("^run-"; "")) | join(" ")' <<< '${{ toJSON(needs) }}')" >> "$GITHUB_OUTPUT"
|
run: echo "tags=$(jq -r 'keys | map(sub("^run-"; "")) | join(" ")' <<< '${{ toJSON(needs) }}')" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Checkout RTLMeter
|
- name: Checkout RTLMeter
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
with:
|
with:
|
||||||
repository: "verilator/rtlmeter"
|
repository: "verilator/rtlmeter"
|
||||||
path: rtlmeter
|
path: rtlmeter
|
||||||
@@ -298,7 +306,7 @@ jobs:
|
|||||||
repositories: verilator-rtlmeter-results
|
repositories: verilator-rtlmeter-results
|
||||||
permission-contents: write
|
permission-contents: write
|
||||||
- name: Checkout verilator-rtlmeter-results
|
- name: Checkout verilator-rtlmeter-results
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
with:
|
with:
|
||||||
repository: "verilator/verilator-rtlmeter-results"
|
repository: "verilator/verilator-rtlmeter-results"
|
||||||
token: ${{ steps.generate-token.outputs.token }}
|
token: ${{ steps.generate-token.outputs.token }}
|
||||||
@@ -331,7 +339,7 @@ jobs:
|
|||||||
actions: read
|
actions: read
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout RTLMeter
|
- name: Checkout RTLMeter
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
with:
|
with:
|
||||||
repository: "verilator/rtlmeter"
|
repository: "verilator/rtlmeter"
|
||||||
path: rtlmeter
|
path: rtlmeter
|
||||||
@@ -341,7 +349,7 @@ jobs:
|
|||||||
run: make venv
|
run: make venv
|
||||||
|
|
||||||
- name: Checkout Verilator
|
- name: Checkout Verilator
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||||
with:
|
with:
|
||||||
path: verilator
|
path: verilator
|
||||||
|
|
||||||
@@ -361,10 +369,6 @@ jobs:
|
|||||||
mkdir ../report-artifact
|
mkdir ../report-artifact
|
||||||
mv rtlmeter-report/report ../report-artifact/
|
mv rtlmeter-report/report ../report-artifact/
|
||||||
echo ${{ github.event.number }} > ../report-artifact/pr-number.txt
|
echo ${{ github.event.number }} > ../report-artifact/pr-number.txt
|
||||||
# Create the notification artifact
|
|
||||||
mkdir ../notification-artifact
|
|
||||||
mv rtlmeter-report/notification.txt ../notification-artifact/body.txt
|
|
||||||
echo ${{ github.event.number }} > ../notification-artifact/pr-number.txt
|
|
||||||
|
|
||||||
- name: Upload report
|
- name: Upload report
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
@@ -372,11 +376,11 @@ jobs:
|
|||||||
path: report-artifact
|
path: report-artifact
|
||||||
name: rtlmeter-report
|
name: rtlmeter-report
|
||||||
|
|
||||||
- name: Upload notification
|
- name: Upload PR notification
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
uses: ./verilator/.github/actions/upload-pr-notification
|
||||||
with:
|
with:
|
||||||
path: notification-artifact
|
path: verilator/rtlmeter-report/notification
|
||||||
name: pr-notification
|
key: rtlmeter
|
||||||
|
|
||||||
- name: Report status
|
- name: Report status
|
||||||
run: exit ${{ steps.report.outputs.status }}
|
run: exit ${{ steps.report.outputs.status }}
|
||||||
|
|||||||
@@ -96,9 +96,15 @@ ______________________________________________________________________
|
|||||||
- [ ] Ran the full regression on at least one OS before submitting. Partial runs
|
- [ ] Ran the full regression on at least one OS before submitting. Partial runs
|
||||||
are fine during development, but the submitted PR is expected to pass every
|
are fine during development, but the submitted PR is expected to pass every
|
||||||
test.
|
test.
|
||||||
|
- [ ] Validated the code changes against recommendations in the AGENTS.md files.
|
||||||
- [ ] Did not edit `docs/CONTRIBUTORS` (humans only) or `Changes` (maintainer
|
- [ ] Did not edit `docs/CONTRIBUTORS` (humans only) or `Changes` (maintainer
|
||||||
updates it near release).
|
updates it near release).
|
||||||
|
|
||||||
|
## Drafting a PR
|
||||||
|
|
||||||
|
- [ ] When creating a pull request message, omit itemized lists of changed
|
||||||
|
files and changes, since reviewers already have access to the diff.
|
||||||
|
|
||||||
## Pick the right diagnostic (and its required test)
|
## Pick the right diagnostic (and its required test)
|
||||||
|
|
||||||
The API you choose determines which test must accompany the change.
|
The API you choose determines which test must accompany the change.
|
||||||
|
|||||||
+4
-3
@@ -16,7 +16,7 @@ cmake_minimum_required(VERSION 3.15)
|
|||||||
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
||||||
project(
|
project(
|
||||||
Verilator
|
Verilator
|
||||||
VERSION 5.050
|
VERSION 5.052
|
||||||
HOMEPAGE_URL https://verilator.org
|
HOMEPAGE_URL https://verilator.org
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
@@ -155,11 +155,12 @@ install(
|
|||||||
foreach(
|
foreach(
|
||||||
program
|
program
|
||||||
verilator
|
verilator
|
||||||
verilator_gantt
|
|
||||||
verilator_ccache_report
|
verilator_ccache_report
|
||||||
|
verilator_coverage
|
||||||
verilator_difftree
|
verilator_difftree
|
||||||
verilator_profcfunc
|
verilator_gantt
|
||||||
verilator_includer
|
verilator_includer
|
||||||
|
verilator_profcfunc
|
||||||
)
|
)
|
||||||
install(PROGRAMS bin/${program} TYPE BIN)
|
install(PROGRAMS bin/${program} TYPE BIN)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|||||||
@@ -10,6 +10,182 @@ The changes in each Verilator version are described below. The
|
|||||||
contributors that suggested or implemented a given issue are shown in []. Thanks!
|
contributors that suggested or implemented a given issue are shown in []. Thanks!
|
||||||
|
|
||||||
|
|
||||||
|
Verilator 5.052 2026-09-05
|
||||||
|
==========================
|
||||||
|
|
||||||
|
**Important:**
|
||||||
|
|
||||||
|
* Verilator now supports UVM 2020-3.2; see (#1538) for limitations.
|
||||||
|
|
||||||
|
**Other:**
|
||||||
|
|
||||||
|
* Add comments as a branch description in coverage .info files (#7843). [Eryk Szpotanski]
|
||||||
|
* Add --enable-light-debug configure option (#7886). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Add user-provided DPI-C function declarations (#7626) (#7893). [Jakub Michalski]
|
||||||
|
* Add error on static virtual functions (#7932). [Igor Zaworski, Antmicro Ltd.]
|
||||||
|
* Add error when scalar is passed to array task argument (#7948). [Pawel Klopotek]
|
||||||
|
* Add MULTIDRIVENPROC warning for signals driven by multiple plain always blocks (#7968). [Aisha]
|
||||||
|
* Add FSM arc and state coverage to verilator_coverage .info output (#7972) (#7973). [Igor Zaworski, Antmicro Ltd.]
|
||||||
|
* Add SIMILARNAME warning when variables have names that differ in case (#7992) (#8020) (#8186) (#8226) (#8233). [Paul Campbell]
|
||||||
|
* Add Unigen2 constrained randomization algorithm (#8042). [Jakub Wasilewski, Antmicro Ltd.]
|
||||||
|
* Add `+verilator+assert+lock` to ignore RTL assert control statements (#8086). [Sumanth Kadiyala]
|
||||||
|
* Add NEVERMATCH warning when an SVA sequence can never match (#8176) (#8183). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Remove and deprecate `--assert-unroll-limit`. (#8096). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Support embedded covergroup member references (#7749) (#8015). [Marco Bartoli]
|
||||||
|
* Support a sequence used as an event control (#7797) (#7846). [Yilou Wang]
|
||||||
|
* Support `[\*N:$]` consecutive repetition (#7940). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Support dynamic containers in unique constraints (#7947). [Adam Kostrzewski, Antmicro Ltd.]
|
||||||
|
* Support delayed tristate gates (#7960) (#7961). [Patrick Creighton]
|
||||||
|
* Support `default clocking` (#7984). [Kamil Danecki, Antmicro Ltd.]
|
||||||
|
* Support embedded covergroup clocking events (#8028). [Marco Bartoli]
|
||||||
|
* Support `weak`/`strong` keywords in property expressions (#8054). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Support class handle covergroup arguments (#8071). [Marco Bartoli]
|
||||||
|
* Support `soft foreach` constraints (#8174). [Kamil Danecki, Antmicro Ltd.]
|
||||||
|
* Support overlong `within` sequences as never-matching (#8177). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Support covergroup/function/task (ref/virtual/array) interface arguments (#8180). [Marco Bartoli]
|
||||||
|
* Support covergroup events with reference members or ref arguments (#8201). [Marco Bartoli]
|
||||||
|
* Support s_until/s_until_with in property expression (#8220). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Support solve before with associative array (#8232). [Kamil Danecki, Antmicro Ltd.]
|
||||||
|
* Optimize random initialization. [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize more always blocks in DFG (#7775). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize assertion NFAs using bit-vector ring buffers (#7885). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Optimize circular logic in DFG (#7902). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize VPI symbol registration and scope construction (#7936). [Nick Brereton]
|
||||||
|
* Optimize bounded always properties using ring buffers (#8061) (#8092). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Optimize VL_WORDS_I/VL_BYTES_I (#8095). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize consecutive and goto repetitions using ring buffers (#8096). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Optimize temporary insertion for single bit replicates in DFG (#8110). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize mtask coarsening in multi-threaded scheduling (#8120). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Optimize NFA delay-ring edge traversal, drop complexity to linear (#8145). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Optimize associative constant patterns to fixed point (#8147) (#8209). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix procedural tristate assignment overrides (#6785) (#8130). [Eddie Rydell]
|
||||||
|
* Fix $finish continuing event loop (#7267) (#7950). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix continuing on wait(0) (#7372) (#8231). [Szymon Gizler, Antmicro Ltd.]
|
||||||
|
* Fix $display accepting streaming concat arguments (#7663) (#7890). [Jaeuk Lee]
|
||||||
|
* Fix typedef clocking input sampling (#7688 partial) (#8204). [Marco Bartoli]
|
||||||
|
* Fix DFG misoptimizing bound checks (#7755). [Jakub Michalski]
|
||||||
|
* Fix unique0 case side effects (#7787). [Pawel Klopotek]
|
||||||
|
* Fix mid-window disable iff (#7792) (#7869). [Yilou Wang]
|
||||||
|
* Fix cleaning purity cache after assertions. [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix uncaught type error leading to invalid C++ output (#7814). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix internal error for coverpoints that reference a covergroup formal parameter (#7853 partial) (#7889). [Matthew Ballance]
|
||||||
|
* Fix immediate disable of fork join branches (#7856) (#7931). [Marco Bartoli]
|
||||||
|
* Fix self-disable of named blocks with forks (Part of #7857) (#7996) (#8006). [Marco Bartoli]
|
||||||
|
* Fix clang++ ambiguous overload of '==' operator (#7863). [Pawel Kojma, Antmicro Ltd.]
|
||||||
|
* Fix heap-use-after-free in `VlRNG::VlRNG()` (#7865). [Dragon-Git]
|
||||||
|
* Fix mixed-width inside and dist range bounds failing randomization (#7875). [Yilou Wang]
|
||||||
|
* Fix solve-before over array variables failing randomization (#7876). [Yilou Wang]
|
||||||
|
* Fix scoped randomize with array members under rand_mode (#7877). [Yilou Wang]
|
||||||
|
* Fix dist constraint on a frozen variable failing randomization (#7878). [Yilou Wang]
|
||||||
|
* Fix range delays with parameter bounds (#7882). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix --coverage on labeled inline assert/cover property (#7898) (#7904). [Patrick Creighton]
|
||||||
|
* Fix memory leak in VerilatedFst::close() (#7899). [Jakub Michalski]
|
||||||
|
* Fix spurious FSM COVERIGN on comparisons (#7900) (#7908). [Yogish Sekhar]
|
||||||
|
* Fix release of forced port nets (#7901) (#7907). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix independent force of multiply instantiated signals (#7905). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix scheduling of variables written in non-inlined functions in suspendable processes (#7909). [Igor Zaworski, Antmicro Ltd.]
|
||||||
|
* Fix randomization of unreferenced rand members of unpacked structs (#7910) (#7911). [Philip Axer]
|
||||||
|
* Fix VL_TO_STRING function for array of structs (#7912). [Kornel Uriasz, Antmicro Ltd.]
|
||||||
|
* Fix queues falling into wrong template spec (#7914). [Adam Kostrzewski, Antmicro Ltd.]
|
||||||
|
* Fix type resolution when a local name shadows a type name (#7915). [Pawel Klopotek]
|
||||||
|
* Fix crash streaming an unpacked array of unpacked structs (#7917). [Nick Brereton]
|
||||||
|
* Fix streaming concat as output-port lvalue into unpacked struct (#7918). [Nick Brereton]
|
||||||
|
* Fix dropping variable writes across opaque calls (#7921) (#7933). [Philip Axer]
|
||||||
|
* Fix dynamic array handling in solve...before (#7922). [Kornel Uriasz, Antmicro Ltd.]
|
||||||
|
* Fix unlinked error with function call in derived class parameter (#7923). [Mateusz Gancarz, Antmicro Ltd.]
|
||||||
|
* Fix scheduling of variables written in non-inlined functions in suspendable processes (#7924). [Igor Zaworski, Antmicro Ltd.]
|
||||||
|
* Fix class parameter resolution (#7935).
|
||||||
|
* Fix FSM detection of coverage-only branches (#7941) (#7942). [Patrick Creighton]
|
||||||
|
* Fix use-after-free in V3LinkDotIfaceCapture (#7943). [Nick Brereton]
|
||||||
|
* Fix sampled-value clocks in repeated assertions (#7944). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix queued $finish/$stop request thread ordering (#7946 prep) (#7952). [Yilou Wang]
|
||||||
|
* Fix NFA assertion scheduling to fix outcome counts (#7946). [Yilou Wang]
|
||||||
|
* Fix DFG nested shifts with overflowing shift amount (#7955) (#7977).
|
||||||
|
* Fix timing controls in interface tasks called via virtual interface (#7959). [Yilou Wang]
|
||||||
|
* Fix lambda parameter types in queue min and max (#7962). [Bartosz Skorowski]
|
||||||
|
* Fix solve-before dropping all soft constraints in randomize() (#7963). [Yilou Wang]
|
||||||
|
* Fix generic interface param resolution in module/cell parameterization (#7970) (#7971). [David Garau]
|
||||||
|
* Fix lost writes when select width exceeds variable width (#7975). [Bartosz Skorowski]
|
||||||
|
* Fix $fgets being mis-optimized away (#7976). [G-A. Kamendje]
|
||||||
|
* Fix SYNCASYNCNET false positive with changed non-edge logic (#7980). [Oron Port]
|
||||||
|
* Fix variable scope in unique on dynamic array (#7981). [Kornel Uriasz, Antmicro Ltd.]
|
||||||
|
* Fix table optimization causing not contextually convertible to bool error (#7983). [Jakub Michalski]
|
||||||
|
* Fix wait fork trigger temporary split across generated functions (#7985) (#7986). [Marco Brambilla]
|
||||||
|
* Fix randc cycling in a class that also uses solve...before (#7991 partial) (#8055). [Yilou Wang]
|
||||||
|
* Fix solver session stability to avoid breaking randomize (#7991 partial). [Yilou Wang]
|
||||||
|
* Fix simulation hang when the solver stops answering (#7991 partial) (#8129) (#8136). [Yilou Wang]
|
||||||
|
* Fix randomize() with a user variable named 'item' (#7993) (#7994).
|
||||||
|
* Fix UNSATCONSTR reporting constraint indices above 9 (#7995). [Yilou Wang]
|
||||||
|
* Fix MULTIDRIVEN/MULTIDRIVENPROC warning suppression via lint_off (#8000). [Gilberto Abram]
|
||||||
|
* Fix force not substituted into an unpacked array index (#8002).
|
||||||
|
* Fix dist weights ignored when an item is not a literal (#8003).
|
||||||
|
* Fix error when forcing an array element read at a run-time index (#8004).
|
||||||
|
* Fix FSM coverage on empty reset branches (#8005) (#8064). [Yogish Sekhar]
|
||||||
|
* Fix missing verilator_coverage in cmake install (#8008) (#8011).
|
||||||
|
* Fix dist inside a foreach nested in a constraint if (#8016).
|
||||||
|
* Fix gcov dump on warnings discarding later coverage counts (#8017). [Yilou Wang]
|
||||||
|
* Fix unique constraint crash, guards, and size (#8018).
|
||||||
|
* Fix Linux peak memory stat to use VmHWM (#8022) (#8070). [Tyrone Marhguy]
|
||||||
|
* Fix assignment pattern key constant expressions (#8029) (#8030). [Josep Sans]
|
||||||
|
* Fix skipping optimization for unpacked data types (#8031). [Kornel Uriasz, Antmicro Ltd.]
|
||||||
|
* Fix gate deduplication with function arguments (#8038). [JOTEGO]
|
||||||
|
* Fix conditional expression with parameterized classes (#8039). [Pawel Klopotek, Antmicro Ltd.]
|
||||||
|
* Fix array size references in constraints (#8040). [Kornel Uriasz, Antmicro Ltd.]
|
||||||
|
* Fix mid-range consecutive repetition rejects (#8041). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix write access to dynamic arrays (#8043). [Bartosz Skorowski, Antmicro Ltd.]
|
||||||
|
* Fix nondeterminism in trace stage (#8046). [Sumanth Kadiyala]
|
||||||
|
* Fix force helpers in multiply instantiated modules (#8047). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix pin to non-existent port with PINNOTFOUND suppressed (#8051) (#8052). [Nikolai Kumar]
|
||||||
|
* Fix wildcard equality against a 4-state constant in an assertion (#8056) (#8057). [Nikolai Kumar]
|
||||||
|
* Fix untyped datatype error on sampling functions with property arguments (#8060). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix VPI cbValueChange for 1-bit select (#8063). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||||
|
* Fix NFA assertion crash and mis-counted property if/case (#8074). [Yilou Wang]
|
||||||
|
* Fix skipping non-constrained enum constraining when inside object of other class (#8075). [Kornel Uriasz, Antmicro Ltd.]
|
||||||
|
* Fix use-after-free of captured interface typedef reference during parameter cloning (#8076). [em2machine]
|
||||||
|
* Fix unintended side-effect insertion on associative array read (#8077). [Adam Kostrzewski, Antmicro Ltd.]
|
||||||
|
* Fix undefined symbol solver error (#8080). [Igor Zaworski, Antmicro Ltd.]
|
||||||
|
* Fix unpacked array element force with procedural assign (#8084) (#8085). [Nikolai Kumar]
|
||||||
|
* Fix reading another parameter resolves to 0 in cloned modules (#8086) (#8069). [em2machine]
|
||||||
|
* Fix hierarchical class scope resolution (#8094). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix segmentation fault on parameters (#8102) (#8149). [Sumanth Kadiyala]
|
||||||
|
* Fix the clang compilation using precompiled headers (#8105). [Demin Han]
|
||||||
|
* Fix invalid typedef (#8106). [Adam Kostrzewski, Antmicro Ltd.]
|
||||||
|
* Fix R/W references to random builtin function seeds (#8112). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix invalid C++ on cast (#8113). [Pawel Klopotek, Antmicro Ltd.]
|
||||||
|
* Fix COVERIGN on SVA goto repetition (#8118). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix unordered data hazards in multi-threaded scheduling (#8133). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix public table offsets larger than 32 bits (#8135). [Sunimali Rathnayake]
|
||||||
|
* Fix 'get-value' for empty constrained arrays (#8138). [Kornel Uriasz, Antmicro Ltd.]
|
||||||
|
* Fix streaming concatenation uninitialized read-modify-write access (#8143). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix unpacked array passing to logic task argument error (#8148). [Pawel Klopotek, Antmicro Ltd.]
|
||||||
|
* Fix $past in final blocks on a sampling-tick finish (#8153). [Yilou Wang]
|
||||||
|
* Fix array reference in reduction constraints (#8158). [Kornel Uriasz, Antmicro Ltd.]
|
||||||
|
* Fix VPI force data corruption (#8160). [Jonathan Drolet]
|
||||||
|
* Fix sampled-value functions output on the first cycle (#8162). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix null pointer dereference in process destruction (#8171). [Andrii, Antmicro Ltd.]
|
||||||
|
* Fix invalid conversion of queue (#8172). [Andrii, Antmicro Ltd.]
|
||||||
|
* Fix crash on forward-referencing parameters (#8175). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix crash on empty `#()` parameter list on class instance (#8182). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix crash on multiple missing type parameters (#8184). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix SVA bound limit guard, leave headroom for alignment, respect --max-num-width (#8192). [Artur Bieniek, Antmicro Ltd.]
|
||||||
|
* Fix internal error on an enum literal inside a `with` lambda body (#8190) (#8193). [Aditya Shevade]
|
||||||
|
* Fix internal error on backslash-quoted strings (#8198). [Henry Hsieh]
|
||||||
|
* Fix backslash behavior in string literals (#8211). [Pawel Klopotek, Antmicro Ltd.]
|
||||||
|
* Fix task inout pin resizing error (#8212). [Pawel Klopotek, Antmicro Ltd.]
|
||||||
|
* Fix code generation for postponed region (#8218). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix method calls to be a reorder barrier (#8222). [Matthew Ballance]
|
||||||
|
* Fix errors on stream connected to instance port (#8234). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix folding of short circuiting operators guarding member access (#8238). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix MULTIDRIVENPROC on static loop induction variables (#8242). [Geza Lore, Testorrent USA, Inc.]
|
||||||
|
* Fix multiply undefined behavior on signed int overflow (#8247) (#8248). [Paul Rigge]
|
||||||
|
* Fix initial statements with gate optimization (#8250). [Prithayan Barua]
|
||||||
|
* Fix segmentation fault on context destruction (#8265).
|
||||||
|
* Fix mis-randomizing an unpacked struct member when not rand/randc (#8277) (#8278). [Aditya Shevade]
|
||||||
|
* Fix std::randomize() with-clause array index arguments (#8279) (#8280). [Aditya Shevade]
|
||||||
|
* Fix incorrect reference to sync/async in SYNCASYNCNET warning (#8281). [Andrii, Antmicro Ltd.]
|
||||||
|
* Fix use-after-free of captured interface typedef in deleted generate branch (#8287). [Nick Brereton]
|
||||||
|
|
||||||
|
|
||||||
Verilator 5.050 2026-07-01
|
Verilator 5.050 2026-07-01
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
@@ -5738,7 +5914,7 @@ Verilator 3.104 2003-04-30
|
|||||||
**Major:**
|
**Major:**
|
||||||
|
|
||||||
* Indicate direction of ports with VL_IN and VL_OUT.
|
* Indicate direction of ports with VL_IN and VL_OUT.
|
||||||
* Allow $c32, etc, to specify width of the $c statement for VCS.
|
* Allow $c32, etc, to specify width of the $c statement.
|
||||||
* Numerous performance improvements, worth about 25%
|
* Numerous performance improvements, worth about 25%
|
||||||
|
|
||||||
**Minor:**
|
**Minor:**
|
||||||
|
|||||||
+17
-4
@@ -94,6 +94,7 @@ CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
|
|||||||
CFG_WITH_DEV_GCOV = @CFG_WITH_DEV_GCOV@
|
CFG_WITH_DEV_GCOV = @CFG_WITH_DEV_GCOV@
|
||||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||||
CFG_WITH_SOLVER = @CFG_WITH_SOLVER@
|
CFG_WITH_SOLVER = @CFG_WITH_SOLVER@
|
||||||
|
GCOV = @GCOV@
|
||||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||||
|
|
||||||
#### End of system configuration section. ####
|
#### End of system configuration section. ####
|
||||||
@@ -466,9 +467,11 @@ analyzer-include:
|
|||||||
|
|
||||||
# Bash/sh files
|
# Bash/sh files
|
||||||
BASH_FILES = \
|
BASH_FILES = \
|
||||||
|
ci/ci-coverage-report.bash \
|
||||||
ci/ci-install.bash \
|
ci/ci-install.bash \
|
||||||
ci/ci-pages-notify.bash \
|
ci/ci-pages-notify.bash \
|
||||||
ci/ci-pages.bash \
|
ci/ci-pages.bash \
|
||||||
|
ci/ci-rtlmeter-report.bash \
|
||||||
ci/ci-script.bash \
|
ci/ci-script.bash \
|
||||||
ci/docker/run/hooks/post_push \
|
ci/docker/run/hooks/post_push \
|
||||||
ci/docker/run/verilator-docker \
|
ci/docker/run/verilator-docker \
|
||||||
@@ -536,6 +539,7 @@ PY_PROGRAMS = \
|
|||||||
src/vlcovgen \
|
src/vlcovgen \
|
||||||
test_regress/*.py \
|
test_regress/*.py \
|
||||||
test_regress/t/*.pf \
|
test_regress/t/*.pf \
|
||||||
|
test_regress/t/randomize_solver_tamper.py \
|
||||||
|
|
||||||
# Python files, subject to format but not lint
|
# Python files, subject to format but not lint
|
||||||
PY_FILES = \
|
PY_FILES = \
|
||||||
@@ -695,20 +699,28 @@ COVERAGE_DIR := obj_coverage
|
|||||||
ifeq ($(CFG_WITH_DEV_GCOV),yes)
|
ifeq ($(CFG_WITH_DEV_GCOV),yes)
|
||||||
|
|
||||||
# Figure out base and head refs for coverage report
|
# Figure out base and head refs for coverage report
|
||||||
COVERAGE_REF_BASE := $(if $(COVERAGE_BASE),$(shell git rev-parse --short $(COVERAGE_BASE)))
|
COVERAGE_REF_BASE := $(if $(COVERAGE_BASE),$(shell git rev-parse --short $(COVERAGE_BASE) 2>/dev/null))
|
||||||
|
ifneq ($(COVERAGE_BASE),)
|
||||||
|
ifeq ($(COVERAGE_REF_BASE),)
|
||||||
|
$(error COVERAGE_BASE='$(COVERAGE_BASE)' is not a valid git revision)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
COVERAGE_REF_HEAD := $(shell git rev-parse --short HEAD)
|
COVERAGE_REF_HEAD := $(shell git rev-parse --short HEAD)
|
||||||
override undefine COVERAGE_BASE # Use the above variabels instead
|
override undefine COVERAGE_BASE # Use the above variabels instead
|
||||||
|
|
||||||
# 'fastcov' setup
|
# 'fastcov' setup
|
||||||
FASTCOV := nodist/fastcov.py
|
FASTCOV := nodist/fastcov.py
|
||||||
FASTCOV_OPT := -j $(shell nproc)
|
FASTCOV_OPT := -j $(shell nproc)
|
||||||
|
FASTCOV_OPT += --gcov $(GCOV)
|
||||||
FASTCOV_OPT += --lcov
|
FASTCOV_OPT += --lcov
|
||||||
FASTCOV_OPT += --process-gcno
|
FASTCOV_OPT += --process-gcno
|
||||||
FASTCOV_OPT += --branch-coverage
|
FASTCOV_OPT += --branch-coverage
|
||||||
FASTCOV_OPT += --dump-statistic
|
FASTCOV_OPT += --dump-statistic
|
||||||
# Files matching the following glob patterns will be excluded from coverage
|
# Files matching the following glob patterns will be excluded from coverage
|
||||||
FASTCOV_OPT += --exclude-glob
|
FASTCOV_OPT += --exclude-glob
|
||||||
FASTCOV_OPT += '/usr/*'
|
FASTCOV_OPT += '/usr/include/*'
|
||||||
|
FASTCOV_OPT += '/usr/lib*/*'
|
||||||
|
FASTCOV_OPT += '/usr/share/*'
|
||||||
FASTCOV_OPT += '*examples/*'
|
FASTCOV_OPT += '*examples/*'
|
||||||
FASTCOV_OPT += '*include/fstcpp/*'
|
FASTCOV_OPT += '*include/fstcpp/*'
|
||||||
FASTCOV_OPT += '*src/obj_dbg/*'
|
FASTCOV_OPT += '*src/obj_dbg/*'
|
||||||
@@ -749,6 +761,7 @@ GENHTML_OPT += --missed
|
|||||||
GENHTML_OPT += --rc branch_coverage=1
|
GENHTML_OPT += --rc branch_coverage=1
|
||||||
GENHTML_OPT += --rc genhtml_hi_limit=100
|
GENHTML_OPT += --rc genhtml_hi_limit=100
|
||||||
GENHTML_OPT += --ignore-errors negative
|
GENHTML_OPT += --ignore-errors negative
|
||||||
|
GENHTML_OPT += --ignore-errors inconsistent
|
||||||
ifeq ($(COVERAGE_REF_BASE),)
|
ifeq ($(COVERAGE_REF_BASE),)
|
||||||
GENHTML_OPT += --header-title "Code coverage for Verilator $(shell git describe --dirty)"
|
GENHTML_OPT += --header-title "Code coverage for Verilator $(shell git describe --dirty)"
|
||||||
else
|
else
|
||||||
@@ -780,7 +793,7 @@ $(COVERAGE_DIR)/verilator-patch.info: $(COVERAGE_DIR)/verilator.info
|
|||||||
@echo "####################################################################"
|
@echo "####################################################################"
|
||||||
rm -f $(COVERAGE_DIR)/empty-patch
|
rm -f $(COVERAGE_DIR)/empty-patch
|
||||||
git diff $(COVERAGE_REF_BASE) -- include src > $(COVERAGE_DIR)/filter.patch
|
git diff $(COVERAGE_REF_BASE) -- include src > $(COVERAGE_DIR)/filter.patch
|
||||||
[ -s $(COVERAGE_DIR)/filter.patch ]] || touch $(COVERAGE_DIR)/empty-patch
|
[ -s $(COVERAGE_DIR)/filter.patch ] || touch $(COVERAGE_DIR)/empty-patch
|
||||||
$(FASTCOV) -C $^ --lcov -o $@ --diff-filter $(COVERAGE_DIR)/filter.patch
|
$(FASTCOV) -C $^ --lcov -o $@ --diff-filter $(COVERAGE_DIR)/filter.patch
|
||||||
|
|
||||||
# Build coverage report
|
# Build coverage report
|
||||||
@@ -789,7 +802,7 @@ $(COVERAGE_DIR)/report/index.html: $(COVERAGE_DIR)/verilator$(if $(COVERAGE_REF_
|
|||||||
@echo "# genhtml: Generating coverage report"
|
@echo "# genhtml: Generating coverage report"
|
||||||
@echo "####################################################################"
|
@echo "####################################################################"
|
||||||
@rm -rf $(COVERAGE_DIR)/report
|
@rm -rf $(COVERAGE_DIR)/report
|
||||||
[ -f $(COVERAGE_DIR)/empty-patch ]] || /usr/bin/time -f "That took %E" \
|
[ -f $(COVERAGE_DIR)/empty-patch ] || /usr/bin/time -f "That took %E" \
|
||||||
$(GENHTML) $(GENHTML_OPT) --output-directory $(COVERAGE_DIR)/report $^ || true
|
$(GENHTML) $(GENHTML_OPT) --output-directory $(COVERAGE_DIR)/report $^ || true
|
||||||
@# Uncommitted changes not tracked, force rebuild on next run if patch coverage
|
@# Uncommitted changes not tracked, force rebuild on next run if patch coverage
|
||||||
@$(if $(COVERAGE_REF_BASE),mv $(COVERAGE_DIR)/verilator-patch.info $(COVERAGE_DIR)/verilator-patch-last.info)
|
@$(if $(COVERAGE_REF_BASE),mv $(COVERAGE_DIR)/verilator-patch.info $(COVERAGE_DIR)/verilator-patch-last.info)
|
||||||
|
|||||||
+5
-3
@@ -4,7 +4,9 @@
|
|||||||
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|badge1| |badge2| |badge3| |badge4| |badge5| |badge7| |badge8|
|
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||||
|
|
||||||
|
|badge7| |badge8|
|
||||||
|
|
||||||
.. |badge1| image:: https://img.shields.io/badge/Website-Verilator.org-181717.svg
|
.. |badge1| image:: https://img.shields.io/badge/Website-Verilator.org-181717.svg
|
||||||
:target: https://verilator.org
|
:target: https://verilator.org
|
||||||
@@ -21,8 +23,8 @@
|
|||||||
.. |badge5| image:: https://img.shields.io/docker/pulls/verilator/verilator
|
.. |badge5| image:: https://img.shields.io/docker/pulls/verilator/verilator
|
||||||
:target: https://hub.docker.com/r/verilator/verilator
|
:target: https://hub.docker.com/r/verilator/verilator
|
||||||
|
|
||||||
.. |badge7| image:: https://github.com/verilator/verilator/workflows/build/badge.svg
|
.. |badge7| image:: https://img.shields.io/github/actions/workflow/status/verilator/verilator/build-test.yml?branch=master&label=regressions
|
||||||
:target: https://github.com/verilator/verilator/actions?query=workflow%3Abuild
|
:target: https://github.com/verilator/verilator/actions/workflows/build-test.yml
|
||||||
|
|
||||||
.. |badge8| image:: https://img.shields.io/github/actions/workflow/status/verilator/verilator/rtlmeter.yml?branch=master&event=schedule&label=benchmarks
|
.. |badge8| image:: https://img.shields.io/github/actions/workflow/status/verilator/verilator/rtlmeter.yml?branch=master&event=schedule&label=benchmarks
|
||||||
:target: https://verilator.github.io/verilator-rtlmeter-results
|
:target: https://verilator.github.io/verilator-rtlmeter-results
|
||||||
|
|||||||
@@ -636,6 +636,7 @@ description of these arguments.
|
|||||||
|
|
||||||
=for VL_SPHINX_EXTRACT "_build/gen/args_verilated.rst"
|
=for VL_SPHINX_EXTRACT "_build/gen/args_verilated.rst"
|
||||||
|
|
||||||
|
+verilator+assert+lock Lock assertion status changes at startup
|
||||||
+verilator+coverage+file+<filename> Set coverage output filename
|
+verilator+coverage+file+<filename> Set coverage output filename
|
||||||
+verilator+debug Enable debugging
|
+verilator+debug Enable debugging
|
||||||
+verilator+debugi+<value> Enable debugging at a level
|
+verilator+debugi+<value> Enable debugging at a level
|
||||||
|
|||||||
@@ -51,12 +51,17 @@ def profcfunc(filename: str) -> None:
|
|||||||
# Find modules
|
# Find modules
|
||||||
verilated_mods = {}
|
verilated_mods = {}
|
||||||
for func in funcs:
|
for func in funcs:
|
||||||
match = re.search(r'(.*)::eval(_step)?\(', func)
|
# Match only the model entry points: 'eval', 'eval_step', 'eval_end_step',
|
||||||
|
# and the 'evalXxx' region entry points, but not e.g. a user's '::evaluate'
|
||||||
|
match = re.match(r'([A-Za-z_][A-Za-z_0-9]*)::eval(_step|_end_step|[A-Z][A-Za-z_0-9]*)?\(',
|
||||||
|
func)
|
||||||
if match:
|
if match:
|
||||||
prefix = match.group(1)
|
prefix = match.group(1)
|
||||||
|
if prefix.startswith('Verilated'): # Run-time library, not a model
|
||||||
|
continue
|
||||||
if Args.debug:
|
if Args.debug:
|
||||||
print("-got _eval %s prefix=%s" % (func, prefix))
|
print("-got _eval %s prefix=%s" % (func, prefix))
|
||||||
verilated_mods[prefix] = re.compile(r'^' + prefix)
|
verilated_mods[prefix] = re.compile(r'^' + re.escape(prefix))
|
||||||
# pprint(verilated_mods)
|
# pprint(verilated_mods)
|
||||||
|
|
||||||
# Sort by Verilog name
|
# Sort by Verilog name
|
||||||
|
|||||||
Executable
+93
@@ -0,0 +1,93 @@
|
|||||||
|
#!/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_LIGHT_DEBUG=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 ;;
|
||||||
|
--light-debug) OPT_LIGHT_DEBUG=1 ;;
|
||||||
|
--prefix)
|
||||||
|
[ $# -ge 2 ] || fatal "--prefix requires an argument"
|
||||||
|
OPT_PREFIX="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*) fatal "Unknown option: '$1'" ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -n "$OPT_COMPILER" ] || fatal "--compiler is required"
|
||||||
|
[ -n "$OPT_PREFIX" ] || fatal "--prefix is required"
|
||||||
|
|
||||||
|
# Map the compiler name to the executable name configure CXX expects
|
||||||
|
case "$OPT_COMPILER" in
|
||||||
|
clang) CXX=clang++ ;;
|
||||||
|
gcc) CXX=g++ ;;
|
||||||
|
*) fatal "Unknown compiler: '$OPT_COMPILER'" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Configure
|
||||||
|
|
||||||
|
CONFIGURE_ARGS="--prefix=$OPT_PREFIX --enable-longtests"
|
||||||
|
if [ "$OPT_CCWARN" = 1 ]; then
|
||||||
|
CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-ccwarn"
|
||||||
|
fi
|
||||||
|
if [ "$OPT_ASAN" = 1 ]; then
|
||||||
|
CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-dev-asan"
|
||||||
|
CXX="$CXX -DVL_LEAK_CHECKS"
|
||||||
|
# Replaces VNUser's union with a std::variant to validate type usage.
|
||||||
|
# Only takes effect when the build is C++17 or newer.
|
||||||
|
CXX="$CXX -DVL_USER_TYPE_CHECKS"
|
||||||
|
fi
|
||||||
|
if [ "$OPT_GCOV" = 1 ]; then
|
||||||
|
CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-dev-gcov"
|
||||||
|
fi
|
||||||
|
if [ "$OPT_LIGHT_DEBUG" = 1 ]; then
|
||||||
|
CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-light-debug"
|
||||||
|
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
|
||||||
Executable
+100
@@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# DESCRIPTION: Verilator: CI script for 'coverage.yml' results
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
# This script combines the code coverage data gathered by the test jobs into
|
||||||
|
# the HTML report published on GitHub Pages, and for a pull request, builds the
|
||||||
|
# content of the response comment posted on it.
|
||||||
|
|
||||||
|
# Developer note: You should be able to run this script in your local checkout
|
||||||
|
# if you have GitHub CLI (command 'gh') setup, authenticated ('gh auth login'),
|
||||||
|
# and have set a default repository ('gh repo set-default').
|
||||||
|
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
# Trace when running in the CI
|
||||||
|
[ "$GITHUB_ACTIONS" != "true" ] || set -x
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# 1. run ID
|
||||||
|
# 2. number of the pull request, or empty for a non-pull-request run
|
||||||
|
# 3. base SHA of the pull request (pull requests only)
|
||||||
|
# 4. head SHA of the pull request (pull requests only)
|
||||||
|
RUN_ID=$1
|
||||||
|
PR_NUMBER=$2
|
||||||
|
PR_BASE_SHA=$3
|
||||||
|
PR_HEAD_SHA=$4
|
||||||
|
|
||||||
|
# Coverage data and report directory, uploaded as the 'coverage-report' artifact
|
||||||
|
COVERAGE_DIR=obj_coverage
|
||||||
|
ls -lsha ${COVERAGE_DIR}
|
||||||
|
|
||||||
|
# Combine the reports from the test jobs
|
||||||
|
nodist/fastcov.py -C ${COVERAGE_DIR}/verilator-*.info --lcov -o ${COVERAGE_DIR}/verilator.info
|
||||||
|
|
||||||
|
# Create the report. For a pull request, report patch coverage against the
|
||||||
|
# merge-base between the head of the pull request and the target branch. The
|
||||||
|
# summary quoted in the notification below is only in the log of 'make'.
|
||||||
|
MAKE_LOG=make-coverage-report.log
|
||||||
|
if [ -n "${PR_NUMBER}" ]; then
|
||||||
|
COVERAGE_BASE=$(git rev-parse --short $(git merge-base ${PR_BASE_SHA} ${PR_HEAD_SHA}))
|
||||||
|
make coverage-report COVERAGE_BASE=${COVERAGE_BASE} |& tee ${MAKE_LOG}
|
||||||
|
else
|
||||||
|
make coverage-report
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove the data files, only the HTML report is published
|
||||||
|
rm -f ${COVERAGE_DIR}/verilator*.info
|
||||||
|
|
||||||
|
# The rest is for pull requests only
|
||||||
|
if [ -z "${PR_NUMBER}" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get some metadata about the run
|
||||||
|
RUN_NUM=$(gh run view ${RUN_ID} --json number --jq ".number")
|
||||||
|
RUN_URL=$(gh run view ${RUN_ID} --json url --jq ".url")
|
||||||
|
|
||||||
|
# Repository owner and name of the default repository, used to build the
|
||||||
|
# GitHub Pages URL of the report. The owner is lowercased, as required for the
|
||||||
|
# '<owner>.github.io' Pages domain.
|
||||||
|
PAGES_OWNER=$(gh repo view --json owner --jq '.owner.login' | tr '[:upper:]' '[:lower:]')
|
||||||
|
PAGES_NAME=$(gh repo view --json name --jq '.name')
|
||||||
|
|
||||||
|
REPORT_URL=https://${PAGES_OWNER}.github.io/${PAGES_NAME}/coverage-reports/${RUN_ID}/index.html
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Create the PR notification
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
NOTIFICATION_DIR=notification
|
||||||
|
mkdir -p ${NOTIFICATION_DIR}
|
||||||
|
|
||||||
|
cat > ${NOTIFICATION_DIR}/body.txt <<NOTIFICATION_TEMPLATE
|
||||||
|
Patch coverage from PR workflow [#${RUN_NUM}](${RUN_URL}) (code coverage of lines changed relative to ${COVERAGE_BASE}):
|
||||||
|
NOTIFICATION_TEMPLATE
|
||||||
|
|
||||||
|
if [ -f ${COVERAGE_DIR}/empty-patch ]; then
|
||||||
|
# Patch is empty
|
||||||
|
cat >> ${NOTIFICATION_DIR}/body.txt <<SUMMARY_TEMPLATE
|
||||||
|
Patch contains no code changes
|
||||||
|
SUMMARY_TEMPLATE
|
||||||
|
|
||||||
|
echo "Workflow [#${RUN_NUM}](${RUN_URL}): patch contains no code changes" > ${NOTIFICATION_DIR}/hist.txt
|
||||||
|
|
||||||
|
else
|
||||||
|
# Patch contains code changes
|
||||||
|
|
||||||
|
cat >> ${NOTIFICATION_DIR}/body.txt <<SUMMARY_TEMPLATE
|
||||||
|
<pre>
|
||||||
|
$(grep -E "(lines|branches)\.*:" ${MAKE_LOG} | sed "s/\.*:/:/" || true)
|
||||||
|
</pre>
|
||||||
|
Report: [${RUN_ID}](${REPORT_URL})
|
||||||
|
|
||||||
|
Please get to 100% line coverage, and understand all branches; see the [developer docs](https://github.com/verilator/verilator/blob/master/docs/internals.rst#code-coverage-results)
|
||||||
|
SUMMARY_TEMPLATE
|
||||||
|
|
||||||
|
echo "Workflow [#${RUN_NUM}](${RUN_URL}) report: [${RUN_ID}](${REPORT_URL})" > ${NOTIFICATION_DIR}/hist.txt
|
||||||
|
fi
|
||||||
+161
-91
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# DESCRIPTION: Verilator: CI dependency install script
|
# DESCRIPTION: Verilator: CI dependency install script
|
||||||
#
|
#
|
||||||
# SPDX-FileCopyrightText: 2020 Geza Lore
|
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -10,141 +10,211 @@
|
|||||||
# required by the particular build stage.
|
# required by the particular build stage.
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
# Installs system packages with sudo; never run locally
|
||||||
|
if [ "$GITHUB_ACTIONS" != "true" ]; then
|
||||||
|
echo "ERROR: $(basename "$0") must only be run in GitHub Actions CI" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
cd $(dirname "$0")/..
|
cd $(dirname "$0")/..
|
||||||
|
|
||||||
# Avoid occasional cpan failures "Issued certificate has expired."
|
source "$(dirname "$0")/ci-common.bash"
|
||||||
export PERL_LWP_SSL_VERIFY_HOSTNAME=0
|
|
||||||
echo "check_certificate = off" >> ~/.wgetrc
|
|
||||||
|
|
||||||
fatal() {
|
################################################################################
|
||||||
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
# Parse arguments
|
||||||
|
|
||||||
|
# Which stage to install dependencies for
|
||||||
|
STAGE="$1"
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Install dependencies
|
||||||
|
|
||||||
|
if [ "$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
|
||||||
|
|
||||||
|
# Run 'sudo apt-get', with timeout, retrying if failed
|
||||||
|
apt-get-retry() {
|
||||||
|
local _attempt
|
||||||
|
for _attempt in 1 2 3; do
|
||||||
|
[ "$_attempt" -eq 1 ] || sleep $((15 * _attempt))
|
||||||
|
sudo timeout --kill-after=30s 5m env DEBIAN_FRONTEND=noninteractive \
|
||||||
|
apt-get -o DPkg::Lock::Timeout=60 "$@" && return 0
|
||||||
|
done
|
||||||
|
fatal "'apt-get $*' failed on all attempts"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
# Run 'brew', retrying if failed
|
||||||
MAKE=make
|
brew-retry() {
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
local _attempt
|
||||||
MAKE=make
|
for _attempt in 1 2 3; do
|
||||||
elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
[ "$_attempt" -eq 1 ] || sleep $((15 * _attempt))
|
||||||
MAKE=gmake
|
brew "$@" && return 0
|
||||||
else
|
done
|
||||||
fatal "Unknown CI_OS_NAME: '$CI_OS_NAME'"
|
fatal "'brew $*' failed on all attempts"
|
||||||
fi
|
}
|
||||||
|
|
||||||
if [ "$CI_OS_NAME" = "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
|
|
||||||
fi
|
|
||||||
|
|
||||||
install-wavediff() {
|
install-wavediff() {
|
||||||
source ci/docker/buildenv/wavetools.conf
|
source ci/docker/buildenv/wavetools.conf
|
||||||
local _base_url="https://github.com/hudson-trading/wavetools/releases/download/${WAVETOOLS_VERSION}"
|
local _base_url="https://github.com/hudson-trading/wavetools/releases/download/${WAVETOOLS_VERSION}"
|
||||||
local _platform
|
local _platform
|
||||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
if [ "$HOST_OS" = "linux" ]; then
|
||||||
_platform="linux-x86_64"
|
_platform="linux-x86_64"
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
elif [ "$HOST_OS" = "macOS" ]; then
|
||||||
_platform="macos-arm64"
|
_platform="macos-arm64"
|
||||||
elif [ "$CI_OS_NAME" = "windows" ]; then
|
|
||||||
_platform="windows-x86_64"
|
|
||||||
else
|
else
|
||||||
echo "WARNING: No wavetools binary available for CI_OS_NAME=$CI_OS_NAME, skipping"
|
echo "WARNING: No wavetools binary available for HOST_OS=$HOST_OS, skipping"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
local _tmpdir
|
local _tmpdir
|
||||||
_tmpdir=$(mktemp -d)
|
_tmpdir=$(mktemp -d)
|
||||||
local _archive="wavetools-${WAVETOOLS_VERSION}-${_platform}"
|
local _archive="wavetools-${WAVETOOLS_VERSION}-${_platform}"
|
||||||
if [ "$CI_OS_NAME" = "windows" ]; then
|
wget -q -O "${_tmpdir}/${_archive}.tar.gz" "${_base_url}/${_archive}.tar.gz"
|
||||||
wget -q -O "${_tmpdir}/${_archive}.zip" "${_base_url}/${_archive}.zip"
|
tar -xzf "${_tmpdir}/${_archive}.tar.gz" -C "${_tmpdir}"
|
||||||
unzip -o "${_tmpdir}/${_archive}.zip" -d "${_tmpdir}"
|
|
||||||
else
|
|
||||||
wget -q -O "${_tmpdir}/${_archive}.tar.gz" "${_base_url}/${_archive}.tar.gz"
|
|
||||||
tar -xzf "${_tmpdir}/${_archive}.tar.gz" -C "${_tmpdir}"
|
|
||||||
fi
|
|
||||||
sudo cp "${_tmpdir}/${_archive}/wavediff" /usr/local/bin/wavediff
|
sudo cp "${_tmpdir}/${_archive}/wavediff" /usr/local/bin/wavediff
|
||||||
rm -rf "${_tmpdir}"
|
rm -rf "${_tmpdir}"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
if [ "$STAGE" = "build" ]; then
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Dependencies of jobs in the 'build' stage, i.e.: packages required to
|
# Dependencies of jobs in the 'build' stage, i.e.: packages required to
|
||||||
# build Verilator
|
# build Verilator
|
||||||
|
|
||||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
if [ "$HOST_OS" = "linux" ]; then
|
||||||
sudo apt-get update ||
|
if [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||||
sudo apt-get update
|
PACKAGES=(
|
||||||
sudo apt-get install --yes ccache help2man libfl-dev ||
|
bear
|
||||||
sudo apt-get install --yes ccache help2man libfl-dev
|
ccache
|
||||||
if [[ ! "$CI_RUNS_ON" =~ "ubuntu-22.04" ]]; then
|
help2man
|
||||||
# Some conflict of libunwind verison on 22.04, can live without it for now
|
libfl-dev
|
||||||
sudo apt-get install --yes libjemalloc-dev ||
|
libsystemc-dev
|
||||||
sudo apt-get install --yes libjemalloc-dev
|
mold
|
||||||
fi
|
)
|
||||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
# libunwind conflict on 22.04, can live without libjemalloc there
|
||||||
if [[ ! "$CI_RUNS_ON" =~ "-riscv" ]]; then
|
if [ "$DISTRO_VERSION" != "22.04" ]; then
|
||||||
sudo apt-get install --yes libsystemc libsystemc-dev ||
|
PACKAGES+=(libjemalloc-dev)
|
||||||
sudo apt-get install --yes libsystemc libsystemc-dev
|
|
||||||
fi
|
fi
|
||||||
|
apt-get-retry update
|
||||||
|
apt-get-retry install --yes "${PACKAGES[@]}"
|
||||||
fi
|
fi
|
||||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
elif [ "$HOST_OS" = "macOS" ]; then
|
||||||
sudo apt-get install --yes bear mold ||
|
PACKAGES=(
|
||||||
sudo apt-get install --yes bear mold
|
autoconf
|
||||||
fi
|
bison
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
ccache
|
||||||
brew update ||
|
flex
|
||||||
brew update
|
gperftools
|
||||||
brew install ccache perl gperftools autoconf bison flex help2man ||
|
help2man
|
||||||
brew install ccache perl gperftools autoconf bison flex help2man
|
perl
|
||||||
elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
)
|
||||||
sudo pkg install -y autoconf bison ccache gmake perl5
|
brew-retry update
|
||||||
|
brew-retry install "${PACKAGES[@]}"
|
||||||
else
|
else
|
||||||
fatal "Unknown CI_OS_NAME: '$CI_OS_NAME'"
|
fatal "Unknown HOST_OS: '$HOST_OS'"
|
||||||
fi
|
fi
|
||||||
|
elif [ "$STAGE" = "test" ]; then
|
||||||
if [ -n "$CCACHE_DIR" ]; then
|
|
||||||
mkdir -p "$CCACHE_DIR"
|
|
||||||
fi
|
|
||||||
elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Dependencies of jobs in the 'test' stage, i.e.: packages required to
|
# Dependencies of jobs in the 'test' stage, i.e.: packages required to
|
||||||
# run the tests
|
# run the tests
|
||||||
|
|
||||||
if [ "$CI_OS_NAME" = "linux" ]; then
|
if [ "$HOST_OS" = "linux" ]; then
|
||||||
sudo apt-get update ||
|
if [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||||
sudo apt-get update
|
PACKAGES=(
|
||||||
# libfl-dev needed for internal coverage's test runs
|
ccache
|
||||||
sudo apt-get install --yes gdb gtkwave lcov libfl-dev ccache jq z3 ||
|
gdb
|
||||||
sudo apt-get install --yes gdb gtkwave lcov libfl-dev ccache jq z3
|
jq
|
||||||
# Required for test_regress/t/t_dist_attributes.py
|
lcov
|
||||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
libfl-dev
|
||||||
sudo apt-get install --yes python3-clang mold ||
|
libsystemc-dev
|
||||||
sudo apt-get install --yes python3-clang mold
|
mold
|
||||||
|
python3-clang
|
||||||
|
z3
|
||||||
|
)
|
||||||
|
apt-get-retry update
|
||||||
|
apt-get-retry install --yes "${PACKAGES[@]}"
|
||||||
fi
|
fi
|
||||||
if [[ "$CI_RUNS_ON" =~ "ubuntu-22.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-24.04" ]] || [[ "$CI_RUNS_ON" =~ "ubuntu-26.04" ]]; then
|
elif [ "$HOST_OS" = "macOS" ]; then
|
||||||
if [[ ! "$CI_RUNS_ON" =~ "-riscv" ]]; then
|
PACKAGES=(
|
||||||
sudo apt-get install --yes libsystemc libsystemc-dev ||
|
ccache
|
||||||
sudo apt-get install --yes libsystemc libsystemc-dev
|
jq
|
||||||
fi
|
perl
|
||||||
fi
|
z3
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
)
|
||||||
brew update
|
brew-retry update
|
||||||
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
|
brew-retry install "${PACKAGES[@]}"
|
||||||
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
|
|
||||||
else
|
else
|
||||||
fatal "Unknown CI_OS_NAME: '$CI_OS_NAME'"
|
fatal "Unknown HOST_OS: '$HOST_OS'"
|
||||||
fi
|
fi
|
||||||
# Common installs
|
# Common installs
|
||||||
install-wavediff
|
install-wavediff
|
||||||
# Workaround -fsanitize=address crash
|
# Workaround -fsanitize=address crash
|
||||||
sudo sysctl -w vm.mmap_rnd_bits=28
|
sudo sysctl -w vm.mmap_rnd_bits=28
|
||||||
|
elif [ "$STAGE" = "lint-py" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Dependencies for nodist/clang_check_attributes
|
||||||
|
|
||||||
|
if [ "$HOST_OS" = "linux" ] && [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||||
|
PACKAGES=(
|
||||||
|
python3-clang # Not run, but importers are linted
|
||||||
|
)
|
||||||
|
apt-get-retry update
|
||||||
|
apt-get-retry install --yes "${PACKAGES[@]}"
|
||||||
|
fi
|
||||||
|
elif [ "$STAGE" = "format" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Dependencies of 'make format'
|
||||||
|
|
||||||
|
if [ "$HOST_OS" = "linux" ] && [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||||
|
PACKAGES=(
|
||||||
|
clang-format-18 # Version pinned, so all of CI formats alike
|
||||||
|
)
|
||||||
|
apt-get-retry update
|
||||||
|
apt-get-retry install --yes "${PACKAGES[@]}"
|
||||||
|
fi
|
||||||
|
elif [ "$STAGE" = "coverage" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Dependencies of the coverage report job, which only collates what the
|
||||||
|
# 'test' stage jobs measured
|
||||||
|
|
||||||
|
if [ "$HOST_OS" = "linux" ] && [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||||
|
PACKAGES=(
|
||||||
|
lcov
|
||||||
|
)
|
||||||
|
apt-get-retry update
|
||||||
|
apt-get-retry install --yes "${PACKAGES[@]}"
|
||||||
|
fi
|
||||||
|
elif [ "$STAGE" = "rtlmeter-run" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Dependencies of the RTLMeter jobs, which compile and run designs with an
|
||||||
|
# already built Verilator, so they need its runtime prerequisites only
|
||||||
|
|
||||||
|
if [ "$HOST_OS" = "linux" ] && [ "$DISTRO_ID" = "ubuntu" ]; then
|
||||||
|
PACKAGES=(
|
||||||
|
ccache
|
||||||
|
libfl-dev
|
||||||
|
libjemalloc-dev
|
||||||
|
libsystemc-dev
|
||||||
|
mold
|
||||||
|
)
|
||||||
|
apt-get-retry update
|
||||||
|
apt-get-retry install --yes "${PACKAGES[@]}"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Unknown build stage
|
# Unknown build stage
|
||||||
fatal "Unknown CI_BUILD_STAGE_NAME: '$CI_BUILD_STAGE_NAME'"
|
fatal "Unknown stage '$STAGE'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Report where the tools we may have installed live (ok if some are missing)
|
||||||
|
set +x
|
||||||
|
echo "Tools:"
|
||||||
|
for bin in autoconf bear bison ccache flex gdb help2man jq lcov mold perl wavediff z3; do
|
||||||
|
echo -n " $bin: "
|
||||||
|
which "$bin" || echo "Not found"
|
||||||
|
done
|
||||||
|
|||||||
+139
-14
@@ -6,37 +6,162 @@
|
|||||||
|
|
||||||
# Notify PRs via comment that their workflow reports are available
|
# Notify PRs via comment that their workflow reports are available
|
||||||
|
|
||||||
# Get the current repo URL - might differ on a fork
|
# Note this deliberately does not 'set -e'. A run that cannot be notified, say
|
||||||
readonly REPO_URL=$(gh repo view --json url --jq .url)
|
# because its pull request was locked, must not hold up the notification of all
|
||||||
|
# the others, so each failure below moves on to the next run instead. Its
|
||||||
|
# artifact is then left in place, so it is retried on the next run of 'pages.yml'.
|
||||||
|
|
||||||
|
# The account we post as, which is how we tell our own earlier notifications
|
||||||
|
# from anybody else's comments. 'pages.yml' sets this to the slug of the app the
|
||||||
|
# token belongs to. Set it to your own login when running this by hand. The 'jq'
|
||||||
|
# filter below picks it up from the environment.
|
||||||
|
if [ -z "${GH_AUTHOR:-}" ]; then
|
||||||
|
echo "GH_AUTHOR must hold the account we post as" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Posting as '${GH_AUTHOR}'"
|
||||||
|
|
||||||
|
# Marker line separating the report from the history of the older reports
|
||||||
|
readonly HISTORY_MARKER='<!-- Verilator CI notification history -->'
|
||||||
|
# Opening line of the HTML comment stashing the history entry of the report
|
||||||
|
# itself. It is not shown in its own history, only inherited by the ones
|
||||||
|
# superseding it, hence it is kept out of sight until then.
|
||||||
|
readonly NEXTHIST_MARKER='<!-- Verilator CI notification entry'
|
||||||
|
|
||||||
# Create artifacts root directory
|
# Create artifacts root directory
|
||||||
ARTIFACTS_ROOT=artifacts
|
ARTIFACTS_ROOT=artifacts
|
||||||
mkdir -p ${ARTIFACTS_ROOT}
|
mkdir -p ${ARTIFACTS_ROOT}
|
||||||
|
|
||||||
for RUN_ID in ${PR_RUN_IDS//,/ }; do
|
for RUN_ID in ${PR_RUN_IDS//,/ }; do
|
||||||
echo "@@@ Processing run ${RUN_ID}"
|
|
||||||
|
|
||||||
# Create workflow artifacts directory
|
# Create workflow artifacts directory
|
||||||
ARTIFACTS_DIR=${ARTIFACTS_ROOT}/${RUN_ID}
|
ARTIFACTS_DIR=${ARTIFACTS_ROOT}/${RUN_ID}
|
||||||
mkdir -p ${ARTIFACTS_DIR}
|
mkdir -p ${ARTIFACTS_DIR}
|
||||||
|
|
||||||
# Download artifact of this run, if exists
|
# Download artifact of this run, if exists
|
||||||
gh run download ${RUN_ID} --name pr-notification --dir ${ARTIFACTS_DIR} || true
|
gh run download ${RUN_ID} --name pr-notification --dir ${ARTIFACTS_DIR} &> /dev/null || true
|
||||||
ls -lsha ${ARTIFACTS_DIR}
|
|
||||||
|
|
||||||
# Move on if no notification is required
|
# Move on if no notification is required
|
||||||
if [ ! -f ${ARTIFACTS_DIR}/pr-number.txt ]; then
|
if [ ! -f ${ARTIFACTS_DIR}/pr-number.txt ]; then
|
||||||
echo "No notification found"
|
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
echo "Posting notification found"
|
|
||||||
|
|
||||||
cat ${ARTIFACTS_DIR}/body.txt
|
PR_NUMBER=$(cat ${ARTIFACTS_DIR}/pr-number.txt)
|
||||||
gh pr comment $(cat ${ARTIFACTS_DIR}/pr-number.txt) --body-file ${ARTIFACTS_DIR}/body.txt
|
echo "@@@ Run ${RUN_ID}: notifying PR #${PR_NUMBER}"
|
||||||
|
|
||||||
# Get the artifact ID
|
# Everything below is created and validated by the 'upload-pr-notification'
|
||||||
ARTIFACT_ID=$(gh api "repos/{owner}/{repo}/actions/runs/${RUN_ID}/artifacts" --jq '.artifacts[] | select(.name == "pr-notification") | .id')
|
# action. Move on if this artifact was not made by it, e.g. it is left over
|
||||||
|
# from an earlier version of the CI, so it does not hold up the other runs.
|
||||||
|
for f in body.txt key.txt hist.txt; do
|
||||||
|
if [ ! -f ${ARTIFACTS_DIR}/${f} ]; then
|
||||||
|
echo "Notification has no '${f}'" >&2
|
||||||
|
continue 2 # Note: continues the enclosing 'RUN_ID' loop
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Delete it, so we only notify once
|
# 'key.txt' holds the key naming the source of the notification. It goes on the
|
||||||
gh api --method DELETE "repos/{owner}/{repo}/actions/artifacts/${ARTIFACT_ID}"
|
# first line of the comment as an HTML comment, so it is invisible when
|
||||||
|
# rendered, and is used below to find the stale notifications with the same
|
||||||
|
# key, which are then superseded by the new one and deleted.
|
||||||
|
COMMENT_MARKER="<!-- Verilator CI notification: $(cat ${ARTIFACTS_DIR}/key.txt) -->"
|
||||||
|
|
||||||
|
# Find the stale notifications from the same source on this PR. That is, our
|
||||||
|
# own comments with the same marker on their first line. Oldest first, as
|
||||||
|
# returned by the API. An app posts as '<slug>[bot]', so drop that suffix to
|
||||||
|
# compare against the slug. Move on if they cannot be listed, as without them
|
||||||
|
# we would post a duplicate instead of superseding them.
|
||||||
|
if ! COMMENT_MARKER="${COMMENT_MARKER}" \
|
||||||
|
gh api --paginate "repos/{owner}/{repo}/issues/${PR_NUMBER}/comments" \
|
||||||
|
--jq '.[]
|
||||||
|
| select((.user.login | rtrimstr("[bot]")) == env.GH_AUTHOR)
|
||||||
|
| select((.body | split("\n") | .[0] | rtrimstr("\r")) == env.COMMENT_MARKER)
|
||||||
|
| {id, body}' > ${ARTIFACTS_DIR}/stale.json; then
|
||||||
|
echo "Failed to list the comments of PR #${PR_NUMBER}" >&2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Inherit the history of the newest stale notification. There should only ever
|
||||||
|
# be one, and it holds the whole history anyway, as each notification inherits
|
||||||
|
# the history of the one it superseded. Any older ones are only deleted below.
|
||||||
|
STALE_COUNT=$(wc -l < ${ARTIFACTS_DIR}/stale.json)
|
||||||
|
if [ ${STALE_COUNT} -gt 1 ]; then
|
||||||
|
echo "Found ${STALE_COUNT} stale notifications, only the newest is inherited from"
|
||||||
|
fi
|
||||||
|
|
||||||
|
HISTORY=${ARTIFACTS_DIR}/history.txt
|
||||||
|
touch ${HISTORY}
|
||||||
|
if [ ${STALE_COUNT} -gt 0 ]; then
|
||||||
|
tail -n 1 ${ARTIFACTS_DIR}/stale.json | jq -r '.body' | tr -d '\r' > ${ARTIFACTS_DIR}/stale-body.txt
|
||||||
|
# Its own entry, stashed in an HTML comment
|
||||||
|
awk -v marker="${NEXTHIST_MARKER}" '
|
||||||
|
$0 == marker { inside = 1; next }
|
||||||
|
!inside { next }
|
||||||
|
$0 == "-->" { exit }
|
||||||
|
NF { print }
|
||||||
|
' ${ARTIFACTS_DIR}/stale-body.txt >> ${HISTORY}
|
||||||
|
# Followed by its history, without the enclosing '<details>' markup
|
||||||
|
awk -v marker="${HISTORY_MARKER}" '
|
||||||
|
$0 == marker { inside = 1; next }
|
||||||
|
!inside { next }
|
||||||
|
$0 == "<details>" || /^<summary>/ { next }
|
||||||
|
$0 == "</details>" { exit }
|
||||||
|
NF { print }
|
||||||
|
' ${ARTIFACTS_DIR}/stale-body.txt >> ${HISTORY}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Assemble the comment. Starts with the marker and the report.
|
||||||
|
COMMENT=${ARTIFACTS_DIR}/comment.txt
|
||||||
|
cat > ${COMMENT} <<COMMENT_TEMPLATE
|
||||||
|
${COMMENT_MARKER}
|
||||||
|
$(cat ${ARTIFACTS_DIR}/body.txt)
|
||||||
|
COMMENT_TEMPLATE
|
||||||
|
|
||||||
|
# Then the history inherited from the notifications this one supersedes, so
|
||||||
|
# the older reports remain reachable from the only remaining comment.
|
||||||
|
if [ -s ${HISTORY} ]; then
|
||||||
|
echo "History holds $(wc -l < ${HISTORY}) entries"
|
||||||
|
cat >> ${COMMENT} <<HISTORY_TEMPLATE
|
||||||
|
${HISTORY_MARKER}
|
||||||
|
<details>
|
||||||
|
<summary>PR history</summary>
|
||||||
|
|
||||||
|
$(cat ${HISTORY})
|
||||||
|
</details>
|
||||||
|
HISTORY_TEMPLATE
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Finally this report's own history entry, stashed out of sight until a later
|
||||||
|
# notification inherits it.
|
||||||
|
cat >> ${COMMENT} <<NEXTHIST_TEMPLATE
|
||||||
|
${NEXTHIST_MARKER}
|
||||||
|
$(cat ${ARTIFACTS_DIR}/hist.txt)
|
||||||
|
-->
|
||||||
|
NEXTHIST_TEMPLATE
|
||||||
|
|
||||||
|
# Post it. Move on if this failed, without deleting anything below, otherwise
|
||||||
|
# the history held by the stale notifications would be lost.
|
||||||
|
if ! jq -Rs '{body: .}' ${COMMENT} \
|
||||||
|
| gh api --method POST "repos/{owner}/{repo}/issues/${PR_NUMBER}/comments" \
|
||||||
|
--input - > ${ARTIFACTS_DIR}/posted.json; then
|
||||||
|
echo "Failed to post this notification on PR #${PR_NUMBER}:" >&2
|
||||||
|
cat ${COMMENT} >&2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "Posted $(jq -r '.html_url' ${ARTIFACTS_DIR}/posted.json)"
|
||||||
|
|
||||||
|
# Delete the stale notifications, so only the new one remains
|
||||||
|
for COMMENT_ID in $(jq -r '.id' ${ARTIFACTS_DIR}/stale.json); do
|
||||||
|
echo "Deleting stale comment ${COMMENT_ID}"
|
||||||
|
gh api --method DELETE "repos/{owner}/{repo}/issues/comments/${COMMENT_ID}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# 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 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
|
done
|
||||||
|
|||||||
+6
-22
@@ -35,13 +35,10 @@ compile_coverage_reports() {
|
|||||||
|
|
||||||
# Gather all coverage workflow runs within the time window
|
# Gather all coverage workflow runs within the time window
|
||||||
gh run list -w coverage.yml --limit 1000 --created ">=${OLDEST}" --json "databaseId,event,status,conclusion,createdAt,number" > recentRuns.json
|
gh run list -w coverage.yml --limit 1000 --created ">=${OLDEST}" --json "databaseId,event,status,conclusion,createdAt,number" > recentRuns.json
|
||||||
echo @@@ Recent runs:
|
|
||||||
jq "." recentRuns.json
|
|
||||||
|
|
||||||
# Select completd runs that were not cancelled or skipped, sort by descending run number
|
# Select completd runs that were not cancelled or skipped, sort by descending run number
|
||||||
jq 'sort_by(-.number) | map(select(.status == "completed" and (.conclusion == "success" or .conclusion == "failure")))' recentRuns.json > completedRuns.json
|
jq 'sort_by(-.number) | map(select(.status == "completed" and (.conclusion == "success" or .conclusion == "failure")))' recentRuns.json > completedRuns.json
|
||||||
echo @@@ Completed with success or failure:
|
echo "@@@ $(jq length completedRuns.json) of $(jq length recentRuns.json) runs since ${OLDEST} completed with success or failure"
|
||||||
jq "." completedRuns.json
|
|
||||||
|
|
||||||
# Create artifacts root directory
|
# Create artifacts root directory
|
||||||
local ARTIFACTS_ROOT=artifacts-coverage
|
local ARTIFACTS_ROOT=artifacts-coverage
|
||||||
@@ -64,11 +61,8 @@ compile_coverage_reports() {
|
|||||||
|
|
||||||
# For each worfklow run that was triggered by this event type
|
# For each worfklow run that was triggered by this event type
|
||||||
for RUN_ID in $(jq ".[] | select(.event == \"${EVENT}\") |.databaseId" completedRuns.json); do
|
for RUN_ID in $(jq ".[] | select(.event == \"${EVENT}\") |.databaseId" completedRuns.json); do
|
||||||
echo "@@@ Processing run ${RUN_ID}"
|
|
||||||
|
|
||||||
# Extract the info of this run
|
# Extract the info of this run
|
||||||
jq ".[] | select(.databaseId == $RUN_ID)" completedRuns.json > workflow.json
|
jq ".[] | select(.databaseId == $RUN_ID)" completedRuns.json > workflow.json
|
||||||
jq "." workflow.json
|
|
||||||
|
|
||||||
# Record run ID of PR job
|
# Record run ID of PR job
|
||||||
[[ $EVENT != "pull_request" ]] || PR_RUN_IDS="$PR_RUN_IDS $RUN_ID"
|
[[ $EVENT != "pull_request" ]] || PR_RUN_IDS="$PR_RUN_IDS $RUN_ID"
|
||||||
@@ -78,15 +72,13 @@ compile_coverage_reports() {
|
|||||||
mkdir -p ${ARTIFACTS_DIR}
|
mkdir -p ${ARTIFACTS_DIR}
|
||||||
|
|
||||||
# Download artifacts of this run, if exists
|
# Download artifacts of this run, if exists
|
||||||
gh run download ${RUN_ID} --name coverage-report --dir ${ARTIFACTS_DIR} || true
|
gh run download ${RUN_ID} --name coverage-report --dir ${ARTIFACTS_DIR} &> /dev/null || true
|
||||||
ls -lsha ${ARTIFACTS_DIR}
|
|
||||||
|
|
||||||
# Move on if no coverage report is available
|
# Move on if no coverage report is available
|
||||||
if [ ! -d ${ARTIFACTS_DIR}/report ]; then
|
if [ ! -d ${ARTIFACTS_DIR}/report ]; then
|
||||||
echo "No coverage report found"
|
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
echo "Coverage report found"
|
echo "@@@ Run ${RUN_ID}: coverage report found"
|
||||||
|
|
||||||
# Emit section header
|
# Emit section header
|
||||||
if [[ -n $EMIT_SECTION_HEADER ]]; then
|
if [[ -n $EMIT_SECTION_HEADER ]]; then
|
||||||
@@ -159,13 +151,10 @@ compile_rtlmeter_reports() {
|
|||||||
|
|
||||||
# Gather all RTLMeter workflow runs within the time window
|
# Gather all RTLMeter workflow runs within the time window
|
||||||
gh run list -w rtlmeter.yml --limit 1000 --created ">=${OLDEST}" --json "databaseId,event,status,conclusion,createdAt,number" > recentRuns.json
|
gh run list -w rtlmeter.yml --limit 1000 --created ">=${OLDEST}" --json "databaseId,event,status,conclusion,createdAt,number" > recentRuns.json
|
||||||
echo @@@ Recent runs:
|
|
||||||
jq "." recentRuns.json
|
|
||||||
|
|
||||||
# Select completd runs that were not cancelled or skipped, sort by descending run number
|
# Select completd runs that were not cancelled or skipped, sort by descending run number
|
||||||
jq 'sort_by(-.number) | map(select(.status == "completed" and (.conclusion == "success" or .conclusion == "failure")))' recentRuns.json > completedRuns.json
|
jq 'sort_by(-.number) | map(select(.status == "completed" and (.conclusion == "success" or .conclusion == "failure")))' recentRuns.json > completedRuns.json
|
||||||
echo @@@ Completed with success or failure:
|
echo "@@@ $(jq length completedRuns.json) of $(jq length recentRuns.json) runs since ${OLDEST} completed with success or failure"
|
||||||
jq "." completedRuns.json
|
|
||||||
|
|
||||||
# Create artifacts root directory
|
# Create artifacts root directory
|
||||||
local ARTIFACTS_ROOT=artifacts-rtlmeter
|
local ARTIFACTS_ROOT=artifacts-rtlmeter
|
||||||
@@ -188,11 +177,8 @@ compile_rtlmeter_reports() {
|
|||||||
|
|
||||||
# For each worfklow run that was triggered by this event type
|
# For each worfklow run that was triggered by this event type
|
||||||
for RUN_ID in $(jq ".[] | select(.event == \"${EVENT}\") |.databaseId" completedRuns.json); do
|
for RUN_ID in $(jq ".[] | select(.event == \"${EVENT}\") |.databaseId" completedRuns.json); do
|
||||||
echo "@@@ Processing run ${RUN_ID}"
|
|
||||||
|
|
||||||
# Extract the info of this run
|
# Extract the info of this run
|
||||||
jq ".[] | select(.databaseId == $RUN_ID)" completedRuns.json > workflow.json
|
jq ".[] | select(.databaseId == $RUN_ID)" completedRuns.json > workflow.json
|
||||||
jq "." workflow.json
|
|
||||||
|
|
||||||
# Record run ID of PR job
|
# Record run ID of PR job
|
||||||
[[ $EVENT != "pull_request" ]] || PR_RUN_IDS="$PR_RUN_IDS $RUN_ID"
|
[[ $EVENT != "pull_request" ]] || PR_RUN_IDS="$PR_RUN_IDS $RUN_ID"
|
||||||
@@ -202,15 +188,13 @@ compile_rtlmeter_reports() {
|
|||||||
mkdir -p ${ARTIFACTS_DIR}
|
mkdir -p ${ARTIFACTS_DIR}
|
||||||
|
|
||||||
# Download artifacts of this run, if exists
|
# Download artifacts of this run, if exists
|
||||||
gh run download ${RUN_ID} --name rtlmeter-report --dir ${ARTIFACTS_DIR} || true
|
gh run download ${RUN_ID} --name rtlmeter-report --dir ${ARTIFACTS_DIR} &> /dev/null || true
|
||||||
ls -lsha ${ARTIFACTS_DIR}
|
|
||||||
|
|
||||||
# Move on if no RTLMeter report is available
|
# Move on if no RTLMeter report is available
|
||||||
if [ ! -d ${ARTIFACTS_DIR}/report ]; then
|
if [ ! -d ${ARTIFACTS_DIR}/report ]; then
|
||||||
echo "No RTLMeter report found"
|
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
echo "RTLMeter report found"
|
echo "@@@ Run ${RUN_ID}: RTLMeter report found"
|
||||||
|
|
||||||
# Emit section header
|
# Emit section header
|
||||||
if [[ -n $EMIT_SECTION_HEADER ]]; then
|
if [[ -n $EMIT_SECTION_HEADER ]]; then
|
||||||
|
|||||||
+12
-4
@@ -25,6 +25,8 @@ CASES = {
|
|||||||
("BlackParrot:2x2:*", 14),
|
("BlackParrot:2x2:*", 14),
|
||||||
("BlackParrot:4x4:*", 25),
|
("BlackParrot:4x4:*", 25),
|
||||||
("Caliptra:default:*", 19),
|
("Caliptra:default:*", 19),
|
||||||
|
("HummingbirdV2-E203:default:*", 3),
|
||||||
|
("HummingbirdV2-E203:nodelay:*", 3),
|
||||||
("NVDLA:*", 29),
|
("NVDLA:*", 29),
|
||||||
("OpenPiton:1x1:*", 4),
|
("OpenPiton:1x1:*", 4),
|
||||||
("OpenPiton:2x2:*", 7),
|
("OpenPiton:2x2:*", 7),
|
||||||
@@ -57,13 +59,15 @@ CASES = {
|
|||||||
("BlackParrot:2x2:*", 9),
|
("BlackParrot:2x2:*", 9),
|
||||||
("BlackParrot:4x4:*", 12),
|
("BlackParrot:4x4:*", 12),
|
||||||
("Caliptra:default:*", 16),
|
("Caliptra:default:*", 16),
|
||||||
|
("HummingbirdV2-E203:default:*", 10),
|
||||||
|
("HummingbirdV2-E203:nodelay:*", 10),
|
||||||
("NVDLA:*", 28),
|
("NVDLA:*", 28),
|
||||||
("OpenPiton:1x1:*", 5),
|
("OpenPiton:1x1:*", 5),
|
||||||
("OpenPiton:2x2:*", 6),
|
("OpenPiton:2x2:*", 6),
|
||||||
("OpenPiton:4x4:*", 8),
|
("OpenPiton:4x4:*", 8),
|
||||||
("OpenTitan:*", 10),
|
("OpenTitan:*", 10),
|
||||||
("Servant:qerv:*", 17),
|
("Servant:qerv:phil", 17),
|
||||||
("Servant:serv:*", 15),
|
("Servant:serv:phil", 15),
|
||||||
("VeeR-EH1:asic:*", 6),
|
("VeeR-EH1:asic:*", 6),
|
||||||
("VeeR-EH1:default:*", 8),
|
("VeeR-EH1:default:*", 8),
|
||||||
("VeeR-EH1:hiperf:*", 5),
|
("VeeR-EH1:hiperf:*", 5),
|
||||||
@@ -107,6 +111,8 @@ CASES_PR = {
|
|||||||
("BlackParrot:4x4:*", 25),
|
("BlackParrot:4x4:*", 25),
|
||||||
("Caliptra:default:*", 19),
|
("Caliptra:default:*", 19),
|
||||||
("NVDLA:*", 29),
|
("NVDLA:*", 29),
|
||||||
|
("HummingbirdV2-E203:default:*", 3),
|
||||||
|
("HummingbirdV2-E203:nodelay:*", 3),
|
||||||
("OpenPiton:1x1:*", 4),
|
("OpenPiton:1x1:*", 4),
|
||||||
("OpenPiton:4x4:*", 10),
|
("OpenPiton:4x4:*", 10),
|
||||||
("OpenTitan:*", 16),
|
("OpenTitan:*", 16),
|
||||||
@@ -137,11 +143,13 @@ CASES_PR = {
|
|||||||
("BlackParrot:4x4:*", 12),
|
("BlackParrot:4x4:*", 12),
|
||||||
("Caliptra:default:*", 16),
|
("Caliptra:default:*", 16),
|
||||||
("NVDLA:*", 28),
|
("NVDLA:*", 28),
|
||||||
|
("HummingbirdV2-E203:default:*", 10),
|
||||||
|
("HummingbirdV2-E203:nodelay:*", 10),
|
||||||
("OpenPiton:1x1:*", 5),
|
("OpenPiton:1x1:*", 5),
|
||||||
("OpenPiton:4x4:*", 8),
|
("OpenPiton:4x4:*", 8),
|
||||||
("OpenTitan:*", 10),
|
("OpenTitan:*", 10),
|
||||||
("Servant:qerv:*", 17),
|
("Servant:qerv:phil", 17),
|
||||||
("Servant:serv:*", 15),
|
("Servant:serv:phil", 15),
|
||||||
("VeeR-EH1:asic:*", 6),
|
("VeeR-EH1:asic:*", 6),
|
||||||
("VeeR-EH1:default:*", 8),
|
("VeeR-EH1:default:*", 8),
|
||||||
("VeeR-EH1:hiperf:*", 5),
|
("VeeR-EH1:hiperf:*", 5),
|
||||||
|
|||||||
@@ -88,9 +88,16 @@ venv/bin/python3 $SCRIPT_DIR/ci-rtlmeter-report.py ${SUMMARY_ARGS[@]} > $TMP_DIR
|
|||||||
# Print it
|
# Print it
|
||||||
cat $TMP_DIR/summary.txt
|
cat $TMP_DIR/summary.txt
|
||||||
|
|
||||||
# Create notification comment content
|
REPORT_URL=https://${PAGES_OWNER}.github.io/${PAGES_NAME}/rtlmeter-reports/${RUN_ID}/index.html
|
||||||
NOTIFICATION=$TMP_DIR/notification.txt
|
|
||||||
cat > $NOTIFICATION <<NOTIFICATION_TEMPLATE
|
###############################################################################
|
||||||
|
# Create the PR notification
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
NOTIFICATION_DIR=$TMP_DIR/notification
|
||||||
|
mkdir -p $NOTIFICATION_DIR
|
||||||
|
|
||||||
|
cat > ${NOTIFICATION_DIR}/body.txt <<NOTIFICATION_TEMPLATE
|
||||||
Performance metrics for PR workflow [#$RUN_NUM]($RUN_URL), comparing:
|
Performance metrics for PR workflow [#$RUN_NUM]($RUN_URL), comparing:
|
||||||
- target branch commit [${REF_SHA:0:9}](https://github.com/${PAGES_OWNER}/${PAGES_NAME}/commit/${REF_SHA}) (A)
|
- target branch commit [${REF_SHA:0:9}](https://github.com/${PAGES_OWNER}/${PAGES_NAME}/commit/${REF_SHA}) (A)
|
||||||
- with PR merge commit [${RUN_SHA:0:9}](https://github.com/${PAGES_OWNER}/${PAGES_NAME}/commit/${RUN_SHA}) (B)
|
- with PR merge commit [${RUN_SHA:0:9}](https://github.com/${PAGES_OWNER}/${PAGES_NAME}/commit/${RUN_SHA}) (B)
|
||||||
@@ -106,10 +113,15 @@ The reported numbers are the geometric means of the ratios of the metrics over a
|
|||||||
less than 1 is a regression, greater than 1 is an improvement.
|
less than 1 is a regression, greater than 1 is an improvement.
|
||||||
The jobs run on variable and noisy runners, so some variance is expected between runs.
|
The jobs run on variable and noisy runners, so some variance is expected between runs.
|
||||||
|
|
||||||
Detailed report: [${RUN_ID}](https://${PAGES_OWNER}.github.io/${PAGES_NAME}/rtlmeter-reports/${RUN_ID}/index.html)
|
Detailed report: [${RUN_ID}](${REPORT_URL})
|
||||||
NOTIFICATION_TEMPLATE
|
NOTIFICATION_TEMPLATE
|
||||||
|
|
||||||
|
echo "Workflow [#$RUN_NUM]($RUN_URL) report: [${RUN_ID}](${REPORT_URL})" > ${NOTIFICATION_DIR}/hist.txt
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
# Create detailed report
|
# Create detailed report
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
REPORT=$TMP_DIR/body.html
|
REPORT=$TMP_DIR/body.html
|
||||||
cat > $REPORT <<SUMMARY_TEMPLATE
|
cat > $REPORT <<SUMMARY_TEMPLATE
|
||||||
<h3>Summary of all runs</h3>
|
<h3>Summary of all runs</h3>
|
||||||
|
|||||||
@@ -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
|
|
||||||
Executable
+169
@@ -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
|
||||||
+20
-6
@@ -6,19 +6,33 @@
|
|||||||
|
|
||||||
Set-PSDebug -Trace 1
|
Set-PSDebug -Trace 1
|
||||||
|
|
||||||
if (-Not (Test-Path $PWD/../.ccache/win_bison.exe)) {
|
$NPROC = $env:NUMBER_OF_PROCESSORS
|
||||||
|
|
||||||
|
# Absolute path for the win_flex_bison install; CMake reads this from the environment
|
||||||
|
$env:WIN_FLEX_BISON = "$(Resolve-Path ..)/win_flex_bison"
|
||||||
|
|
||||||
|
if (-Not (Test-Path $env:WIN_FLEX_BISON/win_bison.exe)) {
|
||||||
git clone --depth 1 https://github.com/lexxmark/winflexbison
|
git clone --depth 1 https://github.com/lexxmark/winflexbison
|
||||||
cd winflexbison
|
cd winflexbison
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. --install-prefix $PWD/../../../.ccache
|
cmake .. --install-prefix $env:WIN_FLEX_BISON
|
||||||
cmake --build . --config Release -j 3
|
cmake --build . --config Release -j $NPROC
|
||||||
cmake --install . --prefix $PWD/../../../.ccache
|
cmake --install . --prefix $env:WIN_FLEX_BISON
|
||||||
cd ../..
|
cd ../..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Enter the MSVC developer shell so cl/link are on PATH for the Ninja generator
|
||||||
|
$VsPath = & "${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe" -latest -products * -property installationPath
|
||||||
|
Import-Module "$VsPath/Common7/Tools/Microsoft.VisualStudio.DevShell.dll"
|
||||||
|
Enter-VsDevShell -VsInstallPath $VsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64"
|
||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. --install-prefix $PWD/../install
|
# Ninja saturates all cores; the MSBuild generator only parallelizes across
|
||||||
cmake --build . --config Release -j 3
|
# projects and Verilator is a single target, so it compiles serially. /Od skips
|
||||||
|
# optimization: this job only checks that Verilator builds and can verilate an
|
||||||
|
# example, so an optimized binary is not needed and the codegen time dominates.
|
||||||
|
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release --install-prefix $PWD/../install "-DCMAKE_CXX_FLAGS_RELEASE=/Od /DNDEBUG"
|
||||||
|
cmake --build .
|
||||||
cmake --install . --prefix $PWD/../install
|
cmake --install . --prefix $PWD/../install
|
||||||
|
|||||||
+6
-2
@@ -7,13 +7,17 @@
|
|||||||
|
|
||||||
Set-PSDebug -Trace 1
|
Set-PSDebug -Trace 1
|
||||||
|
|
||||||
|
$NPROC = $env:NUMBER_OF_PROCESSORS
|
||||||
|
|
||||||
cd install
|
cd install
|
||||||
$Env:VERILATOR_ROOT=$PWD
|
$Env:VERILATOR_ROOT=$PWD
|
||||||
cd examples/cmake_tracing_c
|
cd examples/cmake_tracing_c
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
# /Od skips optimization; this only checks the example verilates and builds, so
|
||||||
cmake --build . --config Release -j 3
|
# an optimized binary is not needed (see ci-win-compile.ps1).
|
||||||
|
cmake .. "-DCMAKE_CXX_FLAGS_RELEASE=/Od /DNDEBUG"
|
||||||
|
cmake --build . --config Release -j $NPROC
|
||||||
|
|
||||||
# TODO put this back in, see issue# 5163
|
# TODO put this back in, see issue# 5163
|
||||||
# Release/example.exe
|
# Release/example.exe
|
||||||
|
|||||||
+64
-7
@@ -12,7 +12,7 @@
|
|||||||
# Then 'make maintainer-dist'
|
# Then 'make maintainer-dist'
|
||||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||||
#AC_INIT([Verilator],[#.### devel])
|
#AC_INIT([Verilator],[#.### devel])
|
||||||
AC_INIT([Verilator],[5.050 2026-07-01],
|
AC_INIT([Verilator],[5.052 2026-09-05],
|
||||||
[https://verilator.org],
|
[https://verilator.org],
|
||||||
[verilator],[https://verilator.org])
|
[verilator],[https://verilator.org])
|
||||||
|
|
||||||
@@ -129,6 +129,21 @@ AC_ARG_ENABLE([dev-gcov],
|
|||||||
AC_SUBST(CFG_WITH_DEV_GCOV)
|
AC_SUBST(CFG_WITH_DEV_GCOV)
|
||||||
AC_MSG_RESULT($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
|
# Special Substitutions - CFG_WITH_DEFENV
|
||||||
AC_MSG_CHECKING(whether to use hardcoded paths)
|
AC_MSG_CHECKING(whether to use hardcoded paths)
|
||||||
AC_ARG_ENABLE([defenv],
|
AC_ARG_ENABLE([defenv],
|
||||||
@@ -432,6 +447,7 @@ AC_DEFUN([_MY_LDLIBS_CHECK_SET],
|
|||||||
|
|
||||||
# Add the coverage flags early as they influence later checks.
|
# Add the coverage flags early as they influence later checks.
|
||||||
if test "$CFG_WITH_DEV_GCOV" = "yes"; then
|
if test "$CFG_WITH_DEV_GCOV" = "yes"; then
|
||||||
|
CFG_GCOV_CXX="$CXX"
|
||||||
_MY_CXX_CHECK_OPT(CXX,--coverage)
|
_MY_CXX_CHECK_OPT(CXX,--coverage)
|
||||||
# Otherwise inline may not show as uncovered
|
# Otherwise inline may not show as uncovered
|
||||||
# If we use this then e.g. verilated.h functions properly show up
|
# If we use this then e.g. verilated.h functions properly show up
|
||||||
@@ -453,8 +469,32 @@ if test "$CFG_WITH_DEV_GCOV" = "yes"; then
|
|||||||
_MY_CXX_CHECK_OPT(CXX,-fprofile-abs-path)
|
_MY_CXX_CHECK_OPT(CXX,-fprofile-abs-path)
|
||||||
# Define so compiled code can know
|
# Define so compiled code can know
|
||||||
_MY_CXX_CHECK_OPT(CXX,-DVL_GCOV)
|
_MY_CXX_CHECK_OPT(CXX,-DVL_GCOV)
|
||||||
AC_DEFINE([HAVE_DEV_GCOV],[1],[Defined if compiled with code coverage collection for gcov])]
|
AC_DEFINE([HAVE_DEV_GCOV],[1],[Defined if compiled with code coverage collection for gcov])
|
||||||
|
if test "x$GCOV" = "x"; then GCOV=gcov; fi
|
||||||
|
AC_MSG_CHECKING([whether $GCOV reads coverage data from $CFG_GCOV_CXX])
|
||||||
|
CFG_GCOV_DIR=conftest.gcov.dir
|
||||||
|
rm -rf $CFG_GCOV_DIR
|
||||||
|
AS_MKDIR_P([$CFG_GCOV_DIR])
|
||||||
|
echo 'int main() { return 0; }' > $CFG_GCOV_DIR/conftest_gcov.cpp
|
||||||
|
CFG_GCOV_RES=no
|
||||||
|
if (cd $CFG_GCOV_DIR \
|
||||||
|
&& $CFG_GCOV_CXX --coverage -o conftest_gcov conftest_gcov.cpp \
|
||||||
|
&& ./conftest_gcov) >/dev/null 2>&1; then
|
||||||
|
(cd $CFG_GCOV_DIR && $GCOV conftest_gcov.gcda) >/dev/null 2>&1
|
||||||
|
if test -s $CFG_GCOV_DIR/conftest_gcov.cpp.gcov; then CFG_GCOV_RES=yes; fi
|
||||||
|
else
|
||||||
|
CFG_GCOV_RES=untested
|
||||||
|
fi
|
||||||
|
rm -rf $CFG_GCOV_DIR
|
||||||
|
AC_MSG_RESULT($CFG_GCOV_RES)
|
||||||
|
if test "$CFG_GCOV_RES" = "no"; then
|
||||||
|
AC_MSG_ERROR(['$GCOV' cannot read coverage data written by '$CFG_GCOV_CXX'.
|
||||||
|
Coverage collection would silently produce no data.
|
||||||
|
Pass a matching tool, e.g. GCOV=gcov-<version>
|
||||||
|
or configure without --enable-dev-gcov.])
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
AC_SUBST(GCOV)
|
||||||
AC_SUBST(HAVE_DEV_GCOV)
|
AC_SUBST(HAVE_DEV_GCOV)
|
||||||
|
|
||||||
# Compiler flags to enable profiling
|
# Compiler flags to enable profiling
|
||||||
@@ -492,6 +532,11 @@ _MY_CXX_CHECK_CORO_SET(CFG_CXXFLAGS_COROUTINES,-std=gnu++20)
|
|||||||
AC_SUBST(CFG_CXXFLAGS_COROUTINES)
|
AC_SUBST(CFG_CXXFLAGS_COROUTINES)
|
||||||
AC_SUBST(HAVE_COROUTINES)
|
AC_SUBST(HAVE_COROUTINES)
|
||||||
|
|
||||||
|
# Check if the C++ compiler supports ThreadSanitizer
|
||||||
|
_MY_CXX_CHECK_IFELSE(-fsanitize=thread,
|
||||||
|
[AC_DEFINE([HAVE_TSAN],[1],[Defined if ThreadSanitizer is supported by $CXX])])
|
||||||
|
AC_SUBST(HAVE_TSAN)
|
||||||
|
|
||||||
# Flags for compiling Verilator internals including parser always
|
# Flags for compiling Verilator internals including parser always
|
||||||
if test "$CFG_WITH_DEV_ASAN" = "yes"; then
|
if test "$CFG_WITH_DEV_ASAN" = "yes"; then
|
||||||
_MY_CXX_CHECK_IFELSE(-fsanitize=address -DVL_ASAN,
|
_MY_CXX_CHECK_IFELSE(-fsanitize=address -DVL_ASAN,
|
||||||
@@ -518,15 +563,27 @@ _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-unused)
|
|||||||
AC_SUBST(CFG_CXXFLAGS_PARSER)
|
AC_SUBST(CFG_CXXFLAGS_PARSER)
|
||||||
|
|
||||||
# Flags for compiling the debug version of Verilator (in addition to above CFG_CXXFLAGS_SRC)
|
# 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
|
if test "$CFG_WITH_LIGHT_DEBUG" = "yes"; then
|
||||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-Og)
|
# 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
|
fi
|
||||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-ggdb)
|
|
||||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_DBG,-gz)
|
|
||||||
AC_SUBST(CFG_CXXFLAGS_DBG)
|
AC_SUBST(CFG_CXXFLAGS_DBG)
|
||||||
|
|
||||||
# Flags for linking the debug version of Verilator (in addition to above CFG_LDFLAGS_SRC)
|
# 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)
|
AC_SUBST(CFG_LDFLAGS_DBG)
|
||||||
|
|
||||||
# Flags for compiling the optimized version of Verilator (in addition to above CFG_CXXFLAGS_SRC)
|
# Flags for compiling the optimized version of Verilator (in addition to above CFG_CXXFLAGS_SRC)
|
||||||
|
|||||||
+36
-13
@@ -7,13 +7,16 @@ contribution terms including the AI policy in ``docs/CONTRIBUTING.rst``.
|
|||||||
|
|
||||||
Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
||||||
|
|
||||||
|
24bit-xjkp
|
||||||
404allen404
|
404allen404
|
||||||
Adam Bagley
|
Adam Bagley
|
||||||
Adam Kostrzewski
|
Adam Kostrzewski
|
||||||
|
Aditya Shevade
|
||||||
Adrian Sampson
|
Adrian Sampson
|
||||||
Adrien Le Masle
|
Adrien Le Masle
|
||||||
أحمد المحمودي (Ahmed El-Mahmoudy)
|
أحمد المحمودي (Ahmed El-Mahmoudy)
|
||||||
Aidan McNay
|
Aidan McNay
|
||||||
|
Aisha Salimgereyeva
|
||||||
Aleksander Kiryk
|
Aleksander Kiryk
|
||||||
Alex Chadwick
|
Alex Chadwick
|
||||||
Alex Solomatnikov
|
Alex Solomatnikov
|
||||||
@@ -26,16 +29,20 @@ Andrei Kostovski
|
|||||||
Andrew Miloradovsky
|
Andrew Miloradovsky
|
||||||
Andrew Nolte
|
Andrew Nolte
|
||||||
Andrew Voznytsa
|
Andrew Voznytsa
|
||||||
|
Andrii Andrieiev
|
||||||
anonkey
|
anonkey
|
||||||
Anthony Donlon
|
Anthony Donlon
|
||||||
Anthony Moore
|
Anthony Moore
|
||||||
|
apocelipes
|
||||||
Arkadiusz Kozdra
|
Arkadiusz Kozdra
|
||||||
Arthur Rosa
|
Arthur Rosa
|
||||||
Artur Bieniek
|
Artur Bieniek
|
||||||
AUDIY
|
AUDIY
|
||||||
Aylon Chaim Porat
|
Aylon Chaim Porat
|
||||||
|
Bartosz Skorowski
|
||||||
Bartłomiej Chmiel
|
Bartłomiej Chmiel
|
||||||
Benjamin Collier
|
Benjamin Collier
|
||||||
|
BRDR LIFE
|
||||||
Brian Li
|
Brian Li
|
||||||
Cameron Kirk
|
Cameron Kirk
|
||||||
Cameron Waite
|
Cameron Waite
|
||||||
@@ -53,27 +60,36 @@ Dan Ruelas-Petrisko
|
|||||||
Daniel Bates
|
Daniel Bates
|
||||||
Danny Oler
|
Danny Oler
|
||||||
Dave Sargeant
|
Dave Sargeant
|
||||||
|
David Garau
|
||||||
David Horton
|
David Horton
|
||||||
David Ledger
|
David Ledger
|
||||||
David Metz
|
David Metz
|
||||||
David Stanford
|
David Stanford
|
||||||
David Turner
|
David Turner
|
||||||
|
dependabot[bot]
|
||||||
Dercury
|
Dercury
|
||||||
|
Demin Han
|
||||||
Diego Roux
|
Diego Roux
|
||||||
Dominick Grochowina
|
Dominick Grochowina
|
||||||
Don Williamson
|
Don Williamson
|
||||||
|
Dragon-Git
|
||||||
Drew Ranck
|
Drew Ranck
|
||||||
Drew Taussig
|
Drew Taussig
|
||||||
Driss Hafdi
|
Driss Hafdi
|
||||||
Edgar E. Iglesias
|
Edgar E. Iglesias
|
||||||
|
Eddie Rydell
|
||||||
|
em2machine
|
||||||
|
emmettifelts
|
||||||
Eric Mejdrich
|
Eric Mejdrich
|
||||||
Eric Müller
|
Eric Müller
|
||||||
Eric Rippey
|
Eric Rippey
|
||||||
Eunseo Song
|
Eryk Szpotański
|
||||||
Ethan Sifferman
|
Ethan Sifferman
|
||||||
|
Eunseo Song
|
||||||
Eyck Jentzsch
|
Eyck Jentzsch
|
||||||
Fabian Keßler-Schulz
|
Fabian Keßler-Schulz
|
||||||
Fan Shupei
|
Fan Shupei
|
||||||
|
february cozzocrea
|
||||||
Felix Neumärker
|
Felix Neumärker
|
||||||
Felix Yan
|
Felix Yan
|
||||||
Frans Skarman
|
Frans Skarman
|
||||||
@@ -108,6 +124,8 @@ Ilya Barkov
|
|||||||
Iru Cai
|
Iru Cai
|
||||||
Ivan Vnučec
|
Ivan Vnučec
|
||||||
Iztok Jeras
|
Iztok Jeras
|
||||||
|
JAEUK LEE
|
||||||
|
Jaeuk Lee (이재욱)
|
||||||
Jake Merdich
|
Jake Merdich
|
||||||
Jakub Michalski
|
Jakub Michalski
|
||||||
Jakub Wasilewski
|
Jakub Wasilewski
|
||||||
@@ -122,6 +140,8 @@ Jamie Iles
|
|||||||
Jan Van Winkel
|
Jan Van Winkel
|
||||||
Jean Berniolles
|
Jean Berniolles
|
||||||
Jean-Nicolas Strauss
|
Jean-Nicolas Strauss
|
||||||
|
Jeffrey Song
|
||||||
|
jeffrey.song
|
||||||
Jens Yuechao Liu
|
Jens Yuechao Liu
|
||||||
Jeremy Bennett
|
Jeremy Bennett
|
||||||
Jesse Taube
|
Jesse Taube
|
||||||
@@ -147,6 +167,7 @@ Josep Sans
|
|||||||
Joseph Nwabueze
|
Joseph Nwabueze
|
||||||
Josh Redford
|
Josh Redford
|
||||||
Joshua Leahy
|
Joshua Leahy
|
||||||
|
JOTEGO (Jose Tejada)
|
||||||
Julian Carrier
|
Julian Carrier
|
||||||
Julian Daube
|
Julian Daube
|
||||||
Julie Schwartz
|
Julie Schwartz
|
||||||
@@ -183,6 +204,7 @@ Maarten De Braekeleer
|
|||||||
Maciej Sobkowski
|
Maciej Sobkowski
|
||||||
Marcel Chang
|
Marcel Chang
|
||||||
Marco Bartoli
|
Marco Bartoli
|
||||||
|
Marco Brambilla
|
||||||
Marco Widmer
|
Marco Widmer
|
||||||
Mariusz Glebocki
|
Mariusz Glebocki
|
||||||
Markus Krause
|
Markus Krause
|
||||||
@@ -208,6 +230,7 @@ Mladen Slijepcevic
|
|||||||
Morten Borup Petersen
|
Morten Borup Petersen
|
||||||
Mostafa Gamal
|
Mostafa Gamal
|
||||||
Moubarak Jeje
|
Moubarak Jeje
|
||||||
|
Muzaffer Kal
|
||||||
Nandu Raj
|
Nandu Raj
|
||||||
Natan Kreimer
|
Natan Kreimer
|
||||||
Nathan Graybeal
|
Nathan Graybeal
|
||||||
@@ -218,8 +241,11 @@ Nikolai Kumar
|
|||||||
Nikolay Puzanov
|
Nikolay Puzanov
|
||||||
Nolan Poe
|
Nolan Poe
|
||||||
Oleh Maksymenko
|
Oleh Maksymenko
|
||||||
|
Patrick Creighton
|
||||||
Patrick Stewart
|
Patrick Stewart
|
||||||
Paul Bowen-Huggett
|
Paul Bowen-Huggett
|
||||||
|
Paul Campbell
|
||||||
|
Paul Rigge
|
||||||
Paul Swirhun
|
Paul Swirhun
|
||||||
Paul Wright
|
Paul Wright
|
||||||
Pawel Jewstafjew
|
Pawel Jewstafjew
|
||||||
@@ -262,15 +288,19 @@ Sergey Chusov
|
|||||||
Sergey Fedorov
|
Sergey Fedorov
|
||||||
Sergi Granell
|
Sergi Granell
|
||||||
Seth Pellegrino
|
Seth Pellegrino
|
||||||
|
Shashvat Prabhu
|
||||||
Shogo Yamazaki
|
Shogo Yamazaki
|
||||||
Shou-Li Hsu
|
Shou-Li Hsu
|
||||||
|
spomatasmd
|
||||||
Srinivasan Venkataramanan
|
Srinivasan Venkataramanan
|
||||||
Stefan Wallentowitz
|
Stefan Wallentowitz
|
||||||
Stephen Henry
|
Stephen Henry
|
||||||
Steven Hugg
|
Steven Hugg
|
||||||
Stuart Morris
|
Stuart Morris
|
||||||
|
sumpster
|
||||||
Szymon Gizler
|
Szymon Gizler
|
||||||
Sören Tempel
|
Sören Tempel
|
||||||
|
Sumanth Kadiyala
|
||||||
Teng Huang
|
Teng Huang
|
||||||
Thomas Aldrian
|
Thomas Aldrian
|
||||||
Thomas Brown
|
Thomas Brown
|
||||||
@@ -291,6 +321,7 @@ Tracy Narine
|
|||||||
Trung Nguyen
|
Trung Nguyen
|
||||||
Tudor Timi
|
Tudor Timi
|
||||||
Tymoteusz Blazejczyk
|
Tymoteusz Blazejczyk
|
||||||
|
Tyrone Marhguy
|
||||||
Udaya Raj Subedi
|
Udaya Raj Subedi
|
||||||
Udi Finkelstein
|
Udi Finkelstein
|
||||||
Unai Martinez-Corral
|
Unai Martinez-Corral
|
||||||
@@ -308,9 +339,11 @@ Wolfgang Mayerwieser
|
|||||||
Xi Zhang
|
Xi Zhang
|
||||||
Yan Xu
|
Yan Xu
|
||||||
Yangyu Chen
|
Yangyu Chen
|
||||||
|
Yilin Li
|
||||||
Yilou Wang
|
Yilou Wang
|
||||||
Yinan Xu
|
Yinan Xu
|
||||||
Yoda Lee
|
Yoda Lee
|
||||||
|
Yogish Sekhar
|
||||||
Yossi Nivin
|
Yossi Nivin
|
||||||
Yu-Sheng Lin
|
Yu-Sheng Lin
|
||||||
Yuri Victorovich
|
Yuri Victorovich
|
||||||
@@ -321,17 +354,7 @@ Zhen Yan
|
|||||||
Zhou Shen
|
Zhou Shen
|
||||||
Zhouyi Shen
|
Zhouyi Shen
|
||||||
Zixi Li
|
Zixi Li
|
||||||
apocelipes
|
Zubin Jain
|
||||||
dependabot[bot]
|
|
||||||
february cozzocrea
|
|
||||||
sumpster
|
|
||||||
em2machine
|
|
||||||
emmettifelts
|
|
||||||
Àlex Torregrosa
|
Àlex Torregrosa
|
||||||
Ícaro Lima
|
Ícaro Lima
|
||||||
Yogish Sekhar
|
Sunimali Rathnayake
|
||||||
24bit-xjkp
|
|
||||||
Zubin Jain
|
|
||||||
Muzaffer Kal
|
|
||||||
Yilin Li
|
|
||||||
Shashvat Prabhu
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
-V{t#,#} 'stl' region trigger index 0 is active: @([hybrid] a)
|
-V{t#,#} 'stl' region trigger index 0 is active: @([hybrid] a)
|
||||||
%Error-DIDNOTCONVERGE: t/t_lint_didnotconverge_bad.v:7: Settle region did not converge after '--converge-limit' of 10000 tries
|
%Error-DIDNOTCONVERGE: Settle region did not converge after '--converge-limit' of 10000 tries
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.. comment: generated by t_lint_didnotconverge_nodbg_bad
|
.. comment: generated by t_lint_didnotconverge_nodbg_bad
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
%Error-DIDNOTCONVERGE: t/t_lint_didnotconverge_bad.v:7: Settle region did not converge after '--converge-limit' of 10000 tries
|
%Error-DIDNOTCONVERGE: Settle region did not converge after '--converge-limit' of 10000 tries
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
.. comment: generated by t_lint_multidriven_proc_bad
|
||||||
|
.. code-block:: sv
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
always @(posedge clk) q <= d;
|
||||||
|
always @(posedge clk) q <= ~d;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
.. comment: generated by t_lint_multidriven_proc_bad
|
||||||
|
.. code-block:: sv
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
for (i = 0; i < 4; i = i + 1) q1[i] <= d[i];
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
for (i = 0; i < 4; i = i + 1) q2[i] <= ~d[i];
|
||||||
|
end
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.. comment: generated by t_lint_multidriven_proc_bad
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
%Warning-MULTIDRIVENPROC: example.v:1:25 Variable written to in always block also written by another always block: 'q'
|
||||||
|
: ... note: In instance 't.u1'
|
||||||
|
example.v:1:25
|
||||||
|
54 | always @(posedge clk) q <= ~d;
|
||||||
|
| ^
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
.. comment: generated by t_lint_similarname_bad
|
||||||
|
.. code-block:: sv
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
reg i;
|
||||||
|
wire I;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
.. comment: generated by t_lint_similarname_bad
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
%Warning-SIMILARNAME: example.v:1:8 Declaration overlaps another with different case: 'I'
|
||||||
|
13 | wire I;
|
||||||
|
| ^
|
||||||
|
example.v:1:7 ... Location of original declaration
|
||||||
|
12 | reg i;
|
||||||
|
| ^
|
||||||
@@ -92,13 +92,17 @@ model.
|
|||||||
Refer to ``examples/make_tracing_c`` in the distribution for a detailed
|
Refer to ``examples/make_tracing_c`` in the distribution for a detailed
|
||||||
commented example.
|
commented example.
|
||||||
|
|
||||||
Top level IO signals are read and written as members of the model. You call
|
Top level IO signals are read and written as members of the model. All
|
||||||
the model's ``eval()`` method to evaluate the model. When the simulation is
|
inputs must be sanitized, that is have no bits set above those
|
||||||
complete call the model's ``final()`` method to execute any SystemVerilog
|
corresponding to the width of the Verilog construct;
|
||||||
final blocks, and complete any assertions. If using :vlopt:`--timing`,
|
:vlopt:`--runtime-debug` will assert this is correct.
|
||||||
there are two additional functions for checking if there are any events
|
|
||||||
pending in the simulation due to delays, and for retrieving the simulation
|
Call the model's ``eval()`` method to evaluate the model. When the
|
||||||
time of the next delayed event. See :ref:`Evaluation Loop`.
|
simulation is complete call the model's ``final()`` method to execute any
|
||||||
|
SystemVerilog final blocks, and complete any assertions. If using
|
||||||
|
:vlopt:`--timing`, there are two additional functions for checking if there
|
||||||
|
are any events pending in the simulation due to delays, and for retrieving
|
||||||
|
the simulation time of the next delayed event. See :ref:`Evaluation Loop`.
|
||||||
|
|
||||||
|
|
||||||
Connecting to SystemC
|
Connecting to SystemC
|
||||||
@@ -179,7 +183,7 @@ DPI Example
|
|||||||
In the SYSTEMC example above, if you wanted to import C++ functions into
|
In the SYSTEMC example above, if you wanted to import C++ functions into
|
||||||
Verilog, put in our.v:
|
Verilog, put in our.v:
|
||||||
|
|
||||||
.. code-block:: sv
|
.. code-block::
|
||||||
|
|
||||||
import "DPI-C" function int add (input int a, input int b);
|
import "DPI-C" function int add (input int a, input int b);
|
||||||
|
|
||||||
@@ -211,7 +215,7 @@ Verilator extends the DPI format to allow using the same scheme to
|
|||||||
efficiently add system functions. Use a dollar-sign prefixed system
|
efficiently add system functions. Use a dollar-sign prefixed system
|
||||||
function name for the import, but note it must be escaped.
|
function name for the import, but note it must be escaped.
|
||||||
|
|
||||||
.. code-block:: sv
|
.. code-block::
|
||||||
|
|
||||||
import "DPI-C" function integer \$myRand;
|
import "DPI-C" function integer \$myRand;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,13 @@ Summary:
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
|
.. option:: +verilator+assert+lock
|
||||||
|
|
||||||
|
Only allow command line options to disable / enable assertions.
|
||||||
|
Disables RTL from changing assertion handling via ``$asserton``,
|
||||||
|
``$assertoff``, and ``$assertcontrol``. Also prevents ``VerilatedContext*``
|
||||||
|
assertion control functions from updating assertion handling.
|
||||||
|
|
||||||
.. option:: +verilator+coverage+file+<filename>
|
.. option:: +verilator+coverage+file+<filename>
|
||||||
|
|
||||||
When a model was Verilated using :vlopt:`--coverage`, sets the filename
|
When a model was Verilated using :vlopt:`--coverage`, sets the filename
|
||||||
@@ -114,7 +121,7 @@ Options:
|
|||||||
When a model was Verilated using :vlopt:`--x-initial unique
|
When a model was Verilated using :vlopt:`--x-initial unique
|
||||||
<--x-initial>`, sets the simulation runtime initialization technique. 0
|
<--x-initial>`, sets the simulation runtime initialization technique. 0
|
||||||
= Reset to zeros. 1 = Reset to all-ones. 2 = Randomize. See
|
= Reset to zeros. 1 = Reset to all-ones. 2 = Randomize. See
|
||||||
:ref:`Unknown States`.
|
:ref:`Unknown States`. Default is 0.
|
||||||
|
|
||||||
.. option:: +verilator+seed+<value>
|
.. option:: +verilator+seed+<value>
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,10 @@ Summary:
|
|||||||
|
|
||||||
.. option:: --assert-unroll-limit <iterations>
|
.. option:: --assert-unroll-limit <iterations>
|
||||||
|
|
||||||
|
Deprecated and has no effect (ignored).
|
||||||
|
|
||||||
|
In versions before 5.052:
|
||||||
|
|
||||||
Rarely needed. Specifies the maximum repetition or range count Verilator
|
Rarely needed. Specifies the maximum repetition or range count Verilator
|
||||||
will unroll inside an SVA concurrent assertion (e.g. ``[*N]``, ``[->M:N]``,
|
will unroll inside an SVA concurrent assertion (e.g. ``[*N]``, ``[->M:N]``,
|
||||||
``always[lo:hi]``). Beyond this, the assertion is rejected with an error
|
``always[lo:hi]``). Beyond this, the assertion is rejected with an error
|
||||||
@@ -715,6 +719,10 @@ Summary:
|
|||||||
|
|
||||||
.. option:: -fno-dfg-break-cycles
|
.. option:: -fno-dfg-break-cycles
|
||||||
|
|
||||||
|
Deprecated and has no effect (ignored).
|
||||||
|
|
||||||
|
In versions before 5.052:
|
||||||
|
|
||||||
Rarely needed. Disable breaking combinational cycles during DFG.
|
Rarely needed. Disable breaking combinational cycles during DFG.
|
||||||
|
|
||||||
.. option:: -fno-dfg-peephole
|
.. option:: -fno-dfg-peephole
|
||||||
@@ -936,7 +944,7 @@ Summary:
|
|||||||
:file:`*.mk` files.
|
:file:`*.mk` files.
|
||||||
|
|
||||||
Feature may be one of the following: COROUTINES, DEV_ASAN, DEV_GCOV,
|
Feature may be one of the following: COROUTINES, DEV_ASAN, DEV_GCOV,
|
||||||
SYSTEMC.
|
SYSTEMC, TSAN.
|
||||||
|
|
||||||
.. option:: --getenv <variable>
|
.. option:: --getenv <variable>
|
||||||
|
|
||||||
@@ -1219,6 +1227,8 @@ Summary:
|
|||||||
.. option:: --max-num-width <value>
|
.. option:: --max-num-width <value>
|
||||||
|
|
||||||
Set the maximum number literal width (e.g., in 1024'd22 the 1024).
|
Set the maximum number literal width (e.g., in 1024'd22 the 1024).
|
||||||
|
This also limits SVA cycle delay and temporal bound values.
|
||||||
|
|
||||||
Defaults to 64K.
|
Defaults to 64K.
|
||||||
|
|
||||||
.. option:: --Mdir <directory>
|
.. option:: --Mdir <directory>
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ verilator_coverage Arguments
|
|||||||
|
|
||||||
.. option:: --filter-type <regex>
|
.. option:: --filter-type <regex>
|
||||||
|
|
||||||
Skips records of coverage types that matches with <regex>
|
Keeps records of coverage types that matches with <regex>
|
||||||
Possible values are `toggle`, `line`, `branch`, `expr`, `covergroup`,
|
Possible values are `toggle`, `line`, `branch`, `expr`, `covergroup`,
|
||||||
`user`, `fsm_state`, `fsm_arc` and a wildcard with `\*` or `?`. The
|
`user`, `fsm_state`, `fsm_arc` and a wildcard with `\*` or `?`. The
|
||||||
default value is `\*`.
|
default value is `\*`.
|
||||||
|
|||||||
@@ -294,6 +294,25 @@ or "`ifdef`"'s may break other tools.
|
|||||||
(if appropriate :vlopt:`--coverage` flags are passed) after being
|
(if appropriate :vlopt:`--coverage` flags are passed) after being
|
||||||
disabled earlier with :option:`/*verilator&32;coverage_off*/`.
|
disabled earlier with :option:`/*verilator&32;coverage_off*/`.
|
||||||
|
|
||||||
|
.. option:: /*verilator&32;dpi_c_decl "<C function declaration>"*/
|
||||||
|
|
||||||
|
Specifies C function declaration that will be emitted for given DPI-C
|
||||||
|
function into the Verilator-generated __Dpi.h header, replacing the declaration
|
||||||
|
that Verilator would build by default using the Verilog function signature.
|
||||||
|
|
||||||
|
This enables use of C functions with types not specified in the
|
||||||
|
standard. For example, it enables use of functions that return ``char*``:
|
||||||
|
|
||||||
|
.. code-block:: sv
|
||||||
|
|
||||||
|
module t;
|
||||||
|
import "DPI-C" function string getenv(input string arg) /*verilator dpi_c_decl "char* getenv(const char*)"*/;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$display("%s", getenv("HOME"));
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
.. option:: /*verilator&32;fargs <arguments>*/
|
.. option:: /*verilator&32;fargs <arguments>*/
|
||||||
|
|
||||||
For Verilator developers only. When a source file containing these `fargs`
|
For Verilator developers only. When a source file containing these `fargs`
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ The information in this report is:
|
|||||||
|
|
||||||
.. describe:: "allocated 123 MB"
|
.. describe:: "allocated 123 MB"
|
||||||
|
|
||||||
Total memory used during simulation in megabytes.
|
Peak resident memory used during simulation in megabytes.
|
||||||
|
|
||||||
|
|
||||||
.. _benchmarking & optimization:
|
.. _benchmarking & optimization:
|
||||||
|
|||||||
@@ -623,5 +623,5 @@ The information in this report is:
|
|||||||
|
|
||||||
.. describe:: "allocated 123 MB"
|
.. describe:: "allocated 123 MB"
|
||||||
|
|
||||||
Total memory used during build by Verilator executable (excludes
|
Peak resident memory used by the Verilator executable during build
|
||||||
:vlopt:`--build` compiler's usage) in megabytes.
|
(excludes :vlopt:`--build` compiler's usage) in megabytes.
|
||||||
|
|||||||
@@ -1469,11 +1469,54 @@ List Of Warnings
|
|||||||
q <= d;
|
q <= d;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
A further case is when a signal named as a clocking block ``output`` is
|
||||||
|
also driven by a continuous assignment, or is named as an ``output`` of a
|
||||||
|
second clocking block. The clocking block drives the signal, so the design
|
||||||
|
and the testbench contend for it and the synchronous drive may be silently
|
||||||
|
lost. Declare the clocking block ``input`` if the intent is only to
|
||||||
|
observe the signal.
|
||||||
|
|
||||||
Ignoring this warning may hide clock domain crossing, timing, or
|
Ignoring this warning may hide clock domain crossing, timing, or
|
||||||
portability bugs. It may also cause longer simulation runtimes due to
|
portability bugs. It may also cause longer simulation runtimes due to
|
||||||
reduced optimizations.
|
reduced optimizations.
|
||||||
|
|
||||||
|
|
||||||
|
.. option:: MULTIDRIVENPROC
|
||||||
|
|
||||||
|
Warns that the whole of a variable is driven by more than one plain
|
||||||
|
``always`` block. Unlike the :option:`MULTIDRIVEN` cases, plain
|
||||||
|
``always`` blocks carry no ``always_comb``/``always_ff`` intent, so this
|
||||||
|
is legal SystemVerilog rather than an IEEE 1800 violation. It is,
|
||||||
|
however, typically a synthesis error: hardware cannot have a signal
|
||||||
|
driven by two separate sequential blocks, so the design usually will not
|
||||||
|
behave as the RTL simulation suggests.
|
||||||
|
|
||||||
|
Disabled by default as this is a code-style warning; it will simulate
|
||||||
|
correctly.
|
||||||
|
|
||||||
|
Faulty example:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_MULTIDRIVENPROC_faulty.rst
|
||||||
|
|
||||||
|
Results in:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_MULTIDRIVENPROC_msg.rst
|
||||||
|
|
||||||
|
Also warns when a signal named as a clocking block ``output`` is driven
|
||||||
|
by a plain ``always`` block. Driving a signal from both a clocking block
|
||||||
|
and a plain ``always`` block is a deliberate idiom in some testbenches,
|
||||||
|
so it is reported as MULTIDRIVENPROC rather than under the on-by-default
|
||||||
|
:option:`MULTIDRIVEN`.
|
||||||
|
|
||||||
|
To fix, drive the signal from a single ``always`` block, or use
|
||||||
|
``always_ff``/``always_comb`` if the intent is a single specialized
|
||||||
|
process.
|
||||||
|
|
||||||
|
Does not warn for static variables used as loop induction variables:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_MULTIDRIVENPROC_loopidx.rst
|
||||||
|
|
||||||
|
|
||||||
.. option:: MULTITOP
|
.. option:: MULTITOP
|
||||||
|
|
||||||
.. TODO better example
|
.. TODO better example
|
||||||
@@ -1517,6 +1560,19 @@ List Of Warnings
|
|||||||
(neither :vlopt:`--timing` nor :vlopt:`--no-timing` option was provided).
|
(neither :vlopt:`--timing` nor :vlopt:`--no-timing` option was provided).
|
||||||
|
|
||||||
|
|
||||||
|
.. option:: NEVERMATCH
|
||||||
|
|
||||||
|
Warns that an SVA sequence is statically known to never match. Such a
|
||||||
|
sequence is legal SystemVerilog and is fully supported, the warning
|
||||||
|
only highlights a potential problem. For example, using the sequence as
|
||||||
|
the antecedent of an implication causes the implication to pass
|
||||||
|
vacuously. For an intersect sequence, ensure its operands can match
|
||||||
|
over a common length (IEEE 1800-2023 16.9.6).
|
||||||
|
|
||||||
|
Ignoring this warning will only suppress the lint check; it will
|
||||||
|
simulate correctly.
|
||||||
|
|
||||||
|
|
||||||
.. option:: NEWERSTD
|
.. option:: NEWERSTD
|
||||||
|
|
||||||
Warns that a feature requires a newer standard of Verilog or SystemVerilog
|
Warns that a feature requires a newer standard of Verilog or SystemVerilog
|
||||||
@@ -2089,6 +2145,32 @@ List Of Warnings
|
|||||||
simulators.
|
simulators.
|
||||||
|
|
||||||
|
|
||||||
|
.. option:: SIMILARNAME
|
||||||
|
|
||||||
|
Warns that an entity name only differs from another in lexical case.
|
||||||
|
|
||||||
|
Faulty example:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_SIMILARNAME_faulty.rst
|
||||||
|
|
||||||
|
Results in:
|
||||||
|
|
||||||
|
.. include:: ../../docs/gen/ex_SIMILARNAME_msg.rst
|
||||||
|
|
||||||
|
Only declarations that can reach a downstream VLSI tool as a name are
|
||||||
|
checked, that is nets, variables, instances, named blocks (``begin``,
|
||||||
|
``fork``, and generate blocks), functions and tasks. All of these can form
|
||||||
|
part of a flattened signal or scope name. Other declarations, such as
|
||||||
|
parameters, localparams, genvars and typedefs, are elaborated away, and so
|
||||||
|
are not checked.
|
||||||
|
|
||||||
|
Disabled by default as this is a code-style warning; it will simulate
|
||||||
|
correctly.
|
||||||
|
|
||||||
|
This is a warning as some downstream VLSI tools do
|
||||||
|
not distinguish net and gate names with the same case.
|
||||||
|
|
||||||
|
|
||||||
.. option:: SPECIFYIGN
|
.. option:: SPECIFYIGN
|
||||||
|
|
||||||
Warns that Verilator does not support certain constructs in
|
Warns that Verilator does not support certain constructs in
|
||||||
|
|||||||
+87
-71
@@ -425,8 +425,9 @@ logic.
|
|||||||
|
|
||||||
To achieve this, we invoke ``V3Order::order`` on all of the combinational
|
To achieve this, we invoke ``V3Order::order`` on all of the combinational
|
||||||
and hybrid logic, and iterate the resulting evaluation function until no
|
and hybrid logic, and iterate the resulting evaluation function until no
|
||||||
more hybrid logic is triggered. This yields the `_eval_settle` function,
|
more hybrid logic is triggered. This yields the `_eval_stl` function, which
|
||||||
which is invoked at the beginning of simulation after the `_eval_initial`.
|
the runtime event loop iterates at the beginning of simulation, after the
|
||||||
|
`_eval_initial`.
|
||||||
|
|
||||||
|
|
||||||
Partitioning logic for correct NBA updates
|
Partitioning logic for correct NBA updates
|
||||||
@@ -500,51 +501,66 @@ and clock signals on separate evaluations, as was necessary with earlier
|
|||||||
versions of Verilator).
|
versions of Verilator).
|
||||||
|
|
||||||
|
|
||||||
Constructing the top level `_eval` function
|
Constructing the region evaluation functions
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
To construct the top level `_eval` function, which updates the state of the
|
To update the state of the circuit to the end of the current time step, we
|
||||||
circuit to the end of the current time step, we invoke ``V3Order::order``
|
invoke ``V3Order::order`` separately on the 'ico', 'act' and 'nba' logic,
|
||||||
separately on the 'ico', 'act' and 'nba' logic, which yields the
|
which yields the `_eval_body__ico`, `_eval_body__act`, and
|
||||||
`_eval_ico`, `_eval_act`, and `_eval_nba` functions. We then put these all
|
`_eval_body__nba` functions. Each of these is then combined with the
|
||||||
together with the corresponding functions that compute the respective
|
function computing the respective trigger expressions into a single entry
|
||||||
trigger expressions into the top level `_eval` function, which on the high
|
point per region, `_eval_ico`, `_eval_act` and `_eval_nba`. A region entry
|
||||||
level has the form:
|
point evaluates one iteration of its region, and returns whether it did any
|
||||||
|
work, meaning the region has not converged yet and must be evaluated again.
|
||||||
|
On the high level, `_eval_act` has the form:
|
||||||
|
|
||||||
.. code-block:: C++
|
.. code-block:: C++
|
||||||
|
|
||||||
void _eval() {
|
bool _eval_act() {
|
||||||
// Update combinational logic dependent on top level inputs ('ico' region)
|
_eval_triggers_vec__act();
|
||||||
while (true) {
|
// Remember what 'act' triggers were active, 'nba' uses the same
|
||||||
_eval__triggers__ico();
|
latch_act_triggers_for_nba();
|
||||||
// If no 'ico' region trigger is active
|
const bool execute = act_triggers.any();
|
||||||
if (!ico_triggers.any()) break;
|
// Compute all derived clocks updated in the Active scheduling region,
|
||||||
_eval_ico();
|
// but do not commit any NBAs that executed in 'act' region logic.
|
||||||
}
|
if (execute) _eval_body__act();
|
||||||
|
return execute;
|
||||||
// Iterate 'act' and 'nba' regions together
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
// Iterate 'act' region, this computes all derived clocks updaed in the
|
|
||||||
// Active scheduling region, but does not commit any NBAs that executed
|
|
||||||
// in 'act' region logic.
|
|
||||||
while (true) {
|
|
||||||
_eval__triggers__act();
|
|
||||||
// If no 'act' region trigger is active
|
|
||||||
if (!act_triggers.any()) break;
|
|
||||||
// Remember what 'act' triggers were active, 'nba' uses the same
|
|
||||||
latch_act_triggers_for_nba();
|
|
||||||
_eval_act();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no 'nba' region trigger is active
|
|
||||||
if (!nba_triggers.any()) break;
|
|
||||||
|
|
||||||
// Evaluate all other Active region logic, and commit NBAs
|
|
||||||
_eval_nba();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
The loops iterating these regions are not generated. They live in the
|
||||||
|
runtime library, in ``VerilatedEvalLoop``, and the model exposes its region
|
||||||
|
entry points to it as virtual methods of ``VerilatedModel``. The generated
|
||||||
|
model holds a ``VerilatedEvalLoop`` as a member, which its ``eval_step``
|
||||||
|
runs, and which on the high level has the form:
|
||||||
|
|
||||||
|
.. code-block:: C++
|
||||||
|
|
||||||
|
void VerilatedEvalLoop::evalImpl() {
|
||||||
|
// Update combinational logic dependent on top level inputs ('ico' region)
|
||||||
|
uint32_t icoIterCount = 0;
|
||||||
|
do {
|
||||||
|
if (++icoIterCount > m_convergeLimit) didNotConverge("Input combinational");
|
||||||
|
} while (m_model.evalIco(icoIterCount == 1));
|
||||||
|
|
||||||
|
// Iterate 'act' and 'nba' regions together
|
||||||
|
uint32_t nbaIterCount = 0;
|
||||||
|
do {
|
||||||
|
if (++nbaIterCount > m_convergeLimit) didNotConverge("NBA");
|
||||||
|
// Iterate the 'act' region to convergence
|
||||||
|
uint32_t actIterCount = 0;
|
||||||
|
do {
|
||||||
|
if (++actIterCount > m_convergeLimit) didNotConverge("Active");
|
||||||
|
} while (m_model.evalAct());
|
||||||
|
// Evaluate all other Active region logic, and commit NBAs
|
||||||
|
} while (m_model.evalNba());
|
||||||
|
}
|
||||||
|
|
||||||
|
The remaining regions ('inact', 'obs' and 'react') nest around these in the
|
||||||
|
same manner, each iterating the loops of all regions that precede it in the
|
||||||
|
SystemVerilog scheduling order. The runtime event loop calls every region
|
||||||
|
unconditionally, so scheduling emits an entry point for each one even when
|
||||||
|
the design has no logic in it. Such an entry point immediately returns
|
||||||
|
false, ending its loop after a single iteration.
|
||||||
|
|
||||||
Timing
|
Timing
|
||||||
------
|
------
|
||||||
@@ -730,7 +746,8 @@ they wouldn't be evaluated and next coroutine after resumption would fire
|
|||||||
the event `a` then it is impossible to get to know whether await or fire on
|
the event `a` then it is impossible to get to know whether await or fire on
|
||||||
event `a` was called first - which is necessary to know.
|
event `a` was called first - which is necessary to know.
|
||||||
|
|
||||||
There are two functions for managing timing logic called by ``_eval()``:
|
There are two functions for managing timing logic called by the 'act'
|
||||||
|
region:
|
||||||
|
|
||||||
- ``_timing_ready()``, which commits all coroutines whose triggers were not
|
- ``_timing_ready()``, which commits all coroutines whose triggers were not
|
||||||
set in the current iteration,
|
set in the current iteration,
|
||||||
@@ -751,36 +768,27 @@ Thanks to this separation a coroutine:
|
|||||||
(``test_regress/t/t_event_control_double_lost.v``) - which is possible
|
(``test_regress/t/t_event_control_double_lost.v``) - which is possible
|
||||||
when triggers are not evaluated right before awaiting.
|
when triggers are not evaluated right before awaiting.
|
||||||
|
|
||||||
All coroutines are committed and resumed in the 'act' eval loop. With
|
All coroutines are committed and resumed in the 'act' region. With timing
|
||||||
timing features enabled, the ``_eval()`` function takes this form:
|
features enabled, the 'act' region entry point takes this form:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
void _eval() {
|
bool _eval_act() {
|
||||||
while (true) {
|
_eval_triggers_vec__act();
|
||||||
_eval__triggers__ico();
|
|
||||||
if (!ico_triggers.any()) break;
|
// Commit all non-triggered coroutines
|
||||||
_eval_ico();
|
_timing_commit();
|
||||||
}
|
|
||||||
|
const bool execute = act_triggers.any();
|
||||||
while (true) {
|
if (execute) {
|
||||||
while (true) {
|
latch_act_triggers_for_nba();
|
||||||
_eval__triggers__act();
|
|
||||||
|
// Resume all triggered coroutines
|
||||||
// Commit all non-triggered coroutines
|
_timing_resume();
|
||||||
_timing_commit();
|
|
||||||
|
_eval_body__act();
|
||||||
if (!act_triggers.any()) break;
|
|
||||||
latch_act_triggers_for_nba();
|
|
||||||
|
|
||||||
// Resume all triggered coroutines
|
|
||||||
_timing_resume();
|
|
||||||
|
|
||||||
_eval_act();
|
|
||||||
}
|
|
||||||
if (!nba_triggers.any()) break;
|
|
||||||
_eval_nba();
|
|
||||||
}
|
}
|
||||||
|
return execute;
|
||||||
}
|
}
|
||||||
|
|
||||||
Forks
|
Forks
|
||||||
@@ -1082,9 +1090,17 @@ solver gets a setup query, then the definition of variables, then all the
|
|||||||
constraints (SMT assertions) about the variables. Since the solver has no
|
constraints (SMT assertions) about the variables. Since the solver has no
|
||||||
information about the class' PRNG state, if the problem is satisfiable, the
|
information about the class' PRNG state, if the problem is satisfiable, the
|
||||||
solution space is further constrained by adding extra random constraints,
|
solution space is further constrained by adding extra random constraints,
|
||||||
and querying the values satisfying the problem statement. The constraint is
|
and querying the values satisfying the problem statement. The constraints
|
||||||
currently constructed as fixing a simple xor of randomly chosen bits of the
|
are currently built by the UniGen2 algorithm ("On Parallel Scalable Uniform
|
||||||
variables being randomized.
|
SAT Witness Generation", Chakraborty et al.). It first works out how many
|
||||||
|
random xor equations are needed to split the solution space into cells of a
|
||||||
|
size worth enumerating, then draws one cell and enumerates it, which gives
|
||||||
|
a near-uniform sample of the whole space. Both the estimate and the
|
||||||
|
leftover solutions are cached, so the following calls are answered without
|
||||||
|
asking the solver again. Cases outside its assumptions, such as ``randc``
|
||||||
|
variables or soft constraints, fall back to pinning every free bit to a
|
||||||
|
random value, or, when arrays are involved, to asserting four random xor
|
||||||
|
equations in a row.
|
||||||
|
|
||||||
The runtime classes used for handling the randomization are defined in
|
The runtime classes used for handling the randomization are defined in
|
||||||
``verilated_random.h`` and ``verilated_random.cpp``.
|
``verilated_random.h`` and ``verilated_random.cpp``.
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ Bagri
|
|||||||
Balboni
|
Balboni
|
||||||
Baltazar
|
Baltazar
|
||||||
Bardsley
|
Bardsley
|
||||||
|
Barua
|
||||||
Benchmarking
|
Benchmarking
|
||||||
Berman
|
Berman
|
||||||
Bhagavatula
|
Bhagavatula
|
||||||
@@ -198,6 +199,7 @@ Holme
|
|||||||
Homebrew
|
Homebrew
|
||||||
Hornung
|
Hornung
|
||||||
Hossell
|
Hossell
|
||||||
|
Hsieh
|
||||||
Hsu
|
Hsu
|
||||||
Huggett
|
Huggett
|
||||||
Hutt
|
Hutt
|
||||||
@@ -389,6 +391,7 @@ Preprocess
|
|||||||
Pretet
|
Pretet
|
||||||
Pretl
|
Pretl
|
||||||
Pringlemeir
|
Pringlemeir
|
||||||
|
Prithayan
|
||||||
Priyadharshini
|
Priyadharshini
|
||||||
Pullup
|
Pullup
|
||||||
Pulver
|
Pulver
|
||||||
@@ -477,6 +480,7 @@ Syms
|
|||||||
Synopsys
|
Synopsys
|
||||||
SystemC
|
SystemC
|
||||||
SystemVerilog
|
SystemVerilog
|
||||||
|
Szpotanski
|
||||||
Takatsukasa
|
Takatsukasa
|
||||||
Tambe
|
Tambe
|
||||||
Tarik
|
Tarik
|
||||||
@@ -512,6 +516,7 @@ Ueno
|
|||||||
Uints
|
Uints
|
||||||
Undefine
|
Undefine
|
||||||
Undefines
|
Undefines
|
||||||
|
Unigen
|
||||||
Unsized
|
Unsized
|
||||||
Uppal
|
Uppal
|
||||||
Urbach
|
Urbach
|
||||||
@@ -537,6 +542,7 @@ Verilog
|
|||||||
Vighnesh
|
Vighnesh
|
||||||
Viktor
|
Viktor
|
||||||
Vilp
|
Vilp
|
||||||
|
VlRNG
|
||||||
VlWide
|
VlWide
|
||||||
Vlip
|
Vlip
|
||||||
Vm
|
Vm
|
||||||
@@ -644,6 +650,7 @@ casez
|
|||||||
casted
|
casted
|
||||||
castro
|
castro
|
||||||
cb
|
cb
|
||||||
|
cbValueChange
|
||||||
ccache
|
ccache
|
||||||
ccall
|
ccall
|
||||||
cdc
|
cdc
|
||||||
@@ -707,6 +714,7 @@ de
|
|||||||
dearray
|
dearray
|
||||||
deassign
|
deassign
|
||||||
debugi
|
debugi
|
||||||
|
deduplication
|
||||||
defenv
|
defenv
|
||||||
defname
|
defname
|
||||||
defparam
|
defparam
|
||||||
@@ -947,6 +955,7 @@ misconnected
|
|||||||
misconversion
|
misconversion
|
||||||
misdetecting
|
misdetecting
|
||||||
misoptimized
|
misoptimized
|
||||||
|
misoptimizing
|
||||||
missized
|
missized
|
||||||
mk
|
mk
|
||||||
mno
|
mno
|
||||||
@@ -995,6 +1004,7 @@ noprivate
|
|||||||
noreturn
|
noreturn
|
||||||
notif
|
notif
|
||||||
nullptr
|
nullptr
|
||||||
|
num
|
||||||
numactl
|
numactl
|
||||||
onehot
|
onehot
|
||||||
ooo
|
ooo
|
||||||
@@ -1174,6 +1184,7 @@ tcmalloc
|
|||||||
tcmalloc
|
tcmalloc
|
||||||
tenghtt
|
tenghtt
|
||||||
testbench
|
testbench
|
||||||
|
testbenches
|
||||||
threadsafe
|
threadsafe
|
||||||
threashold
|
threashold
|
||||||
timeInc
|
timeInc
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ static inline constexpr unsigned bitPerEncodedBit(EncodingType type) {
|
|||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
static const char* kEncodedBitToCharTable = (
|
static const char* kEncodedBitToCharTable = (
|
||||||
"01" // Binary
|
"01" // Binary
|
||||||
"xzhu" // Verilog
|
"zxhu" // Verilog
|
||||||
"wl-? " // Vhdl (padded with ' ')
|
"wl-? " // Vhdl (padded with ' ')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -423,18 +423,26 @@ public:
|
|||||||
|
|
||||||
void emitValueChange(uint64_t current_time_index, const uint32_t *val, EncodingType encoding) {
|
void emitValueChange(uint64_t current_time_index, const uint32_t *val, EncodingType encoding) {
|
||||||
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
|
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
|
||||||
for (unsigned i = 0; i < bitPerEncodedBit(encoding); ++i) {
|
// C++17: replace this with if constexpr
|
||||||
// C++17: replace this with if constexpr
|
if (sizeof(T) == 8) {
|
||||||
if (sizeof(T) == 8) {
|
if (encoding == EncodingType::VERILOG) {
|
||||||
|
uint64_t v = val[2]; // high bits
|
||||||
|
v <<= 32;
|
||||||
|
v |= val[0]; // low bits
|
||||||
|
wh.template write<uint64_t>(v);
|
||||||
|
v = val[3]; // high bits
|
||||||
|
v <<= 32;
|
||||||
|
v |= val[1]; // low bits
|
||||||
|
wh.template write<uint64_t>(v);
|
||||||
|
} else {
|
||||||
uint64_t v = val[1]; // high bits
|
uint64_t v = val[1]; // high bits
|
||||||
v <<= 32;
|
v <<= 32;
|
||||||
v |= val[0]; // low bits
|
v |= val[0]; // low bits
|
||||||
wh.template write<uint64_t>(v);
|
wh.template write<uint64_t>(v);
|
||||||
val += 2;
|
|
||||||
} else {
|
|
||||||
wh.template write<T>(val[0]);
|
|
||||||
val += 1;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
wh.template write<T>(val[0]);
|
||||||
|
if (encoding == EncodingType::VERILOG) wh.template write<T>(val[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,7 +525,7 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
unsigned val = 0;
|
unsigned val = 0;
|
||||||
for (unsigned i = 0; i < num_element; ++i) {
|
for (unsigned i = 0; i < num_element; ++i) {
|
||||||
val |= rh.peek<T>(i);
|
val |= rh.peek<T>(i) << i;
|
||||||
}
|
}
|
||||||
uint64_t delta_time_index = time_index - prev_time_index;
|
uint64_t delta_time_index = time_index - prev_time_index;
|
||||||
prev_time_index = time_index;
|
prev_time_index = time_index;
|
||||||
@@ -525,8 +533,8 @@ public:
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
case 0: delta_time_index = (delta_time_index<<2) | (0<<1) | 0; break; // '0'
|
case 0: delta_time_index = (delta_time_index<<2) | (0<<1) | 0; break; // '0'
|
||||||
case 1: delta_time_index = (delta_time_index<<2) | (1<<1) | 0; break; // '1'
|
case 1: delta_time_index = (delta_time_index<<2) | (1<<1) | 0; break; // '1'
|
||||||
case 2: delta_time_index = (delta_time_index<<4) | (0<<1) | 1; break; // 'X'
|
case 2: delta_time_index = (delta_time_index<<4) | (1<<1) | 1; break; // 'Z'
|
||||||
case 3: delta_time_index = (delta_time_index<<4) | (1<<1) | 1; break; // 'Z'
|
case 3: delta_time_index = (delta_time_index<<4) | (0<<1) | 1; break; // 'X'
|
||||||
// Not supporting VHDL now
|
// Not supporting VHDL now
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
case 4: delta_time_index = (delta_time_index<<4) | (2<<1) | 1; break; // 'H'
|
case 4: delta_time_index = (delta_time_index<<4) | (2<<1) | 1; break; // 'H'
|
||||||
@@ -556,13 +564,29 @@ public:
|
|||||||
if (first) {
|
if (first) {
|
||||||
first = false;
|
first = false;
|
||||||
} else {
|
} else {
|
||||||
FST_CHECK(enc == EncodingType::BINARY); // TODO
|
|
||||||
const bool has_non_binary = enc != EncodingType::BINARY;
|
|
||||||
const uint64_t delta_time_index = time_index - prev_time_index;
|
const uint64_t delta_time_index = time_index - prev_time_index;
|
||||||
prev_time_index = time_index;
|
prev_time_index = time_index;
|
||||||
h //
|
switch (enc) {
|
||||||
.writeLEB128((delta_time_index << 1) | has_non_binary)
|
case EncodingType::BINARY: {
|
||||||
.writeUIntPartialForValueChange(rh.peek<T>(), bitwidth);
|
h //
|
||||||
|
.writeLEB128(delta_time_index << 1)
|
||||||
|
.writeUIntPartialForValueChange(rh.peek<T>(), bitwidth);
|
||||||
|
} break;
|
||||||
|
case EncodingType::VERILOG: {
|
||||||
|
h.writeLEB128((delta_time_index << 1) | 1);
|
||||||
|
const T val = rh.peek<T>();
|
||||||
|
const T xz = rh.peek<T>(1);
|
||||||
|
for (int j = bitwidth; j > 0;) {
|
||||||
|
--j;
|
||||||
|
h.writeUIntBE(
|
||||||
|
kEncodedBitToCharTable[(((xz >> j) << 1) & 2) | ((val >> j) & 1)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
[[unlikely]] case EncodingType::VHDL: {
|
||||||
|
FST_FAIL_STRING("VHDL format is unsupported with wide values");
|
||||||
|
} break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rh.skip(num_byte);
|
rh.skip(num_byte);
|
||||||
}
|
}
|
||||||
@@ -573,16 +597,26 @@ public:
|
|||||||
class VariableInfoLongInt {
|
class VariableInfoLongInt {
|
||||||
VariableInfo &info;
|
VariableInfo &info;
|
||||||
unsigned num_words() const { return (info.bitwidth() + 63) / 64; }
|
unsigned num_words() const { return (info.bitwidth() + 63) / 64; }
|
||||||
|
unsigned num_words32() const { return (info.bitwidth() + 31) / 32; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VariableInfoLongInt(VariableInfo &info_) : info(info_) {}
|
VariableInfoLongInt(VariableInfo &info_) : info(info_) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
size_t computeBytesNeededNoHeader(EncodingType encoding) const {
|
||||||
|
switch (encoding) {
|
||||||
|
case EncodingType::BINARY:
|
||||||
|
return num_words() * sizeof(uint64_t);
|
||||||
|
case EncodingType::VERILOG:
|
||||||
|
return num_words32() * sizeof(uint32_t) * 2;
|
||||||
|
[[unlikely]] case EncodingType::VHDL:
|
||||||
|
FST_FAIL_STRING("VHDL format is unsupported with wide values");
|
||||||
|
}
|
||||||
|
FST_UNREACHABLE;
|
||||||
|
}
|
||||||
|
|
||||||
size_t computeBytesNeeded(EncodingType encoding) const {
|
size_t computeBytesNeeded(EncodingType encoding) const {
|
||||||
return (
|
return kEmitTimeIndexAndEncodingSize + computeBytesNeededNoHeader(encoding);
|
||||||
kEmitTimeIndexAndEncodingSize +
|
|
||||||
num_words() * sizeof(uint64_t) * bitPerEncodedBit(encoding)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitWriterHelper emitValueChangeCommonPart(uint64_t current_time_index, EncodingType encoding) {
|
EmitWriterHelper emitValueChangeCommonPart(uint64_t current_time_index, EncodingType encoding) {
|
||||||
@@ -600,13 +634,12 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void construct() {
|
void construct() {
|
||||||
const size_t nw = num_words();
|
const size_t nw = num_words32();
|
||||||
info.resize(computeBytesNeeded(EncodingType::VERILOG));
|
info.resize(computeBytesNeeded(EncodingType::VERILOG));
|
||||||
EmitWriterHelper wh(info.data_ptr());
|
EmitWriterHelper wh(info.data_ptr());
|
||||||
wh //
|
wh //
|
||||||
.writeTimeIndexAndEncoding(0, EncodingType::VERILOG)
|
.writeTimeIndexAndEncoding(0, EncodingType::VERILOG)
|
||||||
.fill(uint64_t(0), nw)
|
.fill(static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) << 32, nw);
|
||||||
.fill(uint64_t(-1), nw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitValueChange(uint64_t current_time_index, const uint64_t val) {
|
void emitValueChange(uint64_t current_time_index, const uint64_t val) {
|
||||||
@@ -616,12 +649,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void emitValueChange(uint64_t current_time_index, const uint32_t *val, EncodingType encoding) {
|
void emitValueChange(uint64_t current_time_index, const uint32_t *val, EncodingType encoding) {
|
||||||
const unsigned nw32 = (info.bitwidth() + 31) / 32;
|
const unsigned nw32 = num_words32();
|
||||||
const unsigned bpb = bitPerEncodedBit(encoding);
|
|
||||||
|
|
||||||
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
|
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
|
||||||
|
|
||||||
for (unsigned i = 0; i < bpb; ++i) {
|
switch (encoding) {
|
||||||
|
case EncodingType::BINARY: {
|
||||||
for (unsigned j = 0; j < nw32 / 2; ++j) {
|
for (unsigned j = 0; j < nw32 / 2; ++j) {
|
||||||
uint64_t v = val[1]; // high bits
|
uint64_t v = val[1]; // high bits
|
||||||
v <<= 32;
|
v <<= 32;
|
||||||
@@ -634,13 +667,25 @@ public:
|
|||||||
wh.write(v);
|
wh.write(v);
|
||||||
val += 1;
|
val += 1;
|
||||||
}
|
}
|
||||||
|
} break;
|
||||||
|
case EncodingType::VERILOG: {
|
||||||
|
for (unsigned j = 0; j < nw32; ++j) {
|
||||||
|
uint64_t v = val[1]; // high bits
|
||||||
|
v <<= 32;
|
||||||
|
v |= val[0]; // low bits
|
||||||
|
wh.write(v);
|
||||||
|
val += 2;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
[[unlikely]] case EncodingType::VHDL:
|
||||||
|
FST_FAIL_STRING("VHDL format is unsupported with wide values");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitValueChange(uint64_t current_time_index, const uint64_t *val, EncodingType encoding) {
|
void emitValueChange(uint64_t current_time_index, const uint64_t *val, EncodingType encoding) {
|
||||||
const unsigned nw_encoded = num_words() * bitPerEncodedBit(encoding);
|
|
||||||
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
|
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
|
||||||
wh.write(val, nw_encoded);
|
FST_CHECK(encoding == EncodingType::BINARY);
|
||||||
|
wh.write(val, num_words());
|
||||||
}
|
}
|
||||||
|
|
||||||
void dumpInitialBits(std::vector<uint8_t> &buf) const {
|
void dumpInitialBits(std::vector<uint8_t> &buf) const {
|
||||||
@@ -663,15 +708,16 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EncodingType::VERILOG: {
|
case EncodingType::VERILOG: {
|
||||||
for (unsigned word_index = nw; word_index-- > 0;) {
|
for (unsigned word_index = num_words32(); word_index-- > 0;) {
|
||||||
const uint64_t v0 = rh.peek<uint64_t>(nw * 0 + word_index);
|
const uint64_t val = rh.peek<uint64_t>(word_index);
|
||||||
const uint64_t v1 = rh.peek<uint64_t>(nw * 1 + word_index);
|
const uint32_t aval = static_cast<uint32_t>(val);
|
||||||
|
const uint32_t bval = static_cast<uint32_t>(val >> 32);
|
||||||
const unsigned num_bit =
|
const unsigned num_bit =
|
||||||
(word_index * 64 + 64 > info.bitwidth()) ? (info.bitwidth() % 64) : 64;
|
(word_index * 32 + 32 > info.bitwidth()) ? (info.bitwidth() % 32) : 32;
|
||||||
for (unsigned bit_index = num_bit; bit_index-- > 0;) {
|
for (unsigned bit_index = num_bit; bit_index-- > 0;) {
|
||||||
const bool b0 = ((v0 >> bit_index) & uint64_t(1));
|
const bool a = ((aval >> bit_index) & 1);
|
||||||
const bool b1 = ((v1 >> bit_index) & uint64_t(1));
|
const bool b = ((bval >> bit_index) & 1);
|
||||||
const char c = kEncodedBitToCharTable[(b1 << 1) | b0];
|
const char c = kEncodedBitToCharTable[(b << 1) | a];
|
||||||
buf.push_back(c);
|
buf.push_back(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -717,33 +763,58 @@ public:
|
|||||||
FST_DCHECK_GT(tail, rh.ptr);
|
FST_DCHECK_GT(tail, rh.ptr);
|
||||||
const auto time_index = rh.read<uint64_t>();
|
const auto time_index = rh.read<uint64_t>();
|
||||||
const auto enc = rh.read<EncodingType>();
|
const auto enc = rh.read<EncodingType>();
|
||||||
const auto num_element = bitPerEncodedBit(enc);
|
const auto num_byte = computeBytesNeededNoHeader(enc);
|
||||||
const auto num_byte = num_element * nw * sizeof(uint64_t);
|
|
||||||
if (first) {
|
if (first) {
|
||||||
// Note: [0] is initial value, which is already dumped in dumpInitialBits()
|
// Note: [0] is initial value, which is already dumped in dumpInitialBits()
|
||||||
first = false;
|
first = false;
|
||||||
} else {
|
} else {
|
||||||
FST_CHECK(enc == EncodingType::BINARY); // TODO
|
|
||||||
const bool has_non_binary = enc != EncodingType::BINARY;
|
|
||||||
const uint64_t delta_time_index = time_index - prev_time_index;
|
const uint64_t delta_time_index = time_index - prev_time_index;
|
||||||
prev_time_index = time_index;
|
prev_time_index = time_index;
|
||||||
h.writeLEB128((delta_time_index << 1) | has_non_binary);
|
switch (enc) {
|
||||||
if (bitwidth % 64 != 0) {
|
case EncodingType::BINARY: {
|
||||||
const unsigned remaining = bitwidth % 64;
|
h.writeLEB128((delta_time_index << 1));
|
||||||
uint64_t hi64 = rh.peek<uint64_t>(nw - 1);
|
if (bitwidth % 64 != 0) {
|
||||||
// write from nw-1 to 1
|
const unsigned remaining = bitwidth % 64;
|
||||||
for (unsigned j = nw - 1; j > 0; --j) {
|
uint64_t hi64 = rh.peek<uint64_t>(nw - 1);
|
||||||
uint64_t lo64 = rh.peek<uint64_t>(j - 1);
|
// write from nw-1 to 1
|
||||||
h.writeUIntBE((hi64 << (64 - remaining)) | (lo64 >> remaining));
|
for (unsigned j = nw - 1; j > 0; --j) {
|
||||||
hi64 = lo64;
|
uint64_t lo64 = rh.peek<uint64_t>(j - 1);
|
||||||
|
h.writeUIntBE((hi64 << (64 - remaining)) | (lo64 >> remaining));
|
||||||
|
hi64 = lo64;
|
||||||
|
}
|
||||||
|
// write 0
|
||||||
|
h.writeUIntPartialForValueChange(hi64, remaining);
|
||||||
|
} else {
|
||||||
|
// write from nw-1 to 0
|
||||||
|
for (unsigned j = nw; j-- > 0;) {
|
||||||
|
h.writeUIntBE(rh.peek<uint64_t>(j));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// write 0
|
} break;
|
||||||
h.writeUIntPartialForValueChange(hi64, remaining);
|
case EncodingType::VERILOG: {
|
||||||
} else {
|
h.writeLEB128((delta_time_index << 1) | 1);
|
||||||
// write from nw-1 to 0
|
const int fullWords = (bitwidth / 32);
|
||||||
for (unsigned j = nw; j-- > 0;) {
|
if (int j = bitwidth % 32) {
|
||||||
h.writeUIntBE(rh.peek<uint64_t>(j));
|
const uint64_t val = rh.peek<uint64_t>(fullWords);
|
||||||
|
while (j > 0) {
|
||||||
|
--j;
|
||||||
|
const uint64_t v = val >> j;
|
||||||
|
h.writeUIntBE(kEncodedBitToCharTable[((v >> 31) & 2) | (v & 1)]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
for (size_t i = fullWords; i > 0;) {
|
||||||
|
--i;
|
||||||
|
const uint64_t val = rh.peek<uint64_t>(i);
|
||||||
|
for (int j = 32; j > 0;) {
|
||||||
|
--j;
|
||||||
|
const uint64_t v = val >> j;
|
||||||
|
h.writeUIntBE(kEncodedBitToCharTable[((v >> 31) & 2) | (v & 1)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
[[unlikely]] case EncodingType::VHDL: {
|
||||||
|
FST_FAIL_STRING("VHDL format is unsupported with wide values");
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rh.skip(num_byte);
|
rh.skip(num_byte);
|
||||||
|
|||||||
@@ -268,26 +268,55 @@ void Writer::emitValueChange(Handle handle, const char *val) {
|
|||||||
|
|
||||||
// For normal integer handles, const char* is "01xz..." (1B per bit)
|
// For normal integer handles, const char* is "01xz..." (1B per bit)
|
||||||
const uint32_t bitwidth{var_info.bitwidth()};
|
const uint32_t bitwidth{var_info.bitwidth()};
|
||||||
|
const bool hasXZ = // Detects A-Z and a-z but not 0-9 and NOT `-` `?`
|
||||||
|
(std::accumulate(val, val + bitwidth, 0, [](int a, char b) { return a | b; }) & (1 << 6)) !=
|
||||||
|
0;
|
||||||
FST_DCHECK_NE(bitwidth, 0);
|
FST_DCHECK_NE(bitwidth, 0);
|
||||||
|
|
||||||
val += bitwidth;
|
val += bitwidth;
|
||||||
const unsigned num_words{(bitwidth + 63) / 64};
|
const unsigned num_words{(bitwidth + 63) / 64};
|
||||||
m_packed_value_buffer_.assign(num_words, 0);
|
m_packed_value_buffer_.assign(num_words << (hasXZ ? 1 : 0), 0);
|
||||||
for (unsigned i = 0; i < num_words; ++i) {
|
for (unsigned i = 0; i < num_words; ++i) {
|
||||||
const char *start{val - std::min((i + 1) * 64, bitwidth)};
|
const char *start{val - std::min((i + 1) * 64, bitwidth)};
|
||||||
const char *end{val - 64 * i};
|
const char *end{val - 64 * i};
|
||||||
m_packed_value_buffer_[i] = 0;
|
m_packed_value_buffer_[i] = 0;
|
||||||
for (const char *p = start; p < end; ++p) {
|
for (const char *p = start; p < end; ++p) {
|
||||||
// No checking for invalid characters, follow original C implementation
|
// No checking for invalid characters, follow original C implementation
|
||||||
m_packed_value_buffer_[i] <<= 1;
|
if (hasXZ) {
|
||||||
m_packed_value_buffer_[i] |= static_cast<uint64_t>(*p - '0');
|
const size_t j = i << 1;
|
||||||
|
m_packed_value_buffer_[j] <<= 1;
|
||||||
|
m_packed_value_buffer_[j | 1] <<= 1;
|
||||||
|
switch (*p) {
|
||||||
|
case '0':
|
||||||
|
break;
|
||||||
|
case '1': {
|
||||||
|
m_packed_value_buffer_[i] |= 1;
|
||||||
|
} break;
|
||||||
|
case 'X':
|
||||||
|
case 'x': {
|
||||||
|
m_packed_value_buffer_[i] |= 1;
|
||||||
|
} // FALLTHROUGH
|
||||||
|
case 'Z':
|
||||||
|
case 'z': {
|
||||||
|
m_packed_value_buffer_[j | 1] |= 1;
|
||||||
|
} break;
|
||||||
|
[[unlikely]] default: { FST_FAIL_STRING("Unexpected char"); } break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_packed_value_buffer_[i] <<= 1;
|
||||||
|
m_packed_value_buffer_[i] |= static_cast<uint64_t>(*p - '0');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bitwidth <= 64) {
|
if (bitwidth <= 64 && !hasXZ) {
|
||||||
emitValueChange(handle, m_packed_value_buffer_.front());
|
emitValueChange(handle, m_packed_value_buffer_.front());
|
||||||
} else {
|
} else {
|
||||||
emitValueChange(handle, m_packed_value_buffer_.data(), EncodingType::BINARY);
|
emitValueChange(
|
||||||
|
handle,
|
||||||
|
m_packed_value_buffer_.data(),
|
||||||
|
hasXZ ? EncodingType::VERILOG : EncodingType::BINARY
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -605,7 +634,7 @@ void detail::ValueChangeData::writeEncodedPositions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// encode as signed (value << 1) | 1 and write as signed LEB128
|
// encode as signed (value << 1) | 1 and write as signed LEB128
|
||||||
h.writeLEB128Signed((value_to_encode << 1) | 1);
|
h.writeLEB128Signed((static_cast<uint64_t>(value_to_encode) << 1) | 1);
|
||||||
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
@@ -695,7 +724,7 @@ void Writer::flushValueChangeDataConstPart_(
|
|||||||
(void)count;
|
(void)count;
|
||||||
return std::make_pair(positions, memory_usage);
|
return std::make_pair(positions, memory_usage);
|
||||||
}();
|
}();
|
||||||
const std::vector<int64_t> positions{p_tmp2.first};
|
const std::vector<int64_t> positions{std::move(p_tmp2.first)};
|
||||||
const size_t memory_usage{p_tmp2.second};
|
const size_t memory_usage{p_tmp2.second};
|
||||||
|
|
||||||
// 4. Position Section
|
// 4. Position Section
|
||||||
|
|||||||
+202
-32
@@ -243,20 +243,32 @@ void vl_warn(const char* filename, int linenum, const char* hier, const char* ms
|
|||||||
// Wrapper to call certain functions via messages when multithreaded
|
// Wrapper to call certain functions via messages when multithreaded
|
||||||
|
|
||||||
void VL_FINISH_MT(const char* filename, int linenum, const char* hier) VL_MT_SAFE {
|
void VL_FINISH_MT(const char* filename, int linenum, const char* hier) VL_MT_SAFE {
|
||||||
|
VerilatedContext* const contextp = Verilated::threadContextp();
|
||||||
|
contextp->finishPendingInc();
|
||||||
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
|
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
|
||||||
vl_finish(filename, linenum, hier);
|
vl_finish(filename, linenum, hier);
|
||||||
|
contextp->finishPendingDec();
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VL_STOP_MT(const char* filename, int linenum, const char* hier, bool maybe) VL_MT_SAFE {
|
void VL_STOP_MT(const char* filename, int linenum, const char* hier, bool maybe) VL_MT_SAFE {
|
||||||
|
// Classify now, so a queued request is pending from the moment it is posted
|
||||||
|
VerilatedContext* const contextp = Verilated::threadContextp();
|
||||||
|
const bool stop = contextp->stopRequestReserve(maybe);
|
||||||
|
if (stop) contextp->finishPendingInc();
|
||||||
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
|
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
|
||||||
vl_stop_maybe(filename, linenum, hier, maybe);
|
vl_stop_maybe(filename, linenum, hier, maybe);
|
||||||
|
contextp->stopRequestRelease();
|
||||||
|
if (stop) contextp->finishPendingDec();
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_SAFE {
|
void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_SAFE {
|
||||||
|
VerilatedContext* const contextp = Verilated::threadContextp();
|
||||||
|
contextp->finishPendingInc();
|
||||||
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
|
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
|
||||||
vl_fatal(filename, linenum, hier, msg);
|
vl_fatal(filename, linenum, hier, msg);
|
||||||
|
contextp->finishPendingDec();
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,9 +575,10 @@ IData VL_URANDOM_SEEDED_II(IData seed) VL_MT_SAFE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IData VL_SCOPED_RAND_RESET_I(int obits, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE {
|
IData VL_SCOPED_RAND_RESET_I(int obits, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE {
|
||||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
const int randReset = Verilated::threadContextp()->randReset();
|
||||||
|
if (randReset == 0) return 0;
|
||||||
IData data = ~0;
|
IData data = ~0;
|
||||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
if (randReset != 1) { // if 2, randomize
|
||||||
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
||||||
data = rng.rand64();
|
data = rng.rand64();
|
||||||
}
|
}
|
||||||
@@ -574,9 +587,10 @@ IData VL_SCOPED_RAND_RESET_I(int obits, uint64_t scopeHash, uint64_t salt) VL_MT
|
|||||||
}
|
}
|
||||||
|
|
||||||
QData VL_SCOPED_RAND_RESET_Q(int obits, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE {
|
QData VL_SCOPED_RAND_RESET_Q(int obits, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE {
|
||||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
const int randReset = Verilated::threadContextp()->randReset();
|
||||||
|
if (randReset == 0) return 0;
|
||||||
QData data = ~0ULL;
|
QData data = ~0ULL;
|
||||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
if (randReset != 1) { // if 2, randomize
|
||||||
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
||||||
data = rng.rand64();
|
data = rng.rand64();
|
||||||
}
|
}
|
||||||
@@ -586,10 +600,17 @@ QData VL_SCOPED_RAND_RESET_Q(int obits, uint64_t scopeHash, uint64_t salt) VL_MT
|
|||||||
|
|
||||||
WDataOutP VL_SCOPED_RAND_RESET_W(int obits, WDataOutP outwp, uint64_t scopeHash,
|
WDataOutP VL_SCOPED_RAND_RESET_W(int obits, WDataOutP outwp, uint64_t scopeHash,
|
||||||
uint64_t salt) VL_MT_UNSAFE {
|
uint64_t salt) VL_MT_UNSAFE {
|
||||||
if (Verilated::threadContextp()->randReset() != 2) { return VL_RAND_RESET_W(obits, outwp); }
|
const int words = VL_WORDS_I(obits);
|
||||||
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
const int randReset = Verilated::threadContextp()->randReset();
|
||||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = rng.rand64();
|
if (randReset == 0) {
|
||||||
outwp[VL_WORDS_I(obits) - 1] = rng.rand64() & VL_MASK_E(obits);
|
VL_MEMSET_ZERO_W(outwp, words);
|
||||||
|
} else if (randReset == 1) {
|
||||||
|
VL_MEMSET_ONES_W(outwp, words);
|
||||||
|
} else {
|
||||||
|
VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt};
|
||||||
|
for (int i = 0; i < words; ++i) outwp[i] = rng.rand64();
|
||||||
|
}
|
||||||
|
outwp[words - 1] &= VL_MASK_E(obits);
|
||||||
return outwp;
|
return outwp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,30 +635,14 @@ WDataOutP VL_SCOPED_RAND_RESET_ASSIGN_W(int obits, WDataOutP outwp, uint64_t sco
|
|||||||
}
|
}
|
||||||
|
|
||||||
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
||||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
const int randReset = Verilated::threadContextp()->randReset();
|
||||||
|
if (randReset == 0) return 0;
|
||||||
IData data = ~0;
|
IData data = ~0;
|
||||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
if (randReset != 1) data = VL_RANDOM_I(); // if 2, randomize
|
||||||
data = VL_RANDOM_I();
|
|
||||||
}
|
|
||||||
data &= VL_MASK_I(obits);
|
data &= VL_MASK_I(obits);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
|
|
||||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
|
||||||
QData data = ~0ULL;
|
|
||||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
|
||||||
data = VL_RANDOM_Q();
|
|
||||||
}
|
|
||||||
data &= VL_MASK_Q(obits);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
|
||||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = VL_RAND_RESET_I(32);
|
|
||||||
outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_I(32) & VL_MASK_E(obits);
|
|
||||||
return outwp;
|
|
||||||
}
|
|
||||||
WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||||
// Not inlined to speed up compilation of slowpath code
|
// Not inlined to speed up compilation of slowpath code
|
||||||
return VL_ZERO_W(obits, outwp);
|
return VL_ZERO_W(obits, outwp);
|
||||||
@@ -3067,9 +3072,11 @@ VerilatedContext::VerilatedContext()
|
|||||||
|
|
||||||
// Must declare here not in interface, as otherwise forward declarations not known
|
// Must declare here not in interface, as otherwise forward declarations not known
|
||||||
VerilatedContext::~VerilatedContext() {
|
VerilatedContext::~VerilatedContext() {
|
||||||
|
Verilated::threadContextp(this); // In unlikely case some other destructor needs it
|
||||||
checkMagic(this);
|
checkMagic(this);
|
||||||
m_magic = 0x1; // Arbitrary but 0x1 is what Verilator src uses for a deleted pointer
|
m_magic = 0x1; // Arbitrary but 0x1 is what Verilator src uses for a deleted pointer
|
||||||
logRestoreOutput();
|
logRestoreOutput();
|
||||||
|
Verilated::threadContextp(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedContext::checkMagic(const VerilatedContext* contextp) {
|
void VerilatedContext::checkMagic(const VerilatedContext* contextp) {
|
||||||
@@ -3087,6 +3094,7 @@ VerilatedContext::Serialized::Serialized() {
|
|||||||
|
|
||||||
bool VerilatedContext::assertOn() const VL_MT_SAFE { return m_s.m_assertOn; }
|
bool VerilatedContext::assertOn() const VL_MT_SAFE { return m_s.m_assertOn; }
|
||||||
void VerilatedContext::assertOn(bool flag) VL_MT_SAFE {
|
void VerilatedContext::assertOn(bool flag) VL_MT_SAFE {
|
||||||
|
if (assertCtlsLocked()) return;
|
||||||
// Set all assert and directive types when true, clear otherwise.
|
// Set all assert and directive types when true, clear otherwise.
|
||||||
m_s.m_assertOn = VL_MASK_I(ASSERT_ON_WIDTH) * flag;
|
m_s.m_assertOn = VL_MASK_I(ASSERT_ON_WIDTH) * flag;
|
||||||
}
|
}
|
||||||
@@ -3105,16 +3113,22 @@ uint32_t VerilatedContext::assertOnMask(VerilatedAssertType_t types,
|
|||||||
}
|
}
|
||||||
void VerilatedContext::assertOnSet(VerilatedAssertType_t types,
|
void VerilatedContext::assertOnSet(VerilatedAssertType_t types,
|
||||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||||
|
if (assertCtlsLocked()) return;
|
||||||
m_s.m_assertOn |= assertOnMask(types, directives);
|
m_s.m_assertOn |= assertOnMask(types, directives);
|
||||||
}
|
}
|
||||||
void VerilatedContext::assertOnClear(VerilatedAssertType_t types,
|
void VerilatedContext::assertOnClear(VerilatedAssertType_t types,
|
||||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||||
|
if (assertCtlsLocked()) return;
|
||||||
m_s.m_assertOn &= ~assertOnMask(types, directives);
|
m_s.m_assertOn &= ~assertOnMask(types, directives);
|
||||||
}
|
}
|
||||||
|
bool VerilatedContext::assertCtlsLocked() const VL_MT_SAFE { return m_ns.m_assertCtlsLocked; }
|
||||||
|
void VerilatedContext::assertCtlsLocked(bool flag) VL_MT_SAFE { m_ns.m_assertCtlsLocked = flag; }
|
||||||
void VerilatedContext::assertCtl(uint32_t controlType, VerilatedAssertType_t types,
|
void VerilatedContext::assertCtl(uint32_t controlType, VerilatedAssertType_t types,
|
||||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||||
// IEEE 1800-2023 Table 20-5 control_type. Lock freezes the On/Off state of the
|
// IEEE 1800-2023 Table 20-5 control_type. Lock freezes the On/Off state of the
|
||||||
// selected bits until Unlock; On/Off/Kill leave locked bits unchanged.
|
// selected bits until Unlock; On/Off/Kill leave locked bits unchanged.
|
||||||
|
// +verilator+assert+lock freezes everything, including Lock/Unlock itself.
|
||||||
|
if (assertCtlsLocked()) return;
|
||||||
const uint32_t mask = assertOnMask(types, directives);
|
const uint32_t mask = assertOnMask(types, directives);
|
||||||
const uint32_t lockedMask = mask & ~m_s.m_assertLock;
|
const uint32_t lockedMask = mask & ~m_s.m_assertLock;
|
||||||
switch (controlType) {
|
switch (controlType) {
|
||||||
@@ -3286,6 +3300,15 @@ void VerilatedContext::gotFinish(bool flag) VL_MT_SAFE {
|
|||||||
const VerilatedLockGuard lock{m_mutex};
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
m_s.m_gotFinish = flag;
|
m_s.m_gotFinish = flag;
|
||||||
}
|
}
|
||||||
|
bool VerilatedContext::stopRequestReserve(bool maybe) VL_MT_SAFE {
|
||||||
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
|
const int reserved = ++m_ns.m_stopReserved;
|
||||||
|
return !maybe || m_s.m_errorCount + reserved >= m_s.m_errorLimit;
|
||||||
|
}
|
||||||
|
void VerilatedContext::stopRequestRelease() VL_MT_SAFE {
|
||||||
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
|
--m_ns.m_stopReserved;
|
||||||
|
}
|
||||||
bool VerilatedContext::executingFinal() const VL_MT_SAFE {
|
bool VerilatedContext::executingFinal() const VL_MT_SAFE {
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
return m_ns.m_executingFinal;
|
return m_ns.m_executingFinal;
|
||||||
@@ -3556,7 +3579,9 @@ void VerilatedContextImp::commandArgVl(const std::string& arg) {
|
|||||||
if (0 == std::strncmp(arg.c_str(), "+verilator+", std::strlen("+verilator+"))) {
|
if (0 == std::strncmp(arg.c_str(), "+verilator+", std::strlen("+verilator+"))) {
|
||||||
std::string str;
|
std::string str;
|
||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
if (commandArgVlString(arg, "+verilator+coverage+file+", str)) {
|
if (arg == "+verilator+assert+lock") {
|
||||||
|
assertCtlsLocked(true);
|
||||||
|
} else if (commandArgVlString(arg, "+verilator+coverage+file+", str)) {
|
||||||
coverageFilename(str);
|
coverageFilename(str);
|
||||||
} else if (arg == "+verilator+debug") {
|
} else if (arg == "+verilator+debug") {
|
||||||
Verilated::debug(4);
|
Verilated::debug(4);
|
||||||
@@ -3575,7 +3600,8 @@ void VerilatedContextImp::commandArgVl(const std::string& arg) {
|
|||||||
logFilename(str);
|
logFilename(str);
|
||||||
logOutputToFile(false /* append */);
|
logOutputToFile(false /* append */);
|
||||||
} else if (arg == "+verilator+noassert") {
|
} else if (arg == "+verilator+noassert") {
|
||||||
assertOn(false);
|
// Set directly on to avoid conflicts with +verilator+assert+lock
|
||||||
|
m_s.m_assertOn = 0;
|
||||||
} else if (commandArgVlUint64(arg, "+verilator+prof+exec+start+", u64)) {
|
} else if (commandArgVlUint64(arg, "+verilator+prof+exec+start+", u64)) {
|
||||||
profExecStart(u64);
|
profExecStart(u64);
|
||||||
} else if (commandArgVlUint64(arg, "+verilator+prof+exec+window+", u64, 1)) {
|
} else if (commandArgVlUint64(arg, "+verilator+prof+exec+window+", u64, 1)) {
|
||||||
@@ -3891,7 +3917,7 @@ void Verilated::runFlushCallbacks() VL_MT_SAFE {
|
|||||||
// When running internal code coverage (gcc --coverage, as opposed to
|
// When running internal code coverage (gcc --coverage, as opposed to
|
||||||
// verilator --coverage), dump coverage data to properly cover failing
|
// verilator --coverage), dump coverage data to properly cover failing
|
||||||
// tests.
|
// tests.
|
||||||
VL_GCOV_DUMP();
|
VL_GCOV_DUMP_RESET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Verilated::addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE { addCbExit(cb, datap); }
|
void Verilated::addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE { addCbExit(cb, datap); }
|
||||||
@@ -4012,6 +4038,106 @@ void VerilatedImp::versionDump() VL_MT_SAFE {
|
|||||||
VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
|
VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
// VerilatedEvalLoop:: Methods
|
||||||
|
|
||||||
|
void VerilatedEvalLoop::didNotConverge(const char* namep,
|
||||||
|
void (VerilatedModel::*dumpTriggersp)()) {
|
||||||
|
if (dumpTriggersp) (m_model.*dumpTriggersp)();
|
||||||
|
const std::string msg = "DIDNOTCONVERGE: "s + namep
|
||||||
|
+ " region did not converge after '--converge-limit' of "
|
||||||
|
+ std::to_string(m_convergeLimit) + " tries";
|
||||||
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||||
|
VL_UNREACHABLE; // VL_FATAL_MT does not return
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool Profiling>
|
||||||
|
void VerilatedEvalLoop::evalImpl() {
|
||||||
|
VL_DEBUG_IF(VL_DBG_MSGF("+ Eval\n"););
|
||||||
|
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) {
|
||||||
|
// Advance the profiling window
|
||||||
|
if (VL_UNLIKELY(m_profTopLevel)) m_profilerp->configure();
|
||||||
|
m_profilerp->sectionPush("eval");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_model.evalBegin();
|
||||||
|
|
||||||
|
// Initialization on first time step only
|
||||||
|
if (VL_UNLIKELY(!m_model.m_didInit)) {
|
||||||
|
VL_DEBUG_IF(VL_DBG_MSGF("+ Initial\n"););
|
||||||
|
// Static initializers
|
||||||
|
m_model.evalStatic();
|
||||||
|
// Initial blocks
|
||||||
|
m_model.evalInitial();
|
||||||
|
// The 'Settle' region, iterated until it converges
|
||||||
|
uint32_t stlIterCount = 0;
|
||||||
|
do {
|
||||||
|
checkConvergence(++stlIterCount, "Settle", &VerilatedModel::dumpTriggersStl);
|
||||||
|
} while (m_model.evalStl(stlIterCount == 1));
|
||||||
|
m_model.m_didInit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sampled values are collected before anything can read them
|
||||||
|
m_model.evalSample();
|
||||||
|
|
||||||
|
// The 'Input combinational' region updates combinational logic driven from primary inputs
|
||||||
|
{
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop ico");
|
||||||
|
uint32_t icoIterCount = 0;
|
||||||
|
do {
|
||||||
|
checkConvergence(++icoIterCount, "Input combinational",
|
||||||
|
&VerilatedModel::dumpTriggersIco);
|
||||||
|
} while (m_model.evalIco(icoIterCount == 1));
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop ico
|
||||||
|
}
|
||||||
|
|
||||||
|
// The remaining regions are nested: each iteration of a region's loop
|
||||||
|
// re-runs the loops of all regions that precede it in the scheduling order.
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop react");
|
||||||
|
uint32_t reactIterCount = 0;
|
||||||
|
do {
|
||||||
|
checkConvergence(++reactIterCount, "Reactive", &VerilatedModel::dumpTriggersReact);
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop obs");
|
||||||
|
uint32_t obsIterCount = 0;
|
||||||
|
do {
|
||||||
|
checkConvergence(++obsIterCount, "Observed", &VerilatedModel::dumpTriggersObs);
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop nba");
|
||||||
|
uint32_t nbaIterCount = 0;
|
||||||
|
do {
|
||||||
|
checkConvergence(++nbaIterCount, "NBA", &VerilatedModel::dumpTriggersNba);
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop inact");
|
||||||
|
uint32_t inactIterCount = 0;
|
||||||
|
do {
|
||||||
|
checkConvergence(++inactIterCount, "Inactive");
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPush("loop act");
|
||||||
|
uint32_t actIterCount = 0;
|
||||||
|
do {
|
||||||
|
checkConvergence(++actIterCount, "Active",
|
||||||
|
&VerilatedModel::dumpTriggersAct);
|
||||||
|
} while (m_model.evalAct());
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop act
|
||||||
|
} while (m_model.evalInact());
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop inact
|
||||||
|
} while (m_model.evalNba());
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop nba
|
||||||
|
} while (m_model.evalObs());
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop obs
|
||||||
|
} while (m_model.evalReact());
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // loop react
|
||||||
|
|
||||||
|
// The 'Postponed' region runs once, at the end of the time step
|
||||||
|
m_model.evalPostponed();
|
||||||
|
|
||||||
|
m_model.evalEnd();
|
||||||
|
|
||||||
|
if VL_CONSTEXPR_CXX17 (Profiling) m_profilerp->sectionPop(); // eval
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template instantiations
|
||||||
|
template void VerilatedEvalLoop::evalImpl<false>();
|
||||||
|
template void VerilatedEvalLoop::evalImpl<true>();
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
// VerilatedModel:: Methods
|
// VerilatedModel:: Methods
|
||||||
|
|
||||||
@@ -4078,12 +4204,12 @@ VerilatedScope::VerilatedScope(VerilatedSyms* symsp, const char* suffixp, const
|
|||||||
, m_defnamep{defnamep}
|
, m_defnamep{defnamep}
|
||||||
, m_timeunit{timeunit}
|
, m_timeunit{timeunit}
|
||||||
, m_type{type} {
|
, m_type{type} {
|
||||||
Verilated::threadContextp()->impp()->scopeInsert(this);
|
contextp()->impp()->scopeInsert(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
VerilatedScope::~VerilatedScope() {
|
VerilatedScope::~VerilatedScope() {
|
||||||
// Memory cleanup - not called during normal operation
|
// Memory cleanup - not called during normal operation
|
||||||
Verilated::threadContextp()->impp()->scopeErase(this);
|
contextp()->impp()->scopeErase(this);
|
||||||
VL_DO_DANGLING(delete[] m_namep, m_namep);
|
VL_DO_DANGLING(delete[] m_namep, m_namep);
|
||||||
VL_DO_DANGLING(delete[] m_callbacksp, m_callbacksp);
|
VL_DO_DANGLING(delete[] m_callbacksp, m_callbacksp);
|
||||||
VL_DO_DANGLING(delete m_varsp, m_varsp);
|
VL_DO_DANGLING(delete m_varsp, m_varsp);
|
||||||
@@ -4142,6 +4268,50 @@ VerilatedVar* VerilatedScope::varInsert(const char* namep, void* datap, bool isP
|
|||||||
return &(m_varsp->find(namep)->second);
|
return &(m_varsp->find(namep)->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VerilatedScope::varsInsertFromTable(const VlVarTableEntry* entp, size_t n,
|
||||||
|
void* basep) VL_MT_UNSAFE {
|
||||||
|
// Table-driven equivalent of a run of varInsert()/varInsertSized() calls; see VlVarTableEntry.
|
||||||
|
if (!m_varsp) m_varsp = new VerilatedVarNameMap;
|
||||||
|
uint8_t* const base = static_cast<uint8_t*>(basep);
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
const VlVarTableEntry& e = entp[i];
|
||||||
|
void* const datap = base + e.byteOffset;
|
||||||
|
const VerilatedVarFlags vlflags = static_cast<VerilatedVarFlags>(e.vlflags);
|
||||||
|
VerilatedVar var{e.namep, datap, e.vltype, vlflags, e.udims, e.pdims, /*isParam=*/false};
|
||||||
|
for (int d = 0; d < e.udims; ++d) {
|
||||||
|
var.m_unpacked[d].m_left = e.dims[2 * d];
|
||||||
|
var.m_unpacked[d].m_right = e.dims[2 * d + 1];
|
||||||
|
}
|
||||||
|
for (int d = 0; d < e.pdims; ++d) {
|
||||||
|
var.m_packed[d].m_left = e.dims[2 * (e.udims + d)];
|
||||||
|
var.m_packed[d].m_right = e.dims[2 * (e.udims + d) + 1];
|
||||||
|
}
|
||||||
|
// Recompute the flattened DPI packed range now dims are known (see
|
||||||
|
// VerilatedVarProps::initPacked)
|
||||||
|
if (e.pdims == 1) {
|
||||||
|
var.m_packedDpi = var.m_packed.front();
|
||||||
|
} else if (e.pdims > 1) {
|
||||||
|
int packedSize = 1;
|
||||||
|
for (int d = 0; d < e.pdims; ++d) packedSize *= var.m_packed[d].elements();
|
||||||
|
var.m_packedDpi = VerilatedRange{packedSize - 1, 0};
|
||||||
|
}
|
||||||
|
m_varsp->emplace(e.namep, std::move(var));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerilatedScope::scopesConstructFromTable(const VlScopeTableEntry* entp, size_t n,
|
||||||
|
VerilatedSyms* symsp) VL_MT_UNSAFE {
|
||||||
|
// Table-driven equivalent of a run of 'new VerilatedScope{...}' statements; see
|
||||||
|
// VlScopeTableEntry. The generated Syms class derives VerilatedSyms as its sole primary
|
||||||
|
// base at offset 0, so symsp doubles as the base for the offsetof-baked member addresses.
|
||||||
|
uint8_t* const base = reinterpret_cast<uint8_t*>(symsp);
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
const VlScopeTableEntry& e = entp[i];
|
||||||
|
VerilatedScope** const slotp = reinterpret_cast<VerilatedScope**>(base + e.ptrOffset);
|
||||||
|
*slotp = new VerilatedScope{symsp, e.namep, e.identp, e.defnamep, e.timeunit, e.type};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VerilatedVar* VerilatedScope::varInsertSized(const char* namep, void* datap, bool isParam,
|
VerilatedVar* VerilatedScope::varInsertSized(const char* namep, void* datap, bool isParam,
|
||||||
VerilatedVarType vltype, int vlflags, int udims,
|
VerilatedVarType vltype, int vlflags, int udims,
|
||||||
uint32_t entSize...) VL_MT_UNSAFE {
|
uint32_t entSize...) VL_MT_UNSAFE {
|
||||||
|
|||||||
@@ -160,6 +160,21 @@ enum VerilatedVarFlags : uint32_t {
|
|||||||
VLVF_NET = (1 << 15) // Net object
|
VLVF_NET = (1 << 15) // Net object
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// One VPI-visible variable, consumed by VerilatedScope::varsInsertFromTable();
|
||||||
|
// replaces per-variable varInsert() calls, which compiles faster at scale.
|
||||||
|
struct VlVarTableEntry final {
|
||||||
|
static constexpr int kMaxDims = 3; // Max packed+unpacked dims a table row holds
|
||||||
|
const char* namep; // VPI-facing (protected) variable name, string literal
|
||||||
|
size_t byteOffset; // offsetof of storage member from module instance base
|
||||||
|
VerilatedVarType vltype;
|
||||||
|
uint32_t vlflags; // Direction + flags (VLVD_*/VLVF_*)
|
||||||
|
uint8_t udims; // udims + pdims <= kMaxDims
|
||||||
|
uint8_t pdims;
|
||||||
|
// (left,right) pairs: unpacked dims first, then packed; int32_t since large
|
||||||
|
// unpacked memories exceed int16 range
|
||||||
|
int32_t dims[kMaxDims * 2];
|
||||||
|
};
|
||||||
|
|
||||||
// IEEE 1800-2023 Table 20-6
|
// IEEE 1800-2023 Table 20-6
|
||||||
enum class VerilatedAssertType : uint8_t {
|
enum class VerilatedAssertType : uint8_t {
|
||||||
ASSERT_TYPE_CONCURRENT = (1 << 0),
|
ASSERT_TYPE_CONCURRENT = (1 << 0),
|
||||||
@@ -286,6 +301,8 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VlExecutionProfilerBase;
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
/// Base class of a Verilator generated (Verilated) model.
|
/// Base class of a Verilator generated (Verilated) model.
|
||||||
///
|
///
|
||||||
@@ -298,6 +315,8 @@ class VerilatedModel VL_NOT_FINAL {
|
|||||||
VerilatedContext& m_context; // The VerilatedContext this model is instantiated under
|
VerilatedContext& m_context; // The VerilatedContext this model is instantiated under
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool m_didInit = false; // Time 0 initialization has run
|
||||||
|
|
||||||
explicit VerilatedModel(VerilatedContext& context);
|
explicit VerilatedModel(VerilatedContext& context);
|
||||||
virtual ~VerilatedModel() = default;
|
virtual ~VerilatedModel() = default;
|
||||||
|
|
||||||
@@ -316,8 +335,82 @@ private:
|
|||||||
// The following are for use by Verilator internals only
|
// The following are for use by Verilator internals only
|
||||||
template <typename, typename>
|
template <typename, typename>
|
||||||
friend class VerilatedTrace;
|
friend class VerilatedTrace;
|
||||||
|
friend class VerilatedEvalLoop;
|
||||||
|
|
||||||
// Run-time trace configuration requested by this model
|
// Run-time trace configuration requested by this model
|
||||||
virtual std::unique_ptr<VerilatedTraceConfig> traceConfig() const;
|
virtual std::unique_ptr<VerilatedTraceConfig> traceConfig() const;
|
||||||
|
|
||||||
|
// Entry points called by VerilatedEvalLoop
|
||||||
|
virtual void evalBegin() = 0;
|
||||||
|
virtual void evalEnd() = 0;
|
||||||
|
virtual void evalStatic() = 0;
|
||||||
|
virtual void evalInitial() = 0;
|
||||||
|
virtual void evalSample() = 0;
|
||||||
|
virtual bool evalStl(bool firstIteration) = 0;
|
||||||
|
virtual bool evalIco(bool firstIteration) = 0;
|
||||||
|
virtual bool evalAct() = 0;
|
||||||
|
virtual bool evalInact() = 0;
|
||||||
|
virtual bool evalNba() = 0;
|
||||||
|
virtual bool evalObs() = 0;
|
||||||
|
virtual bool evalReact() = 0;
|
||||||
|
virtual void evalPostponed() = 0;
|
||||||
|
virtual void dumpTriggersStl() = 0;
|
||||||
|
virtual void dumpTriggersIco() = 0;
|
||||||
|
virtual void dumpTriggersAct() = 0;
|
||||||
|
virtual void dumpTriggersNba() = 0;
|
||||||
|
virtual void dumpTriggersObs() = 0;
|
||||||
|
virtual void dumpTriggersReact() = 0;
|
||||||
|
|
||||||
|
// Runs 'final' blocks at the end of the simulation
|
||||||
|
virtual void evalFinal() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
/// Evaluation loop calling a VerilatedModel's entry points
|
||||||
|
|
||||||
|
class VerilatedEvalLoop final {
|
||||||
|
VL_UNCOPYABLE(VerilatedEvalLoop);
|
||||||
|
|
||||||
|
// MEMBERS
|
||||||
|
VerilatedModel& m_model; // The model this loop evaluates
|
||||||
|
const uint32_t m_convergeLimit; // --converge-limit from compiler command line
|
||||||
|
// Where to record --prof-exec sections, or null if not profiling
|
||||||
|
VlExecutionProfilerBase* m_profilerp = nullptr;
|
||||||
|
// Whether this is the top level model during profiling
|
||||||
|
bool m_profTopLevel = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// CONSTRUCTORS
|
||||||
|
VerilatedEvalLoop(VerilatedModel& model, uint32_t convergeLimit)
|
||||||
|
: m_model{model}
|
||||||
|
, m_convergeLimit{convergeLimit} {}
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
// Evaluate a single time step of the SV scheduling model
|
||||||
|
void eval() {
|
||||||
|
if (VL_UNLIKELY(m_profilerp)) {
|
||||||
|
evalImpl<true>();
|
||||||
|
} else {
|
||||||
|
evalImpl<false>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set --prof-exec profiler
|
||||||
|
void profiler(VlExecutionProfilerBase* profilerp, bool topLevel) {
|
||||||
|
m_profilerp = profilerp;
|
||||||
|
m_profTopLevel = topLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Evaluate a time step, recording --prof-exec sections iff 'Profiling'.
|
||||||
|
template <bool Profiling>
|
||||||
|
void evalImpl();
|
||||||
|
// Check the iteration convergence
|
||||||
|
void checkConvergence(uint32_t iterCount, const char* namep,
|
||||||
|
void (VerilatedModel::*dumpTriggersp)() = nullptr) {
|
||||||
|
if (VL_UNLIKELY(iterCount > m_convergeLimit)) didNotConverge(namep, dumpTriggersp);
|
||||||
|
}
|
||||||
|
// Dump the region's triggers, if it has any, then report non-convergence and abort
|
||||||
|
void didNotConverge(const char* namep, void (VerilatedModel::*dumpTriggersp)());
|
||||||
};
|
};
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
@@ -342,6 +435,23 @@ public:
|
|||||||
virtual ~VerilatedVirtualBase() = default;
|
virtual ~VerilatedVirtualBase() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
// Internal: Base of the '--prof-exec' execution profiler
|
||||||
|
//
|
||||||
|
// Implemented by VlExecutionProfiler, see verilated_profiler.h. Declared here
|
||||||
|
// so the evaluation loop can drive the profiler without naming it, as it is
|
||||||
|
// only linked when Verilated with --prof-exec.
|
||||||
|
|
||||||
|
class VlExecutionProfilerBase VL_NOT_FINAL : public VerilatedVirtualBase {
|
||||||
|
public:
|
||||||
|
// Mark the beginning of a section of execution
|
||||||
|
virtual void sectionPush(const char* namep) = 0;
|
||||||
|
// Mark the end of the innermost open section
|
||||||
|
virtual void sectionPop() = 0;
|
||||||
|
// Advance the profiling window at the start of a time step
|
||||||
|
virtual void configure() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
/// Verilator simulation context
|
/// Verilator simulation context
|
||||||
///
|
///
|
||||||
@@ -372,6 +482,8 @@ private:
|
|||||||
static uint32_t assertOnMask(VerilatedAssertType_t types,
|
static uint32_t assertOnMask(VerilatedAssertType_t types,
|
||||||
VerilatedAssertDirectiveType_t directives) VL_PURE;
|
VerilatedAssertDirectiveType_t directives) VL_PURE;
|
||||||
static constexpr size_t ASSERT_CONTROL_SLOT_COUNT = ASSERT_ON_WIDTH - 1;
|
static constexpr size_t ASSERT_CONTROL_SLOT_COUNT = ASSERT_ON_WIDTH - 1;
|
||||||
|
// No termination request has stamped m_finishPendingTime yet
|
||||||
|
static constexpr uint64_t TIME_UNSET = ~0ULL;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// TYPES
|
// TYPES
|
||||||
@@ -430,6 +542,12 @@ protected:
|
|||||||
struct NonSerialized final { // Non-serialized information
|
struct NonSerialized final { // Non-serialized information
|
||||||
// These are reloaded from on command-line settings, so do not need to persist
|
// These are reloaded from on command-line settings, so do not need to persist
|
||||||
// Fast path
|
// Fast path
|
||||||
|
// A worker queues $finish before the main thread callback can set m_gotFinish.
|
||||||
|
std::atomic<uint32_t> m_finishPending{0}; // Number of queued $finish callbacks
|
||||||
|
std::atomic<uint64_t> m_finishPendingTime{TIME_UNSET}; // Time of the first callback
|
||||||
|
std::atomic<bool> m_assertCtlsLocked{
|
||||||
|
false}; // When true, all assertion-control updates are ignored
|
||||||
|
int m_stopReserved = 0; // Posted $stop requests not yet executed
|
||||||
bool m_executingFinal = false; // Running generated final() code
|
bool m_executingFinal = false; // Running generated final() code
|
||||||
uint64_t m_profExecStart = 1; // +prof+exec+start time
|
uint64_t m_profExecStart = 1; // +prof+exec+start time
|
||||||
uint32_t m_profExecWindow = 2; // +prof+exec+window size
|
uint32_t m_profExecWindow = 2; // +prof+exec+window size
|
||||||
@@ -510,6 +628,12 @@ public:
|
|||||||
/// Clear enabled status for given assertion types
|
/// Clear enabled status for given assertion types
|
||||||
void assertOnClear(VerilatedAssertType_t types,
|
void assertOnClear(VerilatedAssertType_t types,
|
||||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
|
||||||
|
/// Return if assertion-control updates are locked. When locked, RTL assert
|
||||||
|
// control statements ($asserton/$assertoff/$assertcontrol) are ignored, as
|
||||||
|
// are updates from the C++ API.
|
||||||
|
bool assertCtlsLocked() const VL_MT_SAFE;
|
||||||
|
/// Lock/unlock assertion-control updates.
|
||||||
|
void assertCtlsLocked(bool flag) VL_MT_SAFE;
|
||||||
/// Apply assertion control for given control, assertion, and directive types
|
/// Apply assertion control for given control, assertion, and directive types
|
||||||
void assertCtl(uint32_t controlType, VerilatedAssertType_t types,
|
void assertCtl(uint32_t controlType, VerilatedAssertType_t types,
|
||||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
|
||||||
@@ -669,6 +793,27 @@ public:
|
|||||||
|
|
||||||
// METHODS - public but for internal use only
|
// METHODS - public but for internal use only
|
||||||
|
|
||||||
|
// Internal: Track $finish/$stop callbacks queued by worker threads
|
||||||
|
bool finishPending() const VL_MT_SAFE { return m_ns.m_finishPending.load() != 0; }
|
||||||
|
void finishPendingInc() VL_MT_SAFE {
|
||||||
|
++m_ns.m_finishPending;
|
||||||
|
uint64_t unset = TIME_UNSET;
|
||||||
|
m_ns.m_finishPendingTime.compare_exchange_strong(unset, time());
|
||||||
|
}
|
||||||
|
void finishPendingDec() VL_MT_SAFE {
|
||||||
|
const uint32_t previous = m_ns.m_finishPending.fetch_sub(1);
|
||||||
|
assert(previous > 0);
|
||||||
|
if (previous == 1 && !gotFinish()) m_ns.m_finishPendingTime = TIME_UNSET;
|
||||||
|
}
|
||||||
|
// Internal: Time of the first termination request, else the current time
|
||||||
|
uint64_t finishPendingTime() const VL_MT_SAFE {
|
||||||
|
const uint64_t stamped = m_ns.m_finishPendingTime.load();
|
||||||
|
return stamped == TIME_UNSET ? time() : stamped;
|
||||||
|
}
|
||||||
|
// Internal: Reserve a posted $stop, returning true if it reaches the termination limit
|
||||||
|
bool stopRequestReserve(bool maybe) VL_MT_SAFE;
|
||||||
|
void stopRequestRelease() VL_MT_SAFE;
|
||||||
|
|
||||||
// Internal: access to implementation class
|
// Internal: access to implementation class
|
||||||
VerilatedContextImp* impp() VL_MT_SAFE { return reinterpret_cast<VerilatedContextImp*>(this); }
|
VerilatedContextImp* impp() VL_MT_SAFE { return reinterpret_cast<VerilatedContextImp*>(this); }
|
||||||
const VerilatedContextImp* impp() const VL_MT_SAFE {
|
const VerilatedContextImp* impp() const VL_MT_SAFE {
|
||||||
@@ -756,6 +901,8 @@ public: // But for internal use only
|
|||||||
// Verilator scope information class
|
// Verilator scope information class
|
||||||
// Used for internal VPI implementation, and introspection into scopes
|
// Used for internal VPI implementation, and introspection into scopes
|
||||||
|
|
||||||
|
struct VlScopeTableEntry; // Defined below VerilatedScope; used by scopesConstructFromTable()
|
||||||
|
|
||||||
class VerilatedScope final {
|
class VerilatedScope final {
|
||||||
public:
|
public:
|
||||||
enum Type : uint8_t {
|
enum Type : uint8_t {
|
||||||
@@ -792,6 +939,9 @@ public: // But internals only - called from verilated modules, VerilatedSyms
|
|||||||
void* forceReadSignalData, const char* forceReadSignalName,
|
void* forceReadSignalData, const char* forceReadSignalName,
|
||||||
std::pair<VerilatedVar*, VerilatedVar*> forceControlSignals,
|
std::pair<VerilatedVar*, VerilatedVar*> forceControlSignals,
|
||||||
int udims, int pdims...) VL_MT_UNSAFE;
|
int udims, int pdims...) VL_MT_UNSAFE;
|
||||||
|
void varsInsertFromTable(const VlVarTableEntry* entp, size_t n, void* basep) VL_MT_UNSAFE;
|
||||||
|
static void scopesConstructFromTable(const VlScopeTableEntry* entp, size_t n,
|
||||||
|
VerilatedSyms* symsp) VL_MT_UNSAFE;
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; }
|
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; }
|
||||||
const char* identifier() const VL_MT_SAFE_POSTINIT { return m_identifierp; }
|
const char* identifier() const VL_MT_SAFE_POSTINIT { return m_identifierp; }
|
||||||
@@ -805,6 +955,18 @@ public: // But internals only - called from verilated modules, VerilatedSyms
|
|||||||
static void* exportFindNullError(int funcnum) VL_MT_SAFE;
|
static void* exportFindNullError(int funcnum) VL_MT_SAFE;
|
||||||
static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE;
|
static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE;
|
||||||
Type type() const { return m_type; }
|
Type type() const { return m_type; }
|
||||||
|
VerilatedContext* contextp() const { return m_symsp->_vm_contextp__; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// One scope, consumed by VerilatedScope::scopesConstructFromTable(); replaces
|
||||||
|
// per-scope 'new VerilatedScope{...}' statements, which compiles faster at scale.
|
||||||
|
struct VlScopeTableEntry final {
|
||||||
|
size_t ptrOffset; // offsetof of the target __Vscopep_* member within the Syms object
|
||||||
|
const char* namep; // Scope suffix name (protected), string literal
|
||||||
|
const char* identp; // Identifier with escapes removed (protected)
|
||||||
|
const char* defnamep; // Definition name (SCOPE_MODULE only), else "<null>"
|
||||||
|
int8_t timeunit; // Timeunit in negative power-of-10
|
||||||
|
VerilatedScope::Type type;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VerilatedHierarchy final {
|
class VerilatedHierarchy final {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
|
|||||||
# Compiler flags that enable coroutine support
|
# Compiler flags that enable coroutine support
|
||||||
CFG_CXXFLAGS_COROUTINES = @CFG_CXXFLAGS_COROUTINES@
|
CFG_CXXFLAGS_COROUTINES = @CFG_CXXFLAGS_COROUTINES@
|
||||||
# Compiler flags when creating a precompiled header
|
# Compiler flags when creating a precompiled header
|
||||||
CFG_CXXFLAGS_PCH = -x c++-header
|
CFG_CXXFLAGS_PCH = -c -x c++-header
|
||||||
# Compiler option to put in front of filename to read precompiled header
|
# Compiler option to put in front of filename to read precompiled header
|
||||||
CFG_CXXFLAGS_PCH_I = @CFG_CXXFLAGS_PCH_I@
|
CFG_CXXFLAGS_PCH_I = @CFG_CXXFLAGS_PCH_I@
|
||||||
# Compiler's filename prefix for precompiled headers, .gch if clang, empty if GCC
|
# Compiler's filename prefix for precompiled headers, .gch if clang, empty if GCC
|
||||||
|
|||||||
+12
-12
@@ -75,24 +75,24 @@ class VerilatedCovImp;
|
|||||||
ccontextp->_insertp("hier", name, __VA_ARGS__); \
|
ccontextp->_insertp("hier", name, __VA_ARGS__); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
static inline void VL_COV_TOGGLE_CHG_ST_I(const int width, uint32_t* covp, const IData newData,
|
inline void VL_COV_TOGGLE_CHG_ST_I(const int width, uint32_t* covp, const IData newData,
|
||||||
const IData oldData) {
|
const IData oldData) {
|
||||||
const IData chgData = newData ^ oldData;
|
const IData chgData = newData ^ oldData;
|
||||||
for (int i = 0; i < width; ++i) {
|
for (int i = 0; i < width; ++i) {
|
||||||
*(covp + 2 * i + ((newData >> i) & 1)) += (chgData >> i) & 1;
|
*(covp + 2 * i + ((newData >> i) & 1)) += (chgData >> i) & 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void VL_COV_TOGGLE_CHG_ST_Q(const int width, uint32_t* covp, const QData newData,
|
inline void VL_COV_TOGGLE_CHG_ST_Q(const int width, uint32_t* covp, const QData newData,
|
||||||
const QData oldData) {
|
const QData oldData) {
|
||||||
const QData chgData = newData ^ oldData;
|
const QData chgData = newData ^ oldData;
|
||||||
for (int i = 0; i < width; ++i) {
|
for (int i = 0; i < width; ++i) {
|
||||||
*(covp + 2 * i + ((newData >> i) & 1)) += (chgData >> i) & 1;
|
*(covp + 2 * i + ((newData >> i) & 1)) += (chgData >> i) & 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void VL_COV_TOGGLE_CHG_ST_W(const int width, uint32_t* covp, WDataInP newData,
|
inline void VL_COV_TOGGLE_CHG_ST_W(const int width, uint32_t* covp, WDataInP newData,
|
||||||
WDataInP oldData) {
|
WDataInP oldData) {
|
||||||
for (int i = 0; i < VL_WORDS_I(width); ++i) {
|
for (int i = 0; i < VL_WORDS_I(width); ++i) {
|
||||||
const EData chgData = newData[i] ^ oldData[i];
|
const EData chgData = newData[i] ^ oldData[i];
|
||||||
if (chgData) {
|
if (chgData) {
|
||||||
@@ -104,8 +104,8 @@ static inline void VL_COV_TOGGLE_CHG_ST_W(const int width, uint32_t* covp, WData
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void VL_COV_TOGGLE_CHG_MT_I(const int width, std::atomic<uint32_t>* covp,
|
inline void VL_COV_TOGGLE_CHG_MT_I(const int width, std::atomic<uint32_t>* covp,
|
||||||
const IData newData, const IData oldData) VL_MT_SAFE {
|
const IData newData, const IData oldData) VL_MT_SAFE {
|
||||||
const IData chgData = newData ^ oldData;
|
const IData chgData = newData ^ oldData;
|
||||||
for (int i = 0; i < width; ++i) {
|
for (int i = 0; i < width; ++i) {
|
||||||
if (VL_BITISSET_I(chgData, i)) {
|
if (VL_BITISSET_I(chgData, i)) {
|
||||||
@@ -114,8 +114,8 @@ static inline void VL_COV_TOGGLE_CHG_MT_I(const int width, std::atomic<uint32_t>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void VL_COV_TOGGLE_CHG_MT_Q(const int width, std::atomic<uint32_t>* covp,
|
inline void VL_COV_TOGGLE_CHG_MT_Q(const int width, std::atomic<uint32_t>* covp,
|
||||||
const QData newData, const QData oldData) VL_MT_SAFE {
|
const QData newData, const QData oldData) VL_MT_SAFE {
|
||||||
const QData chgData = newData ^ oldData;
|
const QData chgData = newData ^ oldData;
|
||||||
for (int i = 0; i < width; ++i) {
|
for (int i = 0; i < width; ++i) {
|
||||||
if (VL_BITISSET_Q(chgData, i)) {
|
if (VL_BITISSET_Q(chgData, i)) {
|
||||||
@@ -124,8 +124,8 @@ static inline void VL_COV_TOGGLE_CHG_MT_Q(const int width, std::atomic<uint32_t>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void VL_COV_TOGGLE_CHG_MT_W(const int width, std::atomic<uint32_t>* covp,
|
inline void VL_COV_TOGGLE_CHG_MT_W(const int width, std::atomic<uint32_t>* covp, WDataInP newData,
|
||||||
WDataInP newData, WDataInP oldData) VL_MT_SAFE {
|
WDataInP oldData) VL_MT_SAFE {
|
||||||
for (int i = 0; i < VL_WORDS_I(width); ++i) {
|
for (int i = 0; i < VL_WORDS_I(width); ++i) {
|
||||||
const EData chgData = newData[i] ^ oldData[i];
|
const EData chgData = newData[i] ^ oldData[i];
|
||||||
if (chgData) {
|
if (chgData) {
|
||||||
|
|||||||
@@ -41,9 +41,13 @@ enum class VlCovBinKind : uint8_t {
|
|||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VlCoverpointIf
|
// VlCoverpointIf
|
||||||
/// Read-side view of a coverpoint. The writer queries bins by index; the
|
/// Read-side view of a coverpoint -- a named, index-addressable set of bins
|
||||||
/// implementor computes names/kinds on demand. Bounded bin count, so random
|
/// with a coverage fraction. A cross is also a coverpoint from this view: its
|
||||||
/// access by index is the primary usage.
|
/// auto cross bins (one per element of the Cartesian product of the feeding
|
||||||
|
/// coverpoints' Normal bins) are all Normal, and their names are built on
|
||||||
|
/// demand by concatenating the feeding coverpoints' bin names. The writer
|
||||||
|
/// queries bins by index; the implementor computes names/kinds on demand.
|
||||||
|
/// Bounded bin count, so random access by index is the primary usage.
|
||||||
|
|
||||||
class VlCoverpointIf VL_NOT_FINAL {
|
class VlCoverpointIf VL_NOT_FINAL {
|
||||||
public:
|
public:
|
||||||
@@ -51,11 +55,11 @@ public:
|
|||||||
virtual ~VlCoverpointIf() = default;
|
virtual ~VlCoverpointIf() = default;
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
// All bins, across every set; index range [0, binCount())
|
// All bins, across every set; index range [0, binCount()).
|
||||||
virtual int binCount() const = 0;
|
virtual uint32_t binCount() const = 0;
|
||||||
// Bin name in declaration order (e.g. "myBin" or "b[3]")
|
// Bin name in declaration order (e.g. "myBin" or "b[3]"); for a cross,
|
||||||
virtual std::string binName(int i) const = 0;
|
// the concatenated cross bin name (e.g. "b1_x_b2_x_b3")
|
||||||
virtual VlCovBinKind binKind(int i) const = 0;
|
virtual std::string binName(uint32_t i) const = 0;
|
||||||
// Bins covered / effective total (Normal set only) for the coverage calc
|
// Bins covered / effective total (Normal set only) for the coverage calc
|
||||||
virtual void coverageParts(double& covered, double& total) const = 0;
|
virtual void coverageParts(double& covered, double& total) const = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,34 +23,57 @@
|
|||||||
|
|
||||||
#include "verilated_covergroup.h"
|
#include "verilated_covergroup.h"
|
||||||
|
|
||||||
|
#include "verilated.h"
|
||||||
|
|
||||||
|
// This file is compiled whenever covergroups are used, with or without
|
||||||
|
// "verilator --coverage" (see V3Global::verilatedCppFiles). Bin counts are
|
||||||
|
// members of the covergroup objects themselves, so sampling, bin naming, and
|
||||||
|
// coverage queries such as get_inst_coverage() all work with no coverage
|
||||||
|
// database present. VL_COVER_INSERT does not copy a count; it hands the
|
||||||
|
// database the address of a counter to read at write time. Only that
|
||||||
|
// publication step needs verilated_cov.cpp, which is compiled solely under
|
||||||
|
// --coverage, so only the registerBins() bodies are gated on VM_COVERAGE.
|
||||||
#if VM_COVERAGE
|
#if VM_COVERAGE
|
||||||
#include "verilated_cov.h"
|
#include "verilated_cov.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void VlCoverpoint::init(const char* hier, uint32_t atLeast, int nBins) {
|
void VlCoverpoint::init(const char* hier, uint32_t atLeast, uint32_t nBins) {
|
||||||
m_hier = hier;
|
m_hier = hier;
|
||||||
m_atLeast = atLeast;
|
m_atLeast = atLeast;
|
||||||
m_total = nBins;
|
m_total = nBins;
|
||||||
m_counts.assign(nBins, 0);
|
m_counts.assign(nBins, 0);
|
||||||
|
m_crossIdx.assign(nBins, -1);
|
||||||
|
m_crossToBin.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlCoverpoint::addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name,
|
void VlCoverpoint::addNamer(VlCovBinKind set, uint32_t count, VlCovBinNaming naming,
|
||||||
const char* file, int line, int col) {
|
const char* name, const char* file, int line, int col) {
|
||||||
m_namers.emplace_back(set, count, m_nextBase, naming, name, file, line, col);
|
m_namers.emplace_back(set, count, m_nextBase, naming, name, file, line, col);
|
||||||
|
if (set == VlCovBinKind::KIND_NORMAL) {
|
||||||
|
// Assign each Normal bin a cross index, and record the inverse map.
|
||||||
|
for (uint32_t b = m_nextBase; b < m_nextBase + count; ++b) {
|
||||||
|
m_crossIdx[b] = static_cast<int>(m_crossToBin.size());
|
||||||
|
m_crossToBin.push_back(b);
|
||||||
|
}
|
||||||
|
m_normal += count;
|
||||||
|
}
|
||||||
m_nextBase += count;
|
m_nextBase += count;
|
||||||
if (set == VlCovBinKind::KIND_NORMAL) m_normal += count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const VlCovNamer& VlCoverpoint::namerFor(int i) const {
|
std::string VlCoverpoint::normalBinName(uint32_t crossIdx) const {
|
||||||
// Namers are appended in ascending, contiguous index order covering [0, m_total),
|
// Build the bin name based on the bin index
|
||||||
// and i is always a valid bin index, so the matching namer always exists.
|
return binName(m_crossToBin[crossIdx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VlCovNamer& VlCoverpoint::namerFor(uint32_t i) const {
|
||||||
|
// Namers are appended in ascending order covering [0, m_total),
|
||||||
for (const VlCovNamer& nm : m_namers) {
|
for (const VlCovNamer& nm : m_namers) {
|
||||||
if (i < nm.base() + nm.count()) return nm;
|
if (i < nm.base() + nm.count()) return nm;
|
||||||
}
|
}
|
||||||
VL_UNREACHABLE;
|
VL_UNREACHABLE; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string VlCoverpoint::binName(int i) const {
|
std::string VlCoverpoint::binName(uint32_t i) const {
|
||||||
const VlCovNamer& nm = namerFor(i);
|
const VlCovNamer& nm = namerFor(i);
|
||||||
std::string name = nm.name();
|
std::string name = nm.name();
|
||||||
if (nm.naming() == VlCovBinNaming::Array) name += '[' + std::to_string(i - nm.base()) + ']';
|
if (nm.naming() == VlCovBinNaming::Array) name += '[' + std::to_string(i - nm.base()) + ']';
|
||||||
@@ -59,7 +82,7 @@ std::string VlCoverpoint::binName(int i) const {
|
|||||||
|
|
||||||
#if VM_COVERAGE
|
#if VM_COVERAGE
|
||||||
void VlCoverpoint::registerBins(VerilatedCovContext* covcontextp, const char* page) {
|
void VlCoverpoint::registerBins(VerilatedCovContext* covcontextp, const char* page) {
|
||||||
for (int i = 0; i < binCount(); ++i) {
|
for (uint32_t i = 0; i < binCount(); ++i) {
|
||||||
const VlCovNamer& nm = namerFor(i);
|
const VlCovNamer& nm = namerFor(i);
|
||||||
const VlCovBinKind kind = binKind(i);
|
const VlCovBinKind kind = binKind(i);
|
||||||
const std::string binp = binName(i);
|
const std::string binp = binName(i);
|
||||||
@@ -81,3 +104,89 @@ void VlCoverpoint::registerBins(VerilatedCovContext* covcontextp, const char* pa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // VM_COVERAGE
|
#endif // VM_COVERAGE
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VlCoverCross
|
||||||
|
|
||||||
|
void VlCoverCross::init(const char* hier, uint32_t dims, VlCoverpoint* const* cps,
|
||||||
|
const char* file, int line, int col) {
|
||||||
|
m_hier = hier;
|
||||||
|
m_file = file;
|
||||||
|
m_line = line;
|
||||||
|
m_col = col;
|
||||||
|
m_dims = dims;
|
||||||
|
m_cps.assign(cps, cps + dims);
|
||||||
|
m_cpBinCounts.resize(dims);
|
||||||
|
// Accumulate in 64 bits so the overflow check itself cannot overflow.
|
||||||
|
uint64_t product = 1;
|
||||||
|
for (uint32_t d = 0; d < dims; ++d) {
|
||||||
|
m_cpBinCounts[d] = cps[d]->normalBinCount();
|
||||||
|
product *= m_cpBinCounts[d];
|
||||||
|
if (VL_UNLIKELY(product > UINT32_MAX)) { // LCOV_EXCL_START
|
||||||
|
VL_FATAL_MT(file, line, "", "Cross has too many auto bins to represent");
|
||||||
|
} // LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
|
m_numAutoBins = static_cast<uint32_t>(product);
|
||||||
|
// stride[d] = product of the Normal bin counts of all dimensions after d.
|
||||||
|
// Counts down with an offset so the unsigned index never wraps below zero.
|
||||||
|
m_stride.assign(dims, 1);
|
||||||
|
for (uint32_t d = dims; d > 1; --d) m_stride[d - 2] = m_stride[d - 1] * m_cpBinCounts[d - 1];
|
||||||
|
m_flatCounts.assign(m_numAutoBins, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VlCoverCross::iterateProduct(VlCoverpoint* const* cps, uint32_t dim, uint32_t baseIdx) {
|
||||||
|
const uint32_t hits = cps[dim]->hitCount();
|
||||||
|
const uint32_t* const list = cps[dim]->hitList();
|
||||||
|
const bool last = (dim == m_dims - 1);
|
||||||
|
const uint32_t stride = m_stride[dim];
|
||||||
|
for (uint32_t hit = 0; hit < hits; ++hit) {
|
||||||
|
const uint32_t idx = baseIdx + list[hit] * stride;
|
||||||
|
if (last) {
|
||||||
|
incrementTuple(idx);
|
||||||
|
} else {
|
||||||
|
iterateProduct(cps, dim + 1, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VlCoverCross::sample(VlCoverpoint* const* cps) {
|
||||||
|
// Fast path: if any dimension had no Normal-bin hit, the cross cannot hit.
|
||||||
|
for (uint32_t d = 0; d < m_dims; ++d) {
|
||||||
|
if (cps[d]->hitCount() == 0) return;
|
||||||
|
}
|
||||||
|
iterateProduct(cps, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string VlCoverCross::binName(uint32_t flat) const {
|
||||||
|
// Built on demand by concatenating each coverpoint's own bin name.
|
||||||
|
std::string name;
|
||||||
|
for (uint32_t d = 0; d < m_dims; ++d) {
|
||||||
|
const uint32_t crossIdx = (flat / m_stride[d]) % m_cpBinCounts[d];
|
||||||
|
if (d > 0) name += "_x_";
|
||||||
|
name += m_cps[d]->normalBinName(crossIdx);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if VM_COVERAGE
|
||||||
|
void VlCoverCross::registerBins(VerilatedCovContext* covcontextp, const char* page) {
|
||||||
|
// Register every auto cross bin (zero-count bins included), so the report
|
||||||
|
// shows the full Cartesian product of cross bins. Names are built on the fly.
|
||||||
|
const std::string lineStr = std::to_string(m_line);
|
||||||
|
const std::string colStr = std::to_string(m_col);
|
||||||
|
for (uint32_t flat = 0; flat < binCount(); ++flat) {
|
||||||
|
const std::string bin = binName(flat); // "b1_x_b2_x_..."
|
||||||
|
// cross_bins metadata: the same components joined by ',' (not read by the report)
|
||||||
|
std::string crossBins;
|
||||||
|
for (uint32_t d = 0; d < m_dims; ++d) {
|
||||||
|
const uint32_t crossIdx = (flat / m_stride[d]) % m_cpBinCounts[d];
|
||||||
|
if (d > 0) crossBins += ",";
|
||||||
|
crossBins += m_cps[d]->normalBinName(crossIdx);
|
||||||
|
}
|
||||||
|
const std::string full = m_hier + "." + bin;
|
||||||
|
VL_COVER_INSERT(covcontextp, full.c_str(), &m_flatCounts[flat], "page", page, "filename",
|
||||||
|
m_file, "lineno", lineStr.c_str(), "column", colStr.c_str(), "bin",
|
||||||
|
bin.c_str(), "cross", "1", "cross_bins", crossBins.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // VM_COVERAGE
|
||||||
|
|||||||
+136
-23
@@ -22,6 +22,9 @@
|
|||||||
/// it in the constructor (init + add*Namer), increments bins from sample(),
|
/// it in the constructor (init + add*Namer), increments bins from sample(),
|
||||||
/// and registers via registerBins().
|
/// and registers via registerBins().
|
||||||
///
|
///
|
||||||
|
/// Collection and coverage queries are always available; only registerBins(),
|
||||||
|
/// which publishes bin counters to the coverage database, requires VM_COVERAGE.
|
||||||
|
///
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
#ifndef VERILATOR_VERILATED_COVERGROUP_H_
|
#ifndef VERILATOR_VERILATED_COVERGROUP_H_
|
||||||
@@ -49,8 +52,8 @@ enum class VlCovBinNaming : uint8_t {
|
|||||||
class VlCovNamer final {
|
class VlCovNamer final {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
VlCovBinKind m_set; // which set the bins belong to
|
VlCovBinKind m_set; // which set the bins belong to
|
||||||
int m_count; // bins this namer covers (1 for Single)
|
uint32_t m_count; // bins this namer covers (1 for Single)
|
||||||
int m_base; // first bin index (declaration order), assigned on append
|
uint32_t m_base; // first bin index (declaration order), assigned on append
|
||||||
VlCovBinNaming m_naming; // how bin names are built
|
VlCovBinNaming m_naming; // how bin names are built
|
||||||
const char* m_name; // bin name (Single) or array base name (Array)
|
const char* m_name; // bin name (Single) or array base name (Array)
|
||||||
const char* m_file; // declaration file
|
const char* m_file; // declaration file
|
||||||
@@ -59,8 +62,8 @@ class VlCovNamer final {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VlCovNamer(VlCovBinKind set, int count, int base, VlCovBinNaming naming, const char* name,
|
VlCovNamer(VlCovBinKind set, uint32_t count, uint32_t base, VlCovBinNaming naming,
|
||||||
const char* file, int line, int col)
|
const char* name, const char* file, int line, int col)
|
||||||
: m_set{set}
|
: m_set{set}
|
||||||
, m_count{count}
|
, m_count{count}
|
||||||
, m_base{base}
|
, m_base{base}
|
||||||
@@ -72,8 +75,8 @@ public:
|
|||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
VlCovBinKind set() const { return m_set; }
|
VlCovBinKind set() const { return m_set; }
|
||||||
int count() const { return m_count; }
|
uint32_t count() const { return m_count; }
|
||||||
int base() const { return m_base; }
|
uint32_t base() const { return m_base; }
|
||||||
VlCovBinNaming naming() const { return m_naming; }
|
VlCovBinNaming naming() const { return m_naming; }
|
||||||
const char* name() const { return m_name; }
|
const char* name() const { return m_name; }
|
||||||
const char* file() const { return m_file; }
|
const char* file() const { return m_file; }
|
||||||
@@ -87,19 +90,30 @@ public:
|
|||||||
/// bin's set/name come from the owning namer. coverage() is computed on demand
|
/// bin's set/name come from the owning namer. coverage() is computed on demand
|
||||||
/// by scanning bin counts, keeping the sample() hot path a plain counter bump.
|
/// by scanning bin counts, keeping the sample() hot path a plain counter bump.
|
||||||
|
|
||||||
class VlCoverpoint final : public VlCoverpointIf {
|
// Base coverpoint runtime (read side + collection logic, no hit-list storage).
|
||||||
// MEMBERS
|
// VlCoverpointT<MaxHits> adds the inline hit-list array and the incrementBin write
|
||||||
|
// path; the cross holds VlCoverpoint* and reads via hitCount()/hitList().
|
||||||
|
class VlCoverpoint VL_NOT_FINAL : public VlCoverpointIf {
|
||||||
|
protected:
|
||||||
|
// MEMBERS (protected so VlCoverpointT::incrementBin can update them)
|
||||||
std::string m_hier; // "covergroup.coverpoint"
|
std::string m_hier; // "covergroup.coverpoint"
|
||||||
uint32_t m_atLeast = 1; // option.at_least (coverpoint-wide)
|
uint32_t m_atLeast = 1; // option.at_least (coverpoint-wide)
|
||||||
int m_total = 0; // bins across all sets
|
uint32_t m_total = 0; // bins across all sets
|
||||||
int m_normal = 0; // Normal bins (coverage denominator)
|
uint32_t m_normal = 0; // Normal bins (coverage denominator)
|
||||||
int m_nextBase = 0; // running append cursor
|
uint32_t m_nextBase = 0; // running append cursor
|
||||||
std::vector<uint32_t> m_counts; // [m_total], one per bin
|
std::vector<uint32_t> m_counts; // [m_total], one per bin
|
||||||
std::vector<VlCovNamer> m_namers; // appended in declaration order
|
std::vector<VlCovNamer> m_namers; // appended in declaration order
|
||||||
|
// [m_total] full bin idx -> cross idx (Normal-only), -1 otherwise. The only
|
||||||
|
// signed index here: -1 marks a non-Normal bin, which incrementBin filters on.
|
||||||
|
std::vector<int> m_crossIdx;
|
||||||
|
// [m_normal] inverse of m_crossIdx: cross idx -> full bin idx, appended in cross-index order
|
||||||
|
std::vector<uint32_t> m_crossToBin;
|
||||||
|
uint32_t m_hitCount = 0; // entries valid in the hit list this sample
|
||||||
|
|
||||||
|
private:
|
||||||
// PRIVATE METHODS
|
// PRIVATE METHODS
|
||||||
const VlCovNamer& namerFor(int i) const; // obtain the bin-specific name producer
|
const VlCovNamer& namerFor(uint32_t i) const; // obtain the bin-specific name producer
|
||||||
void addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name,
|
void addNamer(VlCovBinKind set, uint32_t count, VlCovBinNaming naming, const char* name,
|
||||||
const char* file, int line, int col);
|
const char* file, int line, int col);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -108,31 +122,44 @@ public:
|
|||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
// ---- configuration (from generated constructor) ----
|
// ---- configuration (from generated constructor) ----
|
||||||
void init(const char* hier, uint32_t atLeast, int nBins);
|
void init(const char* hier, uint32_t atLeast, uint32_t nBins);
|
||||||
void addSingleNamer(VlCovBinKind set, const char* name, const char* file, int line, int col) {
|
void addSingleNamer(VlCovBinKind set, const char* name, const char* file, int line, int col) {
|
||||||
addNamer(set, 1, VlCovBinNaming::Single, name, file, line, col);
|
addNamer(set, 1, VlCovBinNaming::Single, name, file, line, col);
|
||||||
}
|
}
|
||||||
void addArrayNamer(VlCovBinKind set, int count, const char* name, const char* file, int line,
|
void addArrayNamer(VlCovBinKind set, uint32_t count, const char* name, const char* file,
|
||||||
int col) {
|
int line, int col) {
|
||||||
addNamer(set, count, VlCovBinNaming::Array, name, file, line, col);
|
addNamer(set, count, VlCovBinNaming::Array, name, file, line, col);
|
||||||
}
|
}
|
||||||
void registerBins(VerilatedCovContext* covcontextp, const char* page);
|
void registerBins(VerilatedCovContext* covcontextp, const char* page);
|
||||||
|
|
||||||
// ---- hot path (from generated sample()) ----
|
// ---- hot path (from generated sample()) ----
|
||||||
void incrementBin(int i) { ++m_counts[i]; } // Normal bin: count only
|
// Clear the hit list at the start of each sample() for a cross-fed coverpoint.
|
||||||
void recordHit(int i) { ++m_counts[i]; } // Ignore/Illegal/Default: count only
|
void clearHitList() { m_hitCount = 0; }
|
||||||
|
// Ignore/Illegal/Default: count only; never propagates to cross coverage.
|
||||||
|
void recordHit(uint32_t i) { ++m_counts[i]; }
|
||||||
|
// incrementBin (Normal bin: count + hit-list append) lives in VlCoverpointT<MaxHits>,
|
||||||
|
// where MaxHits is the gen-time max per-sample bin overlap.
|
||||||
|
|
||||||
|
// ---- cross support (read by VlCoverCross) ----
|
||||||
|
uint32_t hitCount() const { return m_hitCount; }
|
||||||
|
virtual const uint32_t* hitList() const = 0; // provided by VlCoverpointT
|
||||||
|
uint32_t normalBinCount() const { return m_normal; } // cross dimension size (Normal bins)
|
||||||
|
std::string normalBinName(uint32_t crossIdx) const; // name of the crossIdx-th Normal bin
|
||||||
|
|
||||||
// ---- VlCoverpointIf ----
|
// ---- VlCoverpointIf ----
|
||||||
int binCount() const override { return m_total; }
|
uint32_t binCount() const override { return m_total; }
|
||||||
std::string binName(int i) const override;
|
std::string binName(uint32_t i) const override;
|
||||||
VlCovBinKind binKind(int i) const override { return namerFor(i).set(); }
|
// Deliberately not on VlCoverpointIf: only registerBins() needs it, via the
|
||||||
|
// concrete coverpoint. A cross has all-Normal bins and exposes no kind, so the
|
||||||
|
// interface omits it; add it back only if a writer needs it polymorphically.
|
||||||
|
VlCovBinKind binKind(uint32_t i) const { return namerFor(i).set(); }
|
||||||
void coverageParts(double& covered, double& total) const override {
|
void coverageParts(double& covered, double& total) const override {
|
||||||
// Count Normal bins that reached option.at_least on demand, so the hot
|
// Count Normal bins that reached option.at_least on demand, so the hot
|
||||||
// path (incrementBin) stays a plain counter bump.
|
// path (incrementBin) stays a plain counter bump.
|
||||||
int numCovered = 0;
|
uint32_t numCovered = 0;
|
||||||
for (const VlCovNamer& nm : m_namers) {
|
for (const VlCovNamer& nm : m_namers) {
|
||||||
if (nm.set() != VlCovBinKind::KIND_NORMAL) continue;
|
if (nm.set() != VlCovBinKind::KIND_NORMAL) continue;
|
||||||
for (int i = nm.base(); i < nm.base() + nm.count(); ++i) {
|
for (uint32_t i = nm.base(); i < nm.base() + nm.count(); ++i) {
|
||||||
if (m_counts[i] >= m_atLeast) ++numCovered;
|
if (m_counts[i] >= m_atLeast) ++numCovered;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,4 +168,90 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VlCoverpointT
|
||||||
|
/// Concrete coverpoint with an inline hit-list array sized to MaxHits -- the
|
||||||
|
/// gen-time maximum number of Normal bins one sample value can match (1 for the
|
||||||
|
/// common non-overlapping case). The bound is a compile-time constant, so for
|
||||||
|
/// MaxHits == 1 incrementBin collapses to a single store. Generated code holds
|
||||||
|
/// the coverpoint as VlCoverpointT<K> and calls incrementBin via the concrete
|
||||||
|
/// type; the cross reads it polymorphically through VlCoverpoint*.
|
||||||
|
|
||||||
|
template <uint32_t MaxHits>
|
||||||
|
class VlCoverpointT final : public VlCoverpoint {
|
||||||
|
// MEMBERS
|
||||||
|
uint32_t m_hits[MaxHits]; // cross indices of Normal bins hit this sample
|
||||||
|
|
||||||
|
public:
|
||||||
|
// CONSTRUCTORS
|
||||||
|
VlCoverpointT() = default;
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
// Normal bin: bump count and append the bin's cross index to the hit list.
|
||||||
|
// m_hitCount can never exceed MaxHits (the gen-time overlap bound), so no hit
|
||||||
|
// is ever dropped; the bound check is a compile-time-folded safety net.
|
||||||
|
void incrementBin(uint32_t i) {
|
||||||
|
++m_counts[i];
|
||||||
|
// m_crossIdx is signed only to carry the -1 "not a Normal bin" marker;
|
||||||
|
// the >= 0 test below is what makes every stored hit index unsigned-safe.
|
||||||
|
const int cx = m_crossIdx[i];
|
||||||
|
if (cx >= 0 && m_hitCount < MaxHits) m_hits[m_hitCount++] = static_cast<uint32_t>(cx);
|
||||||
|
}
|
||||||
|
const uint32_t* hitList() const override { return m_hits; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VlCoverCross
|
||||||
|
/// Per-instance auto cross runtime. Holds flat uint32_t[] storage over the
|
||||||
|
/// Cartesian product of the feeding coverpoints' Normal bins. Each sample()
|
||||||
|
/// walks the coverpoint hit lists (O(hits), not O(product)). Bin names are
|
||||||
|
/// built on demand from the coverpoints, so no per-bin name is stored.
|
||||||
|
|
||||||
|
class VlCoverCross final : public VlCoverpointIf {
|
||||||
|
// MEMBERS
|
||||||
|
std::string m_hier; // "covergroup.cross"
|
||||||
|
const char* m_file = nullptr; // Cross declaration file (registration metadata)
|
||||||
|
int m_line = 0; // Cross declaration line
|
||||||
|
int m_col = 0; // Cross declaration column
|
||||||
|
uint32_t m_dims = 0; // Number of feeding coverpoints
|
||||||
|
// Cross bin indexes are unsigned, like the coverpoint bin indexes they are
|
||||||
|
// built from. init() fatals if the product would exceed UINT32_MAX, so every
|
||||||
|
// index computed here provably fits. That bound is far beyond anything
|
||||||
|
// storable anyway: m_flatCounts alone would need 16GB.
|
||||||
|
uint32_t m_numAutoBins = 0; // Product of per-dim Normal bin counts
|
||||||
|
uint32_t m_numCovered = 0; // Distinct bins hit >= 1 (maintained incrementally)
|
||||||
|
std::vector<uint32_t> m_cpBinCounts; // [m_dims] Normal bin count per dimension
|
||||||
|
std::vector<uint32_t> m_stride; // [m_dims] Flat-index stride per dimension
|
||||||
|
std::vector<uint32_t> m_flatCounts; // [m_numAutoBins] Per-bin hit counts
|
||||||
|
std::vector<VlCoverpoint*> m_cps; // Feeding coverpoints (the only name source)
|
||||||
|
|
||||||
|
// PRIVATE METHODS
|
||||||
|
void iterateProduct(VlCoverpoint* const* cps, uint32_t dim, uint32_t baseIdx);
|
||||||
|
void incrementTuple(uint32_t idx) {
|
||||||
|
if (m_flatCounts[idx]++ == 0) ++m_numCovered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// CONSTRUCTORS
|
||||||
|
VlCoverCross() = default;
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
// ---- configuration (from generated constructor, after coverpoints init'd) ----
|
||||||
|
void init(const char* hier, uint32_t dims, VlCoverpoint* const* cps, const char* file,
|
||||||
|
int line, int col);
|
||||||
|
void registerBins(VerilatedCovContext* covcontextp, const char* page);
|
||||||
|
|
||||||
|
// ---- hot path (from generated sample(), after all coverpoints sampled) ----
|
||||||
|
void sample(VlCoverpoint* const* cps);
|
||||||
|
|
||||||
|
// ---- VlCoverpointIf ----
|
||||||
|
// A cross is a coverpoint whose bins are the auto cross bins (all Normal).
|
||||||
|
uint32_t binCount() const override { return m_numAutoBins; }
|
||||||
|
std::string binName(uint32_t flat) const override;
|
||||||
|
void coverageParts(double& covered, double& total) const override {
|
||||||
|
covered = m_numCovered;
|
||||||
|
total = m_numAutoBins;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|||||||
+16
-16
@@ -37,68 +37,68 @@
|
|||||||
// SETTING OPERATORS
|
// SETTING OPERATORS
|
||||||
|
|
||||||
// Convert svBitVecVal to Verilator internal data
|
// Convert svBitVecVal to Verilator internal data
|
||||||
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, const svBitVecVal* lwp) VL_MT_SAFE {
|
inline void VL_SET_W_SVBV(int obits, WDataOutP owp, const svBitVecVal* lwp) VL_MT_SAFE {
|
||||||
const int words = VL_WORDS_I(obits);
|
const int words = VL_WORDS_I(obits);
|
||||||
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i];
|
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i];
|
||||||
owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits);
|
owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits);
|
||||||
}
|
}
|
||||||
static inline void VL_SET_Q_SVBV(int obits, QData& out, const svBitVecVal* lwp) VL_MT_SAFE {
|
inline void VL_SET_Q_SVBV(int obits, QData& out, const svBitVecVal* lwp) VL_MT_SAFE {
|
||||||
out = VL_MASK_Q(obits) & VL_SET_QII(lwp[1], lwp[0]);
|
out = VL_MASK_Q(obits) & VL_SET_QII(lwp[1], lwp[0]);
|
||||||
}
|
}
|
||||||
static inline void VL_SET_I_SVBV(int obits, IData& out, const svBitVecVal* lwp) VL_MT_SAFE {
|
inline void VL_SET_I_SVBV(int obits, IData& out, const svBitVecVal* lwp) VL_MT_SAFE {
|
||||||
out = VL_MASK_I(obits) & lwp[0];
|
out = VL_MASK_I(obits) & lwp[0];
|
||||||
}
|
}
|
||||||
static inline void VL_SET_S_SVBV(int obits, SData& out, const svBitVecVal* lwp) VL_MT_SAFE {
|
inline void VL_SET_S_SVBV(int obits, SData& out, const svBitVecVal* lwp) VL_MT_SAFE {
|
||||||
out = VL_MASK_I(obits) & lwp[0];
|
out = VL_MASK_I(obits) & lwp[0];
|
||||||
}
|
}
|
||||||
static inline void VL_SET_C_SVBV(int obits, CData& out, const svBitVecVal* lwp) VL_MT_SAFE {
|
inline void VL_SET_C_SVBV(int obits, CData& out, const svBitVecVal* lwp) VL_MT_SAFE {
|
||||||
out = VL_MASK_I(obits) & lwp[0];
|
out = VL_MASK_I(obits) & lwp[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert Verilator internal data to svBitVecVal
|
// Convert Verilator internal data to svBitVecVal
|
||||||
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, const WDataInP lwp) VL_MT_SAFE {
|
inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, const WDataInP lwp) VL_MT_SAFE {
|
||||||
const int words = VL_WORDS_I(obits);
|
const int words = VL_WORDS_I(obits);
|
||||||
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i];
|
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i];
|
||||||
owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits);
|
owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits);
|
||||||
}
|
}
|
||||||
static inline void VL_SET_SVBV_I(int, svBitVecVal* owp, const IData ld) VL_MT_SAFE { owp[0] = ld; }
|
inline void VL_SET_SVBV_I(int, svBitVecVal* owp, const IData ld) VL_MT_SAFE { owp[0] = ld; }
|
||||||
static inline void VL_SET_SVBV_Q(int, svBitVecVal* owp, const QData ld) VL_MT_SAFE {
|
inline void VL_SET_SVBV_Q(int, svBitVecVal* owp, const QData ld) VL_MT_SAFE {
|
||||||
VL_SET_WQ(WDataOutP::external(owp), ld);
|
VL_SET_WQ(WDataOutP::external(owp), ld);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert svLogicVecVal to Verilator internal data
|
// Convert svLogicVecVal to Verilator internal data
|
||||||
// Note these functions ignore X/Z in svLogicVecVal
|
// Note these functions ignore X/Z in svLogicVecVal
|
||||||
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, const svLogicVecVal* lwp) VL_MT_SAFE {
|
inline void VL_SET_W_SVLV(int obits, WDataOutP owp, const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||||
const int words = VL_WORDS_I(obits);
|
const int words = VL_WORDS_I(obits);
|
||||||
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i].aval;
|
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i].aval;
|
||||||
owp[words - 1] = lwp[words - 1].aval & VL_MASK_I(obits);
|
owp[words - 1] = lwp[words - 1].aval & VL_MASK_I(obits);
|
||||||
}
|
}
|
||||||
static inline void VL_SET_Q_SVLV(int obits, QData& out, const svLogicVecVal* lwp) VL_MT_SAFE {
|
inline void VL_SET_Q_SVLV(int obits, QData& out, const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||||
out = VL_MASK_Q(obits) & VL_SET_QII(lwp[1].aval, lwp[0].aval);
|
out = VL_MASK_Q(obits) & VL_SET_QII(lwp[1].aval, lwp[0].aval);
|
||||||
}
|
}
|
||||||
static inline void VL_SET_I_SVLV(int obits, IData& out, const svLogicVecVal* lwp) VL_MT_SAFE {
|
inline void VL_SET_I_SVLV(int obits, IData& out, const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||||
out = VL_MASK_I(obits) & lwp[0].aval;
|
out = VL_MASK_I(obits) & lwp[0].aval;
|
||||||
}
|
}
|
||||||
static inline void VL_SET_S_SVLV(int obits, SData& out, const svLogicVecVal* lwp) VL_MT_SAFE {
|
inline void VL_SET_S_SVLV(int obits, SData& out, const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||||
out = VL_MASK_I(obits) & lwp[0].aval;
|
out = VL_MASK_I(obits) & lwp[0].aval;
|
||||||
}
|
}
|
||||||
static inline void VL_SET_C_SVLV(int obits, CData& out, const svLogicVecVal* lwp) VL_MT_SAFE {
|
inline void VL_SET_C_SVLV(int obits, CData& out, const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||||
out = VL_MASK_I(obits) & lwp[0].aval;
|
out = VL_MASK_I(obits) & lwp[0].aval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert Verilator internal data to svLogicVecVal
|
// Convert Verilator internal data to svLogicVecVal
|
||||||
// Note these functions never create X/Z in svLogicVecVal
|
// Note these functions never create X/Z in svLogicVecVal
|
||||||
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, const WDataInP lwp) VL_MT_SAFE {
|
inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, const WDataInP lwp) VL_MT_SAFE {
|
||||||
const int words = VL_WORDS_I(obits);
|
const int words = VL_WORDS_I(obits);
|
||||||
for (int i = 0; i < words; ++i) owp[i].bval = 0;
|
for (int i = 0; i < words; ++i) owp[i].bval = 0;
|
||||||
for (int i = 0; i < words - 1; ++i) owp[i].aval = lwp[i];
|
for (int i = 0; i < words - 1; ++i) owp[i].aval = lwp[i];
|
||||||
owp[words - 1].aval = lwp[words - 1] & VL_MASK_I(obits);
|
owp[words - 1].aval = lwp[words - 1] & VL_MASK_I(obits);
|
||||||
}
|
}
|
||||||
static inline void VL_SET_SVLV_I(int, svLogicVecVal* owp, const IData ld) VL_MT_SAFE {
|
inline void VL_SET_SVLV_I(int, svLogicVecVal* owp, const IData ld) VL_MT_SAFE {
|
||||||
owp[0].aval = ld;
|
owp[0].aval = ld;
|
||||||
owp[0].bval = 0;
|
owp[0].bval = 0;
|
||||||
}
|
}
|
||||||
static inline void VL_SET_SVLV_Q(int, svLogicVecVal* owp, const QData ld) VL_MT_SAFE {
|
inline void VL_SET_SVLV_Q(int, svLogicVecVal* owp, const QData ld) VL_MT_SAFE {
|
||||||
VlWide<2> lwp;
|
VlWide<2> lwp;
|
||||||
VL_SET_WQ(lwp, ld);
|
VL_SET_WQ(lwp, ld);
|
||||||
owp[0].aval = lwp[0];
|
owp[0].aval = lwp[0];
|
||||||
|
|||||||
@@ -98,8 +98,10 @@ void VerilatedFst::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
|||||||
const VerilatedLockGuard lock{m_mutex};
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
Super::closeBase();
|
Super::closeBase();
|
||||||
emitTimeChangeMaybe();
|
emitTimeChangeMaybe();
|
||||||
if (m_fst) m_fst->close(); // LCOV_EXCL_BR_LINE
|
if (m_fst) {
|
||||||
m_fst = nullptr;
|
m_fst->close();
|
||||||
|
VL_DO_CLEAR(delete m_fst, m_fst = nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedFst::flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
void VerilatedFst::flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
|
|||||||
+406
-465
File diff suppressed because it is too large
Load Diff
@@ -90,23 +90,26 @@ static double _vl_dbase_chi_square(IData& seedr, int32_t deg_of_free) VL_MT_SAFE
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static IData _vl_round_to_int32(double r) VL_PURE {
|
||||||
|
int32_t i;
|
||||||
|
if (r >= 0) {
|
||||||
|
i = static_cast<int32_t>(r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding
|
||||||
|
} else {
|
||||||
|
r = -r;
|
||||||
|
i = static_cast<int32_t>(r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding
|
||||||
|
i = -i;
|
||||||
|
}
|
||||||
|
return static_cast<IData>(i);
|
||||||
|
}
|
||||||
|
|
||||||
IData VL_DIST_CHI_SQUARE(IData& seedr, IData udf) VL_MT_SAFE {
|
IData VL_DIST_CHI_SQUARE(IData& seedr, IData udf) VL_MT_SAFE {
|
||||||
const int32_t df = static_cast<int32_t>(udf);
|
const int32_t df = static_cast<int32_t>(udf);
|
||||||
if (VL_UNLIKELY(df <= 0)) {
|
if (VL_UNLIKELY(df <= 0)) {
|
||||||
// Chi_square distribution must have positive degree of freedom
|
// Chi_square distribution must have positive degree of freedom
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
double r = _vl_dbase_chi_square(seedr, df);
|
const double r = _vl_dbase_chi_square(seedr, df);
|
||||||
int32_t i;
|
return _vl_round_to_int32(r);
|
||||||
if (r >= 0) {
|
|
||||||
i = static_cast<int32_t>(r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding
|
|
||||||
} else {
|
|
||||||
r = -r; // LCOV_EXCL_LINE
|
|
||||||
i = static_cast<int32_t>(
|
|
||||||
r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding // LCOV_EXCL_LINE
|
|
||||||
i = -i; // LCOV_EXCL_LINE
|
|
||||||
}
|
|
||||||
return static_cast<IData>(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IData VL_DIST_ERLANG(IData& seedr, IData uk, IData umean) VL_MT_SAFE {
|
IData VL_DIST_ERLANG(IData& seedr, IData uk, IData umean) VL_MT_SAFE {
|
||||||
@@ -120,16 +123,8 @@ IData VL_DIST_ERLANG(IData& seedr, IData uk, IData umean) VL_MT_SAFE {
|
|||||||
for (int32_t i = 1; i <= k; ++i) x = x * _vl_dbase_uniform(seedr, 0, 1);
|
for (int32_t i = 1; i <= k; ++i) x = x * _vl_dbase_uniform(seedr, 0, 1);
|
||||||
const double a = static_cast<double>(mean);
|
const double a = static_cast<double>(mean);
|
||||||
const double b = static_cast<double>(k);
|
const double b = static_cast<double>(k);
|
||||||
double r = -a * log(x) / b;
|
const double r = -a * log(x) / b;
|
||||||
int32_t i;
|
return _vl_round_to_int32(r);
|
||||||
if (r >= 0) {
|
|
||||||
i = static_cast<int32_t>(r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding
|
|
||||||
} else {
|
|
||||||
r = -r;
|
|
||||||
i = static_cast<int32_t>(r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding
|
|
||||||
i = -i;
|
|
||||||
}
|
|
||||||
return static_cast<IData>(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IData VL_DIST_EXPONENTIAL(IData& seedr, IData umean) VL_MT_SAFE {
|
IData VL_DIST_EXPONENTIAL(IData& seedr, IData umean) VL_MT_SAFE {
|
||||||
@@ -139,31 +134,15 @@ IData VL_DIST_EXPONENTIAL(IData& seedr, IData umean) VL_MT_SAFE {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int32_t i;
|
int32_t i;
|
||||||
double r = _vl_dbase_exponential(seedr, mean);
|
const double r = _vl_dbase_exponential(seedr, mean);
|
||||||
if (r >= 0) {
|
return _vl_round_to_int32(r);
|
||||||
i = static_cast<int32_t>(r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding
|
|
||||||
} else {
|
|
||||||
r = -r; // LCOV_EXCL_LINE
|
|
||||||
i = static_cast<int32_t>(
|
|
||||||
r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding // LCOV_EXCL_LINE
|
|
||||||
i = -i; // LCOV_EXCL_LINE
|
|
||||||
}
|
|
||||||
return static_cast<IData>(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IData VL_DIST_NORMAL(IData& seedr, IData umean, IData usd) VL_MT_SAFE {
|
IData VL_DIST_NORMAL(IData& seedr, IData umean, IData usd) VL_MT_SAFE {
|
||||||
const int32_t mean = static_cast<int32_t>(umean);
|
const int32_t mean = static_cast<int32_t>(umean);
|
||||||
const int32_t sd = static_cast<int32_t>(usd);
|
const int32_t sd = static_cast<int32_t>(usd);
|
||||||
double r = _vl_dbase_normal(seedr, mean, sd);
|
const double r = _vl_dbase_normal(seedr, mean, sd);
|
||||||
int32_t i;
|
return _vl_round_to_int32(r);
|
||||||
if (r >= 0) {
|
|
||||||
i = static_cast<int32_t>(r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding
|
|
||||||
} else {
|
|
||||||
r = -r;
|
|
||||||
i = static_cast<int32_t>(r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding
|
|
||||||
i = -i;
|
|
||||||
}
|
|
||||||
return static_cast<IData>(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IData VL_DIST_POISSON(IData& seedr, IData umean) VL_MT_SAFE {
|
IData VL_DIST_POISSON(IData& seedr, IData umean) VL_MT_SAFE {
|
||||||
@@ -192,16 +171,8 @@ IData VL_DIST_T(IData& seedr, IData udf) VL_MT_SAFE {
|
|||||||
const double chi2 = _vl_dbase_chi_square(seedr, df);
|
const double chi2 = _vl_dbase_chi_square(seedr, df);
|
||||||
const double div = chi2 / static_cast<double>(df);
|
const double div = chi2 / static_cast<double>(df);
|
||||||
const double root = std::sqrt(div);
|
const double root = std::sqrt(div);
|
||||||
double r = _vl_dbase_normal(seedr, 0, 1) / root;
|
const double r = _vl_dbase_normal(seedr, 0, 1) / root;
|
||||||
int32_t i;
|
return _vl_round_to_int32(r);
|
||||||
if (r >= 0) {
|
|
||||||
i = static_cast<int32_t>(r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding
|
|
||||||
} else {
|
|
||||||
r = -r;
|
|
||||||
i = static_cast<int32_t>(r + 0.5); // cppcheck-suppress bugprone-incorrect-rounding
|
|
||||||
i = -i;
|
|
||||||
}
|
|
||||||
return static_cast<IData>(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IData VL_DIST_UNIFORM(IData& seedr, IData ustart, IData uend) VL_MT_SAFE {
|
IData VL_DIST_UNIFORM(IData& seedr, IData ustart, IData uend) VL_MT_SAFE {
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ static_assert(std::is_trivially_destructible<VlExecutionRecord>::value,
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VlExecutionProfiler is for collecting profiling data about model execution
|
// VlExecutionProfiler is for collecting profiling data about model execution
|
||||||
|
|
||||||
class VlExecutionProfiler final : public VerilatedVirtualBase {
|
class VlExecutionProfiler final : public VlExecutionProfilerBase {
|
||||||
// CONSTANTS
|
// CONSTANTS
|
||||||
|
|
||||||
// In order to try to avoid dynamic memory allocations during the actual profiling phase,
|
// In order to try to avoid dynamic memory allocations during the actual profiling phase,
|
||||||
@@ -193,8 +193,15 @@ public:
|
|||||||
t_trace.emplace_back();
|
t_trace.emplace_back();
|
||||||
return t_trace.back();
|
return t_trace.back();
|
||||||
}
|
}
|
||||||
// Configure profiler (called in beginning of 'eval')
|
// Record the beginning/end of a section, for the run-time library
|
||||||
void configure();
|
void sectionPush(const char* namep) override {
|
||||||
|
if (VL_UNLIKELY(m_enabled)) addRecord().sectionPush(namep);
|
||||||
|
}
|
||||||
|
void sectionPop() override {
|
||||||
|
if (VL_UNLIKELY(m_enabled)) addRecord().sectionPop();
|
||||||
|
}
|
||||||
|
// Advance the profiling window, called by the run-time evaluation loop
|
||||||
|
void configure() override;
|
||||||
// Setup profiling on a particular thread;
|
// Setup profiling on a particular thread;
|
||||||
void setupThread(uint32_t threadId);
|
void setupThread(uint32_t threadId);
|
||||||
// Clear all profiling data
|
// Clear all profiling data
|
||||||
|
|||||||
+1132
-466
File diff suppressed because it is too large
Load Diff
+158
-32
@@ -79,10 +79,14 @@ public:
|
|||||||
virtual void* datap(int /*idx*/) const { return m_datap; }
|
virtual void* datap(int /*idx*/) const { return m_datap; }
|
||||||
std::uint32_t randModeIdx() const { return m_randModeIdx; }
|
std::uint32_t randModeIdx() const { return m_randModeIdx; }
|
||||||
bool randModeIdxNone() const { return randModeIdx() == std::numeric_limits<unsigned>::max(); }
|
bool randModeIdxNone() const { return randModeIdx() == std::numeric_limits<unsigned>::max(); }
|
||||||
bool set(const std::string& idx, const std::string& val) const;
|
void set(const std::string& idx, const std::string& val) const;
|
||||||
virtual void emitGetValue(std::ostream& s) const;
|
virtual void emitGetValue(std::ostream& s) const;
|
||||||
virtual void emitExtract(std::ostream& s, int i) const;
|
virtual void emitExtract(std::ostream& s, int i) const;
|
||||||
virtual void emitType(std::ostream& s) const;
|
virtual void emitType(std::ostream& s) const;
|
||||||
|
// Emit the expression referring to element j as a whole (the full var
|
||||||
|
// for scalars, "(select arr idx...)" for array element j). Used by BSAT
|
||||||
|
// to query/re-assert one whole element's value, not a single bit.
|
||||||
|
virtual void emitElement(std::ostream& s, int j) const;
|
||||||
// Emit the current runtime value as an SMT bit-vector literal (#b...).
|
// Emit the current runtime value as an SMT bit-vector literal (#b...).
|
||||||
// Used by randomize(null) to pin a var to its existing value.
|
// Used by randomize(null) to pin a var to its existing value.
|
||||||
virtual void emitConcreteValue(std::ostream& s) const;
|
virtual void emitConcreteValue(std::ostream& s) const;
|
||||||
@@ -104,13 +108,32 @@ public:
|
|||||||
count_cache[base_name] = count;
|
count_cache[base_name] = count;
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
bool hasMatchingElements(const ArrayInfoMap& arr_vars, const std::string& base_name) const {
|
||||||
|
return arr_vars.find(base_name + "0") != arr_vars.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// SMT key width per associative-array level (string = 128, integral = 8 * sizeof).
|
||||||
|
template <typename T>
|
||||||
|
struct VlRandomAssocKeyWidths final {
|
||||||
|
static void push(std::vector<size_t>&) {}
|
||||||
|
};
|
||||||
|
template <typename T_Key, typename T_Value>
|
||||||
|
struct VlRandomAssocKeyWidths<VlAssocArray<T_Key, T_Value>> final {
|
||||||
|
static void push(std::vector<size_t>& widths) {
|
||||||
|
widths.push_back(std::is_same<T_Key, std::string>::value ? 128 : sizeof(T_Key) * 8);
|
||||||
|
VlRandomAssocKeyWidths<T_Value>::push(widths);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class VlRandomArrayVarTemplate final : public VlRandomVar {
|
class VlRandomArrayVarTemplate final : public VlRandomVar {
|
||||||
|
// Static key widths per level for the empty-array declaration fallback
|
||||||
|
const std::vector<size_t> m_fallbackIdxWidths;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VlRandomArrayVarTemplate(const std::string& name, int width, void* datap, int dimension,
|
VlRandomArrayVarTemplate(const std::string& name, int width, void* datap, int dimension,
|
||||||
std::uint32_t randModeIdx)
|
std::uint32_t randModeIdx, const std::vector<size_t>& idxWidths = {})
|
||||||
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
: VlRandomVar{name, width, datap, dimension, randModeIdx}
|
||||||
|
, m_fallbackIdxWidths{idxWidths} {}
|
||||||
void* datap(int idx) const override {
|
void* datap(int idx) const override {
|
||||||
const std::string indexed_name = name() + std::to_string(idx);
|
const std::string indexed_name = name() + std::to_string(idx);
|
||||||
const auto it = m_arrVarsRefp->find(indexed_name);
|
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||||
@@ -175,7 +198,13 @@ public:
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (dimension() > 0) {
|
if (dimension() > 0) {
|
||||||
for (int i = 0; i < dimension(); ++i) s << "(Array (_ BitVec 32) ";
|
// Empty array: declare from the static key widths, not a 32-bit default.
|
||||||
|
for (int i = 0; i < dimension(); ++i) {
|
||||||
|
const size_t idxWidth = i < static_cast<int>(m_fallbackIdxWidths.size())
|
||||||
|
? m_fallbackIdxWidths[i]
|
||||||
|
: 32;
|
||||||
|
s << "(Array (_ BitVec " << idxWidth << ") ";
|
||||||
|
}
|
||||||
s << "(_ BitVec " << width() << ")";
|
s << "(_ BitVec " << width() << ")";
|
||||||
for (int i = 0; i < dimension(); ++i) s << ")";
|
for (int i = 0; i < dimension(); ++i) s << ")";
|
||||||
} else {
|
} else {
|
||||||
@@ -188,6 +217,20 @@ public:
|
|||||||
const int elementCounts = countMatchingElements(*m_arrVarsRefp, name());
|
const int elementCounts = countMatchingElements(*m_arrVarsRefp, name());
|
||||||
return width() * elementCounts;
|
return width() * elementCounts;
|
||||||
}
|
}
|
||||||
|
void emitElement(std::ostream& s, int j) const override {
|
||||||
|
const std::string indexed_name = name() + std::to_string(j);
|
||||||
|
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||||
|
// Callers take j from totalWidth(), which counts these same keys, so the element
|
||||||
|
// should always be there
|
||||||
|
if (VL_UNCOVERABLE(it == m_arrVarsRefp->end())) {
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
VL_FATAL_MT(__FILE__, __LINE__, "randomize", "indexed_name not found in m_arr_vars");
|
||||||
|
return;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
|
s << ' ';
|
||||||
|
emitSelect(s, it->second->m_indices, it->second->m_idxWidths);
|
||||||
|
} // LCOV_EXCL_BR_LINE
|
||||||
void emitExtract(std::ostream& s, int i) const override {
|
void emitExtract(std::ostream& s, int i) const override {
|
||||||
const int j = i / width();
|
const int j = i / width();
|
||||||
i = i % width();
|
i = i % width();
|
||||||
@@ -205,6 +248,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VlSolverSession;
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Object holding constraints and variable references.
|
// Object holding constraints and variable references.
|
||||||
class VlRandomizer VL_NOT_FINAL {
|
class VlRandomizer VL_NOT_FINAL {
|
||||||
@@ -217,8 +262,7 @@ class VlRandomizer VL_NOT_FINAL {
|
|||||||
std::set<std::string> m_disabledVars; // Variables with rand_mode off (skip write-back)
|
std::set<std::string> m_disabledVars; // Variables with rand_mode off (skip write-back)
|
||||||
// variables
|
// variables
|
||||||
ArrayInfoMap m_arr_vars; // Tracks each element in array structures for iteration
|
ArrayInfoMap m_arr_vars; // Tracks each element in array structures for iteration
|
||||||
std::vector<std::string> m_unique_arrays;
|
std::vector<std::string> m_unique_arrays; // Arrays whose elements must be distinct
|
||||||
std::map<std::string, uint32_t> m_unique_array_sizes;
|
|
||||||
const VlQueue<CData>* m_randmodep = nullptr; // rand_mode state;
|
const VlQueue<CData>* m_randmodep = nullptr; // rand_mode state;
|
||||||
const VlQueue<CData>* m_static_randmodep = nullptr; // Static rand_mode state (shared)
|
const VlQueue<CData>* m_static_randmodep = nullptr; // Static rand_mode state (shared)
|
||||||
std::unordered_set<std::string> m_staticVars; // Names of static rand vars
|
std::unordered_set<std::string> m_staticVars; // Names of static rand vars
|
||||||
@@ -230,17 +274,88 @@ class VlRandomizer VL_NOT_FINAL {
|
|||||||
std::vector<std::pair<std::string, std::string>>
|
std::vector<std::pair<std::string, std::string>>
|
||||||
m_solveBefore; // Solve-before ordering pairs (beforeVar, afterVar)
|
m_solveBefore; // Solve-before ordering pairs (beforeVar, afterVar)
|
||||||
bool m_checkOnly = false; // Set for randomize(null)
|
bool m_checkOnly = false; // Set for randomize(null)
|
||||||
|
bool isFrozenVar(const std::string& name,
|
||||||
|
const VlRandomVar& var) const; // true if this var is currently frozen
|
||||||
|
bool hasFrozenVar() const; // true if any var is currently rand_mode(0)-frozen
|
||||||
|
|
||||||
// PRIVATE METHODS
|
// PRIVATE METHODS
|
||||||
void randomConstraint(std::ostream& os, VlRNG& rngr, int bits);
|
void randomConstraint(std::ostream& os, VlRNG& rngr, int bits);
|
||||||
bool parseSolution(std::iostream& os, bool log = false);
|
// Fetch the model and write it into the registered variables.
|
||||||
bool checkSat(std::iostream& os);
|
bool applyModel(VlSolverSession& sess);
|
||||||
|
bool parseModel(std::istream& is, size_t requested);
|
||||||
|
// Assert the maximal compatible soft-constraint set onto the open session.
|
||||||
|
void relaxSoftConstraints(VlSolverSession& sess);
|
||||||
// Indices of the "a<N>" literals named by (get-unsat-assumptions).
|
// Indices of the "a<N>" literals named by (get-unsat-assumptions).
|
||||||
std::vector<int> readUnsatAssumptions(std::iostream& os);
|
std::vector<int> readUnsatAssumptions(VlSolverSession& sess);
|
||||||
|
void reportUnsatSetup(VlSolverSession& sess, const std::vector<std::string>& uniqueExprs);
|
||||||
|
void reportUnsatCore(VlSolverSession& sess);
|
||||||
void emitRandcExclusions(std::ostream& os) const; // Emit randc exclusion constraints
|
void emitRandcExclusions(std::ostream& os) const; // Emit randc exclusion constraints
|
||||||
void recordRandcValues(); // Record solved randc values for future exclusion
|
void recordRandcValues(); // Record solved randc values for future exclusion
|
||||||
size_t hashConstraints() const;
|
size_t hashConstraints(const std::vector<std::string>& extras) const;
|
||||||
bool nextPhased(VlRNG& rngr); // Phased solving for solve...before
|
bool nextRandomize(VlRNGReseeds& rngr, bool checkOnly);
|
||||||
|
// "(distinct ...)" expression per unique-constrained array
|
||||||
|
std::vector<std::string> buildUniqueExprs() const;
|
||||||
|
void emitDefines(std::ostream& os) const;
|
||||||
|
void emitDeclares(std::ostream& os, bool pinCurrent) const;
|
||||||
|
void emitAsserts(std::ostream& os, const std::vector<std::string>& extras, bool named) const;
|
||||||
|
bool nextFlat(VlRNG& rngr, VlSolverSession& sess, const std::vector<std::string>& uniqueExprs);
|
||||||
|
|
||||||
|
// --- UniGen2 (a near-uniform constrained randomization sampler) fields ---
|
||||||
|
// Implementation based on the following paper:
|
||||||
|
// "On Parallel Scalable Uniform SAT Witness Generation", Chakraborty et al.
|
||||||
|
|
||||||
|
using Witness = std::map<std::string, std::map<int, std::string>>; // One sampled solution
|
||||||
|
|
||||||
|
// Sample one random solution. False if a sample couldn't be produced
|
||||||
|
bool unigen2(VlRNG& rngr, VlSolverSession& sess, const std::vector<std::string>& uniqueExprs);
|
||||||
|
// Find out how finely to cut the solution space, and what cell size to accept
|
||||||
|
bool estimateParameters(VlSolverSession& sess, VlRNG& rngr);
|
||||||
|
// Collect up to `bound` different solutions of whatever is asserted right now.
|
||||||
|
// diversifyRngp adds a randomization step that spreads the solutions apart
|
||||||
|
int bsat(VlSolverSession& sess, size_t bound, std::vector<Witness>& witnesses,
|
||||||
|
VlRNG* diversifyRngp = nullptr);
|
||||||
|
// Add `bits` random XOR equations, which cut the solution space into cells holding
|
||||||
|
// roughly 1/2**bits of all the solutions
|
||||||
|
void unigenXors(std::iostream& os, VlRNG& rngr, int bits);
|
||||||
|
// Draw a cell and refill the batch of solutions from it
|
||||||
|
bool generateSamples(VlSolverSession& sess, VlRNG& rngr);
|
||||||
|
// Copy one solution into the SV variables
|
||||||
|
void writeBackWitness(const Witness& witness);
|
||||||
|
|
||||||
|
// UniGen2: sampling state
|
||||||
|
struct Unigen2State final {
|
||||||
|
std::vector<Witness> loThreshWitnesses; // Consumable batch of solutions: loThresh random
|
||||||
|
// picks out of the cell BSAT enumerated
|
||||||
|
std::vector<std::pair<std::string, int>> bsatOrder; // (var, element) query order
|
||||||
|
bool isLargeSpace = false; // Large solution space (more than 61 * 2^10 solutions)
|
||||||
|
// Below properties are what estimateParameters worked out, kept until the constraints
|
||||||
|
// change so the expensive search is not repeated on every call.
|
||||||
|
bool paramsValid = false; // Whether the values below are set
|
||||||
|
size_t paramHash = 0; // Constraint set they were computed for
|
||||||
|
int hashBits = 0; // How many XOR equations to cut the space with
|
||||||
|
int loThresh = 0; // Smallest usable cell, and how many samples to take
|
||||||
|
int hiThresh = 0; // First cell size counted as too big
|
||||||
|
uint64_t rngReseeds = 0; // rngr.reseeds() as of the last call
|
||||||
|
int lastSuccessI = -1; // Hash-bit count that worked last time, -1 if none
|
||||||
|
};
|
||||||
|
Unigen2State m_ug2;
|
||||||
|
|
||||||
|
void solveDiversity(VlRNG& rngr, VlSolverSession& sess);
|
||||||
|
void solveDiversityPins(VlRNG& rngr, VlSolverSession& sess);
|
||||||
|
void solveDiversityXor(VlRNG& rngr, VlSolverSession& sess);
|
||||||
|
// Layers of solve...before variables in dependency order
|
||||||
|
bool buildSolveLayers(std::vector<std::vector<std::string>>& layersr);
|
||||||
|
const char* phasedLogic() const;
|
||||||
|
bool nextPhased(VlRNG& rngr, VlSolverSession& sess,
|
||||||
|
const std::vector<std::string>& uniqueExprs);
|
||||||
|
bool solvePhases(VlRNG& rngr, VlSolverSession& sess,
|
||||||
|
const std::vector<std::vector<std::string>>& layers,
|
||||||
|
const std::vector<std::string>& uniqueExprs, bool& exhaustedr);
|
||||||
|
bool solvePhaseValues(VlSolverSession& sess, VlRNG& rngr,
|
||||||
|
const std::vector<std::string>& layerVars,
|
||||||
|
std::map<std::string, std::string>& solvedValuesr);
|
||||||
|
bool readPhaseValues(VlSolverSession& sess, std::map<std::string, std::string>& solvedValuesr);
|
||||||
|
bool parsePhaseValues(std::istream& is, std::map<std::string, std::string>& solvedValuesr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
@@ -249,10 +364,10 @@ public:
|
|||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
// Finds the next solution satisfying the constraints
|
// Finds the next solution satisfying the constraints
|
||||||
bool next(VlRNG& rngr);
|
bool next(VlRNGReseeds& rngr);
|
||||||
// Validate the constraints against the current runtime values of every
|
// Validate the constraints against the current runtime values of every
|
||||||
// registered rand variable without picking new ones.
|
// registered rand variable without picking new ones.
|
||||||
bool next_check_only(VlRNG& rngr);
|
bool next_check_only(VlRNGReseeds& rngr);
|
||||||
|
|
||||||
// --- Process the key for associative array ---
|
// --- Process the key for associative array ---
|
||||||
|
|
||||||
@@ -377,12 +492,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register queue of non-struct types
|
// Register queue of non-struct types
|
||||||
template <typename T>
|
template <typename T, size_t N_MaxSize>
|
||||||
typename std::enable_if<!VlContainsCustomStruct<T>::value, void>::type
|
typename std::enable_if<!VlContainsCustomStruct<T>::value, void>::type
|
||||||
write_var(VlQueue<T>& var, int width, const char* name, int dimension,
|
write_var(VlQueue<T, N_MaxSize>& var, int width, const char* name, int dimension,
|
||||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||||
if (m_vars.find(name) == m_vars.end()) {
|
if (m_vars.find(name) == m_vars.end()) {
|
||||||
m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlQueue<T>>>(
|
m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlQueue<T, N_MaxSize>>>(
|
||||||
name, width, &var, dimension, randmodeIdx);
|
name, width, &var, dimension, randmodeIdx);
|
||||||
}
|
}
|
||||||
if (dimension > 0) {
|
if (dimension > 0) {
|
||||||
@@ -394,9 +509,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register queue of structs
|
// Register queue of structs
|
||||||
template <typename T>
|
template <typename T, size_t N_MaxSize>
|
||||||
typename std::enable_if<VlContainsCustomStruct<T>::value, void>::type
|
typename std::enable_if<VlContainsCustomStruct<T>::value, void>::type
|
||||||
write_var(VlQueue<T>& var, int width, const char* name, int dimension,
|
write_var(VlQueue<T, N_MaxSize>& var, int width, const char* name, int dimension,
|
||||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||||
if (dimension > 0) record_struct_arr(var, name, dimension, {}, {});
|
if (dimension > 0) record_struct_arr(var, name, dimension, {}, {});
|
||||||
}
|
}
|
||||||
@@ -433,9 +548,11 @@ public:
|
|||||||
write_var(VlAssocArray<T_Key, T_Value>& var, int width, const char* name, int dimension,
|
write_var(VlAssocArray<T_Key, T_Value>& var, int width, const char* name, int dimension,
|
||||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||||
if (m_vars.find(name) == m_vars.end()) {
|
if (m_vars.find(name) == m_vars.end()) {
|
||||||
|
std::vector<size_t> keyWidths;
|
||||||
|
VlRandomAssocKeyWidths<VlAssocArray<T_Key, T_Value>>::push(keyWidths);
|
||||||
m_vars[name]
|
m_vars[name]
|
||||||
= std::make_shared<const VlRandomArrayVarTemplate<VlAssocArray<T_Key, T_Value>>>(
|
= std::make_shared<const VlRandomArrayVarTemplate<VlAssocArray<T_Key, T_Value>>>(
|
||||||
name, width, &var, dimension, randmodeIdx);
|
name, width, &var, dimension, randmodeIdx, keyWidths);
|
||||||
}
|
}
|
||||||
if (dimension > 0) {
|
if (dimension > 0) {
|
||||||
m_index = 0;
|
m_index = 0;
|
||||||
@@ -465,11 +582,10 @@ public:
|
|||||||
++m_index;
|
++m_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the "Sender" API for the generated code
|
// This is the "Sender" API for the generated code.
|
||||||
void rand_unique(const std::string& name, uint32_t size) {
|
// The elements to make distinct are taken from the array element table at
|
||||||
m_unique_arrays.push_back(name);
|
// solve time, so a container resized by the solver is handled correctly.
|
||||||
m_unique_array_sizes[name] = size;
|
void rand_unique(const std::string& name) { m_unique_arrays.push_back(name); }
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively record all elements in an unpacked array
|
// Recursively record all elements in an unpacked array
|
||||||
template <typename T, std::size_t N_Depth>
|
template <typename T, std::size_t N_Depth>
|
||||||
@@ -488,8 +604,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recursively record all elements in a queue
|
// Recursively record all elements in a queue
|
||||||
template <typename T>
|
template <typename T, size_t N_MaxSize>
|
||||||
void record_arr_table(VlQueue<T>& var, const std::string& name, int dimension,
|
void record_arr_table(VlQueue<T, N_MaxSize>& var, const std::string& name, int dimension,
|
||||||
std::vector<IData> indices, std::vector<size_t> idxWidths) {
|
std::vector<IData> indices, std::vector<size_t> idxWidths) {
|
||||||
if ((dimension > 0) && (var.size() != 0)) {
|
if ((dimension > 0) && (var.size() != 0)) {
|
||||||
idxWidths.push_back(32);
|
idxWidths.push_back(32);
|
||||||
@@ -522,7 +638,8 @@ public:
|
|||||||
idxWidths.push_back(idx_width);
|
idxWidths.push_back(idx_width);
|
||||||
indices.insert(indices.end(), integral_index.begin(), integral_index.end());
|
indices.insert(indices.end(), integral_index.begin(), integral_index.end());
|
||||||
|
|
||||||
record_arr_table(var.at(key), indexed_name, dimension - 1, indices, idxWidths);
|
record_arr_table(var.atWrite(key), indexed_name, dimension - 1, indices,
|
||||||
|
idxWidths);
|
||||||
|
|
||||||
// Cleanup indices and widths
|
// Cleanup indices and widths
|
||||||
idxWidths.pop_back();
|
idxWidths.pop_back();
|
||||||
@@ -562,8 +679,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recursively process VlQueue of structs
|
// Recursively process VlQueue of structs
|
||||||
template <typename T>
|
template <typename T, size_t N_MaxSize>
|
||||||
void record_struct_arr(VlQueue<T>& var, const std::string& name, int dimension,
|
void record_struct_arr(VlQueue<T, N_MaxSize>& var, const std::string& name, int dimension,
|
||||||
std::vector<IData> indices, std::vector<size_t> idxWidths) {
|
std::vector<IData> indices, std::vector<size_t> idxWidths) {
|
||||||
if ((dimension > 0) && (var.size() != 0)) {
|
if ((dimension > 0) && (var.size() != 0)) {
|
||||||
idxWidths.push_back(32);
|
idxWidths.push_back(32);
|
||||||
@@ -596,7 +713,7 @@ public:
|
|||||||
|
|
||||||
std::string result = oss.str();
|
std::string result = oss.str();
|
||||||
result.insert(result.begin(), int(idx_width / 4) - result.size(), '0');
|
result.insert(result.begin(), int(idx_width / 4) - result.size(), '0');
|
||||||
record_struct_arr(var.at(key), name + "." + result, dimension - 1, indices,
|
record_struct_arr(var.atWrite(key), name + "." + result, dimension - 1, indices,
|
||||||
idxWidths);
|
idxWidths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -666,7 +783,7 @@ public:
|
|||||||
// Light wrapper for RNG used by std::randomize() to support scope-level randomization.
|
// Light wrapper for RNG used by std::randomize() to support scope-level randomization.
|
||||||
class VlStdRandomizer final : public VlRandomizer {
|
class VlStdRandomizer final : public VlRandomizer {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
VlRNG m_rng; // Random number generator
|
VlRNGReseeds m_rng; // Random number generator
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
@@ -724,11 +841,20 @@ public:
|
|||||||
bool basicStdRandomization(VlAssocArray<T_Key, T_Value>& value, size_t width) {
|
bool basicStdRandomization(VlAssocArray<T_Key, T_Value>& value, size_t width) {
|
||||||
T_Key key;
|
T_Key key;
|
||||||
for (int exists = value.first(key); exists; exists = value.next(key)) {
|
for (int exists = value.first(key); exists; exists = value.next(key)) {
|
||||||
basicStdRandomization(value.at(key), width);
|
basicStdRandomization(value.atWrite(key), width);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool next() { return VlRandomizer::next(m_rng); }
|
bool next() { return VlRandomizer::next(m_rng); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
//Helper method for dynamic array handling in SMT expressions
|
||||||
|
|
||||||
|
inline std::string vlToSolverHex(const IData& value) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::hex << std::setfill('0') << std::setw(8) << value;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ VerilatedDeserialize& operator>>(VerilatedDeserialize& os, VlAssocArray<T_Key, T
|
|||||||
T_Value value;
|
T_Value value;
|
||||||
os >> index;
|
os >> index;
|
||||||
os >> value;
|
os >> value;
|
||||||
rhs.at(index) = value;
|
rhs.atWrite(index) = value;
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,7 +196,8 @@ package std;
|
|||||||
static task killQueue(ref process processQueue[$]);
|
static task killQueue(ref process processQueue[$]);
|
||||||
`ifdef VERILATOR_TIMING
|
`ifdef VERILATOR_TIMING
|
||||||
repeat (processQueue.size()) begin
|
repeat (processQueue.size()) begin
|
||||||
processQueue.pop_front().kill();
|
process p = processQueue.pop_front();
|
||||||
|
if (p) p.kill();
|
||||||
end
|
end
|
||||||
`endif
|
`endif
|
||||||
endtask
|
endtask
|
||||||
|
|||||||
@@ -284,13 +284,13 @@ void VlDynamicTriggerScheduler::dump() const {
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
// VlForkSync:: Methods
|
// VlForkSync:: Methods
|
||||||
|
|
||||||
void VlProcess::forkSyncOnKill(VlForkSyncState* forkSyncp) {
|
void VlProcess::forkSyncOnKill(std::shared_ptr<VlForkSyncState> forkSyncp) {
|
||||||
m_forkSyncOnKillp = forkSyncp;
|
m_forkSyncOnKillp = forkSyncp;
|
||||||
m_forkSyncOnKillDone = false;
|
m_forkSyncOnKillDone = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlProcess::forkSyncOnKillClear(VlForkSyncState* forkSyncp) {
|
void VlProcess::forkSyncOnKillClear(VlForkSyncState* forkSyncp) {
|
||||||
if (m_forkSyncOnKillp != forkSyncp) return;
|
if (m_forkSyncOnKillp.get() != forkSyncp) return;
|
||||||
m_forkSyncOnKillp = nullptr;
|
m_forkSyncOnKillp = nullptr;
|
||||||
m_forkSyncOnKillDone = false;
|
m_forkSyncOnKillDone = false;
|
||||||
}
|
}
|
||||||
@@ -301,19 +301,15 @@ void VlProcess::state(int s) {
|
|||||||
m_forkSyncOnKillDone = true;
|
m_forkSyncOnKillDone = true;
|
||||||
m_state = s;
|
m_state = s;
|
||||||
m_forkSyncOnKillp->done();
|
m_forkSyncOnKillp->done();
|
||||||
|
m_forkSyncOnKillp = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_state = s;
|
m_state = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
VlForkSyncState::~VlForkSyncState() {
|
|
||||||
for (const VlProcessRef& processp : m_onKillProcessps) processp->forkSyncOnKillClear(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VlForkSync::onKill(VlProcessRef process) {
|
void VlForkSync::onKill(VlProcessRef process) {
|
||||||
if (!process) return;
|
if (!process) return;
|
||||||
m_state->m_onKillProcessps.emplace_back(process);
|
process->forkSyncOnKill(m_state);
|
||||||
process->forkSyncOnKill(m_state.get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlForkSyncState::done(const char* filename, int lineno) {
|
void VlForkSyncState::done(const char* filename, int lineno) {
|
||||||
@@ -337,16 +333,18 @@ void VlForkSyncState::done(const char* filename, int lineno) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// VlCoroutine:: Methods
|
// VlPromise:: Methods
|
||||||
|
|
||||||
VlCoroutine::VlPromise::~VlPromise() {
|
VlCoroutine VlPromise::get_return_object() { return {this}; }
|
||||||
|
|
||||||
|
VlPromise::~VlPromise() {
|
||||||
// Indicate to the return object that the coroutine has finished or been destroyed
|
// Indicate to the return object that the coroutine has finished or been destroyed
|
||||||
if (m_corop) m_corop->m_promisep = nullptr;
|
if (m_corop) m_corop->m_promisep = nullptr;
|
||||||
// If there is a continuation, destroy it
|
// If there is a continuation, destroy it
|
||||||
if (m_continuation) m_continuation.destroy();
|
if (m_continuation) m_continuation.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::suspend_never VlCoroutine::VlPromise::final_suspend() noexcept {
|
std::suspend_never VlPromise::final_suspend() noexcept {
|
||||||
// Indicate to the return object that the coroutine has finished
|
// Indicate to the return object that the coroutine has finished
|
||||||
if (m_corop) {
|
if (m_corop) {
|
||||||
m_corop->m_promisep = nullptr;
|
m_corop->m_promisep = nullptr;
|
||||||
|
|||||||
+69
-44
@@ -99,11 +99,34 @@ public:
|
|||||||
// cleared, as we assume that either the coroutine has finished and deleted itself, or, if it got
|
// cleared, as we assume that either the coroutine has finished and deleted itself, or, if it got
|
||||||
// suspended, another VlCoroutineHandle was created to manage it.
|
// suspended, another VlCoroutineHandle was created to manage it.
|
||||||
|
|
||||||
|
class VlCoroutine;
|
||||||
|
|
||||||
|
struct VlPromise final {
|
||||||
|
std::coroutine_handle<VlPromise>
|
||||||
|
m_continuation; // Coroutine to resume after this one finishes
|
||||||
|
VlCoroutine* m_corop = nullptr; // Pointer to the coroutine return object
|
||||||
|
bool m_forever = false; // Coroutine suspended forever
|
||||||
|
|
||||||
|
~VlPromise();
|
||||||
|
|
||||||
|
VlCoroutine get_return_object();
|
||||||
|
|
||||||
|
// Never suspend at the start of the coroutine
|
||||||
|
std::suspend_never initial_suspend() const { return {}; }
|
||||||
|
|
||||||
|
// Never suspend at the end of the coroutine (thanks to this, the coroutine will clean up
|
||||||
|
// after itself)
|
||||||
|
std::suspend_never final_suspend() noexcept;
|
||||||
|
|
||||||
|
void unhandled_exception() const { std::abort(); } // LCOV_EXCL_LINE
|
||||||
|
void return_void() const {}
|
||||||
|
};
|
||||||
|
|
||||||
class VlCoroutineHandle final {
|
class VlCoroutineHandle final {
|
||||||
VL_UNCOPYABLE(VlCoroutineHandle);
|
VL_UNCOPYABLE(VlCoroutineHandle);
|
||||||
|
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
std::coroutine_handle<> m_coro; // The wrapped coroutine handle
|
std::coroutine_handle<VlPromise> m_coro; // The wrapped coroutine handle
|
||||||
VlProcessRef m_process; // Data of the suspended process, null if not needed
|
VlProcessRef m_process; // Data of the suspended process, null if not needed
|
||||||
VlFileLineDebug m_fileline;
|
VlFileLineDebug m_fileline;
|
||||||
|
|
||||||
@@ -117,7 +140,8 @@ public:
|
|||||||
, m_process{process} {
|
, m_process{process} {
|
||||||
if (m_process) m_process->state(VlProcess::WAITING);
|
if (m_process) m_process->state(VlProcess::WAITING);
|
||||||
}
|
}
|
||||||
VlCoroutineHandle(std::coroutine_handle<> coro, VlProcessRef process, VlFileLineDebug fileline)
|
VlCoroutineHandle(std::coroutine_handle<VlPromise> coro, VlProcessRef process,
|
||||||
|
VlFileLineDebug fileline)
|
||||||
: m_coro{coro}
|
: m_coro{coro}
|
||||||
, m_process{process}
|
, m_process{process}
|
||||||
, m_fileline{fileline} {
|
, m_fileline{fileline} {
|
||||||
@@ -135,10 +159,11 @@ public:
|
|||||||
// Usually these coroutines should get resumed; we only need to clean up if we destroy a
|
// Usually these coroutines should get resumed; we only need to clean up if we destroy a
|
||||||
// model with some coroutines suspended
|
// model with some coroutines suspended
|
||||||
if (VL_UNLIKELY(m_coro)) {
|
if (VL_UNLIKELY(m_coro)) {
|
||||||
m_coro.destroy();
|
if (m_process && m_process->state() != VlProcess::KILLED
|
||||||
if (m_process && m_process->state() != VlProcess::KILLED) {
|
&& !m_coro.promise().m_forever) {
|
||||||
m_process->state(VlProcess::FINISHED);
|
m_process->state(VlProcess::FINISHED);
|
||||||
}
|
}
|
||||||
|
m_coro.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// METHODS
|
// METHODS
|
||||||
@@ -173,7 +198,13 @@ class VlDelayScheduler final {
|
|||||||
std::vector<VlCoroutineHandle> m_zeroDelayed; // Coroutines waiting for #0
|
std::vector<VlCoroutineHandle> m_zeroDelayed; // Coroutines waiting for #0
|
||||||
// Coroutines that waited for #0 and are being resumed now. As member to avoid reallocations
|
// Coroutines that waited for #0 and are being resumed now. As member to avoid reallocations
|
||||||
std::vector<VlCoroutineHandle> m_zeroDelayesSwap;
|
std::vector<VlCoroutineHandle> m_zeroDelayesSwap;
|
||||||
|
std::vector<VlCoroutineHandle>
|
||||||
|
m_forevered; // Coroutines, that called wait(0), and are to be freed.
|
||||||
|
// Their callers are freed recursively through m_continuation.
|
||||||
|
//
|
||||||
|
// NOTE: it would be possible to clean up forevered coroutines immedietely without storing
|
||||||
|
// them, but it involves a lot of nasty edge cases. Defering cleanup to end of eval step
|
||||||
|
// simplifies logic a lot by ensuring that whole "coroutine stack" was already suspended.
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
explicit VlDelayScheduler(VerilatedContext& context)
|
explicit VlDelayScheduler(VerilatedContext& context)
|
||||||
@@ -195,6 +226,7 @@ public:
|
|||||||
}
|
}
|
||||||
// Are there coroutines to resume in the inactive region after a #0 delay?
|
// Are there coroutines to resume in the inactive region after a #0 delay?
|
||||||
bool awaitingZeroDelay() const { return !m_context.gotFinish() && !m_zeroDelayed.empty(); }
|
bool awaitingZeroDelay() const { return !m_context.gotFinish() && !m_zeroDelayed.empty(); }
|
||||||
|
void cleanupForevered() { m_forevered.clear(); };
|
||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
void dump() const;
|
void dump() const;
|
||||||
#endif
|
#endif
|
||||||
@@ -210,7 +242,7 @@ public:
|
|||||||
const VlFileLineDebug fileline;
|
const VlFileLineDebug fileline;
|
||||||
|
|
||||||
bool await_ready() const { return false; } // Always suspend
|
bool await_ready() const { return false; } // Always suspend
|
||||||
void await_suspend(std::coroutine_handle<> coro) {
|
void await_suspend(std::coroutine_handle<VlPromise> coro) {
|
||||||
// Both active delays and fork..join_none #0 are resumed out of the time queue.
|
// Both active delays and fork..join_none #0 are resumed out of the time queue.
|
||||||
if (phase != VlDelayPhase::INACTIVE) {
|
if (phase != VlDelayPhase::INACTIVE) {
|
||||||
queue.emplace(delay, VlCoroutineHandle{coro, process, fileline});
|
queue.emplace(delay, VlCoroutineHandle{coro, process, fileline});
|
||||||
@@ -233,6 +265,26 @@ public:
|
|||||||
m_zeroDelayed, m_context.time() + delay,
|
m_zeroDelayed, m_context.time() + delay,
|
||||||
phase, VlFileLineDebug{filename, lineno}};
|
phase, VlFileLineDebug{filename, lineno}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper awaitable func for suspending coroutines forever.
|
||||||
|
// Used for constant wait statements.
|
||||||
|
auto waitForever(VlProcessRef process, const char* filename = VL_UNKNOWN, int lineno = 0) {
|
||||||
|
VL_DEBUG_IF(
|
||||||
|
VL_DBG_MSGF(" Awaiting join of fork at: %s:%d\n", filename, lineno););
|
||||||
|
struct Awaitable final {
|
||||||
|
VlProcessRef process; // Data of the suspended process, null if not needed
|
||||||
|
std::vector<VlCoroutineHandle>& forevered;
|
||||||
|
VlFileLineDebug fileline;
|
||||||
|
|
||||||
|
bool await_ready() { return false; }
|
||||||
|
void await_suspend(std::coroutine_handle<VlPromise> coro) {
|
||||||
|
coro.promise().m_forever = true;
|
||||||
|
forevered.emplace_back(VlCoroutineHandle{coro, process, fileline});
|
||||||
|
}
|
||||||
|
void await_resume() const {} // LCOV_EXCL_LINE
|
||||||
|
};
|
||||||
|
return Awaitable{process, m_forevered, VlFileLineDebug{filename, lineno}};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -280,7 +332,7 @@ public:
|
|||||||
VlFileLineDebug fileline;
|
VlFileLineDebug fileline;
|
||||||
|
|
||||||
bool await_ready() const { return false; } // Always suspend
|
bool await_ready() const { return false; } // Always suspend
|
||||||
void await_suspend(std::coroutine_handle<> coro) {
|
void await_suspend(std::coroutine_handle<VlPromise> coro) {
|
||||||
suspended.emplace_back(coro, process, fileline);
|
suspended.emplace_back(coro, process, fileline);
|
||||||
}
|
}
|
||||||
void await_resume() const {}
|
void await_resume() const {}
|
||||||
@@ -327,7 +379,7 @@ class VlDynamicTriggerScheduler final {
|
|||||||
VlFileLineDebug fileline;
|
VlFileLineDebug fileline;
|
||||||
|
|
||||||
bool await_ready() const { return false; } // Always suspend
|
bool await_ready() const { return false; } // Always suspend
|
||||||
void await_suspend(std::coroutine_handle<> coro) {
|
void await_suspend(std::coroutine_handle<VlPromise> coro) {
|
||||||
suspended.emplace_back(coro, process, fileline);
|
suspended.emplace_back(coro, process, fileline);
|
||||||
}
|
}
|
||||||
void await_resume() const {}
|
void await_resume() const {}
|
||||||
@@ -371,16 +423,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
// VlForever is a helper awaitable type for suspending coroutines forever. Used for constant
|
|
||||||
// wait statements.
|
|
||||||
|
|
||||||
struct VlForever final {
|
|
||||||
bool await_ready() const { return false; } // Always suspend
|
|
||||||
void await_suspend(std::coroutine_handle<> coro) const { coro.destroy(); }
|
|
||||||
void await_resume() const {}
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VlForkSync is used to manage fork..join and fork..join_any constructs.
|
// VlForkSync is used to manage fork..join and fork..join_any constructs.
|
||||||
|
|
||||||
@@ -393,11 +435,9 @@ public:
|
|||||||
size_t m_pendingDones = 0; // done() calls seen before init() (e.g. early killed branch)
|
size_t m_pendingDones = 0; // done() calls seen before init() (e.g. early killed branch)
|
||||||
bool m_inDone = false; // Guard against re-entrant resume recursion from nested kills
|
bool m_inDone = false; // Guard against re-entrant resume recursion from nested kills
|
||||||
bool m_resumePending = false; // Join reached zero again while inside done()
|
bool m_resumePending = false; // Join reached zero again while inside done()
|
||||||
std::vector<VlProcessRef> m_onKillProcessps; // Branches registered for kill hooks
|
|
||||||
|
|
||||||
VlForkSyncState() // Construct with a null coroutine handle
|
VlForkSyncState() // Construct with a null coroutine handle
|
||||||
: m_susp{VlProcessRef{}} {}
|
: m_susp{VlProcessRef{}} {}
|
||||||
~VlForkSyncState();
|
|
||||||
void done(const char* filename = VL_UNKNOWN, int lineno = 0);
|
void done(const char* filename = VL_UNKNOWN, int lineno = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -431,7 +471,7 @@ public:
|
|||||||
VlFileLineDebug fileline;
|
VlFileLineDebug fileline;
|
||||||
|
|
||||||
bool await_ready() { return state->m_counter == 0; } // Suspend if join still exists
|
bool await_ready() { return state->m_counter == 0; } // Suspend if join still exists
|
||||||
void await_suspend(std::coroutine_handle<> coro) {
|
void await_suspend(std::coroutine_handle<VlPromise> coro) {
|
||||||
state->m_susp = {coro, process, fileline};
|
state->m_susp = {coro, process, fileline};
|
||||||
}
|
}
|
||||||
void await_resume() const {}
|
void await_resume() const {}
|
||||||
@@ -445,31 +485,10 @@ public:
|
|||||||
// Return value of a coroutine. Used for chaining coroutine suspension/resumption.
|
// Return value of a coroutine. Used for chaining coroutine suspension/resumption.
|
||||||
|
|
||||||
class VlCoroutine final {
|
class VlCoroutine final {
|
||||||
private:
|
public:
|
||||||
// TYPES
|
|
||||||
struct VlPromise final {
|
|
||||||
std::coroutine_handle<> m_continuation; // Coroutine to resume after this one finishes
|
|
||||||
VlCoroutine* m_corop = nullptr; // Pointer to the coroutine return object
|
|
||||||
|
|
||||||
~VlPromise();
|
|
||||||
|
|
||||||
VlCoroutine get_return_object() { return {this}; }
|
|
||||||
|
|
||||||
// Never suspend at the start of the coroutine
|
|
||||||
std::suspend_never initial_suspend() const { return {}; }
|
|
||||||
|
|
||||||
// Never suspend at the end of the coroutine (thanks to this, the coroutine will clean up
|
|
||||||
// after itself)
|
|
||||||
std::suspend_never final_suspend() noexcept;
|
|
||||||
|
|
||||||
void unhandled_exception() const { std::abort(); }
|
|
||||||
void return_void() const {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
VlPromise* m_promisep; // The promise created for this coroutine
|
VlPromise* m_promisep; // The promise created for this coroutine
|
||||||
|
|
||||||
public:
|
|
||||||
// TYPES
|
// TYPES
|
||||||
using promise_type = VlPromise; // promise_type has to be public
|
using promise_type = VlPromise; // promise_type has to be public
|
||||||
|
|
||||||
@@ -495,7 +514,13 @@ public:
|
|||||||
// Suspend the awaiter if the coroutine is suspended (the promise exists)
|
// Suspend the awaiter if the coroutine is suspended (the promise exists)
|
||||||
bool await_ready() const noexcept { return !m_promisep; }
|
bool await_ready() const noexcept { return !m_promisep; }
|
||||||
// Set the awaiting coroutine as the continuation of the current coroutine
|
// Set the awaiting coroutine as the continuation of the current coroutine
|
||||||
void await_suspend(std::coroutine_handle<> coro) { m_promisep->m_continuation = coro; }
|
// If the current coroutine is suspended forever, propagate that to the awaiting coroutine
|
||||||
|
// In that case, m_continuation will be used for cleaning up the whole suspended coroutine
|
||||||
|
// stack
|
||||||
|
void await_suspend(std::coroutine_handle<VlPromise> awaiting_coro) {
|
||||||
|
if (m_promisep->m_forever) awaiting_coro.promise().m_forever = true;
|
||||||
|
m_promisep->m_continuation = awaiting_coro;
|
||||||
|
}
|
||||||
void await_resume() const noexcept {}
|
void await_resume() const noexcept {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -449,7 +449,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::initLib(const std::string& name) VL_MT_
|
|||||||
// All of these take a destination pointer where the string will be emitted,
|
// All of these take a destination pointer where the string will be emitted,
|
||||||
// and a value to convert. There are a couple of variants for efficiency.
|
// and a value to convert. There are a couple of variants for efficiency.
|
||||||
|
|
||||||
static inline void cvtCDataToStr(char* dstp, CData value) {
|
inline void cvtCDataToStr(char* dstp, CData value) {
|
||||||
#ifdef VL_HAVE_SSE2
|
#ifdef VL_HAVE_SSE2
|
||||||
// Similar to cvtSDataToStr but only the bottom 8 byte lanes are used
|
// Similar to cvtSDataToStr but only the bottom 8 byte lanes are used
|
||||||
const __m128i a = _mm_cvtsi32_si128(value);
|
const __m128i a = _mm_cvtsi32_si128(value);
|
||||||
@@ -471,7 +471,7 @@ static inline void cvtCDataToStr(char* dstp, CData value) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void cvtSDataToStr(char* dstp, SData value) {
|
inline void cvtSDataToStr(char* dstp, SData value) {
|
||||||
#ifdef VL_HAVE_SSE2
|
#ifdef VL_HAVE_SSE2
|
||||||
// We want each bit in the 16-bit input value to end up in a byte lane
|
// We want each bit in the 16-bit input value to end up in a byte lane
|
||||||
// within the 128-bit XMM register. Note that x86 is little-endian and we
|
// within the 128-bit XMM register. Note that x86 is little-endian and we
|
||||||
@@ -507,7 +507,7 @@ static inline void cvtSDataToStr(char* dstp, SData value) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void cvtIDataToStr(char* dstp, IData value) {
|
inline void cvtIDataToStr(char* dstp, IData value) {
|
||||||
#ifdef VL_HAVE_AVX2
|
#ifdef VL_HAVE_AVX2
|
||||||
// Similar to cvtSDataToStr but the bottom 16-bits are processed in the
|
// Similar to cvtSDataToStr but the bottom 16-bits are processed in the
|
||||||
// top half of the YMM registers
|
// top half of the YMM registers
|
||||||
@@ -526,7 +526,7 @@ static inline void cvtIDataToStr(char* dstp, IData value) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void cvtQDataToStr(char* dstp, QData value) {
|
inline void cvtQDataToStr(char* dstp, QData value) {
|
||||||
cvtIDataToStr(dstp, value >> 32);
|
cvtIDataToStr(dstp, value >> 32);
|
||||||
cvtIDataToStr(dstp + 32, value);
|
cvtIDataToStr(dstp + 32, value);
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-14
@@ -214,7 +214,7 @@ public:
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(WDataInP) == sizeof(EData*), "WDataInP should be a single pointer");
|
static_assert(sizeof(WDataInP) == sizeof(EData*), "WDataInP should be a single pointer");
|
||||||
|
|
||||||
static int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE;
|
inline int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE;
|
||||||
|
|
||||||
template <std::size_t N_Words>
|
template <std::size_t N_Words>
|
||||||
bool VlWide<N_Words>::operator<(const VlWide<N_Words>& rhs) const VL_PURE {
|
bool VlWide<N_Words>::operator<(const VlWide<N_Words>& rhs) const VL_PURE {
|
||||||
@@ -276,7 +276,7 @@ constexpr IData VL_CLOG2_CE_Q(QData lhs) VL_PURE {
|
|||||||
// Random
|
// Random
|
||||||
|
|
||||||
// Random Number Generator with internal state
|
// Random Number Generator with internal state
|
||||||
class VlRNG final {
|
class VlRNG VL_NOT_FINAL {
|
||||||
std::array<uint64_t, 2> m_state;
|
std::array<uint64_t, 2> m_state;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -295,6 +295,22 @@ public:
|
|||||||
static VlRNG& vl_thread_rng() VL_MT_SAFE;
|
static VlRNG& vl_thread_rng() VL_MT_SAFE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// VlRNG that also counts how often it was reseeded, for randomize() to notice.
|
||||||
|
class VlRNGReseeds final : public VlRNG {
|
||||||
|
uint64_t m_reseeds = 0; // Times the state was set from outside
|
||||||
|
|
||||||
|
public:
|
||||||
|
void srandom(uint64_t n) VL_MT_UNSAFE {
|
||||||
|
VlRNG::srandom(n);
|
||||||
|
++m_reseeds;
|
||||||
|
}
|
||||||
|
void set_randstate(const std::string& state) VL_MT_UNSAFE {
|
||||||
|
VlRNG::set_randstate(state);
|
||||||
|
++m_reseeds;
|
||||||
|
}
|
||||||
|
uint64_t reseeds() const VL_MT_UNSAFE { return m_reseeds; }
|
||||||
|
};
|
||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
// Metadata of processes
|
// Metadata of processes
|
||||||
using VlProcessRef = std::shared_ptr<VlProcess>;
|
using VlProcessRef = std::shared_ptr<VlProcess>;
|
||||||
@@ -306,7 +322,7 @@ class VlProcess final {
|
|||||||
int m_state; // Current state of the process
|
int m_state; // Current state of the process
|
||||||
VlProcessRef m_parentp = nullptr; // Parent process, if exists
|
VlProcessRef m_parentp = nullptr; // Parent process, if exists
|
||||||
std::set<VlProcess*> m_children; // Active child processes
|
std::set<VlProcess*> m_children; // Active child processes
|
||||||
VlForkSyncState* m_forkSyncOnKillp
|
std::shared_ptr<VlForkSyncState> m_forkSyncOnKillp
|
||||||
= nullptr; // Optional fork..join counter to decrement on kill
|
= nullptr; // Optional fork..join counter to decrement on kill
|
||||||
bool m_forkSyncOnKillDone = false; // Ensure on-kill callback fires only once
|
bool m_forkSyncOnKillDone = false; // Ensure on-kill callback fires only once
|
||||||
VlRNG m_rng; // Per-process RNG (IEEE 1800-2023 18.14)
|
VlRNG m_rng; // Per-process RNG (IEEE 1800-2023 18.14)
|
||||||
@@ -337,6 +353,7 @@ public:
|
|||||||
|
|
||||||
~VlProcess() {
|
~VlProcess() {
|
||||||
if (m_parentp) m_parentp->detach(this);
|
if (m_parentp) m_parentp->detach(this);
|
||||||
|
if (t_currentp == this) t_currentp = m_parentp.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void attach(VlProcess* childp) { m_children.insert(childp); }
|
void attach(VlProcess* childp) { m_children.insert(childp); }
|
||||||
@@ -347,13 +364,14 @@ public:
|
|||||||
void disable() {
|
void disable() {
|
||||||
state(KILLED);
|
state(KILLED);
|
||||||
disableFork();
|
disableFork();
|
||||||
|
m_forkSyncOnKillp = nullptr;
|
||||||
}
|
}
|
||||||
void disableFork() {
|
void disableFork() {
|
||||||
// childp->disable() may resume coroutines and mutate m_children
|
// childp->disable() may resume coroutines and mutate m_children
|
||||||
const std::set<VlProcess*> children = m_children;
|
const std::set<VlProcess*> children = m_children;
|
||||||
for (VlProcess* childp : children) childp->disable();
|
for (VlProcess* childp : children) childp->disable();
|
||||||
}
|
}
|
||||||
void forkSyncOnKill(VlForkSyncState* forkSyncp);
|
void forkSyncOnKill(std::shared_ptr<VlForkSyncState> forkSyncp);
|
||||||
void forkSyncOnKillClear(VlForkSyncState* forkSyncp);
|
void forkSyncOnKillClear(VlForkSyncState* forkSyncp);
|
||||||
bool completed() const { return state() == FINISHED || state() == KILLED; }
|
bool completed() const { return state() == FINISHED || state() == KILLED; }
|
||||||
bool completedFork() const {
|
bool completedFork() const {
|
||||||
@@ -931,7 +949,7 @@ public:
|
|||||||
VlQueue min(T_Func with_func) const {
|
VlQueue min(T_Func with_func) const {
|
||||||
if (m_deque.empty()) return VlQueue{};
|
if (m_deque.empty()) return VlQueue{};
|
||||||
const auto it = std::min_element(m_deque.cbegin(), m_deque.cend(),
|
const auto it = std::min_element(m_deque.cbegin(), m_deque.cend(),
|
||||||
[&with_func](const IData& a, const IData& b) {
|
[&with_func](const T_Value& a, const T_Value& b) {
|
||||||
return with_func(0, a) < with_func(0, b);
|
return with_func(0, a) < with_func(0, b);
|
||||||
});
|
});
|
||||||
return VlQueue::consV(*it);
|
return VlQueue::consV(*it);
|
||||||
@@ -945,7 +963,7 @@ public:
|
|||||||
VlQueue max(T_Func with_func) const {
|
VlQueue max(T_Func with_func) const {
|
||||||
if (m_deque.empty()) return VlQueue{};
|
if (m_deque.empty()) return VlQueue{};
|
||||||
const auto it = std::max_element(m_deque.cbegin(), m_deque.cend(),
|
const auto it = std::max_element(m_deque.cbegin(), m_deque.cend(),
|
||||||
[&with_func](const IData& a, const IData& b) {
|
[&with_func](const T_Value& a, const T_Value& b) {
|
||||||
return with_func(0, a) < with_func(0, b);
|
return with_func(0, a) < with_func(0, b);
|
||||||
});
|
});
|
||||||
return VlQueue::consV(*it);
|
return VlQueue::consV(*it);
|
||||||
@@ -1119,9 +1137,7 @@ public:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// Setting. Verilog: assoc[index] = v
|
// Setting. Verilog: assoc[index] = v
|
||||||
// Can't just overload operator[] or provide a "at" reference to set,
|
T_Value& atWrite(const T_Key& index) {
|
||||||
// because we need to be able to insert only when the value is set
|
|
||||||
T_Value& at(const T_Key& index) {
|
|
||||||
const auto it = m_map.find(index);
|
const auto it = m_map.find(index);
|
||||||
if (it == m_map.end()) {
|
if (it == m_map.end()) {
|
||||||
std::pair<typename Map::iterator, bool> pit = m_map.emplace(index, m_defaultValue);
|
std::pair<typename Map::iterator, bool> pit = m_map.emplace(index, m_defaultValue);
|
||||||
@@ -1137,7 +1153,7 @@ public:
|
|||||||
}
|
}
|
||||||
// Setting as a chained operation
|
// Setting as a chained operation
|
||||||
VlAssocArray& set(const T_Key& index, const T_Value& value) {
|
VlAssocArray& set(const T_Key& index, const T_Value& value) {
|
||||||
at(index) = value;
|
atWrite(index) = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
VlAssocArray& setDefault(const T_Value& value) {
|
VlAssocArray& setDefault(const T_Value& value) {
|
||||||
@@ -1394,7 +1410,7 @@ void VL_READMEM_N(bool hex, int bits, const std::string& filename,
|
|||||||
QData addr;
|
QData addr;
|
||||||
std::string data;
|
std::string data;
|
||||||
if (rmem.get(addr /*ref*/, data /*ref*/)) {
|
if (rmem.get(addr /*ref*/, data /*ref*/)) {
|
||||||
rmem.setData(&(obj.at(addr)), data);
|
rmem.setData(&(obj.atWrite(addr)), data);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2069,8 +2085,24 @@ struct VlNull final {
|
|||||||
operator T*() const {
|
operator T*() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
template <class T>
|
||||||
|
bool operator==(T* rhs) const {
|
||||||
|
return !rhs;
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
bool operator==(const T* rhs) const {
|
||||||
|
return !rhs;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
inline bool operator==(const void* ptr, VlNull) { return !ptr; }
|
|
||||||
|
template <class T>
|
||||||
|
inline bool operator==(T* lhs, VlNull) {
|
||||||
|
return !lhs;
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
inline bool operator==(const T* lhs, VlNull) {
|
||||||
|
return !lhs;
|
||||||
|
}
|
||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
// Verilog class reference container
|
// Verilog class reference container
|
||||||
@@ -2223,7 +2255,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T_Lhs, typename T_Out>
|
template <typename T_Lhs, typename T_Out>
|
||||||
static inline bool VL_CAST_DYNAMIC(VlClassRef<T_Lhs> in, VlClassRef<T_Out>& outr) {
|
inline bool VL_CAST_DYNAMIC(VlClassRef<T_Lhs> in, VlClassRef<T_Out>& outr) {
|
||||||
if (!in) {
|
if (!in) {
|
||||||
outr = VlNull{};
|
outr = VlNull{};
|
||||||
return true;
|
return true;
|
||||||
@@ -2237,7 +2269,7 @@ static inline bool VL_CAST_DYNAMIC(VlClassRef<T_Lhs> in, VlClassRef<T_Out>& outr
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T_Lhs>
|
template <typename T_Lhs>
|
||||||
static inline bool VL_CAST_DYNAMIC(VlNull, VlClassRef<T_Lhs>& outr) {
|
inline bool VL_CAST_DYNAMIC(VlNull, VlClassRef<T_Lhs>& outr) {
|
||||||
outr = VlNull{};
|
outr = VlNull{};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+119
-41
@@ -539,7 +539,7 @@ public:
|
|||||||
for (auto idx : index()) m_fullname += "[" + std::to_string(idx) + "]";
|
for (auto idx : index()) m_fullname += "[" + std::to_string(idx) + "]";
|
||||||
return m_fullname.c_str();
|
return m_fullname.c_str();
|
||||||
}
|
}
|
||||||
void* prevDatap() const { return m_prevDatap; }
|
uint8_t* prevDatap() const { return m_prevDatap; }
|
||||||
void* varDatap() const override { return m_varDatap; }
|
void* varDatap() const override { return m_varDatap; }
|
||||||
void createPrevDatap() {
|
void createPrevDatap() {
|
||||||
if (VL_UNLIKELY(!m_prevDatap)) {
|
if (VL_UNLIKELY(!m_prevDatap)) {
|
||||||
@@ -1027,6 +1027,26 @@ struct VerilatedVpiTimedCbsCmp final {
|
|||||||
class VerilatedVpiError;
|
class VerilatedVpiError;
|
||||||
void vl_vpi_put_word(const VerilatedVpioVar* vop, QData word, size_t bitCount, size_t addOffset);
|
void vl_vpi_put_word(const VerilatedVpioVar* vop, QData word, size_t bitCount, size_t addOffset);
|
||||||
|
|
||||||
|
// Information about how to access packed array data.
|
||||||
|
// If underlying type is multi-word (VLVT_WDATA), the packed element might straddle word
|
||||||
|
// boundaries, in which case m_maskHi != 0.
|
||||||
|
template <typename T>
|
||||||
|
struct VarAccessInfo final {
|
||||||
|
T* m_datap; // Typed pointer to packed array base address
|
||||||
|
size_t m_bitOffset; // Data start location (bit offset)
|
||||||
|
size_t m_wordOffset; // Data start location (word offset, VLVT_WDATA only)
|
||||||
|
T m_maskLo; // Access mask for m_datap[m_wordOffset]
|
||||||
|
T m_maskHi; // Access mask for m_datap[m_wordOffset + 1] (VLVT_WDATA only)
|
||||||
|
};
|
||||||
|
template <typename T>
|
||||||
|
VarAccessInfo<T> vl_vpi_var_access_info(const VerilatedVpioVarBase* vop, size_t bitCount,
|
||||||
|
size_t addOffset);
|
||||||
|
template <typename T>
|
||||||
|
T vl_vpi_get_word_gen(VarAccessInfo<T> info);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void vl_vpi_put_word_gen(VarAccessInfo<T> info, T word);
|
||||||
|
|
||||||
class VerilatedVpiImp final {
|
class VerilatedVpiImp final {
|
||||||
enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime + 1 }; // Maximum callback reason
|
enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime + 1 }; // Maximum callback reason
|
||||||
using VpioCbList = std::list<VerilatedVpiCbHolder>;
|
using VpioCbList = std::list<VerilatedVpiCbHolder>;
|
||||||
@@ -1169,6 +1189,72 @@ public:
|
|||||||
s().m_cbCallList.clear();
|
s().m_cbCallList.clear();
|
||||||
return called;
|
return called;
|
||||||
}
|
}
|
||||||
|
template <typename T>
|
||||||
|
static bool valueDiffersFromPrev(VerilatedVpioVar* varop) {
|
||||||
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p size=%d\n",
|
||||||
|
varop->fullname(), *(static_cast<CData*>(varop->varDatap())),
|
||||||
|
*(varop->prevDatap()), varop->varDatap(), varop->prevDatap(),
|
||||||
|
varop->entSize()););
|
||||||
|
if (varop->bitSize() == 1) {
|
||||||
|
T* const prevDatap = reinterpret_cast<T*>(
|
||||||
|
varop->prevDatap()); // Was malloced when we added the callback
|
||||||
|
const VarAccessInfo<T> currInfo
|
||||||
|
= vl_vpi_var_access_info<T>(varop, varop->bitSize(), 0);
|
||||||
|
VarAccessInfo<T> prevInfo = currInfo;
|
||||||
|
prevInfo.m_datap = prevDatap;
|
||||||
|
return vl_vpi_get_word_gen(currInfo) != vl_vpi_get_word_gen(prevInfo);
|
||||||
|
}
|
||||||
|
return std::memcmp(varop->prevDatap(), varop->varDatap(), varop->entSize()) != 0;
|
||||||
|
}
|
||||||
|
static bool valueDiffersFromPrev(VerilatedVpioVar* varop) {
|
||||||
|
switch (varop->varp()->vltype()) {
|
||||||
|
case VLVT_UINT8: return valueDiffersFromPrev<CData>(varop);
|
||||||
|
case VLVT_UINT16: return valueDiffersFromPrev<SData>(varop);
|
||||||
|
case VLVT_UINT32: return valueDiffersFromPrev<IData>(varop);
|
||||||
|
case VLVT_UINT64: return valueDiffersFromPrev<QData>(varop);
|
||||||
|
case VLVT_WDATA:
|
||||||
|
return valueDiffersFromPrev<EData>(varop);
|
||||||
|
// LCOV_EXCL_START - Would require earlier type check to not catch that
|
||||||
|
default:
|
||||||
|
const std::string msg
|
||||||
|
= "Unsupported type (" + std::to_string(varop->varp()->vltype()) + ")";
|
||||||
|
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||||
|
return true;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
static void updatePrev(const VerilatedVpioVar* const varop) {
|
||||||
|
if (varop->bitSize() == 1) {
|
||||||
|
const VarAccessInfo<T> currInfo
|
||||||
|
= vl_vpi_var_access_info<T>(varop, varop->bitSize(), 0);
|
||||||
|
VarAccessInfo<T> prevInfo = currInfo;
|
||||||
|
T* const prevDatap = reinterpret_cast<T*>(varop->prevDatap());
|
||||||
|
prevInfo.m_datap = prevDatap;
|
||||||
|
const T currWord = vl_vpi_get_word_gen(currInfo);
|
||||||
|
vl_vpi_put_word_gen(prevInfo, currWord);
|
||||||
|
assert(std::memcmp(varop->prevDatap(), varop->varDatap(), varop->entSize()) == 0);
|
||||||
|
} else {
|
||||||
|
std::memcpy(varop->prevDatap(), varop->varDatap(), varop->entSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void updatePrev(const VerilatedVpioVar* const varop) {
|
||||||
|
switch (varop->varp()->vltype()) {
|
||||||
|
case VLVT_UINT8: updatePrev<CData>(varop); break;
|
||||||
|
case VLVT_UINT16: updatePrev<SData>(varop); break;
|
||||||
|
case VLVT_UINT32: updatePrev<IData>(varop); break;
|
||||||
|
case VLVT_UINT64: updatePrev<QData>(varop); break;
|
||||||
|
case VLVT_WDATA:
|
||||||
|
updatePrev<EData>(varop);
|
||||||
|
break;
|
||||||
|
// LCOV_EXCL_START - Would require earlier type check to not catch that
|
||||||
|
default:
|
||||||
|
const std::string msg
|
||||||
|
= "Unsupported type (" + std::to_string(varop->varp()->vltype()) + ")";
|
||||||
|
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
|
}
|
||||||
static bool callValueCbs() VL_MT_UNSAFE_ONE {
|
static bool callValueCbs() VL_MT_UNSAFE_ONE {
|
||||||
assertOneCheck();
|
assertOneCheck();
|
||||||
VpioCbList& cbObjList = s().m_cbCurrentLists[cbValueChange];
|
VpioCbList& cbObjList = s().m_cbCurrentLists[cbValueChange];
|
||||||
@@ -1187,15 +1273,10 @@ public:
|
|||||||
VerilatedVpiCbHolder& ho = *it++;
|
VerilatedVpiCbHolder& ho = *it++;
|
||||||
VerilatedVpioVar* const varop
|
VerilatedVpioVar* const varop
|
||||||
= reinterpret_cast<VerilatedVpioVar*>(ho.cb_datap()->obj);
|
= reinterpret_cast<VerilatedVpioVar*>(ho.cb_datap()->obj);
|
||||||
void* const newDatap = varop->varDatap();
|
if (valueDiffersFromPrev(varop)) {
|
||||||
void* const prevDatap = varop->prevDatap(); // Was malloced when we added the callback
|
|
||||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p\n",
|
|
||||||
varop->fullname(), *(static_cast<CData*>(newDatap)),
|
|
||||||
*(static_cast<CData*>(prevDatap)), newDatap, prevDatap););
|
|
||||||
if (std::memcmp(prevDatap, newDatap, varop->entSize()) != 0) {
|
|
||||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %" PRId64 " %s v[0]=%d\n",
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %" PRId64 " %s v[0]=%d\n",
|
||||||
ho.id(), varop->fullname(),
|
ho.id(), varop->fullname(),
|
||||||
*(static_cast<CData*>(newDatap))););
|
*(static_cast<CData*>(varop->varDatap()))););
|
||||||
update.insert(varop);
|
update.insert(varop);
|
||||||
vpi_get_value(ho.cb_datap()->obj, ho.cb_datap()->value);
|
vpi_get_value(ho.cb_datap()->obj, ho.cb_datap()->value);
|
||||||
(ho.cb_rtnp())(ho.cb_datap());
|
(ho.cb_rtnp())(ho.cb_datap());
|
||||||
@@ -1203,9 +1284,7 @@ public:
|
|||||||
}
|
}
|
||||||
if (was_last) break;
|
if (was_last) break;
|
||||||
}
|
}
|
||||||
for (const VerilatedVpioVar* const ip : update) {
|
for (const VerilatedVpioVar* const varop : update) updatePrev(varop);
|
||||||
std::memcpy(ip->prevDatap(), ip->varDatap(), ip->entSize());
|
|
||||||
}
|
|
||||||
return called;
|
return called;
|
||||||
}
|
}
|
||||||
static void dumpCbs() VL_MT_UNSAFE_ONE;
|
static void dumpCbs() VL_MT_UNSAFE_ONE;
|
||||||
@@ -2410,7 +2489,7 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
|
|||||||
return vop->castVpiHandle();
|
return vop->castVpiHandle();
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported callback type %s", __func__,
|
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported callback type '%s'", __func__,
|
||||||
VerilatedVpiError::strFromVpiCallbackReason(reason));
|
VerilatedVpiError::strFromVpiCallbackReason(reason));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -2856,7 +2935,7 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
|||||||
return (new VerilatedVpioConst{vop->rangep()->left()})->castVpiHandle();
|
return (new VerilatedVpioConst{vop->rangep()->left()})->castVpiHandle();
|
||||||
}
|
}
|
||||||
VL_VPI_WARNING_(__FILE__, __LINE__,
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
||||||
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
|
"%s: Unsupported vpiHandle '%p' for type '%s', nothing will be returned",
|
||||||
__func__, object, VerilatedVpiError::strFromVpiMethod(type));
|
__func__, object, VerilatedVpiError::strFromVpiMethod(type));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -2870,7 +2949,7 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
|||||||
return (new VerilatedVpioConst{vop->rangep()->right()})->castVpiHandle();
|
return (new VerilatedVpioConst{vop->rangep()->right()})->castVpiHandle();
|
||||||
}
|
}
|
||||||
VL_VPI_WARNING_(__FILE__, __LINE__,
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
||||||
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
|
"%s: Unsupported vpiHandle '%p' for type '%s', nothing will be returned",
|
||||||
__func__, object, VerilatedVpiError::strFromVpiMethod(type));
|
__func__, object, VerilatedVpiError::strFromVpiMethod(type));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -3031,8 +3110,9 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) {
|
|||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported property %s, nothing will be returned",
|
VL_VPI_ERROR_(__FILE__, __LINE__,
|
||||||
__func__, VerilatedVpiError::strFromVpiProp(property));
|
"%s: Unsupported property '%s', nothing will be returned", __func__,
|
||||||
|
VerilatedVpiError::strFromVpiProp(property));
|
||||||
return vpiUndefined;
|
return vpiUndefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3195,18 +3275,6 @@ static void vl_strprintf(std::string& buffer, char const* fmt, ...) {
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information about how to access packed array data.
|
|
||||||
// If underlying type is multi-word (VLVT_WDATA), the packed element might straddle word
|
|
||||||
// boundaries, in which case m_maskHi != 0.
|
|
||||||
template <typename T>
|
|
||||||
struct VarAccessInfo final {
|
|
||||||
T* m_datap; // Typed pointer to packed array base address
|
|
||||||
size_t m_bitOffset; // Data start location (bit offset)
|
|
||||||
size_t m_wordOffset; // Data start location (word offset, VLVT_WDATA only)
|
|
||||||
T m_maskLo; // Access mask for m_datap[m_wordOffset]
|
|
||||||
T m_maskHi; // Access mask for m_datap[m_wordOffset + 1] (VLVT_WDATA only)
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
VarAccessInfo<T> vl_vpi_var_access_info(const VerilatedVpioVarBase* vop, size_t bitCount,
|
VarAccessInfo<T> vl_vpi_var_access_info(const VerilatedVpioVarBase* vop, size_t bitCount,
|
||||||
size_t addOffset) {
|
size_t addOffset) {
|
||||||
@@ -3262,21 +3330,25 @@ VarAccessInfo<T> vl_vpi_var_access_info(const VerilatedVpioVarBase* vop, size_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T vl_vpi_get_word_gen(const VerilatedVpioVarBase* vop, size_t bitCount, size_t addOffset) {
|
T vl_vpi_get_word_gen(VarAccessInfo<T> info) {
|
||||||
const size_t wordBits = sizeof(T) * 8;
|
const size_t wordBits = sizeof(T) * 8;
|
||||||
const VarAccessInfo<T> info = vl_vpi_var_access_info<T>(vop, bitCount, addOffset);
|
if (info.m_maskHi) {
|
||||||
if (info.m_maskHi)
|
|
||||||
return ((info.m_datap[info.m_wordOffset] & info.m_maskLo) >> info.m_bitOffset)
|
return ((info.m_datap[info.m_wordOffset] & info.m_maskLo) >> info.m_bitOffset)
|
||||||
| ((info.m_datap[info.m_wordOffset + 1] & info.m_maskHi)
|
| ((info.m_datap[info.m_wordOffset + 1] & info.m_maskHi)
|
||||||
<< (wordBits - info.m_bitOffset));
|
<< (wordBits - info.m_bitOffset));
|
||||||
|
}
|
||||||
return (info.m_datap[info.m_wordOffset] & info.m_maskLo) >> info.m_bitOffset;
|
return (info.m_datap[info.m_wordOffset] & info.m_maskLo) >> info.m_bitOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void vl_vpi_put_word_gen(const VerilatedVpioVar* vop, T word, size_t bitCount, size_t addOffset) {
|
T vl_vpi_get_word_gen(const VerilatedVpioVarBase* vop, size_t bitCount, size_t addOffset) {
|
||||||
const size_t wordBits = sizeof(T) * 8;
|
|
||||||
const VarAccessInfo<T> info = vl_vpi_var_access_info<T>(vop, bitCount, addOffset);
|
const VarAccessInfo<T> info = vl_vpi_var_access_info<T>(vop, bitCount, addOffset);
|
||||||
|
return vl_vpi_get_word_gen(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void vl_vpi_put_word_gen(VarAccessInfo<T> info, T word) {
|
||||||
|
const size_t wordBits = sizeof(T) * 8;
|
||||||
if (info.m_maskHi) {
|
if (info.m_maskHi) {
|
||||||
info.m_datap[info.m_wordOffset + 1]
|
info.m_datap[info.m_wordOffset + 1]
|
||||||
= (info.m_datap[info.m_wordOffset + 1] & ~info.m_maskHi)
|
= (info.m_datap[info.m_wordOffset + 1] & ~info.m_maskHi)
|
||||||
@@ -3287,6 +3359,12 @@ void vl_vpi_put_word_gen(const VerilatedVpioVar* vop, T word, size_t bitCount, s
|
|||||||
| ((word << info.m_bitOffset) & info.m_maskLo);
|
| ((word << info.m_bitOffset) & info.m_maskLo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void vl_vpi_put_word_gen(const VerilatedVpioVar* vop, T word, size_t bitCount, size_t addOffset) {
|
||||||
|
const VarAccessInfo<T> info = vl_vpi_var_access_info<T>(vop, bitCount, addOffset);
|
||||||
|
vl_vpi_put_word_gen(info, word);
|
||||||
|
}
|
||||||
|
|
||||||
// bitCount: maximum number of bits to read, will stop earlier if it reaches the var bounds
|
// bitCount: maximum number of bits to read, will stop earlier if it reaches the var bounds
|
||||||
// addOffset: additional read bitoffset
|
// addOffset: additional read bitoffset
|
||||||
QData vl_vpi_get_word(const VerilatedVpioVarBase* vop, size_t bitCount, size_t addOffset) {
|
QData vl_vpi_get_word(const VerilatedVpioVarBase* vop, size_t bitCount, size_t addOffset) {
|
||||||
@@ -3500,7 +3578,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value valuep) {
|
|||||||
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
|
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", __func__, object);
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle '%p'", __func__, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_p*/,
|
vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_p*/,
|
||||||
@@ -3841,7 +3919,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||||||
__func__, vop->fullname());
|
__func__, vop->fullname());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", __func__, object);
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle '%p'", __func__, object);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4236,13 +4314,13 @@ void vpi_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_IN
|
|||||||
|
|
||||||
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||||
if (VL_UNLIKELY(!vop)) {
|
if (VL_UNLIKELY(!vop)) {
|
||||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", __func__, object);
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle '%p'", __func__, object);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vop->type() != vpiRegArray) {
|
if (vop->type() != vpiRegArray) {
|
||||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported type (%p, %s)", __func__, object,
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported type '%s' for '%s'", __func__,
|
||||||
VerilatedVpiError::strFromVpiObjType(vop->type()));
|
VerilatedVpiError::strFromVpiObjType(vop->type()), vop->name());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4418,13 +4496,13 @@ void vpi_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_IN
|
|||||||
|
|
||||||
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||||
if (VL_UNLIKELY(!vop)) {
|
if (VL_UNLIKELY(!vop)) {
|
||||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", __func__, object);
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle '%p'", __func__, object);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vop->type() != vpiRegArray) {
|
if (vop->type() != vpiRegArray) {
|
||||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported type (%p, %s)", __func__, object,
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle type '%s' for '%s'", __func__,
|
||||||
VerilatedVpiError::strFromVpiObjType(vop->type()));
|
VerilatedVpiError::strFromVpiObjType(vop->type()), vop->name());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-4
@@ -332,10 +332,19 @@
|
|||||||
|
|
||||||
#ifdef VL_GCOV
|
#ifdef VL_GCOV
|
||||||
extern "C" void __gcov_dump();
|
extern "C" void __gcov_dump();
|
||||||
|
extern "C" void __gcov_reset();
|
||||||
// Dump internal code coverage data before e.g. std::abort()
|
// Dump internal code coverage data before e.g. std::abort()
|
||||||
# define VL_GCOV_DUMP() __gcov_dump()
|
# define VL_GCOV_DUMP() __gcov_dump()
|
||||||
|
// Dump, then re-arm dumping; dumping is one-shot, so without the reset a dump
|
||||||
|
// on a nonfatal path would silently discard everything counted after it
|
||||||
|
# define VL_GCOV_DUMP_RESET() \
|
||||||
|
do { \
|
||||||
|
__gcov_dump(); \
|
||||||
|
__gcov_reset(); \
|
||||||
|
} while (false)
|
||||||
#else
|
#else
|
||||||
# define VL_GCOV_DUMP()
|
# define VL_GCOV_DUMP()
|
||||||
|
# define VL_GCOV_DUMP_RESET()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
@@ -368,6 +377,7 @@ extern "C" void __gcov_dump();
|
|||||||
#define __STDC_FORMAT_MACROS
|
#define __STDC_FORMAT_MACROS
|
||||||
|
|
||||||
// Now that C++ requires these standard types the vl types are deprecated
|
// Now that C++ requires these standard types the vl types are deprecated
|
||||||
|
#include <cstddef> // offsetof (used by generated VlVarTableEntry tables)
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@@ -460,6 +470,7 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
|
|||||||
// Integer size macros
|
// Integer size macros
|
||||||
|
|
||||||
#define VL_BYTESIZE 8 ///< Bits in a CData / byte
|
#define VL_BYTESIZE 8 ///< Bits in a CData / byte
|
||||||
|
#define VL_BYTESIZE_LOG2 3 ///< log2(VL_BYTESIZE)
|
||||||
#define VL_SHORTSIZE 16 ///< Bits in a SData / short
|
#define VL_SHORTSIZE 16 ///< Bits in a SData / short
|
||||||
#define VL_IDATASIZE 32 ///< Bits in an IData / word
|
#define VL_IDATASIZE 32 ///< Bits in an IData / word
|
||||||
#define VL_QUADSIZE 64 ///< Bits in a QData / quadword
|
#define VL_QUADSIZE 64 ///< Bits in a QData / quadword
|
||||||
@@ -472,9 +483,9 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Return number of bytes argument-number of bits needs (1 bit=1 byte)
|
/// Return number of bytes argument-number of bits needs (1 bit=1 byte)
|
||||||
#define VL_BYTES_I(nbits) (((nbits) + (VL_BYTESIZE - 1)) / VL_BYTESIZE)
|
#define VL_BYTES_I(nbits) (((nbits) + (VL_BYTESIZE - 1)) >> VL_BYTESIZE_LOG2)
|
||||||
/// Return Words/EDatas in argument-number of bits needs (1 bit=1 word)
|
/// Return Words/EDatas in argument-number of bits needs (1 bit=1 word)
|
||||||
#define VL_WORDS_I(nbits) (((nbits) + (VL_EDATASIZE - 1)) / VL_EDATASIZE)
|
#define VL_WORDS_I(nbits) (((nbits) + (VL_EDATASIZE - 1)) >> VL_EDATASIZE_LOG2)
|
||||||
// Number of Words/EDatas a quad requires
|
// Number of Words/EDatas a quad requires
|
||||||
#define VL_WQ_WORDS_E VL_WORDS_I(VL_QUADSIZE)
|
#define VL_WQ_WORDS_E VL_WORDS_I(VL_QUADSIZE)
|
||||||
|
|
||||||
@@ -536,10 +547,10 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
|
|||||||
// #defines, to avoid requiring math.h on all compile runs
|
// #defines, to avoid requiring math.h on all compile runs
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
static inline double VL_TRUNC(double n) {
|
inline double VL_TRUNC(double n) {
|
||||||
return (n < 0) ? std::ceil(n) : std::floor(n);
|
return (n < 0) ? std::ceil(n) : std::floor(n);
|
||||||
}
|
}
|
||||||
static inline double VL_ROUND(double n) {
|
inline double VL_ROUND(double n) {
|
||||||
return (n < 0) ? std::ceil(n-0.5) : std::floor(n + 0.5);
|
return (n < 0) ? std::ceil(n-0.5) : std::floor(n + 0.5);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -608,6 +619,8 @@ static inline double VL_ROUND(double n) {
|
|||||||
# define VL_CPU_RELAX() asm volatile("lr 0,0" ::: "memory")
|
# define VL_CPU_RELAX() asm volatile("lr 0,0" ::: "memory")
|
||||||
#elif defined(__sparc__)
|
#elif defined(__sparc__)
|
||||||
# define VL_CPU_RELAX() asm volatile("rd %%ccr, %%g0" ::: "memory")
|
# define VL_CPU_RELAX() asm volatile("rd %%ccr, %%g0" ::: "memory")
|
||||||
|
#elif defined(__wasm__) // Wasm has no spin-wait hint, and no inline asm
|
||||||
|
# define VL_CPU_RELAX()
|
||||||
#elif defined(VL_IGNORE_UNKNOWN_ARCH)
|
#elif defined(VL_IGNORE_UNKNOWN_ARCH)
|
||||||
# define VL_CPU_RELAX()
|
# define VL_CPU_RELAX()
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ double DeltaCpuTime::gettime() VL_MT_SAFE {
|
|||||||
| static_cast<uint64_t>(lpUserTime.dwHighDateTime) << 32ULL)
|
| static_cast<uint64_t>(lpUserTime.dwHighDateTime) << 32ULL)
|
||||||
* 1e-7;
|
* 1e-7;
|
||||||
}
|
}
|
||||||
#else
|
#elif !defined(__wasi__) // WASI has no CLOCK_PROCESS_CPUTIME_ID
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||||
timespec ts;
|
timespec ts;
|
||||||
if (0 == clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) // MT-Safe // LCOV_EXCL_BR_LINE
|
if (0 == clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) // MT-Safe // LCOV_EXCL_BR_LINE
|
||||||
@@ -169,17 +169,19 @@ void memUsageBytes(uint64_t& peakr, uint64_t& currentr) VL_MT_SAFE {
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// Highly unportable. Sorry
|
// Highly unportable. Sorry
|
||||||
|
// Use VmHWM (peak resident), matching Windows PeakWorkingSetSize and macOS resident_size_max.
|
||||||
|
// VmHWM excludes pages swapped out before the peak; /proc has no peak-(RSS+Swap) counter.
|
||||||
std::ifstream is{"/proc/self/status"};
|
std::ifstream is{"/proc/self/status"};
|
||||||
if (!is) return;
|
if (!is) return;
|
||||||
std::string line;
|
std::string line;
|
||||||
uint64_t vmPeak = 0;
|
uint64_t vmHwm = 0;
|
||||||
uint64_t vmRss = 0;
|
uint64_t vmRss = 0;
|
||||||
uint64_t vmSwap = 0;
|
uint64_t vmSwap = 0;
|
||||||
std::string field;
|
std::string field;
|
||||||
while (std::getline(is, line)) {
|
while (std::getline(is, line)) {
|
||||||
if (line.rfind("VmPeak:", 0) == 0) {
|
if (line.rfind("VmHWM:", 0) == 0) {
|
||||||
std::stringstream ss{line};
|
std::stringstream ss{line};
|
||||||
ss >> field >> vmPeak;
|
ss >> field >> vmHwm;
|
||||||
} else if (line.rfind("VmRSS:", 0) == 0) {
|
} else if (line.rfind("VmRSS:", 0) == 0) {
|
||||||
std::stringstream ss{line};
|
std::stringstream ss{line};
|
||||||
ss >> field >> vmRss;
|
ss >> field >> vmRss;
|
||||||
@@ -188,7 +190,7 @@ void memUsageBytes(uint64_t& peakr, uint64_t& currentr) VL_MT_SAFE {
|
|||||||
ss >> field >> vmSwap;
|
ss >> field >> vmSwap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
peakr = vmPeak * 1024;
|
peakr = vmHwm * 1024;
|
||||||
currentr = (vmRss + vmSwap) * 1024;
|
currentr = (vmRss + vmSwap) * 1024;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
# These flags tested against verible-v0.0-4080-ga0a8d8eb
|
||||||
|
|
||||||
verible-verilog-format \
|
verible-verilog-format \
|
||||||
--inplace \
|
--inplace \
|
||||||
--wrap_end_else_clauses \
|
--wrap_end_else_clauses \
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ sphinxcontrib-spelling==8.0.2
|
|||||||
yamlfix==1.19.1
|
yamlfix==1.19.1
|
||||||
yapf==0.43.0
|
yapf==0.43.0
|
||||||
|
|
||||||
git+https://github.com/antmicro/astsee.git
|
git+https://github.com/antmicro/astsee.git@222480a8ec13b312809ea4acc08c81b4c0f4da2f
|
||||||
|
|||||||
+7
-2
@@ -62,6 +62,7 @@ set(HEADERS
|
|||||||
V3Cast.h
|
V3Cast.h
|
||||||
V3Cfg.h
|
V3Cfg.h
|
||||||
V3Class.h
|
V3Class.h
|
||||||
|
V3ClassGraph.h
|
||||||
V3Clean.h
|
V3Clean.h
|
||||||
V3Clock.h
|
V3Clock.h
|
||||||
V3Combine.h
|
V3Combine.h
|
||||||
@@ -149,6 +150,7 @@ set(HEADERS
|
|||||||
V3OrderGraph.h
|
V3OrderGraph.h
|
||||||
V3OrderInternal.h
|
V3OrderInternal.h
|
||||||
V3OrderMoveGraph.h
|
V3OrderMoveGraph.h
|
||||||
|
V3OrderMTaskGraph.h
|
||||||
V3Os.h
|
V3Os.h
|
||||||
V3PairingHeap.h
|
V3PairingHeap.h
|
||||||
V3Param.h
|
V3Param.h
|
||||||
@@ -156,6 +158,7 @@ set(HEADERS
|
|||||||
V3ParseImp.h
|
V3ParseImp.h
|
||||||
V3PchAstMT.h
|
V3PchAstMT.h
|
||||||
V3PchAstNoMT.h
|
V3PchAstNoMT.h
|
||||||
|
V3PoolAllocator.h
|
||||||
V3PreExpr.h
|
V3PreExpr.h
|
||||||
V3PreLex.h
|
V3PreLex.h
|
||||||
V3PreProc.h
|
V3PreProc.h
|
||||||
@@ -170,7 +173,6 @@ set(HEADERS
|
|||||||
V3Sampled.h
|
V3Sampled.h
|
||||||
V3Sched.h
|
V3Sched.h
|
||||||
V3Scope.h
|
V3Scope.h
|
||||||
V3Scoreboard.h
|
|
||||||
V3SenExprBuilder.h
|
V3SenExprBuilder.h
|
||||||
V3SenTree.h
|
V3SenTree.h
|
||||||
V3Simulate.h
|
V3Simulate.h
|
||||||
@@ -229,6 +231,7 @@ set(COMMON_SOURCES
|
|||||||
V3CfgBuilder.cpp
|
V3CfgBuilder.cpp
|
||||||
V3CfgLiveVariables.cpp
|
V3CfgLiveVariables.cpp
|
||||||
V3Class.cpp
|
V3Class.cpp
|
||||||
|
V3ClassGraph.cpp
|
||||||
V3Clean.cpp
|
V3Clean.cpp
|
||||||
V3Clock.cpp
|
V3Clock.cpp
|
||||||
V3Combine.cpp
|
V3Combine.cpp
|
||||||
@@ -319,6 +322,9 @@ set(COMMON_SOURCES
|
|||||||
V3Order.cpp
|
V3Order.cpp
|
||||||
V3OrderGraphBuilder.cpp
|
V3OrderGraphBuilder.cpp
|
||||||
V3OrderMoveGraph.cpp
|
V3OrderMoveGraph.cpp
|
||||||
|
V3OrderMTaskContraction.cpp
|
||||||
|
V3OrderMTaskFixHazards.cpp
|
||||||
|
V3OrderMTaskGraph.cpp
|
||||||
V3OrderParallel.cpp
|
V3OrderParallel.cpp
|
||||||
V3OrderProcessDomains.cpp
|
V3OrderProcessDomains.cpp
|
||||||
V3OrderSerial.cpp
|
V3OrderSerial.cpp
|
||||||
@@ -346,7 +352,6 @@ set(COMMON_SOURCES
|
|||||||
V3SchedUtil.cpp
|
V3SchedUtil.cpp
|
||||||
V3SchedVirtIface.cpp
|
V3SchedVirtIface.cpp
|
||||||
V3Scope.cpp
|
V3Scope.cpp
|
||||||
V3Scoreboard.cpp
|
|
||||||
V3Slice.cpp
|
V3Slice.cpp
|
||||||
V3Split.cpp
|
V3Split.cpp
|
||||||
V3SplitVar.cpp
|
V3SplitVar.cpp
|
||||||
|
|||||||
+7
-1
@@ -105,6 +105,9 @@ CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include
|
|||||||
#CPPFLAGS += -DVL_ALLOC_RANDOM_CHECKS # To allow --debug-new-random
|
#CPPFLAGS += -DVL_ALLOC_RANDOM_CHECKS # To allow --debug-new-random
|
||||||
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||||
CPPFLAGS += -MP # Only works on recent GCC versions
|
CPPFLAGS += -MP # Only works on recent GCC versions
|
||||||
|
# Replaces VNUser's union with a std::variant to validate int vs void* usage
|
||||||
|
# Ignored unless the build is C++17 or newer
|
||||||
|
#CPPFLAGS += -DVL_USER_TYPE_CHECKS
|
||||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||||
CPPFLAGS += -W -Wall $(CFG_CXXFLAGS_WEXTRA) $(CFG_CXXFLAGS_SRC) -Werror
|
CPPFLAGS += -W -Wall $(CFG_CXXFLAGS_WEXTRA) $(CFG_CXXFLAGS_SRC) -Werror
|
||||||
#CPPFLAGS += -pedantic-errors
|
#CPPFLAGS += -pedantic-errors
|
||||||
@@ -244,6 +247,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||||||
V3CfgBuilder.o \
|
V3CfgBuilder.o \
|
||||||
V3CfgLiveVariables.o \
|
V3CfgLiveVariables.o \
|
||||||
V3Class.o \
|
V3Class.o \
|
||||||
|
V3ClassGraph.o \
|
||||||
V3Clean.o \
|
V3Clean.o \
|
||||||
V3Clock.o \
|
V3Clock.o \
|
||||||
V3Combine.o \
|
V3Combine.o \
|
||||||
@@ -309,6 +313,9 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||||||
V3Order.o \
|
V3Order.o \
|
||||||
V3OrderGraphBuilder.o \
|
V3OrderGraphBuilder.o \
|
||||||
V3OrderMoveGraph.o \
|
V3OrderMoveGraph.o \
|
||||||
|
V3OrderMTaskContraction.o \
|
||||||
|
V3OrderMTaskFixHazards.o \
|
||||||
|
V3OrderMTaskGraph.o \
|
||||||
V3OrderParallel.o \
|
V3OrderParallel.o \
|
||||||
V3OrderProcessDomains.o \
|
V3OrderProcessDomains.o \
|
||||||
V3OrderSerial.o \
|
V3OrderSerial.o \
|
||||||
@@ -330,7 +337,6 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||||||
V3SchedUtil.o \
|
V3SchedUtil.o \
|
||||||
V3SchedVirtIface.o \
|
V3SchedVirtIface.o \
|
||||||
V3Scope.o \
|
V3Scope.o \
|
||||||
V3Scoreboard.o \
|
|
||||||
V3Slice.o \
|
V3Slice.o \
|
||||||
V3Split.o \
|
V3Split.o \
|
||||||
V3SplitVar.o \
|
V3SplitVar.o \
|
||||||
|
|||||||
+31
-3
@@ -34,6 +34,7 @@
|
|||||||
#include "V3Graph.h"
|
#include "V3Graph.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
|
|
||||||
@@ -670,6 +671,32 @@ public:
|
|||||||
//######################################################################
|
//######################################################################
|
||||||
// Pass 2: inject automatic sample() calls for covergroup instances
|
// Pass 2: inject automatic sample() calls for covergroup instances
|
||||||
|
|
||||||
|
class CovergroupEventBindVisitor final : public VNVisitor {
|
||||||
|
AstVarScope* const m_instancep; // Variable scope for the covergroup instance being sampled
|
||||||
|
std::unordered_set<const AstVar*> m_memberps; // Non-static variables in the covergroup class
|
||||||
|
|
||||||
|
void visit(AstVarRef* nodep) override {
|
||||||
|
if (!m_memberps.count(nodep->varp())) return;
|
||||||
|
FileLine* const fl = nodep->fileline();
|
||||||
|
AstMemberSel* const selp
|
||||||
|
= new AstMemberSel{fl, new AstVarRef{fl, m_instancep, VAccess::READ}, nodep->varp()};
|
||||||
|
selp->access(nodep->access());
|
||||||
|
nodep->replaceWith(selp);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
}
|
||||||
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
CovergroupEventBindVisitor(AstSenTree* eventp, AstClass* classp, AstVarScope* instancep)
|
||||||
|
: m_instancep{instancep} {
|
||||||
|
classp->foreachMember([&](AstClass* const, AstVar* const varp) {
|
||||||
|
if (!varp->isStatic()) m_memberps.emplace(varp);
|
||||||
|
});
|
||||||
|
iterate(eventp);
|
||||||
|
}
|
||||||
|
~CovergroupEventBindVisitor() override = default;
|
||||||
|
};
|
||||||
|
|
||||||
class CovergroupInjectVisitor final : public VNVisitor {
|
class CovergroupInjectVisitor final : public VNVisitor {
|
||||||
// NODE STATE (set by CovergroupCollectVisitor, consumed here)
|
// NODE STATE (set by CovergroupCollectVisitor, consumed here)
|
||||||
// AstClass::user1p() -> AstCFunc*. The sample() CFunc for this covergroup class
|
// AstClass::user1p() -> AstCFunc*. The sample() CFunc for this covergroup class
|
||||||
@@ -719,10 +746,11 @@ class CovergroupInjectVisitor final : public VNVisitor {
|
|||||||
cmethodCallp->dtypeSetVoid();
|
cmethodCallp->dtypeSetVoid();
|
||||||
cmethodCallp->argTypes("vlSymsp");
|
cmethodCallp->argTypes("vlSymsp");
|
||||||
|
|
||||||
// Clone the sensitivity for this active block.
|
// Clone the sensitivity for this active block. References to covergroup members need
|
||||||
// V3Scope has already resolved all VarRefs in eventp, so the clone
|
// to select through this particular instance; all other VarRefs retain the VarScopes
|
||||||
// inherits correct varScopep values with no fixup needed.
|
// resolved by V3Scope.
|
||||||
AstSenTree* senTreep = eventp->cloneTree(false);
|
AstSenTree* senTreep = eventp->cloneTree(false);
|
||||||
|
CovergroupEventBindVisitor{senTreep, classp, nodep};
|
||||||
|
|
||||||
// Get or create the AstActive node for this sensitivity
|
// Get or create the AstActive node for this sensitivity
|
||||||
// senTreep is a template used by getActive() which clones it into the AstActive;
|
// senTreep is a template used by getActive() which clones it into the AstActive;
|
||||||
|
|||||||
+3
-1
@@ -36,11 +36,13 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||||||
// Active class functions
|
// Active class functions
|
||||||
|
|
||||||
class ActiveTopVisitor final : public VNVisitor {
|
class ActiveTopVisitor final : public VNVisitor {
|
||||||
|
// NODE STATE
|
||||||
|
// AstVarScope::user1() // bool. Processed
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
SenTreeFinder m_finder; // Find global sentree's / add them under the AstTopScope
|
SenTreeFinder m_finder; // Find global sentree's / add them under the AstTopScope
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
static bool isInitial(AstNode* nodep) {
|
static bool isInitial(AstNode* nodep) {
|
||||||
const VNUser1InUse user1InUse;
|
const VNUser1InUse user1InUse;
|
||||||
// Return true if no variables that read.
|
// Return true if no variables that read.
|
||||||
|
|||||||
+254
-36
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "V3AstUserAllocator.h"
|
#include "V3AstUserAllocator.h"
|
||||||
#include "V3Stats.h"
|
#include "V3Stats.h"
|
||||||
|
#include "V3UniqueNames.h"
|
||||||
|
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
|
|
||||||
@@ -89,6 +90,58 @@ public:
|
|||||||
explicit DefaultDisablePropagateVisitor(AstNetlist* nodep) { iterate(nodep); }
|
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
|
} // namespace
|
||||||
|
|
||||||
void V3AssertCommon::collectDefaultDisable(AstNetlist* nodep) {
|
void V3AssertCommon::collectDefaultDisable(AstNetlist* nodep) {
|
||||||
@@ -96,6 +149,11 @@ void V3AssertCommon::collectDefaultDisable(AstNetlist* nodep) {
|
|||||||
{ DefaultDisablePropagateVisitor{nodep}; }
|
{ DefaultDisablePropagateVisitor{nodep}; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void V3AssertCommon::lowerSequenceEvents(AstNetlist* nodep) {
|
||||||
|
{ SeqEventLowerVisitor{nodep}; }
|
||||||
|
V3Global::dumpCheckGlobalTree("assertseqevent", 0, dumpTreeEitherLevel() >= 3);
|
||||||
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// AssertDeFutureVisitor
|
// AssertDeFutureVisitor
|
||||||
// If any AstFuture, then move all non-future varrefs to be one cycle behind,
|
// If any AstFuture, then move all non-future varrefs to be one cycle behind,
|
||||||
@@ -188,6 +246,41 @@ public:
|
|||||||
~AssertDeFutureVisitor() = default;
|
~AssertDeFutureVisitor() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Prepare one default sampled expression.
|
||||||
|
class DefaultSampledValueVisitor final : public VNVisitor {
|
||||||
|
// METHODS
|
||||||
|
static AstConst* newTypeDefault(AstNodeExpr* nodep) {
|
||||||
|
AstConst* const constp
|
||||||
|
= new AstConst{nodep->fileline(), AstConst::DTyped{}, nodep->dtypep()};
|
||||||
|
if (nodep->dtypep()->isFourstate()) constp->num().setAllBitsX();
|
||||||
|
constp->dtypeFrom(nodep);
|
||||||
|
return constp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// VISITORS
|
||||||
|
void visit(AstCMethodHard* nodep) override {
|
||||||
|
if (nodep->method() == VCMethod::EVENT_IS_TRIGGERED) {
|
||||||
|
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
} else {
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void visit(AstNodeVarRef* nodep) override {
|
||||||
|
AstVar* const varp = nodep->varp();
|
||||||
|
if (varp->isParam()
|
||||||
|
|| (!varp->isNet() && varp->lifetime().isStatic() && varp->hasUserInit())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nodep->replaceWith(newTypeDefault(nodep));
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
}
|
||||||
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DefaultSampledValueVisitor(AstNode* nodep) { iterate(nodep); }
|
||||||
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// AssertVisitor
|
// AssertVisitor
|
||||||
|
|
||||||
@@ -228,9 +321,17 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
AstNode* m_failsp = nullptr; // Current fail statement
|
AstNode* m_failsp = nullptr; // Current fail statement
|
||||||
AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion
|
AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion
|
||||||
AstFinal* m_finalp = nullptr; // Current final block
|
AstFinal* m_finalp = nullptr; // Current final block
|
||||||
// Map from (expression, senTree) to AstAlways that computes delayed values of the expression
|
VDouble0 m_statLiftedCaseExprs; // Count of purified case expressions
|
||||||
|
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||||
|
V3UniqueNames m_caseTempNames{"__VCase"};
|
||||||
|
// Maps from (expression, senTree) to the AstAlways that computes its delayed values.
|
||||||
std::unordered_map<VNRef<AstNodeExpr>, std::unordered_map<VNRef<AstSenTree>, AstAlways*>>
|
std::unordered_map<VNRef<AstNodeExpr>, std::unordered_map<VNRef<AstSenTree>, AstAlways*>>
|
||||||
m_modExpr2Sen2DelayedAlwaysp;
|
m_modExpr2Sen2DelayedAlwaysp;
|
||||||
|
// Source sampled-value history is initialized, unlike internal property-lowering history.
|
||||||
|
std::unordered_map<VNRef<AstNodeExpr>, std::unordered_map<VNRef<AstSenTree>, AstAlways*>>
|
||||||
|
m_modExpr2Sen2DefaultDelayedAlwaysp;
|
||||||
|
// Map from delayed-value AstAlways to its last-sampling-tick time variable
|
||||||
|
std::unordered_map<const AstAlways*, AstVar*> m_delayedAlways2TickTimep;
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
static string assertCtlGetCall(const char* query, VAssertType type,
|
static string assertCtlGetCall(const char* query, VAssertType type,
|
||||||
@@ -326,8 +427,7 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstSampled* newSampledExpr(AstNodeExpr* nodep) {
|
AstSampled* newSampledExpr(AstNodeExpr* nodep) {
|
||||||
AstSampled* const sampledp = new AstSampled{nodep->fileline(), nodep, nodep->dtypep()};
|
return new AstSampled{nodep->fileline(), nodep, nodep->dtypep(), true};
|
||||||
return sampledp;
|
|
||||||
}
|
}
|
||||||
AstVarRef* newMonitorNumVarRefp(const AstNode* nodep, VAccess access) {
|
AstVarRef* newMonitorNumVarRefp(const AstNode* nodep, VAccess access) {
|
||||||
if (!m_monitorNumVarp) {
|
if (!m_monitorNumVarp) {
|
||||||
@@ -437,12 +537,18 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
return bodysp;
|
return bodysp;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstVar* createDelayedVar(const std::string& name, AstAlways* alwaysp, AstNodeExpr* exprp) {
|
AstVar* createDelayedVar(const std::string& name, AstAlways* alwaysp, AstNodeExpr* exprp,
|
||||||
|
AstNodeExpr* initp) {
|
||||||
FileLine* const flp = exprp->fileline();
|
FileLine* const flp = exprp->fileline();
|
||||||
AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, exprp->dtypep()};
|
AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, exprp->dtypep()};
|
||||||
// TODO: this lifetime seems nonsene (can't have NBAs to automatics), but is as before
|
// TODO: this lifetime seems nonsene (can't have NBAs to automatics), but is as before
|
||||||
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||||
m_modp->addStmtsp(varp);
|
m_modp->addStmtsp(varp);
|
||||||
|
// Before enough clock ticks, $past returns the expression's default sampled value.
|
||||||
|
if (initp) {
|
||||||
|
m_modp->addStmtsp(new AstInitialStatic{
|
||||||
|
flp, new AstAssign{flp, new AstVarRef{flp, varp, VAccess::WRITE}, initp}});
|
||||||
|
}
|
||||||
++m_statPastVars;
|
++m_statPastVars;
|
||||||
// Actually set the delayed value
|
// Actually set the delayed value
|
||||||
AstNodeExpr* const lhsp = new AstVarRef{flp, varp, VAccess::WRITE};
|
AstNodeExpr* const lhsp = new AstVarRef{flp, varp, VAccess::WRITE};
|
||||||
@@ -455,8 +561,10 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
return varp;
|
return varp;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstAlways* getDelayedAlways(AstNodeExpr* exprp, AstSenTree* senTreep) {
|
AstAlways* getDelayedAlways(AstNodeExpr* exprp, AstNodeExpr* initp, AstSenTree* senTreep) {
|
||||||
AstAlways*& alwayspr = m_modExpr2Sen2DelayedAlwaysp[*exprp][*senTreep];
|
auto& expr2Sen2Alwaysr
|
||||||
|
= initp ? m_modExpr2Sen2DefaultDelayedAlwaysp : m_modExpr2Sen2DelayedAlwaysp;
|
||||||
|
AstAlways*& alwayspr = expr2Sen2Alwaysr[*exprp][*senTreep];
|
||||||
if (!alwayspr) {
|
if (!alwayspr) {
|
||||||
FileLine* const flp = exprp->fileline();
|
FileLine* const flp = exprp->fileline();
|
||||||
// Create the always block that computes the delayed values
|
// Create the always block that computes the delayed values
|
||||||
@@ -464,36 +572,64 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
m_modp->addStmtsp(alwayspr);
|
m_modp->addStmtsp(alwayspr);
|
||||||
// Create the once-delayed variable
|
// Create the once-delayed variable
|
||||||
const std::string name = "_Vpast_" + cvtToStr(m_modPastNum++) + "_1";
|
const std::string name = "_Vpast_" + cvtToStr(m_modPastNum++) + "_1";
|
||||||
AstVar* const varp = createDelayedVar(name, alwayspr, exprp);
|
AstVar* const varp = createDelayedVar(name, alwayspr, exprp, initp);
|
||||||
// Add it to delayed variable vector
|
// Add it to delayed variable vector
|
||||||
m_delayed(alwayspr).emplace_back(varp);
|
m_delayed(alwayspr).emplace_back(varp);
|
||||||
} else {
|
} else {
|
||||||
// Reusing exiting, not needed
|
// Reusing exiting, not needed
|
||||||
VL_DO_DANGLING(pushDeletep(exprp), exprp);
|
VL_DO_DANGLING(pushDeletep(exprp), exprp);
|
||||||
|
if (initp) VL_DO_DANGLING(pushDeletep(initp), initp);
|
||||||
VL_DO_DANGLING(pushDeletep(senTreep), senTreep);
|
VL_DO_DANGLING(pushDeletep(senTreep), senTreep);
|
||||||
}
|
}
|
||||||
return alwayspr;
|
return alwayspr;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNodeExpr* getPastValue(AstNodeExpr* exprp, AstSenTree* senTreep, uint32_t ticks) {
|
AstNodeExpr* getPastValue(AstNodeExpr* exprp, AstNodeExpr* initp, AstSenTree* senTreep,
|
||||||
|
uint32_t ticks) {
|
||||||
UASSERT_OBJ(ticks > 0, exprp, "Delay must be > 0");
|
UASSERT_OBJ(ticks > 0, exprp, "Delay must be > 0");
|
||||||
AstAlways* const alwaysp = getDelayedAlways(exprp, senTreep);
|
FileLine* const flp = exprp->fileline();
|
||||||
|
AstAlways* const alwaysp
|
||||||
|
= getDelayedAlways(exprp, initp ? initp->cloneTreePure(false) : nullptr, senTreep);
|
||||||
|
AstNodeExpr* const resultp = pastValueRef(alwaysp, flp, ticks, initp);
|
||||||
|
if (initp) VL_DO_DANGLING(pushDeletep(initp), initp);
|
||||||
|
return resultp;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNodeExpr* pastValueRef(AstAlways* alwaysp, FileLine* flp, uint32_t ticks,
|
||||||
|
AstNodeExpr* initp) {
|
||||||
std::vector<AstVar*>& delayedr = m_delayed(alwaysp);
|
std::vector<AstVar*>& delayedr = m_delayed(alwaysp);
|
||||||
// Ensure the required delay exists
|
// Ensure the required delay exists
|
||||||
while (delayedr.size() < ticks) {
|
while (delayedr.size() < ticks) {
|
||||||
AstVar* const firstp = delayedr.front();
|
AstVar* const firstp = delayedr.front();
|
||||||
FileLine* const flp = firstp->fileline();
|
FileLine* const varFlp = firstp->fileline();
|
||||||
// Create once more delayed value
|
// Create once more delayed value
|
||||||
std::string name = firstp->name();
|
std::string name = firstp->name();
|
||||||
name.resize(name.size() - 1);
|
name.resize(name.size() - 1);
|
||||||
name += std::to_string(delayedr.size() + 1);
|
name += std::to_string(delayedr.size() + 1);
|
||||||
AstNodeExpr* const prevp = new AstVarRef{flp, delayedr.back(), VAccess::READ};
|
AstNodeExpr* const prevp = new AstVarRef{varFlp, delayedr.back(), VAccess::READ};
|
||||||
AstVar* const varp = createDelayedVar(name, alwaysp, prevp);
|
AstVar* const varp = createDelayedVar(name, alwaysp, prevp,
|
||||||
|
initp ? initp->cloneTreePure(false) : nullptr);
|
||||||
// Add it to delayed variable vector
|
// Add it to delayed variable vector
|
||||||
delayedr.emplace_back(varp);
|
delayedr.emplace_back(varp);
|
||||||
}
|
}
|
||||||
// Return a reference to the appropriately delayed variable
|
// Return a reference to the appropriately delayed variable
|
||||||
return new AstVarRef{exprp->fileline(), delayedr.at(ticks - 1), VAccess::READ};
|
return new AstVarRef{flp, delayedr.at(ticks - 1), VAccess::READ};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time of the pipeline's last sampling tick, for end-of-simulation readers
|
||||||
|
AstVar* getPastTickTimeVar(AstAlways* alwaysp) {
|
||||||
|
AstVar*& varpr = m_delayedAlways2TickTimep[alwaysp];
|
||||||
|
if (!varpr) {
|
||||||
|
FileLine* const flp = alwaysp->fileline();
|
||||||
|
varpr = new AstVar{flp, VVarType::MODULETEMP,
|
||||||
|
"_Vpast_" + cvtToStr(m_modPastNum++) + "_t",
|
||||||
|
m_modp->findUInt64DType()};
|
||||||
|
m_modp->addStmtsp(varpr);
|
||||||
|
AstNodeExpr* const timep = new AstCExpr{flp, "vlSymsp->_vm_contextp__->time()", 64};
|
||||||
|
alwaysp->addStmtsp(
|
||||||
|
new AstAssign{flp, new AstVarRef{flp, varpr, VAccess::WRITE}, timep});
|
||||||
|
}
|
||||||
|
return varpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitAssertionIterate(AstNodeCoverOrAssert* nodep, AstNode* failsp) {
|
void visitAssertionIterate(AstNodeCoverOrAssert* nodep, AstNode* failsp) {
|
||||||
@@ -542,14 +678,19 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
bool selfDestruct = false;
|
bool selfDestruct = false;
|
||||||
bool passspGated = 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;
|
++m_statCover;
|
||||||
if (!v3Global.opt.coverageUser()) {
|
if (seqEvent) {
|
||||||
|
// Keep the event-fire action, with no coverage bucket
|
||||||
|
} else if (!v3Global.opt.coverageUser()) {
|
||||||
selfDestruct = true;
|
selfDestruct = true;
|
||||||
} else {
|
} else {
|
||||||
// V3Coverage assigned us a bucket to increment.
|
// V3Coverage assigned us a bucket to increment.
|
||||||
AstCoverInc* const covincp = VN_AS(snodep->coverincsp(), CoverInc);
|
AstCoverInc* const covincp = VN_AS(coverp->coverincsp(), CoverInc);
|
||||||
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
|
UASSERT_OBJ(covincp, coverp, "Missing AstCoverInc under assertion");
|
||||||
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
||||||
if (message != "") covincp->declp()->comment(message);
|
if (message != "") covincp->declp()->comment(message);
|
||||||
if (passsp) {
|
if (passsp) {
|
||||||
@@ -584,26 +725,51 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
AstNode* propExprp;
|
AstNode* propExprp;
|
||||||
AstNodeExpr* disablep = nullptr;
|
AstNodeExpr* disablep = nullptr;
|
||||||
|
AstNodeExpr* matchCountp = nullptr;
|
||||||
if (AstPropSpec* const specp = VN_CAST(nodep->propp(), PropSpec)) {
|
if (AstPropSpec* const specp = VN_CAST(nodep->propp(), PropSpec)) {
|
||||||
propExprp = specp->propp()->unlinkFrBack();
|
propExprp = specp->propp()->unlinkFrBack();
|
||||||
if (specp->disablep()) disablep = specp->disablep()->unlinkFrBack();
|
if (specp->disablep()) disablep = specp->disablep()->unlinkFrBack();
|
||||||
|
matchCountp = specp->matchCountp();
|
||||||
} else {
|
} else {
|
||||||
propExprp = nodep->propp()->unlinkFrBack();
|
propExprp = nodep->propp()->unlinkFrBack();
|
||||||
}
|
}
|
||||||
FileLine* const flp = nodep->fileline();
|
FileLine* const flp = nodep->fileline();
|
||||||
bool passspAlreadyGated = false;
|
bool passspAlreadyGated = false;
|
||||||
if (passsp && VN_IS(passsp, If)) passspAlreadyGated = VN_AS(passsp, If)->user1();
|
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(),
|
passsp = newIfAssertPassOn(passsp, nodep->directive(), nodep->userType(),
|
||||||
/*vacuous=*/false);
|
/*vacuous=*/false);
|
||||||
}
|
}
|
||||||
if (failsp && !VN_IS(propExprp, PExpr)) {
|
if (failsp && !VN_IS(propExprp, PExpr)) {
|
||||||
failsp = newIfAssertFailOn(failsp, nodep->directive(), nodep->userType());
|
failsp = newIfAssertFailOn(failsp, nodep->directive(), nodep->userType());
|
||||||
}
|
}
|
||||||
|
if (coverp && matchCountp && passsp) {
|
||||||
|
// Convert the match count into a loop that decrements a temporary variable until it
|
||||||
|
// reaches zero.
|
||||||
|
matchCountp->unlinkFrBack();
|
||||||
|
AstVar* const remainingp = new AstVar{
|
||||||
|
flp, VVarType::BLOCKTEMP, "__VnfaRemainingMatchCount", matchCountp->dtypep()};
|
||||||
|
remainingp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||||
|
AstBegin* const replayp = new AstBegin{flp, "", remainingp, true};
|
||||||
|
replayp->addStmtsp(
|
||||||
|
new AstAssign{flp, new AstVarRef{flp, remainingp, VAccess::WRITE}, matchCountp});
|
||||||
|
AstLoop* const loopp = new AstLoop{flp};
|
||||||
|
loopp->addStmtsp(
|
||||||
|
new AstLoopTest{flp, loopp, new AstVarRef{flp, remainingp, VAccess::READ}});
|
||||||
|
loopp->addStmtsp(passsp);
|
||||||
|
loopp->addStmtsp(
|
||||||
|
new AstAssign{flp, new AstVarRef{flp, remainingp, VAccess::WRITE},
|
||||||
|
new AstSub{flp, new AstVarRef{flp, remainingp, VAccess::READ},
|
||||||
|
new AstConst{flp, AstConst::WidthedValue{},
|
||||||
|
remainingp->dtypep()->width(), 1}}});
|
||||||
|
replayp->addStmtsp(loopp);
|
||||||
|
passsp = replayp;
|
||||||
|
}
|
||||||
AstNode* bodysp = assertBody(nodep, propExprp, passsp, failsp);
|
AstNode* bodysp = assertBody(nodep, propExprp, passsp, failsp);
|
||||||
if (disablep) bodysp = new AstIf{flp, new AstLogNot{flp, disablep}, bodysp};
|
if (disablep) bodysp = new AstIf{flp, new AstLogNot{flp, disablep}, bodysp};
|
||||||
// Add assertOn check last, for better combining
|
// Add assertOn check last, for better combining
|
||||||
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 (sentreep) bodysp = new AstAlways{flp, VAlwaysKwd::ALWAYS, sentreep, bodysp};
|
||||||
|
|
||||||
if (passsp && !passsp->backp()) VL_DO_DANGLING(pushDeletep(passsp), passsp);
|
if (passsp && !passsp->backp()) VL_DO_DANGLING(pushDeletep(passsp), passsp);
|
||||||
@@ -755,6 +921,28 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
//========== Case assertions
|
//========== Case assertions
|
||||||
void visit(AstCase* nodep) override {
|
void visit(AstCase* nodep) override {
|
||||||
|
// Introduce temporary variable for AstCase if needed - it is done here and not in V3Case
|
||||||
|
// because this phase is before V3Scope and V3Case is not. Doing it before V3Scope ensures
|
||||||
|
// that V3Scope will take care of a scope creation
|
||||||
|
// We also need to do it before V3Begin, co that pragmas like `unique0` also work correctly
|
||||||
|
if (!nodep->exprp()->isPure()) {
|
||||||
|
++m_statLiftedCaseExprs;
|
||||||
|
FileLine* const fl = nodep->exprp()->fileline();
|
||||||
|
AstVar* const varp = new AstVar{fl, VVarType::BLOCKTEMP, m_caseTempNames.get(nodep),
|
||||||
|
nodep->exprp()->dtypep()};
|
||||||
|
AstNodeExpr* const origp = nodep->exprp()->unlinkFrBack();
|
||||||
|
nodep->addHereThisAsNext(
|
||||||
|
new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, origp});
|
||||||
|
nodep->exprp(new AstVarRef{fl, varp, VAccess::READ});
|
||||||
|
if (m_ftaskp) {
|
||||||
|
varp->funcLocal(true);
|
||||||
|
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||||
|
m_ftaskp->stmtsp()->addHereThisAsNext(varp);
|
||||||
|
} else {
|
||||||
|
m_modp->stmtsp()->addHereThisAsNext(varp);
|
||||||
|
}
|
||||||
|
VIsCached::clearCacheTree();
|
||||||
|
}
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (!nodep->user1SetOnce()) {
|
if (!nodep->user1SetOnce()) {
|
||||||
bool has_default = false;
|
bool has_default = false;
|
||||||
@@ -878,6 +1066,11 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
//========== Past
|
//========== Past
|
||||||
void visit(AstPast* nodep) override {
|
void visit(AstPast* nodep) override {
|
||||||
|
if (!nodep->propertyTiming()) {
|
||||||
|
nodep->initp(nodep->exprp()->cloneTreePure(false));
|
||||||
|
{ DefaultSampledValueVisitor{nodep->initp()}; }
|
||||||
|
}
|
||||||
|
AstNodeExpr* const initp = nodep->initp() ? nodep->initp()->unlinkFrBack() : nullptr;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
uint32_t ticks = 1;
|
uint32_t ticks = 1;
|
||||||
if (nodep->ticksp()) {
|
if (nodep->ticksp()) {
|
||||||
@@ -887,7 +1080,27 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
|
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
|
||||||
AstNodeExpr* const exprp = newSampledExpr(nodep->exprp()->unlinkFrBack());
|
AstNodeExpr* const exprp = newSampledExpr(nodep->exprp()->unlinkFrBack());
|
||||||
AstNodeExpr* inp = getPastValue(exprp, nodep->sentreep()->unlinkFrBack(), ticks);
|
AstSenTree* const senTreep = nodep->sentreep()->unlinkFrBack();
|
||||||
|
AstNodeExpr* inp = nullptr;
|
||||||
|
// Deliberately emitted for every ftask $past; calls outside final take the normal stage
|
||||||
|
if (VN_IS(m_procedurep, Final) || m_ftaskp) {
|
||||||
|
// A sampling-tick finish reads one stage deeper (IEEE 1800-2023 16.9.3).
|
||||||
|
FileLine* const flp = nodep->fileline();
|
||||||
|
AstAlways* const alwaysp
|
||||||
|
= getDelayedAlways(exprp, initp ? initp->cloneTreePure(false) : nullptr, senTreep);
|
||||||
|
AstNodeExpr* const betweenTicksp = pastValueRef(alwaysp, flp, ticks, initp);
|
||||||
|
AstNodeExpr* const onTickp = pastValueRef(alwaysp, flp, ticks + 1, initp);
|
||||||
|
if (initp) VL_DO_DANGLING(pushDeletep(initp), initp);
|
||||||
|
AstNodeExpr* const onTickCondp = new AstLogAnd{
|
||||||
|
flp, new AstCExpr{flp, "vlSymsp->_vm_contextp__->executingFinal()", 1},
|
||||||
|
new AstEq{flp, new AstVarRef{flp, getPastTickTimeVar(alwaysp), VAccess::READ},
|
||||||
|
new AstCExpr{flp, "vlSymsp->_vm_contextp__->finishPendingTime()", 64}}};
|
||||||
|
AstCond* const condp = new AstCond{flp, onTickCondp, onTickp, betweenTicksp};
|
||||||
|
condp->dtypeFrom(onTickp);
|
||||||
|
inp = condp;
|
||||||
|
} else {
|
||||||
|
inp = getPastValue(exprp, initp, senTreep, ticks);
|
||||||
|
}
|
||||||
nodep->replaceWith(inp);
|
nodep->replaceWith(inp);
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
}
|
}
|
||||||
@@ -983,11 +1196,7 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
= new AstSenItem{fl, VEdgeType::ET_CHANGED,
|
= new AstSenItem{fl, VEdgeType::ET_CHANGED,
|
||||||
// Clone so get VarRef or VarXRef as needed
|
// Clone so get VarRef or VarXRef as needed
|
||||||
varrefp->cloneTree(false)};
|
varrefp->cloneTree(false)};
|
||||||
if (!monSenItemsp) {
|
monSenItemsp = AstNode::addNextNull(monSenItemsp, senItemp);
|
||||||
monSenItemsp = senItemp;
|
|
||||||
} else {
|
|
||||||
monSenItemsp->addNext(senItemp);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1047,9 +1256,9 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
bool assertTypeConst = true;
|
bool assertTypeConst = true;
|
||||||
if (!nodep->assertTypesp()) {
|
if (!nodep->assertTypesp()) {
|
||||||
nodep->ctlAssertTypes(VAssertType{ALL_ASSERT_TYPES});
|
nodep->assertTypes(VAssertType{ALL_ASSERT_TYPES});
|
||||||
} else if (const AstConst* const assertTypesp = VN_CAST(nodep->assertTypesp(), Const)) {
|
} else if (const AstConst* const assertTypesp = VN_CAST(nodep->assertTypesp(), Const)) {
|
||||||
nodep->ctlAssertTypes(VAssertType{assertTypesp->toSInt()});
|
nodep->assertTypes(VAssertType{assertTypesp->toSInt()});
|
||||||
} else {
|
} else {
|
||||||
assertTypeConst = false;
|
assertTypeConst = false;
|
||||||
}
|
}
|
||||||
@@ -1069,9 +1278,9 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (assertTypeConst && nodep->ctlAssertTypes() != ALL_ASSERT_TYPES
|
if (assertTypeConst && nodep->assertTypes() != ALL_ASSERT_TYPES
|
||||||
&& nodep->ctlAssertTypes().containsAny(VAssertType::UNIQUE | VAssertType::UNIQUE0
|
&& nodep->assertTypes().containsAny(VAssertType::UNIQUE | VAssertType::UNIQUE0
|
||||||
| VAssertType::PRIORITY)) {
|
| VAssertType::PRIORITY)) {
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: assert control assertion_type");
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: assert control assertion_type");
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
return;
|
return;
|
||||||
@@ -1079,11 +1288,11 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
bool directiveTypeConst = true;
|
bool directiveTypeConst = true;
|
||||||
if (!nodep->directiveTypesp()) {
|
if (!nodep->directiveTypesp()) {
|
||||||
nodep->ctlDirectiveTypes(VAssertDirectiveType::ASSERT | VAssertDirectiveType::ASSUME
|
nodep->directiveTypes(VAssertDirectiveType::ASSERT | VAssertDirectiveType::ASSUME
|
||||||
| VAssertDirectiveType::COVER);
|
| VAssertDirectiveType::COVER);
|
||||||
} else if (const AstConst* const directiveTypesp
|
} else if (const AstConst* const directiveTypesp
|
||||||
= VN_CAST(nodep->directiveTypesp(), Const)) {
|
= VN_CAST(nodep->directiveTypesp(), Const)) {
|
||||||
nodep->ctlDirectiveTypes(VAssertDirectiveType{directiveTypesp->toSInt()});
|
nodep->directiveTypes(VAssertDirectiveType{directiveTypesp->toSInt()});
|
||||||
} else {
|
} else {
|
||||||
directiveTypeConst = false;
|
directiveTypeConst = false;
|
||||||
}
|
}
|
||||||
@@ -1105,7 +1314,7 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
} else {
|
} else {
|
||||||
newp->add(std::to_string(ALL_ASSERT_TYPES));
|
newp->add(std::to_string(ALL_ASSERT_TYPES));
|
||||||
}
|
}
|
||||||
newp->add(", " + std::to_string(nodep->ctlDirectiveTypes()) + ");\n");
|
newp->add(", " + std::to_string(nodep->directiveTypes()) + ");\n");
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
}
|
}
|
||||||
@@ -1127,12 +1336,13 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
VL_RESTORER(m_modp);
|
VL_RESTORER(m_modp);
|
||||||
VL_RESTORER(m_modPastNum);
|
VL_RESTORER(m_modPastNum);
|
||||||
VL_RESTORER(m_modStrobeNum);
|
VL_RESTORER(m_modStrobeNum);
|
||||||
VL_RESTORER(m_modExpr2Sen2DelayedAlwaysp);
|
|
||||||
VL_RESTORER(m_finalp);
|
VL_RESTORER(m_finalp);
|
||||||
|
VL_RESTORER_CLEAR(m_modExpr2Sen2DelayedAlwaysp);
|
||||||
|
VL_RESTORER_CLEAR(m_modExpr2Sen2DefaultDelayedAlwaysp);
|
||||||
|
VL_RESTORER_CLEAR(m_delayedAlways2TickTimep);
|
||||||
m_modp = nodep;
|
m_modp = nodep;
|
||||||
m_modPastNum = 0;
|
m_modPastNum = 0;
|
||||||
m_modStrobeNum = 0;
|
m_modStrobeNum = 0;
|
||||||
m_modExpr2Sen2DelayedAlwaysp.clear();
|
|
||||||
m_finalp = nullptr;
|
m_finalp = nullptr;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
@@ -1141,6 +1351,11 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
m_procedurep = nodep;
|
m_procedurep = nodep;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
|
void visit(AstNodeFTask* nodep) override {
|
||||||
|
VL_RESTORER(m_ftaskp);
|
||||||
|
m_ftaskp = nodep;
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
void visit(AstGenBlock* nodep) override {
|
void visit(AstGenBlock* nodep) override {
|
||||||
// This code is needed rather than a visitor in V3Begin,
|
// This code is needed rather than a visitor in V3Begin,
|
||||||
// because V3Assert is called before V3Begin
|
// because V3Assert is called before V3Begin
|
||||||
@@ -1180,6 +1395,9 @@ public:
|
|||||||
V3Stats::addStat("Assertions, $past variables", m_statPastVars);
|
V3Stats::addStat("Assertions, $past variables", m_statPastVars);
|
||||||
V3Stats::addStat("Assertions, assertOn checks combined", m_statAssertOnCombined);
|
V3Stats::addStat("Assertions, assertOn checks combined", m_statAssertOnCombined);
|
||||||
V3Stats::addStat("Assertions, assertOn checks hoisted", m_statAssertOnHoisted);
|
V3Stats::addStat("Assertions, assertOn checks hoisted", m_statAssertOnHoisted);
|
||||||
|
V3Stats::addStat("Assertions, lifted impure case expressions", m_statLiftedCaseExprs);
|
||||||
|
// Rewrites can change purity, e.g. by compiling out assertion statements with --no-assert
|
||||||
|
VIsCached::clearCacheTree();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
class V3AssertCommon final {
|
class V3AssertCommon final {
|
||||||
public:
|
public:
|
||||||
static void collectDefaultDisable(AstNetlist* nodep) VL_MT_DISABLED;
|
static void collectDefaultDisable(AstNetlist* nodep) VL_MT_DISABLED;
|
||||||
|
static void lowerSequenceEvents(AstNetlist* nodep) VL_MT_DISABLED;
|
||||||
};
|
};
|
||||||
|
|
||||||
class V3Assert final {
|
class V3Assert final {
|
||||||
|
|||||||
+957
-572
File diff suppressed because it is too large
Load Diff
+44
-20
@@ -79,6 +79,14 @@ private:
|
|||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
|
static void checkSamplingFuncDType(AstNodeExpr* nodep, const AstNode* exprp) {
|
||||||
|
const AstNodeDType* const dtypep = exprp->dtypep()->skipRefp();
|
||||||
|
if (!dtypep->isIntegralOrPacked()) {
|
||||||
|
nodep->v3error("Expected numeric type, but got a " << dtypep->prettyDTypeNameQ()
|
||||||
|
<< " data type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AstSenTree* newSenTree(AstNode* nodep, AstSenTree* useTreep = nullptr,
|
AstSenTree* newSenTree(AstNode* nodep, AstSenTree* useTreep = nullptr,
|
||||||
AstNodeCoverOrAssert* cassertp = nullptr) {
|
AstNodeCoverOrAssert* cassertp = nullptr) {
|
||||||
// Create sentree based on clocked or default clock
|
// Create sentree based on clocked or default clock
|
||||||
@@ -372,7 +380,7 @@ private:
|
|||||||
// #1step means the value that is sampled is always the signal's last value
|
// #1step means the value that is sampled is always the signal's last value
|
||||||
// before the clock edge (IEEE 1800-2023 14.4)
|
// before the clock edge (IEEE 1800-2023 14.4)
|
||||||
AstSampled* const sampledp
|
AstSampled* const sampledp
|
||||||
= new AstSampled{flp, exprp->cloneTreePure(false), exprp->dtypep()};
|
= new AstSampled{flp, exprp->cloneTreePure(false), exprp->dtypep(), true};
|
||||||
AstAssign* const assignp = new AstAssign{flp, refp, sampledp};
|
AstAssign* const assignp = new AstAssign{flp, refp, sampledp};
|
||||||
m_clockingp->addNextHere(new AstAlways{
|
m_clockingp->addNextHere(new AstAlways{
|
||||||
flp, VAlwaysKwd::ALWAYS,
|
flp, VAlwaysKwd::ALWAYS,
|
||||||
@@ -683,6 +691,7 @@ private:
|
|||||||
void visit(AstFalling* nodep) override {
|
void visit(AstFalling* nodep) override {
|
||||||
if (nodep->user1SetOnce()) return;
|
if (nodep->user1SetOnce()) return;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||||
@@ -696,6 +705,7 @@ private:
|
|||||||
void visit(AstFell* nodep) override {
|
void visit(AstFell* nodep) override {
|
||||||
if (nodep->user1SetOnce()) return;
|
if (nodep->user1SetOnce()) return;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||||
@@ -712,11 +722,13 @@ private:
|
|||||||
void visit(AstFuture* nodep) override {
|
void visit(AstFuture* nodep) override {
|
||||||
if (nodep->user1SetOnce()) return;
|
if (nodep->user1SetOnce()) return;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||||
AstSenTree* const sentreep = nodep->sentreep();
|
AstSenTree* const sentreep = nodep->sentreep();
|
||||||
if (sentreep) VL_DO_DANGLING(pushDeletep(sentreep->unlinkFrBack()), sentreep);
|
if (sentreep) VL_DO_DANGLING(pushDeletep(sentreep->unlinkFrBack()), sentreep);
|
||||||
nodep->sentreep(newSenTree(nodep));
|
nodep->sentreep(newSenTree(nodep));
|
||||||
}
|
}
|
||||||
void visit(AstPast* nodep) override {
|
void visit(AstPast* nodep) override {
|
||||||
|
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||||
if (nodep->sentreep()) return; // Already processed
|
if (nodep->sentreep()) return; // Already processed
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
nodep->sentreep(newSenTree(nodep));
|
nodep->sentreep(newSenTree(nodep));
|
||||||
@@ -774,6 +786,7 @@ private:
|
|||||||
void visit(AstRising* nodep) override {
|
void visit(AstRising* nodep) override {
|
||||||
if (nodep->user1SetOnce()) return;
|
if (nodep->user1SetOnce()) return;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||||
@@ -787,6 +800,7 @@ private:
|
|||||||
void visit(AstRose* nodep) override {
|
void visit(AstRose* nodep) override {
|
||||||
if (nodep->user1SetOnce()) return;
|
if (nodep->user1SetOnce()) return;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||||
@@ -849,7 +863,8 @@ private:
|
|||||||
|
|
||||||
// Assertion condition check
|
// Assertion condition check
|
||||||
AstLoop* const loopp = new AstLoop{flp};
|
AstLoop* const loopp = new AstLoop{flp};
|
||||||
AstNodeExpr* const condp = new AstSampled{flp, nodep->exprp()->unlinkFrBack(), nullptr};
|
AstSampled* const condp
|
||||||
|
= new AstSampled{flp, nodep->exprp()->unlinkFrBack(), nullptr, true};
|
||||||
loopp->addStmtsp(new AstLoopTest{flp, loopp, new AstLogNot{flp, condp}});
|
loopp->addStmtsp(new AstLoopTest{flp, loopp, new AstLogNot{flp, condp}});
|
||||||
loopp->addStmtsp(new AstEventControl{flp, sentreep, nullptr});
|
loopp->addStmtsp(new AstEventControl{flp, sentreep, nullptr});
|
||||||
|
|
||||||
@@ -916,6 +931,7 @@ private:
|
|||||||
void visit(AstStable* nodep) override {
|
void visit(AstStable* nodep) override {
|
||||||
if (nodep->user1SetOnce()) return;
|
if (nodep->user1SetOnce()) return;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||||
AstSenTree* sentreep = nodep->sentreep();
|
AstSenTree* sentreep = nodep->sentreep();
|
||||||
@@ -931,6 +947,7 @@ private:
|
|||||||
void visit(AstSteady* nodep) override {
|
void visit(AstSteady* nodep) override {
|
||||||
if (nodep->user1SetOnce()) return;
|
if (nodep->user1SetOnce()) return;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
checkSamplingFuncDType(nodep, nodep->exprp());
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||||
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
|
||||||
@@ -941,6 +958,10 @@ private:
|
|||||||
nodep->replaceWith(exprp);
|
nodep->replaceWith(exprp);
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
}
|
}
|
||||||
|
void visit(AstSampled* nodep) override {
|
||||||
|
iterateChildren(nodep);
|
||||||
|
if (!nodep->internal()) checkSamplingFuncDType(nodep, nodep->exprp());
|
||||||
|
}
|
||||||
|
|
||||||
// Validate repetition count: must be a non-negative elaboration-time constant.
|
// Validate repetition count: must be a non-negative elaboration-time constant.
|
||||||
// Shared by goto [->N] and nonconsecutive [=N] repetition.
|
// Shared by goto [->N] and nonconsecutive [=N] repetition.
|
||||||
@@ -952,7 +973,7 @@ private:
|
|||||||
nodep->v3error("Repetition count is not an elaboration-time constant"
|
nodep->v3error("Repetition count is not an elaboration-time constant"
|
||||||
" (IEEE 1800-2023 16.9.2)");
|
" (IEEE 1800-2023 16.9.2)");
|
||||||
VL_DO_DANGLING(pushDeletep(countp), countp);
|
VL_DO_DANGLING(pushDeletep(countp), countp);
|
||||||
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
|
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalseErroring{}});
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -960,7 +981,7 @@ private:
|
|||||||
nodep->v3error("Repetition count must be non-negative"
|
nodep->v3error("Repetition count must be non-negative"
|
||||||
" (IEEE 1800-2023 16.9.2)");
|
" (IEEE 1800-2023 16.9.2)");
|
||||||
VL_DO_DANGLING(pushDeletep(countp), countp);
|
VL_DO_DANGLING(pushDeletep(countp), countp);
|
||||||
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
|
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalseErroring{}});
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -1203,11 +1224,7 @@ private:
|
|||||||
AstNode* const nextp = stmtp->nextp();
|
AstNode* const nextp = stmtp->nextp();
|
||||||
if (AstAssign* const assignp = VN_CAST(stmtp, Assign)) {
|
if (AstAssign* const assignp = VN_CAST(stmtp, Assign)) {
|
||||||
assignp->unlinkFrBack();
|
assignp->unlinkFrBack();
|
||||||
if (!matchAssignsp) {
|
matchAssignsp = AstNode::addNextNull(matchAssignsp, assignp);
|
||||||
matchAssignsp = assignp;
|
|
||||||
} else {
|
|
||||||
matchAssignsp->addNext(assignp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
stmtp = nextp;
|
stmtp = nextp;
|
||||||
}
|
}
|
||||||
@@ -1233,11 +1250,7 @@ private:
|
|||||||
AstNodeExpr* const assignRhsp = assignp->rhsp()->unlinkFrBack();
|
AstNodeExpr* const assignRhsp = assignp->rhsp()->unlinkFrBack();
|
||||||
AstAssignDly* const dlyp = new AstAssignDly{flp, assignLhsp, assignRhsp};
|
AstAssignDly* const dlyp = new AstAssignDly{flp, assignLhsp, assignRhsp};
|
||||||
VL_DO_DANGLING(pushDeletep(assignp), assignp);
|
VL_DO_DANGLING(pushDeletep(assignp), assignp);
|
||||||
if (!matchAssignsp) {
|
matchAssignsp = AstNode::addNextNull(matchAssignsp, dlyp);
|
||||||
matchAssignsp = dlyp;
|
|
||||||
} else {
|
|
||||||
matchAssignsp->addNext(dlyp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
stmtp = nextp;
|
stmtp = nextp;
|
||||||
}
|
}
|
||||||
@@ -1271,7 +1284,8 @@ private:
|
|||||||
lhsp
|
lhsp
|
||||||
= new AstAnd{flp, new AstNot{flp, m_disablep->cloneTreePure(false)}, lhsp};
|
= new AstAnd{flp, new AstNot{flp, m_disablep->cloneTreePure(false)}, lhsp};
|
||||||
}
|
}
|
||||||
AstPast* const pastp = new AstPast{flp, lhsp};
|
AstPast* const pastp
|
||||||
|
= new AstPast{flp, lhsp, nullptr, nullptr, /* propertyTiming */ true};
|
||||||
pastp->dtypeFrom(lhsp);
|
pastp->dtypeFrom(lhsp);
|
||||||
pastp->sentreep(newSenTree(nodep));
|
pastp->sentreep(newSenTree(nodep));
|
||||||
condp = pastp;
|
condp = pastp;
|
||||||
@@ -1295,7 +1309,8 @@ private:
|
|||||||
lhsp = new AstAnd{flp, new AstNot{flp, m_disablep->cloneTreePure(false)}, lhsp};
|
lhsp = new AstAnd{flp, new AstNot{flp, m_disablep->cloneTreePure(false)}, lhsp};
|
||||||
}
|
}
|
||||||
|
|
||||||
AstPast* const pastp = new AstPast{flp, lhsp};
|
AstPast* const pastp
|
||||||
|
= new AstPast{flp, lhsp, nullptr, nullptr, /* propertyTiming */ true};
|
||||||
pastp->dtypeFrom(lhsp);
|
pastp->dtypeFrom(lhsp);
|
||||||
pastp->sentreep(newSenTree(nodep));
|
pastp->sentreep(newSenTree(nodep));
|
||||||
AstNodeExpr* const exprp
|
AstNodeExpr* const exprp
|
||||||
@@ -1312,14 +1327,21 @@ private:
|
|||||||
!m_pexprp, nodep,
|
!m_pexprp, nodep,
|
||||||
"'" << nodep->verilogKwd()
|
"'" << nodep->verilogKwd()
|
||||||
<< "' in complex property expression should have been rejected by V3AssertNfa");
|
<< "' in complex property expression should have been rejected by V3AssertNfa");
|
||||||
|
if (nodep->isStrong()
|
||||||
|
&& (v3Global.opt.timing().isSetFalse() || !v3Global.opt.timing().isSetTrue())) {
|
||||||
|
nodep->v3warn(E_NOTIMING, nodep->verilogKwd() << " requires --timing");
|
||||||
|
nodep->replaceWith(new AstConst{flp, AstConst::BitFalse{}});
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (nodep->isStrong()) {
|
if (nodep->isStrong()) {
|
||||||
// p s_until q / p s_until_with q: q must eventually be true. Until then, p must
|
// p s_until q / p s_until_with q: q must eventually be true. Until then, p must
|
||||||
// be true on every sampled tick. For s_until, check q first: when q is true on
|
// be true on every sampled tick. For s_until, check q first: when q is true on
|
||||||
// this tick, p is not required. For s_until_with, p must be true on the q tick too.
|
// this tick, p is not required. For s_until_with, p must be true on the q tick too.
|
||||||
AstNodeExpr* const rawLhsp = nodep->lhsp()->unlinkFrBack();
|
AstNodeExpr* const rawLhsp = nodep->lhsp()->unlinkFrBack();
|
||||||
AstNodeExpr* const rawRhsp = nodep->rhsp()->unlinkFrBack();
|
AstNodeExpr* const rawRhsp = nodep->rhsp()->unlinkFrBack();
|
||||||
AstSampled* const lhsp = new AstSampled{flp, rawLhsp, rawLhsp->dtypep()};
|
AstSampled* const lhsp = new AstSampled{flp, rawLhsp, rawLhsp->dtypep(), true};
|
||||||
AstSampled* const rhsp = new AstSampled{flp, rawRhsp, rawRhsp->dtypep()};
|
AstSampled* const rhsp = new AstSampled{flp, rawRhsp, rawRhsp->dtypep(), true};
|
||||||
AstNodeExpr* finalCondp = rhsp->cloneTreePure(false);
|
AstNodeExpr* finalCondp = rhsp->cloneTreePure(false);
|
||||||
if (nodep->isOverlapping()) {
|
if (nodep->isOverlapping()) {
|
||||||
finalCondp = new AstLogAnd{flp, lhsp->cloneTreePure(false), finalCondp};
|
finalCondp = new AstLogAnd{flp, lhsp->cloneTreePure(false), finalCondp};
|
||||||
@@ -1466,7 +1488,9 @@ private:
|
|||||||
iterateAndNextNull(nodep->sensesp());
|
iterateAndNextNull(nodep->sensesp());
|
||||||
if (m_senip && m_senip != nodep->sensesp())
|
if (m_senip && m_senip != nodep->sensesp())
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion");
|
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));
|
nodep->disablep(m_defaultDisablep->condp()->cloneTreePure(true));
|
||||||
}
|
}
|
||||||
m_disablep = nodep->disablep();
|
m_disablep = nodep->disablep();
|
||||||
@@ -1476,7 +1500,7 @@ private:
|
|||||||
if (!VN_AS(nodep->backp(), NodeCoverOrAssert)->immediate()) {
|
if (!VN_AS(nodep->backp(), NodeCoverOrAssert)->immediate()) {
|
||||||
const AstNodeDType* const propDtp = nodep->propp()->dtypep();
|
const AstNodeDType* const propDtp = nodep->propp()->dtypep();
|
||||||
nodep->propp(new AstSampled{nodep->fileline(), nodep->propp()->unlinkFrBack(),
|
nodep->propp(new AstSampled{nodep->fileline(), nodep->propp()->unlinkFrBack(),
|
||||||
propDtp->dtypep()});
|
propDtp->dtypep(), true});
|
||||||
}
|
}
|
||||||
// cover counts non-vacuous matches only (IEEE 1800-2023 16.15.2), so an
|
// cover counts non-vacuous matches only (IEEE 1800-2023 16.15.2), so an
|
||||||
// implication antecedent must hold; assert passes vacuously instead.
|
// implication antecedent must hold; assert passes vacuously instead.
|
||||||
|
|||||||
+77
-34
@@ -49,26 +49,31 @@ bool VNUser4InUse::s_userBusy = false;
|
|||||||
|
|
||||||
int AstNodeDType::s_uniqueNum = 0;
|
int AstNodeDType::s_uniqueNum = 0;
|
||||||
|
|
||||||
V3AST_VCMETHOD_ITEMDATA_DECL;
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// VCMethod information
|
// VCMethod information
|
||||||
|
|
||||||
VCMethod VCMethod::arrayMethod(const string& name) {
|
VCMethod VCMethod::arrayMethod(const string& name) {
|
||||||
for (const auto& it : s_itemData)
|
for (int i = 0; i < _ENUM_MAX; ++i) {
|
||||||
if (it.m_name == name) return it.m_e;
|
const VCMethod method{i};
|
||||||
v3fatalSrc("Not a method name known to VCMethod::s_itemData: '" << name << '\'');
|
if (name == method.ascii()) return method;
|
||||||
|
}
|
||||||
|
v3fatalSrc("Not a method name known to VCMethod: '" << name << '\'');
|
||||||
return VCMethod{};
|
return VCMethod{};
|
||||||
}
|
}
|
||||||
void VCMethod::selfTest() {
|
|
||||||
int i = 0;
|
//######################################################################
|
||||||
for (const auto& it : s_itemData) {
|
// VNUser
|
||||||
const VCMethod exp{i};
|
|
||||||
UASSERT_STATIC(it.m_e == exp,
|
std::string VNUser::dumpStr(std::string (*fmtAddrp)(const void*)) const {
|
||||||
"VCMethod::s_itemData table rows are out-of-order, starting at row "s
|
#ifdef VL_USER_TYPE_CHECKS
|
||||||
+ cvtToStr(i) + " '" + +it.m_name + '\'');
|
if (const int* const uip = std::get_if<int>(&m_u)) return "#"s + cvtToStr(*uip);
|
||||||
++i;
|
if (void* const* const upp = std::get_if<void*>(&m_u)) return fmtAddrp(*upp);
|
||||||
}
|
return "";
|
||||||
|
#else
|
||||||
|
// Dumps void* representation
|
||||||
|
if (!m_u.up) return "";
|
||||||
|
return fmtAddrp(m_u.up);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
@@ -1384,10 +1389,15 @@ void AstNode::dumpPtrs(std::ostream& os) const {
|
|||||||
if (op2p()) os << " op2p=" << cvtToHex(op2p());
|
if (op2p()) os << " op2p=" << cvtToHex(op2p());
|
||||||
if (op3p()) os << " op3p=" << cvtToHex(op3p());
|
if (op3p()) os << " op3p=" << cvtToHex(op3p());
|
||||||
if (op4p()) os << " op4p=" << cvtToHex(op4p());
|
if (op4p()) os << " op4p=" << cvtToHex(op4p());
|
||||||
if (user1p()) os << " user1p=" << cvtToHex(user1p());
|
const auto dumpUser = [&os](const char* prefix, const VNUser& user) {
|
||||||
if (user2p()) os << " user2p=" << cvtToHex(user2p());
|
const std::string s
|
||||||
if (user3p()) os << " user3p=" << cvtToHex(user3p());
|
= user.dumpStr([](const void* p) -> std::string { return cvtToHex(p); });
|
||||||
if (user4p()) os << " user4p=" << cvtToHex(user4p());
|
if (!s.empty()) os << prefix << s;
|
||||||
|
};
|
||||||
|
dumpUser(" user1p=", user1u());
|
||||||
|
dumpUser(" user2p=", user2u());
|
||||||
|
dumpUser(" user3p=", user3u());
|
||||||
|
dumpUser(" user4p=", user4u());
|
||||||
if (m_iterpp) {
|
if (m_iterpp) {
|
||||||
os << " iterpp=" << cvtToHex(m_iterpp);
|
os << " iterpp=" << cvtToHex(m_iterpp);
|
||||||
// This may cause address sanitizer failures as iterpp can be stale
|
// This may cause address sanitizer failures as iterpp can be stale
|
||||||
@@ -1542,14 +1552,14 @@ string AstNode::instanceStr() const {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
void AstNode::v3errorEnd(const std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
|
void AstNode::v3errorEnd(const std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
|
||||||
// Don't look for instance name when warning is disabled.
|
|
||||||
// In case of large number of warnings, this can
|
|
||||||
// take significant amount of time
|
|
||||||
const string instanceStrExtra
|
|
||||||
= m_fileline->warnIsOff(V3Error::s().errorCode()) ? "" : instanceStr();
|
|
||||||
if (!m_fileline) {
|
if (!m_fileline) {
|
||||||
V3Error::v3errorEnd(str, instanceStrExtra, nullptr);
|
V3Error::v3errorEnd(str, "", nullptr);
|
||||||
} else {
|
} else {
|
||||||
|
// Don't look for instance name when warning is disabled.
|
||||||
|
// In case of large number of warnings, this can
|
||||||
|
// take significant amount of time
|
||||||
|
const string instanceStrExtra
|
||||||
|
= m_fileline->warnIsOff(V3Error::s().errorCode()) ? "" : instanceStr();
|
||||||
std::ostringstream nsstr;
|
std::ostringstream nsstr;
|
||||||
nsstr << str.str();
|
nsstr << str.str();
|
||||||
if (debug()) {
|
if (debug()) {
|
||||||
@@ -1660,7 +1670,7 @@ static const AstNodeDType* computeCastableBase(const AstNodeDType* nodep) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static VCastable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
static VCastable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||||
const AstNode* fromConstp) {
|
const AstNode* fromConstp, const bool checkIfaceArgCompat) {
|
||||||
const VCastable castable = VCastable::UNSUPPORTED;
|
const VCastable castable = VCastable::UNSUPPORTED;
|
||||||
toDtp = toDtp->skipRefToEnump();
|
toDtp = toDtp->skipRefToEnump();
|
||||||
fromDtp = fromDtp->skipRefToEnump();
|
fromDtp = fromDtp->skipRefToEnump();
|
||||||
@@ -1698,22 +1708,52 @@ static VCastable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDTyp
|
|||||||
if (upcast) return VCastable::COMPATIBLE;
|
if (upcast) return VCastable::COMPATIBLE;
|
||||||
if (downcast) return VCastable::DYNAMIC_CLASS;
|
if (downcast) return VCastable::DYNAMIC_CLASS;
|
||||||
return VCastable::INCOMPATIBLE;
|
return VCastable::INCOMPATIBLE;
|
||||||
} else if (const AstIfaceRefDType* const toIfp = VN_CAST(toDtp, IfaceRefDType)) {
|
} else if (const AstIfaceRefDType* const toIfp
|
||||||
|
= VN_CAST(checkIfaceArgCompat ? toDtp->elemDTypep(true) : toDtp, IfaceRefDType)) {
|
||||||
// Two interface refs are compatible if they point at the same interface
|
// Two interface refs are compatible if they point at the same interface
|
||||||
// module (and modport, if any). Pointer-equality on the dtype isn't
|
// module (and modport, if any). Pointer-equality on the dtype isn't
|
||||||
// enough since every cell binding clones the dtype.
|
// enough since every cell binding clones the dtype.
|
||||||
const AstIfaceRefDType* const fromIfp = VN_CAST(fromDtp, IfaceRefDType);
|
// Argument compatibility also requires matching virtualness for ref arguments, while
|
||||||
if (fromIfp && toIfp->ifaceViaCellp() == fromIfp->ifaceViaCellp()
|
// input arguments may bind an unqualified or same-modport source to a virtual target.
|
||||||
&& (!toIfp->modportp() || toIfp->modportp() == fromIfp->modportp())) {
|
// Argument compatibility also supports fixed-size arrays of interface references.
|
||||||
|
const AstIfaceRefDType* const fromIfp
|
||||||
|
= VN_CAST(checkIfaceArgCompat ? fromDtp->elemDTypep(true) : fromDtp, IfaceRefDType);
|
||||||
|
if (checkIfaceArgCompat && fromIfp && (toDtp != toIfp || fromDtp != fromIfp)) {
|
||||||
|
const AstUnpackArrayDType* const toArrayp = VN_CAST(toDtp, UnpackArrayDType);
|
||||||
|
const AstUnpackArrayDType* const fromArrayp = VN_CAST(fromDtp, UnpackArrayDType);
|
||||||
|
// IEEE 1800-2023 6.22.2: Equal-sized fixed arrays have equivalent types.
|
||||||
|
if (!toArrayp || !fromArrayp
|
||||||
|
|| toArrayp->elementsConst() != fromArrayp->elementsConst()) {
|
||||||
|
return VCastable::INCOMPATIBLE;
|
||||||
|
}
|
||||||
|
return computeCastableImp(toArrayp->subDTypep(), fromArrayp->subDTypep(), nullptr,
|
||||||
|
checkIfaceArgCompat);
|
||||||
|
}
|
||||||
|
if (!fromIfp || toIfp->ifaceViaCellp() != fromIfp->ifaceViaCellp()) {
|
||||||
|
if (!checkIfaceArgCompat) return castable;
|
||||||
|
return VCastable::INCOMPATIBLE;
|
||||||
|
}
|
||||||
|
const bool sameModport = toIfp->modportp() == fromIfp->modportp();
|
||||||
|
if (!checkIfaceArgCompat) {
|
||||||
|
if (!toIfp->modportp() || sameModport) return VCastable::COMPATIBLE;
|
||||||
|
return castable;
|
||||||
|
}
|
||||||
|
if (toIfp->isVirtual() == fromIfp->isVirtual() && sameModport) {
|
||||||
|
return VCastable::SAMEISH;
|
||||||
|
}
|
||||||
|
// An unqualified interface or virtual interface may bind to a modport-qualified
|
||||||
|
// virtual interface.
|
||||||
|
if (toIfp->isVirtual() && (!fromIfp->modportp() || sameModport)) {
|
||||||
return VCastable::COMPATIBLE;
|
return VCastable::COMPATIBLE;
|
||||||
}
|
}
|
||||||
|
return VCastable::INCOMPATIBLE;
|
||||||
}
|
}
|
||||||
return castable;
|
return castable;
|
||||||
}
|
}
|
||||||
|
|
||||||
VCastable AstNode::computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
VCastable AstNode::computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||||
const AstNode* fromConstp) {
|
const AstNode* fromConstp, const bool checkIfaceArgCompat) {
|
||||||
const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp);
|
const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp, checkIfaceArgCompat);
|
||||||
UINFO(9, " castable=" << castable << " for " << toDtp);
|
UINFO(9, " castable=" << castable << " for " << toDtp);
|
||||||
UINFO(9, " =?= " << fromDtp);
|
UINFO(9, " =?= " << fromDtp);
|
||||||
if (fromConstp) UINFO(9, " const= " << fromConstp);
|
if (fromConstp) UINFO(9, " const= " << fromConstp);
|
||||||
@@ -1735,12 +1775,15 @@ AstNodeDType* AstNode::getCommonClassTypep(AstNode* node1p, AstNode* node2p) {
|
|||||||
if (castable == VCastable::DYNAMIC_CLASS) return node2p->dtypep();
|
if (castable == VCastable::DYNAMIC_CLASS) return node2p->dtypep();
|
||||||
}
|
}
|
||||||
|
|
||||||
AstClassRefDType* classDtypep1 = VN_CAST(node1p->dtypep(), ClassRefDType);
|
AstClassRefDType* classDtypep1 = VN_CAST(node1p->dtypep()->skipRefp(), ClassRefDType);
|
||||||
while (classDtypep1) {
|
while (classDtypep1) {
|
||||||
const VCastable castable = computeCastable(classDtypep1, node2p->dtypep(), node2p);
|
const VCastable castable = computeCastable(classDtypep1, node2p->dtypep(), node2p);
|
||||||
if (castable == VCastable::COMPATIBLE) return classDtypep1;
|
if (castable == VCastable::COMPATIBLE) return classDtypep1;
|
||||||
const AstClassExtends* const extendsp = classDtypep1->classp()->extendsp();
|
AstClassExtends* const extendsp = classDtypep1->classp()->extendsp();
|
||||||
classDtypep1 = extendsp ? VN_AS(extendsp->dtypep(), ClassRefDType) : nullptr;
|
if (!extendsp) break;
|
||||||
|
AstNodeDType* const edtp
|
||||||
|
= extendsp->dtypep() ? extendsp->dtypep() : extendsp->childDTypep();
|
||||||
|
classDtypep1 = VN_AS(edtp->skipRefp(), ClassRefDType);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
+62
-2
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "V3Ast__gen_forward_class_decls.h" // From ./astgen
|
#include "V3Ast__gen_forward_class_decls.h" // From ./astgen
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -40,6 +41,14 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// VL_USER_TYPE_CHECKS requires C++17 for std::variant. Ignore on older standards
|
||||||
|
#if defined(VL_USER_TYPE_CHECKS) && __cplusplus < 201703L
|
||||||
|
#undef VL_USER_TYPE_CHECKS
|
||||||
|
#endif
|
||||||
|
#ifdef VL_USER_TYPE_CHECKS
|
||||||
|
#include <variant>
|
||||||
|
#endif
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#include "V3AstAttr.h"
|
#include "V3AstAttr.h"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
@@ -137,12 +146,48 @@ class V3GraphVertex;
|
|||||||
class VSymEnt;
|
class VSymEnt;
|
||||||
|
|
||||||
class VNUser final {
|
class VNUser final {
|
||||||
|
// Defining VL_USER_TYPE_CHECKS replaces the VNUser union with a std::variant
|
||||||
|
// which remembers which form of VNUser is being stored to catch mismatched reads.
|
||||||
|
#ifdef VL_USER_TYPE_CHECKS
|
||||||
|
// monostate is an unwritten / cleared slot. It can be read as either form
|
||||||
|
// and yields nullptr/0.
|
||||||
|
std::variant<std::monostate, int, void*> m_u;
|
||||||
|
#else
|
||||||
union {
|
union {
|
||||||
void* up;
|
void* up;
|
||||||
int ui;
|
int ui;
|
||||||
} m_u;
|
} m_u;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
#ifdef VL_USER_TYPE_CHECKS
|
||||||
|
VNUser() = default;
|
||||||
|
// non-explicit:
|
||||||
|
// cppcheck-suppress noExplicitConstructor
|
||||||
|
VNUser(int i) {
|
||||||
|
// VNUser{0} represents the monostate
|
||||||
|
if (i) m_u = i;
|
||||||
|
}
|
||||||
|
explicit VNUser(void* p) {
|
||||||
|
// VNUser{nullptr} represents the monostate
|
||||||
|
if (p) m_u = p;
|
||||||
|
}
|
||||||
|
~VNUser() = default;
|
||||||
|
// Casters
|
||||||
|
template <typename T>
|
||||||
|
typename std::enable_if<std::is_pointer<T>::value, T>::type to() const VL_MT_SAFE {
|
||||||
|
if (std::holds_alternative<std::monostate>(m_u)) return nullptr;
|
||||||
|
void* const* const upp = std::get_if<void*>(&m_u);
|
||||||
|
UASSERT_STATIC(upp, "AstNode user() slot written as int, read as pointer");
|
||||||
|
return reinterpret_cast<T>(*upp);
|
||||||
|
}
|
||||||
|
int toInt() const {
|
||||||
|
if (std::holds_alternative<std::monostate>(m_u)) return 0;
|
||||||
|
const int* const uip = std::get_if<int>(&m_u);
|
||||||
|
UASSERT_STATIC(uip, "AstNode user() slot written as pointer, read as int");
|
||||||
|
return *uip;
|
||||||
|
}
|
||||||
|
#else
|
||||||
VNUser() = default;
|
VNUser() = default;
|
||||||
// non-explicit:
|
// non-explicit:
|
||||||
// cppcheck-suppress noExplicitConstructor
|
// cppcheck-suppress noExplicitConstructor
|
||||||
@@ -157,10 +202,14 @@ public:
|
|||||||
typename std::enable_if<std::is_pointer<T>::value, T>::type to() const VL_MT_SAFE {
|
typename std::enable_if<std::is_pointer<T>::value, T>::type to() const VL_MT_SAFE {
|
||||||
return reinterpret_cast<T>(m_u.up);
|
return reinterpret_cast<T>(m_u.up);
|
||||||
}
|
}
|
||||||
|
int toInt() const { return m_u.ui; }
|
||||||
|
#endif
|
||||||
VSymEnt* toSymEnt() const { return to<VSymEnt*>(); }
|
VSymEnt* toSymEnt() const { return to<VSymEnt*>(); }
|
||||||
AstNode* toNodep() const VL_MT_SAFE { return to<AstNode*>(); }
|
AstNode* toNodep() const VL_MT_SAFE { return to<AstNode*>(); }
|
||||||
V3GraphVertex* toGraphVertex() const { return to<V3GraphVertex*>(); }
|
V3GraphVertex* toGraphVertex() const { return to<V3GraphVertex*>(); }
|
||||||
int toInt() const { return m_u.ui; }
|
// Render for dumps without asserting on the form held: "" if unset, "#<int>"
|
||||||
|
// if an int, else the pointer via fmtAddrp
|
||||||
|
std::string dumpStr(std::string (*fmtAddrp)(const void*)) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
@@ -441,6 +490,8 @@ class AstNode VL_NOT_FINAL {
|
|||||||
static int s_cloneCntGbl; // Count of which userp is set
|
static int s_cloneCntGbl; // Count of which userp is set
|
||||||
|
|
||||||
// This member ordering both allows 64 bit alignment and puts associated data together
|
// This member ordering both allows 64 bit alignment and puts associated data together
|
||||||
|
// (under VL_USER_TYPE_CHECKS a VNUser is larger than 64 bits, so this packing no
|
||||||
|
// longer holds; that build trades node size for catching int/pointer confusion)
|
||||||
VNUser m_user1u{0}; // Contains any information the user iteration routine wants
|
VNUser m_user1u{0}; // Contains any information the user iteration routine wants
|
||||||
uint32_t m_user1Cnt = 0; // Mark of when userp was set
|
uint32_t m_user1Cnt = 0; // Mark of when userp was set
|
||||||
uint32_t m_user2Cnt = 0; // Mark of when userp was set
|
uint32_t m_user2Cnt = 0; // Mark of when userp was set
|
||||||
@@ -730,6 +781,7 @@ public:
|
|||||||
|
|
||||||
// ACCESSORS for specific types
|
// ACCESSORS for specific types
|
||||||
// Alas these can't be virtual or they break when passed a nullptr
|
// Alas these can't be virtual or they break when passed a nullptr
|
||||||
|
bool isDisableQueuePushSelfStmt();
|
||||||
inline bool isClassHandleValue() const;
|
inline bool isClassHandleValue() const;
|
||||||
inline bool isNull() const;
|
inline bool isNull() const;
|
||||||
inline bool isZero() const;
|
inline bool isZero() const;
|
||||||
@@ -808,7 +860,7 @@ public:
|
|||||||
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
||||||
|
|
||||||
static VCastable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
static VCastable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||||
const AstNode* fromConstp);
|
const AstNode* fromConstp, bool checkIfaceArgCompat = false);
|
||||||
static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2);
|
static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2);
|
||||||
|
|
||||||
// METHODS - dump and error
|
// METHODS - dump and error
|
||||||
@@ -1260,6 +1312,14 @@ public:
|
|||||||
this->foreach([&count](const AstNode*) { ++count; });
|
this->foreach([&count](const AstNode*) { ++count; });
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if and only if the tree rooted at this node has more than 'limit' nodes.
|
||||||
|
// Traversal terminates as soon as the result is known, so unlike comparing 'nodeCount',
|
||||||
|
// this is cheap on a large tree.
|
||||||
|
bool isLargerThan(int limit) const {
|
||||||
|
int count = 0;
|
||||||
|
return this->exists([&count, limit](const AstNode*) { return ++count > limit; });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Forward declarations of specializations defined in V3Ast.cpp
|
// Forward declarations of specializations defined in V3Ast.cpp
|
||||||
|
|||||||
+277
-251
@@ -299,6 +299,34 @@ constexpr VAssertType::en operator|(VAssertType::en lhs, VAssertType::en rhs) {
|
|||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
|
|
||||||
|
class VPropStrength final {
|
||||||
|
public:
|
||||||
|
enum en : uint8_t {
|
||||||
|
DEFAULT = 0, // Resolve from assertion/coverage context
|
||||||
|
WEAK,
|
||||||
|
STRONG,
|
||||||
|
};
|
||||||
|
enum en m_e;
|
||||||
|
// cppcheck-suppress noExplicitConstructor
|
||||||
|
constexpr VPropStrength(en _e)
|
||||||
|
: m_e{_e} {}
|
||||||
|
const char* ascii() const {
|
||||||
|
static const char* const names[] = {"default", "weak", "strong"};
|
||||||
|
return names[m_e];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
constexpr bool operator==(const VPropStrength& lhs, const VPropStrength& rhs) {
|
||||||
|
return lhs.m_e == rhs.m_e;
|
||||||
|
}
|
||||||
|
constexpr bool operator==(const VPropStrength& lhs, VPropStrength::en rhs) {
|
||||||
|
return lhs.m_e == rhs;
|
||||||
|
}
|
||||||
|
constexpr bool operator!=(const VPropStrength& lhs, VPropStrength::en rhs) {
|
||||||
|
return lhs.m_e != rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ######################################################################
|
||||||
|
|
||||||
class VAttrType final {
|
class VAttrType final {
|
||||||
public:
|
public:
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@@ -779,137 +807,136 @@ inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) {
|
|||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
|
|
||||||
|
// C++ methods invoked on runtime library data types via AstCMethodHard
|
||||||
|
// clang-format off
|
||||||
|
#define FOR_EACH_CMETHOD(macro) \
|
||||||
|
/* id, method, pure */ \
|
||||||
|
macro(_NONE, "_none", false) \
|
||||||
|
macro(ARRAY_AND, "and", true) \
|
||||||
|
macro(ARRAY_AT, "at", true) \
|
||||||
|
macro(ARRAY_AT_BACK, "atBack", true) \
|
||||||
|
macro(ARRAY_AT_WRITE, "atWrite", true) \
|
||||||
|
macro(ARRAY_FIND, "find", true) \
|
||||||
|
macro(ARRAY_FIND_FIRST, "find_first", true) \
|
||||||
|
macro(ARRAY_FIND_FIRST_INDEX, "find_first_index", true) \
|
||||||
|
macro(ARRAY_FIND_INDEX, "find_index", true) \
|
||||||
|
macro(ARRAY_FIND_LAST, "find_last", true) \
|
||||||
|
macro(ARRAY_FIND_LAST_INDEX, "find_last_index", true) \
|
||||||
|
macro(ARRAY_FIRST, "first", false) \
|
||||||
|
macro(ARRAY_INSIDE, "inside", true) \
|
||||||
|
macro(ARRAY_LAST, "last", false) \
|
||||||
|
macro(ARRAY_MAP, "map", true) \
|
||||||
|
macro(ARRAY_MAX, "max", true) \
|
||||||
|
macro(ARRAY_MIN, "min", true) \
|
||||||
|
macro(ARRAY_NEXT, "next", false) \
|
||||||
|
macro(ARRAY_OR, "or", true) \
|
||||||
|
macro(ARRAY_POP_BACK, "pop_back", false) \
|
||||||
|
macro(ARRAY_POP_FRONT, "pop_front", false) \
|
||||||
|
macro(ARRAY_PREV, "prev", false) \
|
||||||
|
macro(ARRAY_PRODUCT, "product", true) \
|
||||||
|
macro(ARRAY_PUSH_BACK, "push_back", false) \
|
||||||
|
macro(ARRAY_PUSH_FRONT, "push_front", false) \
|
||||||
|
macro(ARRAY_REVERSE, "reverse", false) \
|
||||||
|
macro(ARRAY_RSORT, "rsort", false) \
|
||||||
|
macro(ARRAY_R_AND, "r_and", true) \
|
||||||
|
macro(ARRAY_R_OR, "r_or", true) \
|
||||||
|
macro(ARRAY_R_PRODUCT, "r_product", true) \
|
||||||
|
macro(ARRAY_R_SUM, "r_sum", true) \
|
||||||
|
macro(ARRAY_R_XOR, "r_xor", true) \
|
||||||
|
macro(ARRAY_SHUFFLE, "shuffle", false) \
|
||||||
|
macro(ARRAY_SORT, "sort", false) \
|
||||||
|
macro(ARRAY_SUM, "sum", true) \
|
||||||
|
macro(ARRAY_UNIQUE, "unique", true) \
|
||||||
|
macro(ARRAY_UNIQUE_INDEX, "unique_index", true) \
|
||||||
|
macro(ARRAY_XOR, "xor", true) \
|
||||||
|
macro(ASSOC_CLEAR, "clear", false) \
|
||||||
|
macro(ASSOC_ERASE, "erase", false) \
|
||||||
|
macro(ASSOC_EXISTS, "exists", true) \
|
||||||
|
macro(ASSOC_FIRST, "first", false) \
|
||||||
|
macro(ASSOC_NEXT, "next", false) \
|
||||||
|
macro(ASSOC_SIZE, "size", true) \
|
||||||
|
macro(CLASS_SET_RANDMODE, "set_randmode", false) \
|
||||||
|
macro(DYN_AT_WRITE_APPEND, "atWriteAppend", false) \
|
||||||
|
macro(DYN_AT_WRITE_APPEND_BACK, "atWriteAppendBack", false) \
|
||||||
|
macro(DYN_CLEAR, "clear", false) \
|
||||||
|
macro(DYN_ERASE, "erase", false) \
|
||||||
|
macro(DYN_INSERT, "insert", false) \
|
||||||
|
macro(DYN_POP, "pop", false) \
|
||||||
|
macro(DYN_POP_FRONT, "pop_front", false) \
|
||||||
|
macro(DYN_PUSH, "push", false) \
|
||||||
|
macro(DYN_PUSH_FRONT, "push_front", false) \
|
||||||
|
macro(DYN_RENEW, "renew", false) \
|
||||||
|
macro(DYN_RENEW_COPY, "renew_copy", false) \
|
||||||
|
macro(DYN_RESIZE, "resize", false) \
|
||||||
|
macro(DYN_SIZE, "size", true) \
|
||||||
|
macro(DYN_SLICE, "slice", true) \
|
||||||
|
macro(DYN_SLICE_ASSIGN, "sliceAssign", false) \
|
||||||
|
macro(DYN_SLICE_ASSIGN_BACK_BACK, "sliceAssignBackBack", false) \
|
||||||
|
macro(DYN_SLICE_ASSIGN_FRONT_BACK, "sliceAssignFrontBack", false) \
|
||||||
|
macro(DYN_SLICE_BACK_BACK, "sliceBackBack", true) \
|
||||||
|
macro(DYN_SLICE_FRONT_BACK, "sliceFrontBack", true) \
|
||||||
|
macro(EVENT_CLEAR_FIRED, "clearFired", false) \
|
||||||
|
macro(EVENT_CLEAR_TRIGGERED, "clearTriggered", false) \
|
||||||
|
macro(EVENT_FIRE, "fire", false) \
|
||||||
|
macro(EVENT_IS_FIRED, "isFired", true) \
|
||||||
|
macro(EVENT_IS_TRIGGERED, "isTriggered", true) \
|
||||||
|
macro(FORCE_ADD, "addForce", false) \
|
||||||
|
macro(FORCE_READ, "read", true) \
|
||||||
|
macro(FORCE_READ_INDEX, "readIndex", true) \
|
||||||
|
macro(FORCE_READ_SEL, "readSel", true) \
|
||||||
|
macro(FORCE_RELEASE, "release", false) \
|
||||||
|
macro(FORCE_TOUCH, "touch", false) \
|
||||||
|
macro(FORK_DONE, "done", false) \
|
||||||
|
macro(FORK_INIT, "init", false) \
|
||||||
|
macro(FORK_JOIN, "join", false) \
|
||||||
|
macro(FORK_ON_KILL, "onKill", false) \
|
||||||
|
macro(RANDOMIZER_BASIC_STD_RANDOMIZATION, "basicStdRandomization", false) \
|
||||||
|
macro(RANDOMIZER_CLEARCONSTRAINTS, "clearConstraints", false) \
|
||||||
|
macro(RANDOMIZER_CLEARALL, "clearAll", false) \
|
||||||
|
macro(RANDOMIZER_DISABLE_SOFT, "disable_soft", false) \
|
||||||
|
macro(RANDOMIZER_HARD, "hard", false) \
|
||||||
|
macro(RANDOMIZER_SOFT, "soft", false) \
|
||||||
|
macro(RANDOMIZER_UNIQUE, "rand_unique", false) \
|
||||||
|
macro(RANDOMIZER_MARK_RANDC, "markRandc", false) \
|
||||||
|
macro(RANDOMIZER_SOLVE_BEFORE, "solveBefore", false) \
|
||||||
|
macro(RANDOMIZER_PIN_VAR, "pin_var", false) \
|
||||||
|
macro(RANDOMIZER_WRITE_VAR, "write_var", false) \
|
||||||
|
macro(RANDOMIZER_SET_VAR_DISABLED, "set_var_disabled", false) \
|
||||||
|
macro(RANDOMIZER_CLEAR_VAR_DISABLED, "clear_var_disabled", false) \
|
||||||
|
macro(RANDOMIZER_MARK_VAR_STATIC, "mark_var_static", false) \
|
||||||
|
macro(RANDOMIZER_SET_STATIC_RANDMODE, "set_static_randmode", false) \
|
||||||
|
macro(RNG_GET_RANDSTATE, "__Vm_rng.get_randstate", true) \
|
||||||
|
macro(RNG_SET_RANDSTATE, "__Vm_rng.set_randstate", false) \
|
||||||
|
macro(SCHED_ANY_TRIGGERED, "anyTriggered", false) \
|
||||||
|
macro(SCHED_AWAITING_CURRENT_TIME, "awaitingCurrentTime", true) \
|
||||||
|
macro(SCHED_AWAITING_ZERO_DELAY, "awaitingZeroDelay", true) \
|
||||||
|
macro(SCHED_READY, "ready", false) \
|
||||||
|
macro(SCHED_COMMIT, "commit", false) \
|
||||||
|
macro(SCHED_MOVE_TO_RESUME_QUEUE, "moveToResumeQueue", false) \
|
||||||
|
macro(SCHED_DELAY, "delay", false) \
|
||||||
|
macro(SCHED_DO_POST_UPDATES, "doPostUpdates", false) \
|
||||||
|
macro(SCHED_ENQUEUE, "enqueue", false) \
|
||||||
|
macro(SCHED_EVALUATE, "evaluate", false) \
|
||||||
|
macro(SCHED_EVALUATION, "evaluation", false) \
|
||||||
|
macro(SCHED_POST_UPDATE, "postUpdate", false) \
|
||||||
|
macro(SCHED_RESUME, "resume", false) \
|
||||||
|
macro(SCHED_RESUME_ZERO_DELAY, "resumeZeroDelay", false) \
|
||||||
|
macro(SCHED_RESUMPTION, "resumption", false) \
|
||||||
|
macro(SCHED_TRIGGER, "trigger", false) \
|
||||||
|
macro(SCHED_WAIT_FOREVER, "waitForever", false) \
|
||||||
|
macro(UNPACKED_ASSIGN, "assign", false) \
|
||||||
|
macro(UNPACKED_FILL, "fill", false) \
|
||||||
|
macro(UNPACKED_NEQ, "neq", true)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
class VCMethod final {
|
class VCMethod final {
|
||||||
public:
|
public:
|
||||||
// Entries in this table need to match below VCMethod::s_itemData[] table
|
|
||||||
enum en : uint8_t {
|
enum en : uint8_t {
|
||||||
_NONE, // Unknown
|
#define VL_CMETHOD_ID(id, method, pure) id,
|
||||||
ARRAY_AND,
|
FOR_EACH_CMETHOD(VL_CMETHOD_ID)
|
||||||
ARRAY_AT,
|
#undef VL_CMETHOD_ID
|
||||||
ARRAY_AT_BACK,
|
_ENUM_MAX // Leave last
|
||||||
ARRAY_AT_WRITE,
|
|
||||||
ARRAY_FIND,
|
|
||||||
ARRAY_FIND_FIRST,
|
|
||||||
ARRAY_FIND_FIRST_INDEX,
|
|
||||||
ARRAY_FIND_INDEX,
|
|
||||||
ARRAY_FIND_LAST,
|
|
||||||
ARRAY_FIND_LAST_INDEX,
|
|
||||||
ARRAY_FIRST,
|
|
||||||
ARRAY_INSIDE,
|
|
||||||
ARRAY_LAST,
|
|
||||||
ARRAY_MAP,
|
|
||||||
ARRAY_MAX,
|
|
||||||
ARRAY_MIN,
|
|
||||||
ARRAY_NEXT,
|
|
||||||
ARRAY_OR,
|
|
||||||
ARRAY_POP_BACK,
|
|
||||||
ARRAY_POP_FRONT,
|
|
||||||
ARRAY_PREV,
|
|
||||||
ARRAY_PRODUCT,
|
|
||||||
ARRAY_PUSH_BACK,
|
|
||||||
ARRAY_PUSH_FRONT,
|
|
||||||
ARRAY_REVERSE,
|
|
||||||
ARRAY_RSORT,
|
|
||||||
ARRAY_R_AND,
|
|
||||||
ARRAY_R_OR,
|
|
||||||
ARRAY_R_PRODUCT,
|
|
||||||
ARRAY_R_SUM,
|
|
||||||
ARRAY_R_XOR,
|
|
||||||
ARRAY_SHUFFLE,
|
|
||||||
ARRAY_SORT,
|
|
||||||
ARRAY_SUM,
|
|
||||||
ARRAY_UNIQUE,
|
|
||||||
ARRAY_UNIQUE_INDEX,
|
|
||||||
ARRAY_XOR,
|
|
||||||
ASSOC_CLEAR,
|
|
||||||
ASSOC_ERASE,
|
|
||||||
ASSOC_EXISTS,
|
|
||||||
ASSOC_FIRST,
|
|
||||||
ASSOC_NEXT,
|
|
||||||
ASSOC_SIZE,
|
|
||||||
CLASS_SET_RANDMODE,
|
|
||||||
DYN_AT_WRITE_APPEND,
|
|
||||||
DYN_AT_WRITE_APPEND_BACK,
|
|
||||||
DYN_CLEAR,
|
|
||||||
DYN_ERASE,
|
|
||||||
DYN_INSERT,
|
|
||||||
DYN_POP,
|
|
||||||
DYN_POP_FRONT,
|
|
||||||
DYN_PUSH,
|
|
||||||
DYN_PUSH_FRONT,
|
|
||||||
DYN_RENEW,
|
|
||||||
DYN_RENEW_COPY,
|
|
||||||
DYN_RESIZE,
|
|
||||||
DYN_SIZE,
|
|
||||||
DYN_SLICE,
|
|
||||||
DYN_SLICE_ASSIGN,
|
|
||||||
DYN_SLICE_ASSIGN_BACK_BACK,
|
|
||||||
DYN_SLICE_ASSIGN_FRONT_BACK,
|
|
||||||
DYN_SLICE_BACK_BACK,
|
|
||||||
DYN_SLICE_FRONT_BACK,
|
|
||||||
EVENT_CLEAR_FIRED,
|
|
||||||
EVENT_CLEAR_TRIGGERED,
|
|
||||||
EVENT_FIRE,
|
|
||||||
EVENT_IS_FIRED,
|
|
||||||
EVENT_IS_TRIGGERED,
|
|
||||||
FORCE_ADD,
|
|
||||||
FORCE_READ,
|
|
||||||
FORCE_READ_INDEX,
|
|
||||||
FORCE_READ_SEL,
|
|
||||||
FORCE_RELEASE,
|
|
||||||
FORCE_TOUCH,
|
|
||||||
FORK_DONE,
|
|
||||||
FORK_INIT,
|
|
||||||
FORK_JOIN,
|
|
||||||
FORK_ON_KILL,
|
|
||||||
RANDOMIZER_BASIC_STD_RANDOMIZATION,
|
|
||||||
RANDOMIZER_CLEARCONSTRAINTS,
|
|
||||||
RANDOMIZER_CLEARALL,
|
|
||||||
RANDOMIZER_DISABLE_SOFT,
|
|
||||||
RANDOMIZER_HARD,
|
|
||||||
RANDOMIZER_SOFT,
|
|
||||||
RANDOMIZER_UNIQUE,
|
|
||||||
RANDOMIZER_MARK_RANDC,
|
|
||||||
RANDOMIZER_SOLVE_BEFORE,
|
|
||||||
RANDOMIZER_PIN_VAR,
|
|
||||||
RANDOMIZER_WRITE_VAR,
|
|
||||||
RANDOMIZER_SET_VAR_DISABLED,
|
|
||||||
RANDOMIZER_CLEAR_VAR_DISABLED,
|
|
||||||
RANDOMIZER_MARK_VAR_STATIC,
|
|
||||||
RANDOMIZER_SET_STATIC_RANDMODE,
|
|
||||||
RNG_GET_RANDSTATE,
|
|
||||||
RNG_SET_RANDSTATE,
|
|
||||||
SCHED_ANY_TRIGGERED,
|
|
||||||
SCHED_AWAITING_CURRENT_TIME,
|
|
||||||
SCHED_AWAITING_ZERO_DELAY,
|
|
||||||
SCHED_READY,
|
|
||||||
SCHED_COMMIT,
|
|
||||||
SCHED_MOVE_TO_RESUME_QUEUE,
|
|
||||||
SCHED_DELAY,
|
|
||||||
SCHED_DO_POST_UPDATES,
|
|
||||||
SCHED_ENQUEUE,
|
|
||||||
SCHED_EVALUATE,
|
|
||||||
SCHED_EVALUATION,
|
|
||||||
SCHED_POST_UPDATE,
|
|
||||||
SCHED_RESUME,
|
|
||||||
SCHED_RESUME_ZERO_DELAY,
|
|
||||||
SCHED_RESUMPTION,
|
|
||||||
SCHED_TRIGGER,
|
|
||||||
UNPACKED_ASSIGN,
|
|
||||||
UNPACKED_FILL,
|
|
||||||
UNPACKED_NEQ,
|
|
||||||
_ENUM_MAX // Leave last
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
struct Item final {
|
|
||||||
enum en m_e; // Method's enum mnemonic, for checking
|
|
||||||
const char* m_name; // Method name, printed into C++
|
|
||||||
bool m_pure; // Method being called is pure
|
|
||||||
};
|
|
||||||
static Item s_itemData[];
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum en m_e;
|
enum en m_e;
|
||||||
VCMethod()
|
VCMethod()
|
||||||
: m_e{_NONE} {}
|
: m_e{_NONE} {}
|
||||||
@@ -919,11 +946,26 @@ public:
|
|||||||
explicit VCMethod(int _e)
|
explicit VCMethod(int _e)
|
||||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||||
constexpr operator en() const { return m_e; }
|
constexpr operator en() const { return m_e; }
|
||||||
const char* ascii() const VL_PURE { return s_itemData[m_e].m_name; }
|
const char* ascii() const VL_PURE {
|
||||||
bool isPure() const VL_PURE { return s_itemData[m_e].m_pure; }
|
static const char* const values[] = {
|
||||||
|
#define VL_CMETHOD_NAME(id, method, pure) method,
|
||||||
|
FOR_EACH_CMETHOD(VL_CMETHOD_NAME)
|
||||||
|
#undef VL_CMETHOD_NAME
|
||||||
|
"_ENUM_MAX" //
|
||||||
|
};
|
||||||
|
return values[m_e];
|
||||||
|
}
|
||||||
|
bool isPure() const VL_PURE {
|
||||||
|
static const bool values[] = {
|
||||||
|
#define VL_CMETHOD_PURE(id, method, pure) pure,
|
||||||
|
FOR_EACH_CMETHOD(VL_CMETHOD_PURE)
|
||||||
|
#undef VL_CMETHOD_PURE
|
||||||
|
false //
|
||||||
|
};
|
||||||
|
return values[m_e];
|
||||||
|
}
|
||||||
// Return array method for given name
|
// Return array method for given name
|
||||||
static VCMethod arrayMethod(const string& name);
|
static VCMethod arrayMethod(const string& name);
|
||||||
static void selfTest();
|
|
||||||
};
|
};
|
||||||
constexpr bool operator==(const VCMethod& lhs, const VCMethod& rhs) { return lhs.m_e == rhs.m_e; }
|
constexpr bool operator==(const VCMethod& lhs, const VCMethod& rhs) { return lhs.m_e == rhs.m_e; }
|
||||||
constexpr bool operator==(const VCMethod& lhs, VCMethod::en rhs) { return lhs.m_e == rhs; }
|
constexpr bool operator==(const VCMethod& lhs, VCMethod::en rhs) { return lhs.m_e == rhs; }
|
||||||
@@ -932,127 +974,7 @@ inline std::ostream& operator<<(std::ostream& os, const VCMethod& rhs) {
|
|||||||
return os << rhs.ascii();
|
return os << rhs.ascii();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entries in this table need to match above VCMethod enum table
|
#undef FOR_EACH_CMETHOD
|
||||||
//
|
|
||||||
// {Mnemonic, C++ method, pure}
|
|
||||||
#define V3AST_VCMETHOD_ITEMDATA_DECL \
|
|
||||||
VCMethod::Item VCMethod::s_itemData[] \
|
|
||||||
= {{_NONE, "_none", false}, \
|
|
||||||
{ARRAY_AND, "and", true}, \
|
|
||||||
{ARRAY_AT, "at", true}, \
|
|
||||||
{ARRAY_AT_BACK, "atBack", true}, \
|
|
||||||
{ARRAY_AT_WRITE, "atWrite", true}, \
|
|
||||||
{ARRAY_FIND, "find", true}, \
|
|
||||||
{ARRAY_FIND_FIRST, "find_first", true}, \
|
|
||||||
{ARRAY_FIND_FIRST_INDEX, "find_first_index", true}, \
|
|
||||||
{ARRAY_FIND_INDEX, "find_index", true}, \
|
|
||||||
{ARRAY_FIND_LAST, "find_last", true}, \
|
|
||||||
{ARRAY_FIND_LAST_INDEX, "find_last_index", true}, \
|
|
||||||
{ARRAY_FIRST, "first", false}, \
|
|
||||||
{ARRAY_INSIDE, "inside", true}, \
|
|
||||||
{ARRAY_LAST, "last", false}, \
|
|
||||||
{ARRAY_MAP, "map", true}, \
|
|
||||||
{ARRAY_MAX, "max", true}, \
|
|
||||||
{ARRAY_MIN, "min", true}, \
|
|
||||||
{ARRAY_NEXT, "next", false}, \
|
|
||||||
{ARRAY_OR, "or", true}, \
|
|
||||||
{ARRAY_POP_BACK, "pop_back", false}, \
|
|
||||||
{ARRAY_POP_FRONT, "pop_front", false}, \
|
|
||||||
{ARRAY_PREV, "prev", false}, \
|
|
||||||
{ARRAY_PRODUCT, "product", true}, \
|
|
||||||
{ARRAY_PUSH_BACK, "push_back", false}, \
|
|
||||||
{ARRAY_PUSH_FRONT, "push_front", false}, \
|
|
||||||
{ARRAY_REVERSE, "reverse", false}, \
|
|
||||||
{ARRAY_RSORT, "rsort", false}, \
|
|
||||||
{ARRAY_R_AND, "r_and", true}, \
|
|
||||||
{ARRAY_R_OR, "r_or", true}, \
|
|
||||||
{ARRAY_R_PRODUCT, "r_product", true}, \
|
|
||||||
{ARRAY_R_SUM, "r_sum", true}, \
|
|
||||||
{ARRAY_R_XOR, "r_xor", true}, \
|
|
||||||
{ARRAY_SHUFFLE, "shuffle", false}, \
|
|
||||||
{ARRAY_SORT, "sort", false}, \
|
|
||||||
{ARRAY_SUM, "sum", true}, \
|
|
||||||
{ARRAY_UNIQUE, "unique", true}, \
|
|
||||||
{ARRAY_UNIQUE_INDEX, "unique_index", true}, \
|
|
||||||
{ARRAY_XOR, "xor", true}, \
|
|
||||||
{ASSOC_CLEAR, "clear", false}, \
|
|
||||||
{ASSOC_ERASE, "erase", false}, \
|
|
||||||
{ASSOC_EXISTS, "exists", true}, \
|
|
||||||
{ASSOC_FIRST, "first", false}, \
|
|
||||||
{ASSOC_NEXT, "next", false}, \
|
|
||||||
{ASSOC_SIZE, "size", true}, \
|
|
||||||
{CLASS_SET_RANDMODE, "set_randmode", false}, \
|
|
||||||
{DYN_AT_WRITE_APPEND, "atWriteAppend", false}, \
|
|
||||||
{DYN_AT_WRITE_APPEND_BACK, "atWriteAppendBack", false}, \
|
|
||||||
{DYN_CLEAR, "clear", false}, \
|
|
||||||
{DYN_ERASE, "erase", false}, \
|
|
||||||
{DYN_INSERT, "insert", false}, \
|
|
||||||
{DYN_POP, "pop", false}, \
|
|
||||||
{DYN_POP_FRONT, "pop_front", false}, \
|
|
||||||
{DYN_PUSH, "push", false}, \
|
|
||||||
{DYN_PUSH_FRONT, "push_front", false}, \
|
|
||||||
{DYN_RENEW, "renew", false}, \
|
|
||||||
{DYN_RENEW_COPY, "renew_copy", false}, \
|
|
||||||
{DYN_RESIZE, "resize", false}, \
|
|
||||||
{DYN_SIZE, "size", true}, \
|
|
||||||
{DYN_SLICE, "slice", true}, \
|
|
||||||
{DYN_SLICE_ASSIGN, "sliceAssign", false}, \
|
|
||||||
{DYN_SLICE_ASSIGN_BACK_BACK, "sliceAssignBackBack", false}, \
|
|
||||||
{DYN_SLICE_ASSIGN_FRONT_BACK, "sliceAssignFrontBack", false}, \
|
|
||||||
{DYN_SLICE_BACK_BACK, "sliceBackBack", true}, \
|
|
||||||
{DYN_SLICE_FRONT_BACK, "sliceFrontBack", true}, \
|
|
||||||
{EVENT_CLEAR_FIRED, "clearFired", false}, \
|
|
||||||
{EVENT_CLEAR_TRIGGERED, "clearTriggered", false}, \
|
|
||||||
{EVENT_FIRE, "fire", false}, \
|
|
||||||
{EVENT_IS_FIRED, "isFired", true}, \
|
|
||||||
{EVENT_IS_TRIGGERED, "isTriggered", true}, \
|
|
||||||
{FORCE_ADD, "addForce", false}, \
|
|
||||||
{FORCE_READ, "read", true}, \
|
|
||||||
{FORCE_READ_INDEX, "readIndex", true}, \
|
|
||||||
{FORCE_READ_SEL, "readSel", true}, \
|
|
||||||
{FORCE_RELEASE, "release", false}, \
|
|
||||||
{FORCE_TOUCH, "touch", false}, \
|
|
||||||
{FORK_DONE, "done", false}, \
|
|
||||||
{FORK_INIT, "init", false}, \
|
|
||||||
{FORK_JOIN, "join", false}, \
|
|
||||||
{FORK_ON_KILL, "onKill", false}, \
|
|
||||||
{RANDOMIZER_BASIC_STD_RANDOMIZATION, "basicStdRandomization", false}, \
|
|
||||||
{RANDOMIZER_CLEARCONSTRAINTS, "clearConstraints", false}, \
|
|
||||||
{RANDOMIZER_CLEARALL, "clearAll", false}, \
|
|
||||||
{RANDOMIZER_DISABLE_SOFT, "disable_soft", false}, \
|
|
||||||
{RANDOMIZER_HARD, "hard", false}, \
|
|
||||||
{RANDOMIZER_SOFT, "soft", false}, \
|
|
||||||
{RANDOMIZER_UNIQUE, "rand_unique", false}, \
|
|
||||||
{RANDOMIZER_MARK_RANDC, "markRandc", false}, \
|
|
||||||
{RANDOMIZER_SOLVE_BEFORE, "solveBefore", false}, \
|
|
||||||
{RANDOMIZER_PIN_VAR, "pin_var", false}, \
|
|
||||||
{RANDOMIZER_WRITE_VAR, "write_var", false}, \
|
|
||||||
{RANDOMIZER_SET_VAR_DISABLED, "set_var_disabled", false}, \
|
|
||||||
{RANDOMIZER_CLEAR_VAR_DISABLED, "clear_var_disabled", false}, \
|
|
||||||
{RANDOMIZER_MARK_VAR_STATIC, "mark_var_static", false}, \
|
|
||||||
{RANDOMIZER_SET_STATIC_RANDMODE, "set_static_randmode", false}, \
|
|
||||||
{RNG_GET_RANDSTATE, "__Vm_rng.get_randstate", true}, \
|
|
||||||
{RNG_SET_RANDSTATE, "__Vm_rng.set_randstate", false}, \
|
|
||||||
{SCHED_ANY_TRIGGERED, "anyTriggered", false}, \
|
|
||||||
{SCHED_AWAITING_CURRENT_TIME, "awaitingCurrentTime", true}, \
|
|
||||||
{SCHED_AWAITING_ZERO_DELAY, "awaitingZeroDelay", true}, \
|
|
||||||
{SCHED_READY, "ready", false}, \
|
|
||||||
{SCHED_COMMIT, "commit", false}, \
|
|
||||||
{SCHED_MOVE_TO_RESUME_QUEUE, "moveToResumeQueue", false}, \
|
|
||||||
{SCHED_DELAY, "delay", false}, \
|
|
||||||
{SCHED_DO_POST_UPDATES, "doPostUpdates", false}, \
|
|
||||||
{SCHED_ENQUEUE, "enqueue", false}, \
|
|
||||||
{SCHED_EVALUATE, "evaluate", false}, \
|
|
||||||
{SCHED_EVALUATION, "evaluation", false}, \
|
|
||||||
{SCHED_POST_UPDATE, "postUpdate", false}, \
|
|
||||||
{SCHED_RESUME, "resume", false}, \
|
|
||||||
{SCHED_RESUME_ZERO_DELAY, "resumeZeroDelay", false}, \
|
|
||||||
{SCHED_RESUMPTION, "resumption", false}, \
|
|
||||||
{SCHED_TRIGGER, "trigger", false}, \
|
|
||||||
{UNPACKED_ASSIGN, "assign", false}, \
|
|
||||||
{UNPACKED_FILL, "fill", false}, \
|
|
||||||
{UNPACKED_NEQ, "neq", true}, \
|
|
||||||
{_ENUM_MAX, "_ENUM_MAX", false}};
|
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
|
|
||||||
@@ -1509,6 +1431,110 @@ constexpr bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs
|
|||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
|
|
||||||
|
// Enumeration of the model's evaluation entry points. Fields:
|
||||||
|
// is iterated, has triggers, takes 'firstIteration' flag, is slow
|
||||||
|
// clang-format off
|
||||||
|
#define FOR_EACH_EVAL(macro) \
|
||||||
|
/* id, iterated, hasTrigs, firstIt, slow */ \
|
||||||
|
macro(STATIC, false, false, false, true) \
|
||||||
|
macro(INITIAL, false, false, false, true) \
|
||||||
|
macro(STL, true, true, true, true) \
|
||||||
|
macro(SAMPLE, false, false, false, false) \
|
||||||
|
macro(ICO, true, true, true, false) \
|
||||||
|
macro(ACT, true, true, false, false) \
|
||||||
|
macro(INACT, true, false, false, false) \
|
||||||
|
macro(NBA, true, true, false, false) \
|
||||||
|
macro(OBS, true, true, false, false) \
|
||||||
|
macro(REACT, true, true, false, false) \
|
||||||
|
macro(POSTPONED, false, false, false, false) \
|
||||||
|
macro(FINAL, false, false, false, true)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
class VEval final {
|
||||||
|
public:
|
||||||
|
enum en : uint8_t {
|
||||||
|
#define VL_EVAL_ID(id, iterated, triggers, first, slow) id,
|
||||||
|
FOR_EACH_EVAL(VL_EVAL_ID)
|
||||||
|
#undef VL_EVAL_ID
|
||||||
|
_ENUM_END
|
||||||
|
};
|
||||||
|
enum en m_e;
|
||||||
|
|
||||||
|
const char* ascii() const {
|
||||||
|
static const char* const values[] = {
|
||||||
|
#define VL_EVAL_NAME(id, iterated, triggers, first, slow) #id,
|
||||||
|
FOR_EACH_EVAL(VL_EVAL_NAME)
|
||||||
|
#undef VL_EVAL_NAME
|
||||||
|
"_ENUM_END" //
|
||||||
|
};
|
||||||
|
return values[m_e];
|
||||||
|
}
|
||||||
|
bool isIterated() const {
|
||||||
|
static const bool values[] = {
|
||||||
|
#define VL_EVAL_IS_ITERATED(id, iterated, triggers, first, slow) iterated,
|
||||||
|
FOR_EACH_EVAL(VL_EVAL_IS_ITERATED)
|
||||||
|
#undef VL_EVAL_IS_ITERATED
|
||||||
|
false //
|
||||||
|
};
|
||||||
|
return values[m_e];
|
||||||
|
}
|
||||||
|
bool hasTriggers() const {
|
||||||
|
static const bool values[] = {
|
||||||
|
#define VL_EVAL_HAS_TRIGGERS(id, iterated, triggers, first, slow) triggers,
|
||||||
|
FOR_EACH_EVAL(VL_EVAL_HAS_TRIGGERS)
|
||||||
|
#undef VL_EVAL_HAS_TRIGGERS
|
||||||
|
false //
|
||||||
|
};
|
||||||
|
return values[m_e];
|
||||||
|
}
|
||||||
|
bool firstIteration() const {
|
||||||
|
static const bool values[] = {
|
||||||
|
#define VL_EVAL_FIRST(id, iterated, triggers, first, slow) first,
|
||||||
|
FOR_EACH_EVAL(VL_EVAL_FIRST)
|
||||||
|
#undef VL_EVAL_FIRST
|
||||||
|
false //
|
||||||
|
};
|
||||||
|
return values[m_e];
|
||||||
|
}
|
||||||
|
bool slow() const {
|
||||||
|
static const bool values[] = {
|
||||||
|
#define VL_EVAL_SLOW(id, iterated, triggers, first, slow) slow,
|
||||||
|
FOR_EACH_EVAL(VL_EVAL_SLOW)
|
||||||
|
#undef VL_EVAL_SLOW
|
||||||
|
false //
|
||||||
|
};
|
||||||
|
return values[m_e];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short name
|
||||||
|
std::string tag() const { return VString::downcase(ascii()); }
|
||||||
|
// Name of the generated entry point function
|
||||||
|
std::string funcName() const { return "_eval_" + tag(); }
|
||||||
|
// Name of the VerilatedModel virtual method invoking the entry point
|
||||||
|
std::string evalMethod() const { return "eval" + capitalizedTag(); }
|
||||||
|
// Name of the function dumping the triggers of this region
|
||||||
|
std::string dumpTriggersFuncName() const { return "_eval_dump_triggers__" + tag(); }
|
||||||
|
// Name of the VerilatedModel virtual method dumping this region's triggers
|
||||||
|
std::string dumpTriggersMethod() const { return "dumpTriggers" + capitalizedTag(); }
|
||||||
|
|
||||||
|
// cppcheck-suppress noExplicitConstructor
|
||||||
|
VEval(en _e)
|
||||||
|
: m_e{_e} {}
|
||||||
|
explicit VEval(int _e)
|
||||||
|
: m_e(static_cast<en>(_e)) {}
|
||||||
|
operator en() const { return m_e; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string capitalizedTag() const {
|
||||||
|
const std::string name = ascii();
|
||||||
|
return name.substr(0, 1) + VString::downcase(name.substr(1));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef FOR_EACH_EVAL
|
||||||
|
|
||||||
|
// ######################################################################
|
||||||
|
|
||||||
class VFwdType final {
|
class VFwdType final {
|
||||||
public:
|
public:
|
||||||
enum en : uint8_t { NONE, ENUM, STRUCT, UNION, CLASS, INTERFACE_CLASS, GENERIC_INTERFACE };
|
enum en : uint8_t { NONE, ENUM, STRUCT, UNION, CLASS, INTERFACE_CLASS, GENERIC_INTERFACE };
|
||||||
|
|||||||
+3
-1
@@ -146,6 +146,7 @@ bool AstBasicDType::ascending() const {
|
|||||||
|
|
||||||
bool AstActive::hasClocked() const { return m_sentreep->hasClocked(); }
|
bool AstActive::hasClocked() const { return m_sentreep->hasClocked(); }
|
||||||
bool AstActive::hasCombo() const { return m_sentreep->hasCombo(); }
|
bool AstActive::hasCombo() const { return m_sentreep->hasCombo(); }
|
||||||
|
bool AstActive::hasInitial() const { return m_sentreep->hasInitial(); }
|
||||||
bool AstActive::hasStatic() const { return m_sentreep->hasStatic(); }
|
bool AstActive::hasStatic() const { return m_sentreep->hasStatic(); }
|
||||||
|
|
||||||
AstAlways::AstAlways(AstAssignW* assignp)
|
AstAlways::AstAlways(AstAssignW* assignp)
|
||||||
@@ -160,7 +161,8 @@ AstElabDisplay::AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr*
|
|||||||
|
|
||||||
bool AstVar::sameNode(const AstNode* samep) const {
|
bool AstVar::sameNode(const AstNode* samep) const {
|
||||||
const AstVar* const asamep = VN_DBG_AS(samep, Var);
|
const AstVar* const asamep = VN_DBG_AS(samep, Var);
|
||||||
return m_name == asamep->m_name && varType() == asamep->varType();
|
return m_name == asamep->m_name && varType() == asamep->varType()
|
||||||
|
&& covergroupRefMember() == asamep->covergroupRefMember();
|
||||||
}
|
}
|
||||||
|
|
||||||
AstMatchMasked::AstMatchMasked(FileLine* fl, AstNodeExpr* lhsp, AstVarScope* matchp)
|
AstMatchMasked::AstMatchMasked(FileLine* fl, AstNodeExpr* lhsp, AstVarScope* matchp)
|
||||||
|
|||||||
+19
-5
@@ -38,7 +38,6 @@ class AstNodeDType VL_NOT_FINAL : public AstNode {
|
|||||||
int m_widthMin
|
int m_widthMin
|
||||||
= 0; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation
|
= 0; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation
|
||||||
VSigning m_numeric; // (also in AstTypeTable::Key) Node is signed
|
VSigning m_numeric; // (also in AstTypeTable::Key) Node is signed
|
||||||
// Other members
|
|
||||||
bool m_generic = false; // Simple globally referenced type, don't garbage collect
|
bool m_generic = false; // Simple globally referenced type, don't garbage collect
|
||||||
// Unique number assigned to each dtype during creation for IEEE matching
|
// Unique number assigned to each dtype during creation for IEEE matching
|
||||||
static int s_uniqueNum;
|
static int s_uniqueNum;
|
||||||
@@ -584,6 +583,7 @@ class AstClassRefDType final : public AstNodeDType {
|
|||||||
//
|
//
|
||||||
// @astgen ptr := m_classp : Optional[AstClass] // data type pointed to, BELOW the AstTypedef
|
// @astgen ptr := m_classp : Optional[AstClass] // data type pointed to, BELOW the AstTypedef
|
||||||
// @astgen ptr := m_classOrPackagep : Optional[AstNodeModule] // Package hierarchy
|
// @astgen ptr := m_classOrPackagep : Optional[AstNodeModule] // Package hierarchy
|
||||||
|
bool m_rawPointer = false; // Emit as a non-owning C++ pointer rather than VlClassRef
|
||||||
public:
|
public:
|
||||||
AstClassRefDType(FileLine* fl, AstClass* classp, AstPin* paramsp)
|
AstClassRefDType(FileLine* fl, AstClass* classp, AstPin* paramsp)
|
||||||
: ASTGEN_SUPER_ClassRefDType(fl)
|
: ASTGEN_SUPER_ClassRefDType(fl)
|
||||||
@@ -595,7 +595,8 @@ public:
|
|||||||
// METHODS
|
// METHODS
|
||||||
bool sameNode(const AstNode* samep) const override {
|
bool sameNode(const AstNode* samep) const override {
|
||||||
const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType);
|
const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType);
|
||||||
return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep);
|
return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep
|
||||||
|
&& m_rawPointer == asamep->m_rawPointer);
|
||||||
}
|
}
|
||||||
bool similarDTypeNode(const AstNodeDType* samep) const override;
|
bool similarDTypeNode(const AstNodeDType* samep) const override;
|
||||||
void dump(std::ostream& str = std::cout) const override;
|
void dump(std::ostream& str = std::cout) const override;
|
||||||
@@ -613,6 +614,9 @@ public:
|
|||||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||||
AstClass* classp() const VL_MT_STABLE { return m_classp; }
|
AstClass* classp() const VL_MT_STABLE { return m_classp; }
|
||||||
void classp(AstClass* nodep) { m_classp = nodep; }
|
void classp(AstClass* nodep) { m_classp = nodep; }
|
||||||
|
bool rawPointer() const { return m_rawPointer; }
|
||||||
|
void rawPointer(bool flag) { m_rawPointer = flag; }
|
||||||
|
static void selfTest();
|
||||||
bool isCompound() const override { return true; }
|
bool isCompound() const override { return true; }
|
||||||
};
|
};
|
||||||
class AstConstDType final : public AstNodeDType {
|
class AstConstDType final : public AstNodeDType {
|
||||||
@@ -868,6 +872,8 @@ public:
|
|||||||
dtypep(this);
|
dtypep(this);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstIfaceGenericDType;
|
ASTGEN_MEMBERS_AstIfaceGenericDType;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
void dumpSmall(std::ostream& str) const override;
|
void dumpSmall(std::ostream& str) const override;
|
||||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||||
@@ -918,7 +924,8 @@ public:
|
|||||||
: ASTGEN_SUPER_IfaceRefDType(fl)
|
: ASTGEN_SUPER_IfaceRefDType(fl)
|
||||||
, m_modportFileline{modportFl}
|
, m_modportFileline{modportFl}
|
||||||
, m_cellName{cellName}
|
, m_cellName{cellName}
|
||||||
, m_ifaceName{ifaceName} {
|
, m_ifaceName{ifaceName}
|
||||||
|
, m_modportName{modport} {
|
||||||
addParamsp(paramsp);
|
addParamsp(paramsp);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstIfaceRefDType;
|
ASTGEN_MEMBERS_AstIfaceRefDType;
|
||||||
@@ -968,7 +975,7 @@ class AstMemberDType final : public AstNodeDType {
|
|||||||
string m_tag; // Holds the string of the verilator tag -- used in JSON output.
|
string m_tag; // Holds the string of the verilator tag -- used in JSON output.
|
||||||
int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member
|
int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member
|
||||||
bool m_constrainedRand = false;
|
bool m_constrainedRand = false;
|
||||||
// UNSUP: int m_randType; // Randomization type (IEEE)
|
VRandAttr m_rand; // Randomizability of this member (rand, randc, etc)
|
||||||
public:
|
public:
|
||||||
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp,
|
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp,
|
||||||
AstNode* valuep)
|
AstNode* valuep)
|
||||||
@@ -1025,6 +1032,8 @@ public:
|
|||||||
}
|
}
|
||||||
bool isConstrainedRand() const { return m_constrainedRand; }
|
bool isConstrainedRand() const { return m_constrainedRand; }
|
||||||
void markConstrainedRand(bool flag) { m_constrainedRand = flag; }
|
void markConstrainedRand(bool flag) { m_constrainedRand = flag; }
|
||||||
|
VRandAttr rand() const { return m_rand; }
|
||||||
|
void rand(const VRandAttr flag) { m_rand = flag; }
|
||||||
};
|
};
|
||||||
class AstNBACommitQueueDType final : public AstNodeDType {
|
class AstNBACommitQueueDType final : public AstNodeDType {
|
||||||
// @astgen ptr := m_subDTypep : AstNodeDType // Type of the corresponding variable
|
// @astgen ptr := m_subDTypep : AstNodeDType // Type of the corresponding variable
|
||||||
@@ -1038,7 +1047,8 @@ public:
|
|||||||
dtypep(this);
|
dtypep(this);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstNBACommitQueueDType;
|
ASTGEN_MEMBERS_AstNBACommitQueueDType;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
AstNodeDType* subDTypep() const override VL_MT_STABLE { return m_subDTypep; }
|
AstNodeDType* subDTypep() const override VL_MT_STABLE { return m_subDTypep; }
|
||||||
bool partial() const { return m_partial; }
|
bool partial() const { return m_partial; }
|
||||||
bool sameNode(const AstNode* samep) const override {
|
bool sameNode(const AstNode* samep) const override {
|
||||||
@@ -1108,6 +1118,8 @@ public:
|
|||||||
ASTGEN_MEMBERS_AstParseTypeDType;
|
ASTGEN_MEMBERS_AstParseTypeDType;
|
||||||
AstNodeDType* dtypep() const VL_MT_STABLE { return nullptr; }
|
AstNodeDType* dtypep() const VL_MT_STABLE { return nullptr; }
|
||||||
// METHODS
|
// METHODS
|
||||||
|
void dump(std::ostream& str = std::cout) const override;
|
||||||
|
void dumpJson(std::ostream& str = std::cout) const override;
|
||||||
bool similarDTypeNode(const AstNodeDType* samep) const override { return this == samep; }
|
bool similarDTypeNode(const AstNodeDType* samep) const override { return this == samep; }
|
||||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||||
int widthAlignBytes() const override { return 0; }
|
int widthAlignBytes() const override { return 0; }
|
||||||
@@ -1452,6 +1464,8 @@ public:
|
|||||||
widthFromSub(subDTypep());
|
widthFromSub(subDTypep());
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstUnpackArrayDType;
|
ASTGEN_MEMBERS_AstUnpackArrayDType;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
string prettyDTypeName(bool full) const override;
|
string prettyDTypeName(bool full) const override;
|
||||||
bool sameNode(const AstNode* samep) const override {
|
bool sameNode(const AstNode* samep) const override {
|
||||||
const AstUnpackArrayDType* const sp = VN_DBG_AS(samep, UnpackArrayDType);
|
const AstUnpackArrayDType* const sp = VN_DBG_AS(samep, UnpackArrayDType);
|
||||||
|
|||||||
+83
-45
@@ -237,8 +237,9 @@ private:
|
|||||||
string m_name; // Name of variable
|
string m_name; // Name of variable
|
||||||
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
|
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
|
||||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||||
bool m_pli = false; // Pli system call ($name)
|
|
||||||
bool m_containsGenBlock = false; // Contains gen block reference
|
bool m_containsGenBlock = false; // Contains gen block reference
|
||||||
|
bool m_pli = false; // Pli system call ($name)
|
||||||
|
bool m_superReference = false; // Called with super reference
|
||||||
VIsCached m_purity; // Pure state
|
VIsCached m_purity; // Pure state
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -263,10 +264,12 @@ public:
|
|||||||
void dotted(const string& name) { m_dotted = name; }
|
void dotted(const string& name) { m_dotted = name; }
|
||||||
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
||||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||||
bool pli() const { return m_pli; }
|
|
||||||
void pli(bool flag) { m_pli = flag; }
|
|
||||||
bool containsGenBlock() const { return m_containsGenBlock; }
|
bool containsGenBlock() const { return m_containsGenBlock; }
|
||||||
void containsGenBlock(const bool flag) { m_containsGenBlock = flag; }
|
void containsGenBlock(const bool flag) { m_containsGenBlock = flag; }
|
||||||
|
bool pli() const { return m_pli; }
|
||||||
|
void pli(bool flag) { m_pli = flag; }
|
||||||
|
bool superReference() const { return m_superReference; }
|
||||||
|
void superReference(bool flag) { m_superReference = flag; }
|
||||||
bool isPure() override;
|
bool isPure() override;
|
||||||
bool sameNode(const AstNode* samep) const override {
|
bool sameNode(const AstNode* samep) const override {
|
||||||
const AstNodeFTaskRef* const asamep = VN_DBG_AS(samep, NodeFTaskRef);
|
const AstNodeFTaskRef* const asamep = VN_DBG_AS(samep, NodeFTaskRef);
|
||||||
@@ -276,7 +279,8 @@ public:
|
|||||||
&& dotted() == asamep->dotted() //
|
&& dotted() == asamep->dotted() //
|
||||||
&& inlinedDots() == asamep->inlinedDots() //
|
&& inlinedDots() == asamep->inlinedDots() //
|
||||||
&& pli() == asamep->pli() //
|
&& pli() == asamep->pli() //
|
||||||
&& containsGenBlock() == asamep->containsGenBlock();
|
&& containsGenBlock() == asamep->containsGenBlock()
|
||||||
|
&& superReference() == asamep->superReference();
|
||||||
}
|
}
|
||||||
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
|
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
|
||||||
string emitC() final override { V3ERROR_NA_RETURN(""); }
|
string emitC() final override { V3ERROR_NA_RETURN(""); }
|
||||||
@@ -681,9 +685,9 @@ public:
|
|||||||
init(text, setwidth);
|
init(text, setwidth);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstCExpr;
|
ASTGEN_MEMBERS_AstCExpr;
|
||||||
|
// METHODS
|
||||||
void dump(std::ostream& str = std::cout) const override;
|
void dump(std::ostream& str = std::cout) const override;
|
||||||
void dumpJson(std::ostream& str = std::cout) const override;
|
void dumpJson(std::ostream& str = std::cout) const override;
|
||||||
// METHODS
|
|
||||||
bool cleanOut() const override { return true; }
|
bool cleanOut() const override { return true; }
|
||||||
std::string emitC() override { V3ERROR_NA_RETURN(""); }
|
std::string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||||
std::string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
std::string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||||
@@ -714,6 +718,8 @@ public:
|
|||||||
, m_pure{true} {}
|
, m_pure{true} {}
|
||||||
ASTGEN_MEMBERS_AstCExprUser;
|
ASTGEN_MEMBERS_AstCExprUser;
|
||||||
// METHODS
|
// METHODS
|
||||||
|
void dump(std::ostream& str = std::cout) const override;
|
||||||
|
void dumpJson(std::ostream& str = std::cout) const override;
|
||||||
bool cleanOut() const override { return false; }
|
bool cleanOut() const override { return false; }
|
||||||
std::string emitC() override { V3ERROR_NA_RETURN(""); }
|
std::string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||||
std::string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
std::string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||||
@@ -905,7 +911,7 @@ public:
|
|||||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||||
// There's no classOrPackagep(); use classOrPackageNodep() to get Node,
|
// There's no classOrPackagep(); use classOrPackageNodep() to get Node,
|
||||||
// or iterating to package with classOrPackageSkipp()
|
// or iterating to package with classOrPackageSkipp()
|
||||||
AstNodeModule* classOrPackageSkipp() const;
|
AstNodeModule* classOrPackageSkipp(const bool doRefs = true) const;
|
||||||
AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; }
|
AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; }
|
||||||
void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; }
|
void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; }
|
||||||
void classOrPackagep(AstNodeModule* nodep) {
|
void classOrPackagep(AstNodeModule* nodep) {
|
||||||
@@ -1159,6 +1165,16 @@ public:
|
|||||||
, m_num(this, 1, 0) { // Need () constructor
|
, m_num(this, 1, 0) { // Need () constructor
|
||||||
dtypeSetBit();
|
dtypeSetBit();
|
||||||
}
|
}
|
||||||
|
// False but created due to reporting earlier error; suppress some later errors
|
||||||
|
class BitFalseErroring {};
|
||||||
|
AstConst(FileLine* fl, BitFalseErroring)
|
||||||
|
: ASTGEN_SUPER_Const(fl)
|
||||||
|
, m_num(this, 1, 0) { // Need () constructor
|
||||||
|
dtypeSetBit();
|
||||||
|
FileLine* const newfl = new FileLine{fileline()};
|
||||||
|
newfl->erroringOn(true);
|
||||||
|
fileline(newfl);
|
||||||
|
}
|
||||||
// Shorthand const 1 (or with argument 0/1), dtype should be a bit of size 1
|
// Shorthand const 1 (or with argument 0/1), dtype should be a bit of size 1
|
||||||
class BitTrue {};
|
class BitTrue {};
|
||||||
AstConst(FileLine* fl, BitTrue, bool on = true)
|
AstConst(FileLine* fl, BitTrue, bool on = true)
|
||||||
@@ -1358,6 +1374,8 @@ public:
|
|||||||
this->weightp(weightp);
|
this->weightp(weightp);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstDistItem;
|
ASTGEN_MEMBERS_AstDistItem;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
string emitVerilog() override { return "%l "s + (m_isWhole ? ":/" : ":=") + " %r"; }
|
string emitVerilog() override { return "%l "s + (m_isWhole ? ":/" : ":=") + " %r"; }
|
||||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||||
bool cleanOut() const override { return false; } // NA
|
bool cleanOut() const override { return false; } // NA
|
||||||
@@ -2022,21 +2040,33 @@ class AstPast final : public AstNodeExpr {
|
|||||||
// @astgen op1 := exprp : AstNodeExpr
|
// @astgen op1 := exprp : AstNodeExpr
|
||||||
// @astgen op2 := ticksp : Optional[AstNodeExpr]
|
// @astgen op2 := ticksp : Optional[AstNodeExpr]
|
||||||
// @astgen op3 := sentreep : Optional[AstSenTree]
|
// @astgen op3 := sentreep : Optional[AstSenTree]
|
||||||
|
// @astgen op4 := initp : Optional[AstNodeExpr] // Default sampled expression
|
||||||
|
// True only for history synthesized as property-evaluation bookkeeping (for example, |=> or
|
||||||
|
// NFA local-variable capture). Source $past and AstPast nodes lowering IEEE sampled-value
|
||||||
|
// functions such as $rose/$fell must remain false so they receive default initialization.
|
||||||
|
bool m_propertyTiming : 1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstPast(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ticksp = nullptr,
|
AstPast(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ticksp = nullptr,
|
||||||
AstSenTree* sentreep = nullptr)
|
AstSenTree* sentreep = nullptr, bool propertyTiming = false)
|
||||||
: ASTGEN_SUPER_Past(fl) {
|
: ASTGEN_SUPER_Past(fl)
|
||||||
|
, m_propertyTiming{propertyTiming} {
|
||||||
this->exprp(exprp);
|
this->exprp(exprp);
|
||||||
this->ticksp(ticksp);
|
this->ticksp(ticksp);
|
||||||
this->sentreep(sentreep);
|
this->sentreep(sentreep);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstPast;
|
ASTGEN_MEMBERS_AstPast;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||||
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
||||||
int instrCount() const override { return widthInstrs(); }
|
int instrCount() const override { return widthInstrs(); }
|
||||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
bool sameNode(const AstNode* samep) const override {
|
||||||
|
return m_propertyTiming == VN_DBG_AS(samep, Past)->m_propertyTiming;
|
||||||
|
}
|
||||||
|
bool propertyTiming() const { return m_propertyTiming; }
|
||||||
bool isSystemFunc() const override { return true; }
|
bool isSystemFunc() const override { return true; }
|
||||||
};
|
};
|
||||||
class AstPatMember final : public AstNodeExpr {
|
class AstPatMember final : public AstNodeExpr {
|
||||||
@@ -2163,6 +2193,8 @@ public:
|
|||||||
dtypeSetUInt32();
|
dtypeSetUInt32();
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstRand;
|
ASTGEN_MEMBERS_AstRand;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
string emitVerilog() override {
|
string emitVerilog() override {
|
||||||
return seedp() ? (m_urandom ? "%f$urandom(%l)" : "%f$random(%l)")
|
return seedp() ? (m_urandom ? "%f$urandom(%l)" : "%f$random(%l)")
|
||||||
: (m_urandom ? "%f$urandom()" : "%f$random()");
|
: (m_urandom ? "%f$urandom()" : "%f$random()");
|
||||||
@@ -2262,24 +2294,25 @@ public:
|
|||||||
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
|
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
|
||||||
};
|
};
|
||||||
class AstSConsRep final : public AstNodeExpr {
|
class AstSConsRep final : public AstNodeExpr {
|
||||||
// Consecutive repetition [*N], [*N:M], [+], [*] (IEEE 1800-2023 16.9.2)
|
// Consecutive repetition [*N], [*N:M], [*N:$], [+], [*] (IEEE 1800-2023 16.9.2)
|
||||||
// op1 := exprp -- the repeated expression
|
// op1 := exprp -- the repeated expression
|
||||||
// op2 := countp -- min repetition count (N); always a positive constant after V3Width
|
// op2 := countp -- min repetition count (N); always a non-negative constant after V3Width
|
||||||
// op3 := maxCountp -- max repetition count (M); nullptr when exact or unbounded
|
// op3 := maxCountp -- max repetition count (M); nullptr when exact or unbounded
|
||||||
//
|
//
|
||||||
// Encoding:
|
// Encoding:
|
||||||
// [*N]: countp=N, maxCountp=nullptr, unbounded=false
|
// [*N]: countp=N, maxCountp=nullptr, unbounded=false
|
||||||
// [*N:M]: countp=N, maxCountp=M, unbounded=false
|
// [*N:M]: countp=N, maxCountp=M, unbounded=false
|
||||||
|
// [*N:$]: countp=N, maxCountp=nullptr, unbounded=true
|
||||||
// [+]: countp=1, maxCountp=nullptr, unbounded=true (= [*1:$])
|
// [+]: countp=1, maxCountp=nullptr, unbounded=true (= [*1:$])
|
||||||
// [*]: countp=0, maxCountp=nullptr, unbounded=true (= [*0:$])
|
// [*]: countp=0, maxCountp=nullptr, unbounded=true (= [*0:$])
|
||||||
//
|
//
|
||||||
// Lowering:
|
// Lowering:
|
||||||
// Exact [*N] standalone: V3AssertPre saturating counter
|
// Exact [*N] standalone: V3AssertPre saturating counter
|
||||||
// All other forms and all SExpr-contained forms: V3AssertProp PExpr loop
|
// All other forms and all SExpr-contained forms: V3AssertNfa
|
||||||
// @astgen op1 := exprp : AstNodeExpr
|
// @astgen op1 := exprp : AstNodeExpr
|
||||||
// @astgen op2 := countp : AstNodeExpr
|
// @astgen op2 := countp : AstNodeExpr
|
||||||
// @astgen op3 := maxCountp : Optional[AstNodeExpr]
|
// @astgen op3 := maxCountp : Optional[AstNodeExpr]
|
||||||
const bool m_unbounded = false; // True for [+] and [*] (upper bound is $)
|
const bool m_unbounded = false; // True when the upper bound is $
|
||||||
public:
|
public:
|
||||||
// Exact [*N]
|
// Exact [*N]
|
||||||
AstSConsRep(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* countp)
|
AstSConsRep(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* countp)
|
||||||
@@ -2287,7 +2320,7 @@ public:
|
|||||||
this->exprp(exprp);
|
this->exprp(exprp);
|
||||||
this->countp(countp);
|
this->countp(countp);
|
||||||
}
|
}
|
||||||
// Range [*N:M] or unbounded [+]/[*]
|
// Range [*N:M] or unbounded [*N:$]/[+]/[*]
|
||||||
AstSConsRep(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* countp, AstNodeExpr* maxCountp,
|
AstSConsRep(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* countp, AstNodeExpr* maxCountp,
|
||||||
bool unbounded)
|
bool unbounded)
|
||||||
: ASTGEN_SUPER_SConsRep(fl)
|
: ASTGEN_SUPER_SConsRep(fl)
|
||||||
@@ -2554,19 +2587,26 @@ public:
|
|||||||
class AstSampled final : public AstNodeExpr {
|
class AstSampled final : public AstNodeExpr {
|
||||||
// Verilog $sampled
|
// Verilog $sampled
|
||||||
// @astgen op1 := exprp : AstNode<AstNodeExpr|AstPropSpec>
|
// @astgen op1 := exprp : AstNode<AstNodeExpr|AstPropSpec>
|
||||||
|
bool m_internal : 1; // Internally created, not from a source $sampled
|
||||||
public:
|
public:
|
||||||
AstSampled(FileLine* fl, AstNode* exprp, AstNodeDType* dtypep)
|
AstSampled(FileLine* fl, AstNode* exprp, AstNodeDType* dtypep, bool internal = false)
|
||||||
: ASTGEN_SUPER_Sampled(fl) {
|
: ASTGEN_SUPER_Sampled(fl)
|
||||||
|
, m_internal{internal} {
|
||||||
this->exprp(exprp);
|
this->exprp(exprp);
|
||||||
this->dtypep(dtypep);
|
this->dtypep(dtypep);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstSampled;
|
ASTGEN_MEMBERS_AstSampled;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
string emitVerilog() override { return "$sampled(%l)"; }
|
string emitVerilog() override { return "$sampled(%l)"; }
|
||||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||||
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
||||||
int instrCount() const override { return 0; }
|
int instrCount() const override { return 0; }
|
||||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
bool sameNode(const AstNode* samep) const override {
|
||||||
|
return m_internal == VN_DBG_AS(samep, Sampled)->m_internal;
|
||||||
|
}
|
||||||
|
bool internal() const { return m_internal; }
|
||||||
bool isSystemFunc() const override { return true; }
|
bool isSystemFunc() const override { return true; }
|
||||||
};
|
};
|
||||||
class AstScopeName final : public AstNodeExpr {
|
class AstScopeName final : public AstNodeExpr {
|
||||||
@@ -3063,6 +3103,8 @@ public:
|
|||||||
dtypeSetInt();
|
dtypeSetInt();
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstCompareNN;
|
ASTGEN_MEMBERS_AstCompareNN;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||||
out.opCompareNN(lhs, rhs, m_ignoreCase);
|
out.opCompareNN(lhs, rhs, m_ignoreCase);
|
||||||
}
|
}
|
||||||
@@ -3079,6 +3121,7 @@ public:
|
|||||||
bool cleanRhs() const override { return true; }
|
bool cleanRhs() const override { return true; }
|
||||||
bool sizeMattersLhs() const override { return false; }
|
bool sizeMattersLhs() const override { return false; }
|
||||||
bool sizeMattersRhs() const override { return false; }
|
bool sizeMattersRhs() const override { return false; }
|
||||||
|
bool ignoreCase() const { return m_ignoreCase; }
|
||||||
};
|
};
|
||||||
class AstConcat final : public AstNodeBiop {
|
class AstConcat final : public AstNodeBiop {
|
||||||
// If you're looking for {#{}}, see AstReplicate
|
// If you're looking for {#{}}, see AstReplicate
|
||||||
@@ -3258,6 +3301,7 @@ public:
|
|||||||
bool sizeMattersRhs() const override { return false; }
|
bool sizeMattersRhs() const override { return false; }
|
||||||
bool isSystemFunc() const override { return true; }
|
bool isSystemFunc() const override { return true; }
|
||||||
int instrCount() const override { return widthInstrs() * 64; }
|
int instrCount() const override { return widthInstrs() * 64; }
|
||||||
|
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||||
};
|
};
|
||||||
class AstFUngetC final : public AstNodeBiop {
|
class AstFUngetC final : public AstNodeBiop {
|
||||||
public:
|
public:
|
||||||
@@ -3978,12 +4022,16 @@ public:
|
|||||||
class AstSAnd final : public AstNodeBiop {
|
class AstSAnd final : public AstNodeBiop {
|
||||||
// Sequence 'and' (IEEE 1800-2023 16.9.5): both operand sequences must match.
|
// Sequence 'and' (IEEE 1800-2023 16.9.5): both operand sequences must match.
|
||||||
// Operates on match sets, not values. For boolean operands, lowered to AstLogAnd.
|
// Operates on match sets, not values. For boolean operands, lowered to AstLogAnd.
|
||||||
|
const bool m_propertyControl; // Parser-generated property if/case branch conjunction
|
||||||
public:
|
public:
|
||||||
AstSAnd(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
AstSAnd(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, bool propertyControl = false)
|
||||||
: ASTGEN_SUPER_SAnd(fl, lhsp, rhsp) {
|
: ASTGEN_SUPER_SAnd(fl, lhsp, rhsp)
|
||||||
|
, m_propertyControl{propertyControl} {
|
||||||
dtypeSetBit();
|
dtypeSetBit();
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstSAnd;
|
ASTGEN_MEMBERS_AstSAnd;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||||
out.opLogAnd(lhs, rhs);
|
out.opLogAnd(lhs, rhs);
|
||||||
}
|
}
|
||||||
@@ -3997,6 +4045,10 @@ public:
|
|||||||
bool sizeMattersRhs() const override { return false; }
|
bool sizeMattersRhs() const override { return false; }
|
||||||
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
|
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
|
||||||
bool isMultiCycleSva() const override { return true; }
|
bool isMultiCycleSva() const override { return true; }
|
||||||
|
bool sameNode(const AstNode* samep) const override { // LCOV_EXCL_LINE
|
||||||
|
return m_propertyControl == VN_DBG_AS(samep, SAnd)->m_propertyControl; // LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
bool propertyControl() const { return m_propertyControl; }
|
||||||
};
|
};
|
||||||
class AstSIntersect final : public AstNodeBiop {
|
class AstSIntersect final : public AstNodeBiop {
|
||||||
// Sequence 'intersect' (IEEE 1800-2023 16.9.6): both operands match with equal length.
|
// Sequence 'intersect' (IEEE 1800-2023 16.9.6): both operands match with equal length.
|
||||||
@@ -4886,9 +4938,11 @@ public:
|
|||||||
bool cleanRhs() const override { return true; }
|
bool cleanRhs() const override { return true; }
|
||||||
bool sizeMattersLhs() const override { return false; }
|
bool sizeMattersLhs() const override { return false; }
|
||||||
bool sizeMattersRhs() const override { return false; }
|
bool sizeMattersRhs() const override { return false; }
|
||||||
bool isGateOptimizable() const override { return false; } // AssocSel creates on miss
|
bool isGateOptimizable() const override {
|
||||||
|
return !isLValue(); // AssocSel creates on miss
|
||||||
|
}
|
||||||
bool isPredictOptimizable() const override { return false; }
|
bool isPredictOptimizable() const override { return false; }
|
||||||
bool isPure() override { return false; } // AssocSel creates on miss
|
bool isPure() override { return !isLValue(); } // AssocSel creates on miss
|
||||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||||
int instrCount() const override { return widthInstrs(); }
|
int instrCount() const override { return widthInstrs(); }
|
||||||
};
|
};
|
||||||
@@ -5044,19 +5098,11 @@ public:
|
|||||||
// === AstNodeFTaskRef ===
|
// === AstNodeFTaskRef ===
|
||||||
class AstFuncRef final : public AstNodeFTaskRef {
|
class AstFuncRef final : public AstNodeFTaskRef {
|
||||||
// A reference to a function
|
// A reference to a function
|
||||||
bool m_superReference = false; // Called with super reference
|
|
||||||
public:
|
public:
|
||||||
inline AstFuncRef(FileLine* fl, AstFunc* taskp, AstArg* argsp = nullptr);
|
inline AstFuncRef(FileLine* fl, AstFunc* taskp, AstArg* argsp = nullptr);
|
||||||
AstFuncRef(FileLine* fl, const string& name, AstArg* argsp = nullptr)
|
AstFuncRef(FileLine* fl, const string& name, AstArg* argsp = nullptr)
|
||||||
: ASTGEN_SUPER_FuncRef(fl, name, argsp) {}
|
: ASTGEN_SUPER_FuncRef(fl, name, argsp) {}
|
||||||
ASTGEN_MEMBERS_AstFuncRef;
|
ASTGEN_MEMBERS_AstFuncRef;
|
||||||
bool sameNode(const AstNode* samep) const override {
|
|
||||||
if (!this->AstNodeFTaskRef::sameNode(samep)) return false;
|
|
||||||
const AstFuncRef* const asamep = VN_DBG_AS(samep, FuncRef);
|
|
||||||
return superReference() == asamep->superReference();
|
|
||||||
}
|
|
||||||
bool superReference() const { return m_superReference; }
|
|
||||||
void superReference(bool flag) { m_superReference = flag; }
|
|
||||||
};
|
};
|
||||||
class AstMethodCall final : public AstNodeFTaskRef {
|
class AstMethodCall final : public AstNodeFTaskRef {
|
||||||
// A reference to a member task (or function)
|
// A reference to a member task (or function)
|
||||||
@@ -5097,7 +5143,6 @@ public:
|
|||||||
};
|
};
|
||||||
class AstTaskRef final : public AstNodeFTaskRef {
|
class AstTaskRef final : public AstNodeFTaskRef {
|
||||||
// A reference to a task
|
// A reference to a task
|
||||||
bool m_superReference = false; // Called with super reference
|
|
||||||
public:
|
public:
|
||||||
inline AstTaskRef(FileLine* fl, AstTask* taskp, AstArg* argsp = nullptr);
|
inline AstTaskRef(FileLine* fl, AstTask* taskp, AstArg* argsp = nullptr);
|
||||||
AstTaskRef(FileLine* fl, const string& name, AstArg* argsp = nullptr)
|
AstTaskRef(FileLine* fl, const string& name, AstArg* argsp = nullptr)
|
||||||
@@ -5105,13 +5150,6 @@ public:
|
|||||||
dtypeSetVoid();
|
dtypeSetVoid();
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstTaskRef;
|
ASTGEN_MEMBERS_AstTaskRef;
|
||||||
bool sameNode(const AstNode* samep) const override {
|
|
||||||
if (!this->AstNodeFTaskRef::sameNode(samep)) return false;
|
|
||||||
const AstTaskRef* const asamep = VN_DBG_AS(samep, TaskRef);
|
|
||||||
return superReference() == asamep->superReference();
|
|
||||||
}
|
|
||||||
bool superReference() const { return m_superReference; }
|
|
||||||
void superReference(bool flag) { m_superReference = flag; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// === AstNodePreSel ===
|
// === AstNodePreSel ===
|
||||||
@@ -5392,17 +5430,17 @@ public:
|
|||||||
enum FmtType : int { ATOI = 10, ATOHEX = 16, ATOOCT = 8, ATOBIN = 2, ATOREAL = -1 };
|
enum FmtType : int { ATOI = 10, ATOHEX = 16, ATOOCT = 8, ATOBIN = 2, ATOREAL = -1 };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const FmtType m_fmt; // Operation type
|
const FmtType m_fmtType; // Operation type
|
||||||
public:
|
public:
|
||||||
AstAtoN(FileLine* fl, AstNodeExpr* lhsp, FmtType fmt)
|
AstAtoN(FileLine* fl, AstNodeExpr* lhsp, FmtType fmtType)
|
||||||
: ASTGEN_SUPER_AtoN(fl, lhsp)
|
: ASTGEN_SUPER_AtoN(fl, lhsp)
|
||||||
, m_fmt{fmt} {
|
, m_fmtType{fmtType} {
|
||||||
fmt == ATOREAL ? dtypeSetDouble() : dtypeSetInteger();
|
fmtType == ATOREAL ? dtypeSetDouble() : dtypeSetInteger();
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstAtoN;
|
ASTGEN_MEMBERS_AstAtoN;
|
||||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAtoN(lhs, m_fmt); }
|
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAtoN(lhs, m_fmtType); }
|
||||||
string name() const override VL_MT_STABLE {
|
string name() const override VL_MT_STABLE {
|
||||||
switch (m_fmt) {
|
switch (m_fmtType) {
|
||||||
case ATOI: return "atoi";
|
case ATOI: return "atoi";
|
||||||
case ATOHEX: return "atohex";
|
case ATOHEX: return "atohex";
|
||||||
case ATOOCT: return "atooct";
|
case ATOOCT: return "atooct";
|
||||||
@@ -5413,7 +5451,7 @@ public:
|
|||||||
}
|
}
|
||||||
string emitVerilog() override { return "%l." + name() + "()"; }
|
string emitVerilog() override { return "%l." + name() + "()"; }
|
||||||
string emitC() override {
|
string emitC() override {
|
||||||
switch (m_fmt) {
|
switch (m_fmtType) {
|
||||||
case ATOI: return "VL_ATOI_N(%li, 10)";
|
case ATOI: return "VL_ATOI_N(%li, 10)";
|
||||||
case ATOHEX: return "VL_ATOI_N(%li, 16)";
|
case ATOHEX: return "VL_ATOI_N(%li, 16)";
|
||||||
case ATOOCT: return "VL_ATOI_N(%li, 8)";
|
case ATOOCT: return "VL_ATOI_N(%li, 8)";
|
||||||
@@ -5425,7 +5463,7 @@ public:
|
|||||||
bool cleanOut() const override { return true; }
|
bool cleanOut() const override { return true; }
|
||||||
bool cleanLhs() const override { return true; }
|
bool cleanLhs() const override { return true; }
|
||||||
bool sizeMattersLhs() const override { return false; }
|
bool sizeMattersLhs() const override { return false; }
|
||||||
FmtType format() const { return m_fmt; }
|
FmtType fmtType() const { return m_fmtType; }
|
||||||
};
|
};
|
||||||
class AstBitsToRealD final : public AstNodeUniop {
|
class AstBitsToRealD final : public AstNodeUniop {
|
||||||
public:
|
public:
|
||||||
|
|||||||
+88
-60
@@ -94,6 +94,7 @@ class AstNodeFTask VL_NOT_FINAL : public AstNode {
|
|||||||
// @astgen op4 := scopeNamep : Optional[AstScopeName]
|
// @astgen op4 := scopeNamep : Optional[AstScopeName]
|
||||||
string m_name; // Name of task
|
string m_name; // Name of task
|
||||||
string m_cname; // Name of task if DPI import
|
string m_cname; // Name of task if DPI import
|
||||||
|
string m_dpiCDecl; // Custom DPI-C function declaration
|
||||||
string m_ifacePortName; // Interface port name for out-of-block definition (IEEE 25.8)
|
string m_ifacePortName; // Interface port name for out-of-block definition (IEEE 25.8)
|
||||||
uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees
|
uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees
|
||||||
bool m_taskPublic : 1; // Public task
|
bool m_taskPublic : 1; // Public task
|
||||||
@@ -199,6 +200,9 @@ public:
|
|||||||
void dpiOpenChild(bool flag) { m_dpiOpenChild = flag; }
|
void dpiOpenChild(bool flag) { m_dpiOpenChild = flag; }
|
||||||
bool dpiTask() const { return m_dpiTask; }
|
bool dpiTask() const { return m_dpiTask; }
|
||||||
void dpiTask(bool flag) { m_dpiTask = flag; }
|
void dpiTask(bool flag) { m_dpiTask = flag; }
|
||||||
|
bool dpiCDeclOverride() const { return !m_dpiCDecl.empty(); }
|
||||||
|
const string& dpiCDecl() const { return m_dpiCDecl; }
|
||||||
|
void dpiCDecl(const string& cDecl) { m_dpiCDecl = cDecl; }
|
||||||
bool isConstructor() const { return m_isConstructor; }
|
bool isConstructor() const { return m_isConstructor; }
|
||||||
void isConstructor(bool flag) { m_isConstructor = flag; }
|
void isConstructor(bool flag) { m_isConstructor = flag; }
|
||||||
bool isHideLocal() const { return m_isHideLocal; }
|
bool isHideLocal() const { return m_isHideLocal; }
|
||||||
@@ -456,6 +460,7 @@ public:
|
|||||||
// METHODS
|
// METHODS
|
||||||
inline bool hasClocked() const;
|
inline bool hasClocked() const;
|
||||||
inline bool hasCombo() const;
|
inline bool hasCombo() const;
|
||||||
|
inline bool hasInitial() const;
|
||||||
inline bool hasStatic() const;
|
inline bool hasStatic() const;
|
||||||
};
|
};
|
||||||
class AstAlias final : public AstNode {
|
class AstAlias final : public AstNode {
|
||||||
@@ -504,6 +509,7 @@ class AstCFunc final : public AstNode {
|
|||||||
// @astgen op1 := argsp : List[AstVar] // Argument (and return value) variables
|
// @astgen op1 := argsp : List[AstVar] // Argument (and return value) variables
|
||||||
// @astgen op2 := varsp : List[AstVar] // Local variables
|
// @astgen op2 := varsp : List[AstVar] // Local variables
|
||||||
// @astgen op3 := stmtsp : List[AstNode]
|
// @astgen op3 := stmtsp : List[AstNode]
|
||||||
|
// @astgen op4 := scopeNamep : Optional[AstScopeName] // Scoping context for DPI export
|
||||||
//
|
//
|
||||||
// @astgen ptr := m_scopep : Optional[AstScope] // Scope that function is under
|
// @astgen ptr := m_scopep : Optional[AstScope] // Scope that function is under
|
||||||
string m_name;
|
string m_name;
|
||||||
@@ -511,6 +517,7 @@ class AstCFunc final : public AstNode {
|
|||||||
string m_rtnType; // void, bool, or other return type
|
string m_rtnType; // void, bool, or other return type
|
||||||
string m_argTypes; // Argument types
|
string m_argTypes; // Argument types
|
||||||
string m_ifdef; // #ifdef symbol around this function
|
string m_ifdef; // #ifdef symbol around this function
|
||||||
|
string m_dpiCDecl; // Custom DPI-C function declaration
|
||||||
VBoolOrUnknown m_isConst; // Function is declared const (*this not changed)
|
VBoolOrUnknown m_isConst; // Function is declared const (*this not changed)
|
||||||
bool m_isStatic : 1; // Function is static (no need for a 'this' pointer)
|
bool m_isStatic : 1; // Function is static (no need for a 'this' pointer)
|
||||||
bool m_isTrace : 1; // Function is related to tracing
|
bool m_isTrace : 1; // Function is related to tracing
|
||||||
@@ -640,6 +647,9 @@ public:
|
|||||||
void dpiImportPrototype(bool flag) { m_dpiImportPrototype = flag; }
|
void dpiImportPrototype(bool flag) { m_dpiImportPrototype = flag; }
|
||||||
bool dpiImportWrapper() const { return m_dpiImportWrapper; }
|
bool dpiImportWrapper() const { return m_dpiImportWrapper; }
|
||||||
void dpiImportWrapper(bool flag) { m_dpiImportWrapper = flag; }
|
void dpiImportWrapper(bool flag) { m_dpiImportWrapper = flag; }
|
||||||
|
bool dpiCDeclOverride() const { return !m_dpiCDecl.empty(); }
|
||||||
|
const string& dpiCDecl() const { return m_dpiCDecl; }
|
||||||
|
void dpiCDecl(const string& cDecl) { m_dpiCDecl = cDecl; }
|
||||||
bool isCoroutine() const { return m_rtnType == "VlCoroutine"; }
|
bool isCoroutine() const { return m_rtnType == "VlCoroutine"; }
|
||||||
void recursive(bool flag) { m_recursive = flag; }
|
void recursive(bool flag) { m_recursive = flag; }
|
||||||
bool recursive() const { return m_recursive; }
|
bool recursive() const { return m_recursive; }
|
||||||
@@ -650,20 +660,10 @@ public:
|
|||||||
void cost(int cost) { m_cost = cost; }
|
void cost(int cost) { m_cost = cost; }
|
||||||
// Special methods
|
// Special methods
|
||||||
bool emptyBody() const {
|
bool emptyBody() const {
|
||||||
return !keepIfEmpty() && !argsp() && !varsp() && !stmtsp() && !isVirtual()
|
return !keepIfEmpty() && !argsp() && !varsp() && !stmtsp() && !scopeNamep() && !isVirtual()
|
||||||
&& !dpiImportPrototype();
|
&& !dpiImportPrototype();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
class AstCLocalScope final : public AstNode {
|
|
||||||
// Pack statements into an unnamed scope when generating C++
|
|
||||||
// @astgen op1 := stmtsp : List[AstNode]
|
|
||||||
public:
|
|
||||||
AstCLocalScope(FileLine* fl, AstNode* stmtsp)
|
|
||||||
: ASTGEN_SUPER_CLocalScope(fl) {
|
|
||||||
addStmtsp(stmtsp);
|
|
||||||
}
|
|
||||||
ASTGEN_MEMBERS_AstCLocalScope;
|
|
||||||
};
|
|
||||||
class AstCUse final : public AstNode {
|
class AstCUse final : public AstNode {
|
||||||
// C++ use of a class or #include; indicates need of forward declaration
|
// C++ use of a class or #include; indicates need of forward declaration
|
||||||
// Parents: NODEMODULE
|
// Parents: NODEMODULE
|
||||||
@@ -806,7 +806,7 @@ public:
|
|||||||
void dump(std::ostream& str) const override;
|
void dump(std::ostream& str) const override;
|
||||||
void dumpJson(std::ostream& str) const override;
|
void dumpJson(std::ostream& str) const override;
|
||||||
string name() const override VL_MT_STABLE { return m_name; }
|
string name() const override VL_MT_STABLE { return m_name; }
|
||||||
VCoverOptionType optionType() const { return m_optType; }
|
VCoverOptionType optType() const { return m_optType; }
|
||||||
bool typeOption() const { return m_typeOption; }
|
bool typeOption() const { return m_typeOption; }
|
||||||
};
|
};
|
||||||
class AstClassExtends final : public AstNode {
|
class AstClassExtends final : public AstNode {
|
||||||
@@ -844,7 +844,7 @@ class AstClocking final : public AstNode {
|
|||||||
// @astgen op2 := itemsp : List[AstNode]
|
// @astgen op2 := itemsp : List[AstNode]
|
||||||
// @astgen op3 := eventp : Optional[AstVar]
|
// @astgen op3 := eventp : Optional[AstVar]
|
||||||
std::string m_name; // Clocking block name
|
std::string m_name; // Clocking block name
|
||||||
const bool m_isDefault; // True if default clocking
|
bool m_isDefault; // True if default clocking
|
||||||
const bool m_isGlobal; // True if global clocking
|
const bool m_isGlobal; // True if global clocking
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -865,6 +865,7 @@ public:
|
|||||||
bool isDefault() const { return m_isDefault; }
|
bool isDefault() const { return m_isDefault; }
|
||||||
bool isGlobal() const { return m_isGlobal; }
|
bool isGlobal() const { return m_isGlobal; }
|
||||||
AstVar* ensureEventp(bool childDType = false);
|
AstVar* ensureEventp(bool childDType = false);
|
||||||
|
void makeDefault() { m_isDefault = true; }
|
||||||
};
|
};
|
||||||
class AstClockingItem final : public AstNode {
|
class AstClockingItem final : public AstNode {
|
||||||
// Parents: CLOCKING
|
// Parents: CLOCKING
|
||||||
@@ -1042,22 +1043,6 @@ public:
|
|||||||
void isStatic(bool flag) { m_isStatic = flag; }
|
void isStatic(bool flag) { m_isStatic = flag; }
|
||||||
bool isStatic() const { return m_isStatic; }
|
bool isStatic() const { return m_isStatic; }
|
||||||
};
|
};
|
||||||
class AstConstraintBefore final : public AstNode {
|
|
||||||
// Constraint solve before item
|
|
||||||
// @astgen op1 := lhssp : List[AstNodeExpr]
|
|
||||||
// @astgen op2 := rhssp : List[AstNodeExpr]
|
|
||||||
public:
|
|
||||||
AstConstraintBefore(FileLine* fl, AstNodeExpr* lhssp, AstNodeExpr* rhssp)
|
|
||||||
: ASTGEN_SUPER_ConstraintBefore(fl) {
|
|
||||||
addLhssp(lhssp);
|
|
||||||
addRhssp(rhssp);
|
|
||||||
}
|
|
||||||
ASTGEN_MEMBERS_AstConstraintBefore;
|
|
||||||
bool isGateOptimizable() const override { return false; }
|
|
||||||
bool isPredictOptimizable() const override { return false; }
|
|
||||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class AstCoverBin final : public AstNode {
|
class AstCoverBin final : public AstNode {
|
||||||
// Captures data for a coverpoint 'bins' declaration
|
// Captures data for a coverpoint 'bins' declaration
|
||||||
// @astgen op1 := rangesp : List[AstNode]
|
// @astgen op1 := rangesp : List[AstNode]
|
||||||
@@ -1065,7 +1050,7 @@ class AstCoverBin final : public AstNode {
|
|||||||
// @astgen op3 := arraySizep : Optional[AstNodeExpr]
|
// @astgen op3 := arraySizep : Optional[AstNodeExpr]
|
||||||
// @astgen op4 := transp : List[AstCoverTransSet]
|
// @astgen op4 := transp : List[AstCoverTransSet]
|
||||||
const string m_name; // Base name of the bin
|
const string m_name; // Base name of the bin
|
||||||
const VCoverBinsType m_type; // Bin type (eg AUTO, IGNORE, ILLEGAL)
|
const VCoverBinsType m_binsType; // Bin type (eg AUTO, IGNORE, ILLEGAL)
|
||||||
bool m_isArray = false; // Bin is either an auto-sized array of values or transitions
|
bool m_isArray = false; // Bin is either an auto-sized array of values or transitions
|
||||||
bool m_isWildcard = false; // Bin uses wildcard matching (independent of ignore/illegal)
|
bool m_isWildcard = false; // Bin uses wildcard matching (independent of ignore/illegal)
|
||||||
|
|
||||||
@@ -1074,10 +1059,10 @@ public:
|
|||||||
bool isWildcard = false)
|
bool isWildcard = false)
|
||||||
: ASTGEN_SUPER_CoverBin(fl)
|
: ASTGEN_SUPER_CoverBin(fl)
|
||||||
, m_name{name}
|
, m_name{name}
|
||||||
, m_type{isIllegal ? VCoverBinsType::BINS_ILLEGAL
|
, m_binsType{isIllegal ? VCoverBinsType::BINS_ILLEGAL
|
||||||
: (isIgnore ? VCoverBinsType::BINS_IGNORE
|
: (isIgnore ? VCoverBinsType::BINS_IGNORE
|
||||||
: (isWildcard ? VCoverBinsType::BINS_WILDCARD
|
: (isWildcard ? VCoverBinsType::BINS_WILDCARD
|
||||||
: VCoverBinsType::BINS_USER))}
|
: VCoverBinsType::BINS_USER))}
|
||||||
, m_isWildcard{isWildcard} {
|
, m_isWildcard{isWildcard} {
|
||||||
addRangesp(rangesp);
|
addRangesp(rangesp);
|
||||||
}
|
}
|
||||||
@@ -1085,7 +1070,7 @@ public:
|
|||||||
AstCoverBin(FileLine* fl, const string& name, AstNodeExpr* arraySizep)
|
AstCoverBin(FileLine* fl, const string& name, AstNodeExpr* arraySizep)
|
||||||
: ASTGEN_SUPER_CoverBin(fl)
|
: ASTGEN_SUPER_CoverBin(fl)
|
||||||
, m_name{name}
|
, m_name{name}
|
||||||
, m_type{VCoverBinsType::BINS_AUTO}
|
, m_binsType{VCoverBinsType::BINS_AUTO}
|
||||||
, m_isArray{true} {
|
, m_isArray{true} {
|
||||||
this->arraySizep(arraySizep);
|
this->arraySizep(arraySizep);
|
||||||
}
|
}
|
||||||
@@ -1093,13 +1078,13 @@ public:
|
|||||||
AstCoverBin(FileLine* fl, const string& name, VCoverBinsType type)
|
AstCoverBin(FileLine* fl, const string& name, VCoverBinsType type)
|
||||||
: ASTGEN_SUPER_CoverBin(fl)
|
: ASTGEN_SUPER_CoverBin(fl)
|
||||||
, m_name{name}
|
, m_name{name}
|
||||||
, m_type{type} {}
|
, m_binsType{type} {}
|
||||||
// Constructor for transition bins
|
// Constructor for transition bins
|
||||||
AstCoverBin(FileLine* fl, const string& name, AstCoverTransSet* transp,
|
AstCoverBin(FileLine* fl, const string& name, AstCoverTransSet* transp,
|
||||||
VCoverBinsType type = VCoverBinsType::BINS_TRANSITION, bool isArrayBin = false)
|
VCoverBinsType type = VCoverBinsType::BINS_TRANSITION, bool isArrayBin = false)
|
||||||
: ASTGEN_SUPER_CoverBin(fl)
|
: ASTGEN_SUPER_CoverBin(fl)
|
||||||
, m_name{name}
|
, m_name{name}
|
||||||
, m_type{type}
|
, m_binsType{type}
|
||||||
, m_isArray{isArrayBin} {
|
, m_isArray{isArrayBin} {
|
||||||
UASSERT(transp, "AstCoverBin transition constructor requires non-null transp");
|
UASSERT(transp, "AstCoverBin transition constructor requires non-null transp");
|
||||||
addTransp(transp);
|
addTransp(transp);
|
||||||
@@ -1108,7 +1093,7 @@ public:
|
|||||||
void dump(std::ostream& str) const override;
|
void dump(std::ostream& str) const override;
|
||||||
void dumpJson(std::ostream& str) const override;
|
void dumpJson(std::ostream& str) const override;
|
||||||
string name() const override VL_MT_STABLE { return m_name; }
|
string name() const override VL_MT_STABLE { return m_name; }
|
||||||
VCoverBinsType binsType() const { return m_type; }
|
VCoverBinsType binsType() const { return m_binsType; }
|
||||||
bool isWildcard() const { return m_isWildcard; }
|
bool isWildcard() const { return m_isWildcard; }
|
||||||
bool isArray() const { return m_isArray; }
|
bool isArray() const { return m_isArray; }
|
||||||
void isArray(bool flag) { m_isArray = flag; }
|
void isArray(bool flag) { m_isArray = flag; }
|
||||||
@@ -1116,18 +1101,18 @@ public:
|
|||||||
class AstCoverOption final : public AstNode {
|
class AstCoverOption final : public AstNode {
|
||||||
// Coverage-option assignment
|
// Coverage-option assignment
|
||||||
// @astgen op1 := valuep : AstNodeExpr
|
// @astgen op1 := valuep : AstNodeExpr
|
||||||
const VCoverOptionType m_type; // Option being assigned
|
const VCoverOptionType m_optType; // Option being assigned
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstCoverOption(FileLine* fl, VCoverOptionType type, AstNodeExpr* valuep)
|
AstCoverOption(FileLine* fl, VCoverOptionType optType, AstNodeExpr* valuep)
|
||||||
: ASTGEN_SUPER_CoverOption(fl)
|
: ASTGEN_SUPER_CoverOption(fl)
|
||||||
, m_type{type} {
|
, m_optType{optType} {
|
||||||
this->valuep(valuep);
|
this->valuep(valuep);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstCoverOption;
|
ASTGEN_MEMBERS_AstCoverOption;
|
||||||
void dump(std::ostream& str) const override;
|
void dump(std::ostream& str) const override;
|
||||||
void dumpJson(std::ostream& str) const override;
|
void dumpJson(std::ostream& str) const override;
|
||||||
VCoverOptionType optionType() const { return m_type; }
|
VCoverOptionType optType() const { return m_optType; }
|
||||||
};
|
};
|
||||||
class AstCoverTransItem final : public AstNode {
|
class AstCoverTransItem final : public AstNode {
|
||||||
// Represents a single transition item: value or value[*N] or value[->N] or value[=N]
|
// Represents a single transition item: value or value[*N] or value[->N] or value[=N]
|
||||||
@@ -1222,6 +1207,16 @@ public:
|
|||||||
ASTGEN_MEMBERS_AstDefParam;
|
ASTGEN_MEMBERS_AstDefParam;
|
||||||
bool sameNode(const AstNode*) const override { return true; }
|
bool sameNode(const AstNode*) const override { return true; }
|
||||||
};
|
};
|
||||||
|
class AstDefaultClocking final : public AstNode {
|
||||||
|
std::string m_name; // Clocking block name
|
||||||
|
|
||||||
|
public:
|
||||||
|
AstDefaultClocking(FileLine* fl, const std::string& name)
|
||||||
|
: ASTGEN_SUPER_DefaultClocking(fl)
|
||||||
|
, m_name{name} {}
|
||||||
|
ASTGEN_MEMBERS_AstDefaultClocking;
|
||||||
|
std::string name() const override VL_MT_STABLE { return m_name; }
|
||||||
|
};
|
||||||
class AstDefaultDisable final : public AstNode {
|
class AstDefaultDisable final : public AstNode {
|
||||||
// @astgen op1 := condp : AstNodeExpr
|
// @astgen op1 := condp : AstNodeExpr
|
||||||
|
|
||||||
@@ -1244,6 +1239,8 @@ public:
|
|||||||
, m_name{vname}
|
, m_name{vname}
|
||||||
, m_cname{cname} {}
|
, m_cname{cname} {}
|
||||||
ASTGEN_MEMBERS_AstDpiExport;
|
ASTGEN_MEMBERS_AstDpiExport;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
string name() const override VL_MT_STABLE { return m_name; }
|
string name() const override VL_MT_STABLE { return m_name; }
|
||||||
void name(const string& name) override { m_name = name; }
|
void name(const string& name) override { m_name = name; }
|
||||||
string cname() const { return m_cname; }
|
string cname() const { return m_cname; }
|
||||||
@@ -1447,8 +1444,6 @@ class AstNetlist final : public AstNode {
|
|||||||
// @astgen ptr := m_dollarUnitPkgp : Optional[AstPackage] // $unit
|
// @astgen ptr := m_dollarUnitPkgp : Optional[AstPackage] // $unit
|
||||||
// @astgen ptr := m_stdPackagep : Optional[AstPackage] // SystemVerilog std package
|
// @astgen ptr := m_stdPackagep : Optional[AstPackage] // SystemVerilog std package
|
||||||
// @astgen ptr := m_stdPackageProcessp : Optional[AstClass] // SystemVerilog std process class
|
// @astgen ptr := m_stdPackageProcessp : Optional[AstClass] // SystemVerilog std process class
|
||||||
// @astgen ptr := m_evalp : Optional[AstCFunc] // The '_eval' function
|
|
||||||
// @astgen ptr := m_evalNbap : Optional[AstCFunc] // The '_eval__nba' function
|
|
||||||
// @astgen ptr := m_dpiExportTriggerp : Optional[AstVarScope] // DPI export trigger variable
|
// @astgen ptr := m_dpiExportTriggerp : Optional[AstVarScope] // DPI export trigger variable
|
||||||
// @astgen ptr := m_delaySchedulerp : Optional[AstVar] // Delay scheduler variable
|
// @astgen ptr := m_delaySchedulerp : Optional[AstVar] // Delay scheduler variable
|
||||||
// @astgen ptr := m_nbaEventp : Optional[AstVarScope] // NBA event variable
|
// @astgen ptr := m_nbaEventp : Optional[AstVarScope] // NBA event variable
|
||||||
@@ -1466,6 +1461,10 @@ class AstNetlist final : public AstNode {
|
|||||||
// AstConst itself, as AstConst is a very common node and only a small fraction carry this
|
// AstConst itself, as AstConst is a very common node and only a small fraction carry this
|
||||||
// name.
|
// name.
|
||||||
std::unordered_map<const AstConst*, string> m_constOrigParamNames;
|
std::unordered_map<const AstConst*, string> m_constOrigParamNames;
|
||||||
|
// The model's evaluation entry point functions
|
||||||
|
std::array<AstCFunc*, VEval::_ENUM_END> m_evalFuncps{};
|
||||||
|
// The trigger dump function of each region if exists, otherwise nullptr
|
||||||
|
std::array<AstCFunc*, VEval::_ENUM_END> m_dumpTriggersFuncps{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstNetlist();
|
AstNetlist();
|
||||||
@@ -1489,10 +1488,10 @@ public:
|
|||||||
void astConstOrigParamNameErase(const AstConst* nodep);
|
void astConstOrigParamNameErase(const AstConst* nodep);
|
||||||
AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; }
|
AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; }
|
||||||
AstPackage* dollarUnitPkgAddp();
|
AstPackage* dollarUnitPkgAddp();
|
||||||
AstCFunc* evalp() const { return m_evalp; }
|
AstCFunc* evalFuncp(VEval eval) const { return m_evalFuncps[eval]; }
|
||||||
void evalp(AstCFunc* funcp) { m_evalp = funcp; }
|
void evalFuncp(VEval eval, AstCFunc* funcp) { m_evalFuncps[eval] = funcp; }
|
||||||
AstCFunc* evalNbap() const { return m_evalNbap; }
|
AstCFunc* dumpTriggersFuncp(VEval eval) const { return m_dumpTriggersFuncps[eval]; }
|
||||||
void evalNbap(AstCFunc* funcp) { m_evalNbap = funcp; }
|
void dumpTriggersFuncp(VEval eval, AstCFunc* funcp) { m_dumpTriggersFuncps[eval] = funcp; }
|
||||||
AstVarScope* dpiExportTriggerp() const { return m_dpiExportTriggerp; }
|
AstVarScope* dpiExportTriggerp() const { return m_dpiExportTriggerp; }
|
||||||
void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; }
|
void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; }
|
||||||
AstVar* delaySchedulerp() const { return m_delaySchedulerp; }
|
AstVar* delaySchedulerp() const { return m_delaySchedulerp; }
|
||||||
@@ -1528,6 +1527,9 @@ public:
|
|||||||
const std::string& name = resolvedTopModuleName();
|
const std::string& name = resolvedTopModuleName();
|
||||||
return prettyName(name.empty() ? v3Global.rootp()->topModulep()->name() : name);
|
return prettyName(name.empty() ? v3Global.rootp()->topModulep()->name() : name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record statistics for eval functions
|
||||||
|
void addEvalStats(const std::string& phase);
|
||||||
};
|
};
|
||||||
class AstPackageExport final : public AstNode {
|
class AstPackageExport final : public AstNode {
|
||||||
// A package export declaration
|
// A package export declaration
|
||||||
@@ -1679,17 +1681,25 @@ class AstPropSpec final : public AstNode {
|
|||||||
// @astgen op1 := sensesp : Optional[AstSenItem]
|
// @astgen op1 := sensesp : Optional[AstSenItem]
|
||||||
// @astgen op2 := disablep : Optional[AstNodeExpr]
|
// @astgen op2 := disablep : Optional[AstNodeExpr]
|
||||||
// @astgen op3 := propp : AstNode
|
// @astgen op3 := propp : AstNode
|
||||||
|
// @astgen op4 := matchCountp : Optional[AstNodeExpr] // Cover sequence matches this tick
|
||||||
|
VPropStrength m_propStrength = VPropStrength::DEFAULT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstPropSpec(FileLine* fl, AstSenItem* sensesp, AstNodeExpr* disablep, AstNode* propp)
|
AstPropSpec(FileLine* fl, AstSenItem* sensesp, AstNodeExpr* disablep, AstNode* propp,
|
||||||
: ASTGEN_SUPER_PropSpec(fl) {
|
VPropStrength propStrength = VPropStrength::DEFAULT)
|
||||||
|
: ASTGEN_SUPER_PropSpec(fl)
|
||||||
|
, m_propStrength{propStrength} {
|
||||||
this->sensesp(sensesp);
|
this->sensesp(sensesp);
|
||||||
this->disablep(disablep);
|
this->disablep(disablep);
|
||||||
this->propp(propp);
|
this->propp(propp);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstPropSpec;
|
ASTGEN_MEMBERS_AstPropSpec;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
bool hasDType() const override VL_MT_SAFE {
|
bool hasDType() const override VL_MT_SAFE {
|
||||||
return true;
|
return true;
|
||||||
} // Used under Cover, which expects a bool child
|
} // Used under Cover, which expects a bool child
|
||||||
|
VPropStrength propStrength() const { return m_propStrength; }
|
||||||
};
|
};
|
||||||
class AstPull final : public AstNode {
|
class AstPull final : public AstNode {
|
||||||
// @astgen op1 := lhsp : AstNodeExpr
|
// @astgen op1 := lhsp : AstNodeExpr
|
||||||
@@ -1706,7 +1716,9 @@ public:
|
|||||||
bool sameNode(const AstNode* samep) const override {
|
bool sameNode(const AstNode* samep) const override {
|
||||||
return direction() == VN_DBG_AS(samep, Pull)->direction();
|
return direction() == VN_DBG_AS(samep, Pull)->direction();
|
||||||
}
|
}
|
||||||
uint32_t direction() const { return static_cast<uint32_t>(m_direction); }
|
bool direction() const { return m_direction; }
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
};
|
};
|
||||||
class AstScope final : public AstNode {
|
class AstScope final : public AstNode {
|
||||||
// A particular usage of a cell
|
// A particular usage of a cell
|
||||||
@@ -2091,6 +2103,8 @@ public:
|
|||||||
addOFieldsp(oFieldsp2);
|
addOFieldsp(oFieldsp2);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstUdpTableLine;
|
ASTGEN_MEMBERS_AstUdpTableLine;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
int udpIsCombo() const { return m_udpIsCombo; }
|
int udpIsCombo() const { return m_udpIsCombo; }
|
||||||
};
|
};
|
||||||
class AstUdpTableLineVal final : public AstNode {
|
class AstUdpTableLineVal final : public AstNode {
|
||||||
@@ -2152,7 +2166,8 @@ class AstVar final : public AstNode {
|
|||||||
bool m_attrFsmResetArc : 1; // declared with fsm_reset_arc metacomment
|
bool m_attrFsmResetArc : 1; // declared with fsm_reset_arc metacomment
|
||||||
bool m_attrFsmArcInclCond : 1; // declared with fsm_arc_include_cond metacomment
|
bool m_attrFsmArcInclCond : 1; // declared with fsm_arc_include_cond metacomment
|
||||||
bool m_constPoolEntry : 1; // Constant pool variable
|
bool m_constPoolEntry : 1; // Constant pool variable
|
||||||
bool m_fileDescr : 1; // File descriptor
|
bool m_covergroupRefMember : 1; // Persistent covergroup ref/const ref argument
|
||||||
|
bool m_attrFileDescr : 1; // File descriptor
|
||||||
bool m_gotNansiType : 1; // Linker saw Non-ANSI type declaration
|
bool m_gotNansiType : 1; // Linker saw Non-ANSI type declaration
|
||||||
bool m_icoMaybeWritten : 1; // Design might write this input signal - for ico change detect
|
bool m_icoMaybeWritten : 1; // Design might write this input signal - for ico change detect
|
||||||
bool m_isConst : 1; // Table contains constant data
|
bool m_isConst : 1; // Table contains constant data
|
||||||
@@ -2173,7 +2188,7 @@ class AstVar final : public AstNode {
|
|||||||
bool m_noSubst : 1; // Do not substitute out references
|
bool m_noSubst : 1; // Do not substitute out references
|
||||||
bool m_sampled : 1; // Sampled timing region
|
bool m_sampled : 1; // Sampled timing region
|
||||||
bool m_substConstOnly : 1; // Only substitute if constant
|
bool m_substConstOnly : 1; // Only substitute if constant
|
||||||
bool m_overridenParam : 1; // Overridden parameter by #(...) or defparam
|
bool m_overriddenParam : 1; // Overridden parameter by #(...) or defparam
|
||||||
bool m_trace : 1; // Trace this variable
|
bool m_trace : 1; // Trace this variable
|
||||||
bool m_isLatched : 1; // Not assigned in all control paths of combo always
|
bool m_isLatched : 1; // Not assigned in all control paths of combo always
|
||||||
bool m_isForceable : 1; // May be forced/released externally from user C code
|
bool m_isForceable : 1; // May be forced/released externally from user C code
|
||||||
@@ -2216,7 +2231,8 @@ class AstVar final : public AstNode {
|
|||||||
m_attrFsmResetArc = false;
|
m_attrFsmResetArc = false;
|
||||||
m_attrFsmArcInclCond = false;
|
m_attrFsmArcInclCond = false;
|
||||||
m_constPoolEntry = false;
|
m_constPoolEntry = false;
|
||||||
m_fileDescr = false;
|
m_covergroupRefMember = false;
|
||||||
|
m_attrFileDescr = false;
|
||||||
m_gotNansiType = false;
|
m_gotNansiType = false;
|
||||||
m_icoMaybeWritten = false;
|
m_icoMaybeWritten = false;
|
||||||
m_isConst = false;
|
m_isConst = false;
|
||||||
@@ -2237,7 +2253,7 @@ class AstVar final : public AstNode {
|
|||||||
m_noSubst = false;
|
m_noSubst = false;
|
||||||
m_sampled = false;
|
m_sampled = false;
|
||||||
m_substConstOnly = false;
|
m_substConstOnly = false;
|
||||||
m_overridenParam = false;
|
m_overriddenParam = false;
|
||||||
m_trace = false;
|
m_trace = false;
|
||||||
m_isLatched = false;
|
m_isLatched = false;
|
||||||
m_isForceable = false;
|
m_isForceable = false;
|
||||||
@@ -2356,7 +2372,7 @@ public:
|
|||||||
void ansi(bool flag) { m_ansi = flag; }
|
void ansi(bool flag) { m_ansi = flag; }
|
||||||
void declTyped(bool flag) { m_declTyped = flag; }
|
void declTyped(bool flag) { m_declTyped = flag; }
|
||||||
void sensIfacep(AstIface* nodep) { m_sensIfacep = nodep; }
|
void sensIfacep(AstIface* nodep) { m_sensIfacep = nodep; }
|
||||||
void attrFileDescr(bool flag) { m_fileDescr = flag; }
|
void attrFileDescr(bool flag) { m_attrFileDescr = flag; }
|
||||||
void attrScBv(bool flag) { m_attrScBv = flag; }
|
void attrScBv(bool flag) { m_attrScBv = flag; }
|
||||||
void attrScBigUint(bool flag) { m_attrScBigUint = flag; }
|
void attrScBigUint(bool flag) { m_attrScBigUint = flag; }
|
||||||
void attrSFormat(bool flag) { m_attrSFormat = flag; }
|
void attrSFormat(bool flag) { m_attrSFormat = flag; }
|
||||||
@@ -2367,6 +2383,8 @@ public:
|
|||||||
void attrFsmArcInclCond(bool flag) { m_attrFsmArcInclCond = flag; }
|
void attrFsmArcInclCond(bool flag) { m_attrFsmArcInclCond = flag; }
|
||||||
bool constPoolEntry() const { return m_constPoolEntry; }
|
bool constPoolEntry() const { return m_constPoolEntry; }
|
||||||
void setConstPoolEntry() { m_constPoolEntry = true; }
|
void setConstPoolEntry() { m_constPoolEntry = true; }
|
||||||
|
bool covergroupRefMember() const { return m_covergroupRefMember; }
|
||||||
|
void covergroupRefMember(bool flag) { m_covergroupRefMember = flag; }
|
||||||
void rand(const VRandAttr flag) { m_rand = flag; }
|
void rand(const VRandAttr flag) { m_rand = flag; }
|
||||||
void usedParam(bool flag) { m_usedParam = flag; }
|
void usedParam(bool flag) { m_usedParam = flag; }
|
||||||
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
|
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
|
||||||
@@ -2420,8 +2438,8 @@ public:
|
|||||||
void sampled(bool flag) { m_sampled = flag; }
|
void sampled(bool flag) { m_sampled = flag; }
|
||||||
bool substConstOnly() const { return m_substConstOnly; }
|
bool substConstOnly() const { return m_substConstOnly; }
|
||||||
void substConstOnly(bool flag) { m_substConstOnly = flag; }
|
void substConstOnly(bool flag) { m_substConstOnly = flag; }
|
||||||
bool overriddenParam() const { return m_overridenParam; }
|
bool overriddenParam() const { return m_overriddenParam; }
|
||||||
void overriddenParam(bool flag) { m_overridenParam = flag; }
|
void overriddenParam(bool flag) { m_overriddenParam = flag; }
|
||||||
void trace(bool flag) { m_trace = flag; }
|
void trace(bool flag) { m_trace = flag; }
|
||||||
void isLatched(bool flag) { m_isLatched = flag; }
|
void isLatched(bool flag) { m_isLatched = flag; }
|
||||||
bool isForceable() const { return m_isForceable; }
|
bool isForceable() const { return m_isForceable; }
|
||||||
@@ -2525,7 +2543,7 @@ public:
|
|||||||
bool isPulldown() const { return m_isPulldown; }
|
bool isPulldown() const { return m_isPulldown; }
|
||||||
bool attrScBv() const { return m_attrScBv; }
|
bool attrScBv() const { return m_attrScBv; }
|
||||||
bool attrScBigUint() const { return m_attrScBigUint; }
|
bool attrScBigUint() const { return m_attrScBigUint; }
|
||||||
bool attrFileDescr() const { return m_fileDescr; }
|
bool attrFileDescr() const { return m_attrFileDescr; }
|
||||||
bool attrSFormat() const { return m_attrSFormat; }
|
bool attrSFormat() const { return m_attrSFormat; }
|
||||||
bool attrSplitVar() const { return m_attrSplitVar; }
|
bool attrSplitVar() const { return m_attrSplitVar; }
|
||||||
bool attrFsmState() const { return m_attrFsmState; }
|
bool attrFsmState() const { return m_attrFsmState; }
|
||||||
@@ -2723,6 +2741,8 @@ public:
|
|||||||
AstSequence(FileLine* fl, const string& name, AstNode* stmtp)
|
AstSequence(FileLine* fl, const string& name, AstNode* stmtp)
|
||||||
: ASTGEN_SUPER_Sequence(fl, name, stmtp) {}
|
: ASTGEN_SUPER_Sequence(fl, name, stmtp) {}
|
||||||
ASTGEN_MEMBERS_AstSequence;
|
ASTGEN_MEMBERS_AstSequence;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||||
AstNodeFTask* cloneType(const string& name) override {
|
AstNodeFTask* cloneType(const string& name) override {
|
||||||
return new AstSequence{fileline(), name, nullptr};
|
return new AstSequence{fileline(), name, nullptr};
|
||||||
@@ -2784,11 +2804,14 @@ class AstCoverCross final : public AstNodeFuncCovItem {
|
|||||||
// @astgen op2 := optionsp : List[AstCoverOption] // post-LinkParse only
|
// @astgen op2 := optionsp : List[AstCoverOption] // post-LinkParse only
|
||||||
// @astgen op3 := rawBodyp : List[AstNode] // Parse: raw cross_body items;
|
// @astgen op3 := rawBodyp : List[AstNode] // Parse: raw cross_body items;
|
||||||
// // post-LinkParse: empty
|
// // post-LinkParse: empty
|
||||||
|
// @astgen op4 := iffp : Optional[AstNodeExpr] // Conditional sampling guard
|
||||||
public:
|
public:
|
||||||
AstCoverCross(FileLine* fl, const string& name, AstCoverpointRef* itemsp)
|
AstCoverCross(FileLine* fl, const string& name, AstCoverpointRef* itemsp,
|
||||||
|
AstNodeExpr* iffp = nullptr)
|
||||||
: ASTGEN_SUPER_CoverCross(fl, name) {
|
: ASTGEN_SUPER_CoverCross(fl, name) {
|
||||||
UASSERT(itemsp, "AstCoverCross requires at least one coverpoint reference");
|
UASSERT(itemsp, "AstCoverCross requires at least one coverpoint reference");
|
||||||
addItemsp(itemsp);
|
addItemsp(itemsp);
|
||||||
|
this->iffp(iffp);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstCoverCross;
|
ASTGEN_MEMBERS_AstCoverCross;
|
||||||
void dump(std::ostream& str) const override;
|
void dump(std::ostream& str) const override;
|
||||||
@@ -2889,6 +2912,7 @@ class AstClass final : public AstNodeModule {
|
|||||||
// @astgen op4 := extendsp : List[AstClassExtends]
|
// @astgen op4 := extendsp : List[AstClassExtends]
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
// @astgen ptr := m_classOrPackagep : Optional[AstClassPackage] // Package to be emitted with
|
// @astgen ptr := m_classOrPackagep : Optional[AstClassPackage] // Package to be emitted with
|
||||||
|
// @astgen ptr := m_covergroupEnclosingClassp : Optional[AstClass] // Lexical enclosing class
|
||||||
uint32_t m_declTokenNum; // Declaration token number
|
uint32_t m_declTokenNum; // Declaration token number
|
||||||
VBaseOverride m_baseOverride; // BaseOverride (inital/final/extends)
|
VBaseOverride m_baseOverride; // BaseOverride (inital/final/extends)
|
||||||
bool m_covergroup = false; // Is covergroup (TODO perhaps make a new Ast node type for CG?)
|
bool m_covergroup = false; // Is covergroup (TODO perhaps make a new Ast node type for CG?)
|
||||||
@@ -2913,6 +2937,10 @@ public:
|
|||||||
bool timescaleMatters() const override { return false; }
|
bool timescaleMatters() const override { return false; }
|
||||||
AstClassPackage* classOrPackagep() const VL_MT_STABLE { return m_classOrPackagep; }
|
AstClassPackage* classOrPackagep() const VL_MT_STABLE { return m_classOrPackagep; }
|
||||||
void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; }
|
void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; }
|
||||||
|
AstClass* covergroupEnclosingClassp() const VL_MT_STABLE {
|
||||||
|
return m_covergroupEnclosingClassp;
|
||||||
|
}
|
||||||
|
void covergroupEnclosingClassp(AstClass* classp) { m_covergroupEnclosingClassp = classp; }
|
||||||
AstNode* membersp() const VL_MT_STABLE { return stmtsp(); }
|
AstNode* membersp() const VL_MT_STABLE { return stmtsp(); }
|
||||||
void addMembersp(AstNode* nodep) { addStmtsp(nodep); }
|
void addMembersp(AstNode* nodep) { addStmtsp(nodep); }
|
||||||
bool isCovergroup() const { return m_covergroup; }
|
bool isCovergroup() const { return m_covergroup; }
|
||||||
|
|||||||
+79
-14
@@ -163,6 +163,8 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
ASTGEN_MEMBERS_AstNodeIf;
|
ASTGEN_MEMBERS_AstNodeIf;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
bool isGateOptimizable() const override { return false; }
|
bool isGateOptimizable() const override { return false; }
|
||||||
bool isGateDedupable() const override { return true; }
|
bool isGateDedupable() const override { return true; }
|
||||||
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
||||||
@@ -190,6 +192,8 @@ public:
|
|||||||
this->msbp(msbp);
|
this->msbp(msbp);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstNodeReadWriteMem;
|
ASTGEN_MEMBERS_AstNodeReadWriteMem;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
bool isGateOptimizable() const override { return false; }
|
bool isGateOptimizable() const override { return false; }
|
||||||
bool isPredictOptimizable() const override { return false; }
|
bool isPredictOptimizable() const override { return false; }
|
||||||
bool isPure() override { return false; }
|
bool isPure() override { return false; }
|
||||||
@@ -262,10 +266,10 @@ public:
|
|||||||
bool isOutputter() override { return true; }
|
bool isOutputter() override { return true; }
|
||||||
VAssertCtlType ctlType() const { return m_ctlType; }
|
VAssertCtlType ctlType() const { return m_ctlType; }
|
||||||
void ctlType(int32_t type) { m_ctlType = VAssertCtlType{type}; }
|
void ctlType(int32_t type) { m_ctlType = VAssertCtlType{type}; }
|
||||||
VAssertType ctlAssertTypes() const { return m_assertTypes; }
|
VAssertType assertTypes() const { return m_assertTypes; }
|
||||||
void ctlAssertTypes(VAssertType types) { m_assertTypes = types; }
|
void assertTypes(VAssertType types) { m_assertTypes = types; }
|
||||||
VAssertDirectiveType ctlDirectiveTypes() const { return m_directiveTypes; }
|
VAssertDirectiveType directiveTypes() const { return m_directiveTypes; }
|
||||||
void ctlDirectiveTypes(VAssertDirectiveType types) { m_directiveTypes = types; }
|
void directiveTypes(VAssertDirectiveType types) { m_directiveTypes = types; }
|
||||||
void dump(std::ostream& str = std::cout) const override;
|
void dump(std::ostream& str = std::cout) const override;
|
||||||
void dumpJson(std::ostream& str = std::cout) const override;
|
void dumpJson(std::ostream& str = std::cout) const override;
|
||||||
};
|
};
|
||||||
@@ -297,6 +301,16 @@ public:
|
|||||||
AstSenTree* sentreep() const { return m_sentreep; }
|
AstSenTree* sentreep() const { return m_sentreep; }
|
||||||
void clearSentreep() { m_sentreep = nullptr; }
|
void clearSentreep() { m_sentreep = nullptr; }
|
||||||
};
|
};
|
||||||
|
class AstCLocalScope final : public AstNodeStmt {
|
||||||
|
// Pack statements into an unnamed scope when generating C++
|
||||||
|
// @astgen op1 := stmtsp : List[AstNode]
|
||||||
|
public:
|
||||||
|
AstCLocalScope(FileLine* fl, AstNode* stmtsp)
|
||||||
|
: ASTGEN_SUPER_CLocalScope(fl) {
|
||||||
|
addStmtsp(stmtsp);
|
||||||
|
}
|
||||||
|
ASTGEN_MEMBERS_AstCLocalScope;
|
||||||
|
};
|
||||||
class AstCReturn final : public AstNodeStmt {
|
class AstCReturn final : public AstNodeStmt {
|
||||||
// C++ return from a function
|
// C++ return from a function
|
||||||
// @astgen op1 := lhsp : AstNodeExpr
|
// @astgen op1 := lhsp : AstNodeExpr
|
||||||
@@ -382,6 +396,8 @@ public:
|
|||||||
, m_fromDollarC{fromDollarC} {}
|
, m_fromDollarC{fromDollarC} {}
|
||||||
ASTGEN_MEMBERS_AstCStmtUser;
|
ASTGEN_MEMBERS_AstCStmtUser;
|
||||||
// METHODS
|
// METHODS
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
bool isGateOptimizable() const override { return false; }
|
bool isGateOptimizable() const override { return false; }
|
||||||
bool isOutputter() override { return true; }
|
bool isOutputter() override { return true; }
|
||||||
bool isPredictOptimizable() const override { return false; }
|
bool isPredictOptimizable() const override { return false; }
|
||||||
@@ -447,10 +463,27 @@ public:
|
|||||||
, m_name{name}
|
, m_name{name}
|
||||||
, m_showAt{showAt} {}
|
, m_showAt{showAt} {}
|
||||||
ASTGEN_MEMBERS_AstComment;
|
ASTGEN_MEMBERS_AstComment;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
string name() const override VL_MT_STABLE { return m_name; } // * = Text
|
string name() const override VL_MT_STABLE { return m_name; } // * = Text
|
||||||
bool sameNode(const AstNode* samep) const override { return true; } // Ignore name in comments
|
bool sameNode(const AstNode* samep) const override { return true; } // Ignore name in comments
|
||||||
virtual bool showAt() const { return m_showAt; }
|
virtual bool showAt() const { return m_showAt; }
|
||||||
};
|
};
|
||||||
|
class AstConstraintBefore final : public AstNodeStmt {
|
||||||
|
// Constraint solve before item
|
||||||
|
// @astgen op1 := lhssp : List[AstNodeExpr]
|
||||||
|
// @astgen op2 := rhssp : List[AstNodeExpr]
|
||||||
|
public:
|
||||||
|
AstConstraintBefore(FileLine* fl, AstNodeExpr* lhssp, AstNodeExpr* rhssp)
|
||||||
|
: ASTGEN_SUPER_ConstraintBefore(fl) {
|
||||||
|
addLhssp(lhssp);
|
||||||
|
addRhssp(rhssp);
|
||||||
|
}
|
||||||
|
ASTGEN_MEMBERS_AstConstraintBefore;
|
||||||
|
bool isGateOptimizable() const override { return false; }
|
||||||
|
bool isPredictOptimizable() const override { return false; }
|
||||||
|
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||||
|
};
|
||||||
class AstConstraintExpr final : public AstNodeStmt {
|
class AstConstraintExpr final : public AstNodeStmt {
|
||||||
// Constraint expression
|
// Constraint expression
|
||||||
// @astgen op1 := exprp : AstNodeExpr
|
// @astgen op1 := exprp : AstNodeExpr
|
||||||
@@ -557,11 +590,11 @@ class AstDelay final : public AstNodeStmt {
|
|||||||
// @astgen op3 := rhsp : Optional[AstNodeExpr] // Max bound for cycle range or fall delay
|
// @astgen op3 := rhsp : Optional[AstNodeExpr] // Max bound for cycle range or fall delay
|
||||||
// @astgen op4 := throughoutp : Optional[AstNodeExpr] // Throughout condition (IEEE 16.9.9)
|
// @astgen op4 := throughoutp : Optional[AstNodeExpr] // Throughout condition (IEEE 16.9.9)
|
||||||
VTimescale m_timeunit; // Delay's time unit
|
VTimescale m_timeunit; // Delay's time unit
|
||||||
const bool m_isCycle; // True if it is a cycle delay
|
const bool m_isCycleDelay; // True if it is a cycle delay
|
||||||
public:
|
public:
|
||||||
AstDelay(FileLine* fl, AstNodeExpr* lhsp, bool isCycle)
|
AstDelay(FileLine* fl, AstNodeExpr* lhsp, bool isCycleDelay)
|
||||||
: ASTGEN_SUPER_Delay(fl)
|
: ASTGEN_SUPER_Delay(fl)
|
||||||
, m_isCycle{isCycle} {
|
, m_isCycleDelay{isCycleDelay} {
|
||||||
this->lhsp(lhsp);
|
this->lhsp(lhsp);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstDelay;
|
ASTGEN_MEMBERS_AstDelay;
|
||||||
@@ -571,11 +604,11 @@ public:
|
|||||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||||
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
||||||
VTimescale timeunit() const { return m_timeunit; }
|
VTimescale timeunit() const { return m_timeunit; }
|
||||||
bool isCycleDelay() const { return m_isCycle; }
|
bool isCycleDelay() const { return m_isCycleDelay; }
|
||||||
bool isRangeDelay() const { return m_isCycle && rhsp() != nullptr; }
|
bool isRangeDelay() const { return m_isCycleDelay && rhsp(); }
|
||||||
bool isUnbounded() const { return isRangeDelay() && VN_IS(rhsp(), Unbounded); }
|
bool isUnbounded() const { return isRangeDelay() && VN_IS(rhsp(), Unbounded); }
|
||||||
void fallDelay(AstNodeExpr* const fallDelayp) { rhsp(fallDelayp); }
|
void fallDelay(AstNodeExpr* const fallDelayp) { rhsp(fallDelayp); }
|
||||||
AstNodeExpr* fallDelay() const { return m_isCycle ? nullptr : rhsp(); }
|
AstNodeExpr* fallDelay() const { return m_isCycleDelay ? nullptr : rhsp(); }
|
||||||
};
|
};
|
||||||
class AstDisable final : public AstNodeStmt {
|
class AstDisable final : public AstNodeStmt {
|
||||||
// @astgen op1 := targetRefp : Optional[AstNodeExpr] // Reference to link in V3LinkDot
|
// @astgen op1 := targetRefp : Optional[AstNodeExpr] // Reference to link in V3LinkDot
|
||||||
@@ -598,6 +631,7 @@ public:
|
|||||||
explicit AstDisableFork(FileLine* fl)
|
explicit AstDisableFork(FileLine* fl)
|
||||||
: ASTGEN_SUPER_DisableFork(fl) {}
|
: ASTGEN_SUPER_DisableFork(fl) {}
|
||||||
ASTGEN_MEMBERS_AstDisableFork;
|
ASTGEN_MEMBERS_AstDisableFork;
|
||||||
|
string verilogKwd() const override { return "disable fork"; }
|
||||||
};
|
};
|
||||||
class AstDisplay final : public AstNodeStmt {
|
class AstDisplay final : public AstNodeStmt {
|
||||||
// Parents: stmtlist
|
// Parents: stmtlist
|
||||||
@@ -667,6 +701,8 @@ public:
|
|||||||
bool isPure() override { return false; }
|
bool isPure() override { return false; }
|
||||||
virtual bool cleanOut() const { return true; }
|
virtual bool cleanOut() const { return true; }
|
||||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
VDumpCtlType ctlType() const { return m_ctlType; }
|
VDumpCtlType ctlType() const { return m_ctlType; }
|
||||||
};
|
};
|
||||||
class AstEventControl final : public AstNodeStmt {
|
class AstEventControl final : public AstNodeStmt {
|
||||||
@@ -785,6 +821,8 @@ public:
|
|||||||
this->operandp(operandp);
|
this->operandp(operandp);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstFireEvent;
|
ASTGEN_MEMBERS_AstFireEvent;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
bool isDelayed() const { return m_delayed; }
|
bool isDelayed() const { return m_delayed; }
|
||||||
};
|
};
|
||||||
class AstInitialAutomaticStmt final : public AstNodeStmt {
|
class AstInitialAutomaticStmt final : public AstNodeStmt {
|
||||||
@@ -928,6 +966,8 @@ public:
|
|||||||
: ASTGEN_SUPER_MonitorOff(fl)
|
: ASTGEN_SUPER_MonitorOff(fl)
|
||||||
, m_off{off} {}
|
, m_off{off} {}
|
||||||
ASTGEN_MEMBERS_AstMonitorOff;
|
ASTGEN_MEMBERS_AstMonitorOff;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; }
|
string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; }
|
||||||
bool isGateOptimizable() const override { return false; } // Though deleted before opt
|
bool isGateOptimizable() const override { return false; } // Though deleted before opt
|
||||||
bool isPredictOptimizable() const override { return false; } // Though deleted before opt
|
bool isPredictOptimizable() const override { return false; } // Though deleted before opt
|
||||||
@@ -940,9 +980,9 @@ public:
|
|||||||
bool off() const { return m_off; }
|
bool off() const { return m_off; }
|
||||||
};
|
};
|
||||||
class AstPExprClause final : public AstNodeStmt {
|
class AstPExprClause final : public AstNodeStmt {
|
||||||
const bool m_pass; // True if will be replaced by passing assertion clause, false for
|
const bool m_pass; // Will be replaced by passing assertion clause, false for
|
||||||
// assertion failure clause
|
// assertion failure clause
|
||||||
const bool m_vacuous; // True if pass is vacuous
|
const bool m_vacuous; // Pass is vacuous
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ASTGEN_MEMBERS_AstPExprClause;
|
ASTGEN_MEMBERS_AstPExprClause;
|
||||||
@@ -950,6 +990,8 @@ public:
|
|||||||
: ASTGEN_SUPER_PExprClause(fl)
|
: ASTGEN_SUPER_PExprClause(fl)
|
||||||
, m_pass{pass}
|
, m_pass{pass}
|
||||||
, m_vacuous{vacuous} {}
|
, m_vacuous{vacuous} {}
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
bool pass() const { return m_pass; }
|
bool pass() const { return m_pass; }
|
||||||
bool vacuous() const { return m_vacuous; }
|
bool vacuous() const { return m_vacuous; }
|
||||||
};
|
};
|
||||||
@@ -1406,6 +1448,8 @@ public:
|
|||||||
, m_quotedPrefix{quotedPrefix} {}
|
, m_quotedPrefix{quotedPrefix} {}
|
||||||
ASTGEN_MEMBERS_AstTracePushPrefix;
|
ASTGEN_MEMBERS_AstTracePushPrefix;
|
||||||
bool sameNode(const AstNode* samep) const override { return false; }
|
bool sameNode(const AstNode* samep) const override { return false; }
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
string prefix() const { return m_prefix; }
|
string prefix() const { return m_prefix; }
|
||||||
VTracePrefixType prefixType() const { return m_prefixType; }
|
VTracePrefixType prefixType() const { return m_prefixType; }
|
||||||
int left() const { return m_left; }
|
int left() const { return m_left; }
|
||||||
@@ -1431,6 +1475,7 @@ public:
|
|||||||
: ASTGEN_SUPER_WaitFork(fl) {}
|
: ASTGEN_SUPER_WaitFork(fl) {}
|
||||||
ASTGEN_MEMBERS_AstWaitFork;
|
ASTGEN_MEMBERS_AstWaitFork;
|
||||||
bool isTimingControl() const override { return true; }
|
bool isTimingControl() const override { return true; }
|
||||||
|
string verilogKwd() const override { return "wait fork"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// === AstNodeAssign ===
|
// === AstNodeAssign ===
|
||||||
@@ -1568,15 +1613,23 @@ class AstFork final : public AstNodeBlock {
|
|||||||
//
|
//
|
||||||
// @astgen op3 := forksp : List[AstBegin]
|
// @astgen op3 := forksp : List[AstBegin]
|
||||||
const VJoinType m_joinType; // Join keyword type
|
const VJoinType m_joinType; // Join keyword type
|
||||||
|
bool m_immediateStart = false; // Fork starts before its parent blocks or exits
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstFork(FileLine* fl, VJoinType joinType, const string& name = "")
|
AstFork(FileLine* fl, VJoinType joinType, const string& name = "")
|
||||||
: ASTGEN_SUPER_Fork(fl, name)
|
: ASTGEN_SUPER_Fork(fl, name)
|
||||||
, m_joinType{joinType} {}
|
, m_joinType{joinType} {}
|
||||||
ASTGEN_MEMBERS_AstFork;
|
ASTGEN_MEMBERS_AstFork;
|
||||||
|
bool sameNode(const AstNode* samep) const override {
|
||||||
|
const AstFork* const asamep = VN_DBG_AS(samep, Fork);
|
||||||
|
return joinType() == asamep->joinType() && immediateStart() == asamep->immediateStart();
|
||||||
|
}
|
||||||
bool isTimingControl() const override { return !joinType().joinNone(); }
|
bool isTimingControl() const override { return !joinType().joinNone(); }
|
||||||
void dump(std::ostream& str) const override;
|
void dump(std::ostream& str) const override;
|
||||||
void dumpJson(std::ostream& str) const override;
|
void dumpJson(std::ostream& str) const override;
|
||||||
VJoinType joinType() const { return m_joinType; }
|
VJoinType joinType() const { return m_joinType; }
|
||||||
|
bool immediateStart() const { return m_immediateStart; }
|
||||||
|
void immediateStart(bool flag) { m_immediateStart = flag; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// === AstNodeCoverOrAssert ===
|
// === AstNodeCoverOrAssert ===
|
||||||
@@ -1612,6 +1665,8 @@ class AstCover final : public AstNodeCoverOrAssert {
|
|||||||
// @astgen op3 := coverincsp: List[AstNode] // Coverage node
|
// @astgen op3 := coverincsp: List[AstNode] // Coverage node
|
||||||
bool m_isCoverSeq = false; // 'cover sequence' (IEEE 1800-2023 16.14.3): fires per
|
bool m_isCoverSeq = false; // 'cover sequence' (IEEE 1800-2023 16.14.3): fires per
|
||||||
// end-of-match, not per property success
|
// 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:
|
public:
|
||||||
ASTGEN_MEMBERS_AstCover;
|
ASTGEN_MEMBERS_AstCover;
|
||||||
AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, VAssertType type,
|
AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, VAssertType type,
|
||||||
@@ -1622,6 +1677,8 @@ public:
|
|||||||
void dumpJson(std::ostream& str) const override;
|
void dumpJson(std::ostream& str) const override;
|
||||||
bool isCoverSeq() const { return m_isCoverSeq; }
|
bool isCoverSeq() const { return m_isCoverSeq; }
|
||||||
void isCoverSeq(bool flag) { m_isCoverSeq = flag; }
|
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 {
|
class AstRestrict final : public AstNodeCoverOrAssert {
|
||||||
public:
|
public:
|
||||||
@@ -1636,10 +1693,16 @@ public:
|
|||||||
// === AstNodeForeach ===
|
// === AstNodeForeach ===
|
||||||
class AstConstraintForeach final : public AstNodeForeach {
|
class AstConstraintForeach final : public AstNodeForeach {
|
||||||
// Constraint foreach statement
|
// Constraint foreach statement
|
||||||
|
bool m_soft; // is soft foreach, non-standard extension
|
||||||
public:
|
public:
|
||||||
AstConstraintForeach(FileLine* fl, AstForeachHeader* headerp, AstNode* bodyp)
|
AstConstraintForeach(FileLine* fl, AstForeachHeader* headerp, AstNode* bodyp,
|
||||||
: ASTGEN_SUPER_ConstraintForeach(fl, headerp, bodyp) {}
|
bool soft = false)
|
||||||
|
: ASTGEN_SUPER_ConstraintForeach(fl, headerp, bodyp)
|
||||||
|
, m_soft{soft} {}
|
||||||
ASTGEN_MEMBERS_AstConstraintForeach;
|
ASTGEN_MEMBERS_AstConstraintForeach;
|
||||||
|
bool isSoft() const { return m_soft; }
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
};
|
};
|
||||||
class AstForeach final : public AstNodeForeach {
|
class AstForeach final : public AstNodeForeach {
|
||||||
public:
|
public:
|
||||||
@@ -1670,6 +1733,8 @@ public:
|
|||||||
void unique0Pragma(bool flag) { m_unique0Pragma = flag; }
|
void unique0Pragma(bool flag) { m_unique0Pragma = flag; }
|
||||||
bool priorityPragma() const { return m_priorityPragma; }
|
bool priorityPragma() const { return m_priorityPragma; }
|
||||||
void priorityPragma(bool flag) { m_priorityPragma = flag; }
|
void priorityPragma(bool flag) { m_priorityPragma = flag; }
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
|
void dumpJson(std::ostream& str) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// === AstNodeReadWriteMem ===
|
// === AstNodeReadWriteMem ===
|
||||||
|
|||||||
+399
-38
@@ -22,6 +22,8 @@
|
|||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
#include "V3Graph.h"
|
#include "V3Graph.h"
|
||||||
#include "V3Hasher.h"
|
#include "V3Hasher.h"
|
||||||
|
#include "V3InstrCount.h"
|
||||||
|
#include "V3Stats.h"
|
||||||
#include "V3String.h"
|
#include "V3String.h"
|
||||||
|
|
||||||
#include "V3Ast__gen_impl.h" // Generated by 'astgen'
|
#include "V3Ast__gen_impl.h" // Generated by 'astgen'
|
||||||
@@ -108,11 +110,27 @@ int AstNodeSel::bitConst() const {
|
|||||||
return (constp ? constp->toSInt() : 0);
|
return (constp ? constp->toSInt() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AstNode::isDisableQueuePushSelfStmt() {
|
||||||
|
// Detect LinkJump-generated registration:
|
||||||
|
// __VprocessQueue_*.push_back(std::process::self())
|
||||||
|
AstStmtExpr* const stmtExprp = VN_CAST(this, StmtExpr);
|
||||||
|
if (!stmtExprp) return false;
|
||||||
|
AstCMethodHard* const methodp = VN_CAST(stmtExprp->exprp(), CMethodHard);
|
||||||
|
if (!methodp || methodp->name() != "push_back") return false;
|
||||||
|
AstNode* const basep = AstArraySel::baseFromp(methodp->fromp(), false);
|
||||||
|
if (AstVarRef* const refp = VN_CAST(basep, VarRef)) return refp->varp()->processQueue();
|
||||||
|
if (AstMemberSel* const selp = VN_CAST(basep, MemberSel)) {
|
||||||
|
return selp->varp() && selp->varp()->processQueue();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||||
void AstNodeStmt::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstNodeStmt::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||||
|
|
||||||
void AstNodeCCall::dump(std::ostream& str) const {
|
void AstNodeCCall::dump(std::ostream& str) const {
|
||||||
this->AstNodeExpr::dump(str);
|
this->AstNodeExpr::dump(str);
|
||||||
|
if (superReference()) str << " [SUPERREF]";
|
||||||
if (funcp()) {
|
if (funcp()) {
|
||||||
str << " " << funcp()->name() << " => ";
|
str << " " << funcp()->name() << " => ";
|
||||||
funcp()->dump(str);
|
funcp()->dump(str);
|
||||||
@@ -121,6 +139,7 @@ void AstNodeCCall::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void AstNodeCCall::dumpJson(std::ostream& str) const {
|
void AstNodeCCall::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, superReference);
|
||||||
if (funcp()) dumpJsonStr(str, "funcName", funcp()->name());
|
if (funcp()) dumpJsonStr(str, "funcName", funcp()->name());
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
@@ -420,14 +439,19 @@ void AstCReset::dumpJson(std::ostream& str) const {
|
|||||||
void AstCase::dump(std::ostream& str) const {
|
void AstCase::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " " << verilogKwd();
|
str << " " << verilogKwd();
|
||||||
|
if (fullPragma()) str << " [FULL]";
|
||||||
|
if (parallelPragma()) str << " [PAR]";
|
||||||
|
if (priorityPragma()) str << " [PRI]";
|
||||||
|
if (uniquePragma()) str << " [UNQ]";
|
||||||
|
if (unique0Pragma()) str << " [UNQ0]";
|
||||||
}
|
}
|
||||||
void AstCase::dumpJson(std::ostream& str) const {
|
void AstCase::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonStr(str, "kwd", verilogKwd());
|
dumpJsonStr(str, "kwd", verilogKwd());
|
||||||
dumpJsonBoolIf(str, "full", fullPragma());
|
dumpJsonBoolIf(str, "full", fullPragma());
|
||||||
dumpJsonBoolIf(str, "parallel", parallelPragma());
|
dumpJsonBoolIf(str, "parallel", parallelPragma());
|
||||||
|
dumpJsonBoolIf(str, "priority", priorityPragma());
|
||||||
dumpJsonBoolIf(str, "unique", uniquePragma());
|
dumpJsonBoolIf(str, "unique", uniquePragma());
|
||||||
dumpJsonBoolIf(str, "unique0", unique0Pragma());
|
dumpJsonBoolIf(str, "unique0", unique0Pragma());
|
||||||
dumpJsonBoolIf(str, "priority", priorityPragma());
|
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,6 +492,14 @@ void AstSConsRep::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonBoolFuncIf(str, unbounded);
|
dumpJsonBoolFuncIf(str, unbounded);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
} // LCOV_EXCL_STOP
|
} // LCOV_EXCL_STOP
|
||||||
|
void AstSAnd::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeExpr::dump(str);
|
||||||
|
if (propertyControl()) str << " [PROPERTY_CONTROL]";
|
||||||
|
}
|
||||||
|
void AstSAnd::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, propertyControl);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstPropAlways::dump(std::ostream& str) const {
|
void AstPropAlways::dump(std::ostream& str) const {
|
||||||
this->AstNodeExpr::dump(str);
|
this->AstNodeExpr::dump(str);
|
||||||
if (isStrong()) str << " [strong]";
|
if (isStrong()) str << " [strong]";
|
||||||
@@ -495,6 +527,7 @@ void AstConstraint::dump(std::ostream& str) const {
|
|||||||
str << " [PROTO]";
|
str << " [PROTO]";
|
||||||
if (isKwdPure()) str << " [KWDPURE]";
|
if (isKwdPure()) str << " [KWDPURE]";
|
||||||
if (isStatic()) str << " [STATIC]";
|
if (isStatic()) str << " [STATIC]";
|
||||||
|
if (baseOverride().isAny()) str << " [" << baseOverride().ascii() << "]";
|
||||||
}
|
}
|
||||||
void AstConstraint::dumpJson(std::ostream& str) const {
|
void AstConstraint::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonBoolFuncIf(str, isExternDef);
|
dumpJsonBoolFuncIf(str, isExternDef);
|
||||||
@@ -579,6 +612,15 @@ const char* AstNetlist::broken() const {
|
|||||||
for (const AstVar* const varp : m_deferredParamVarps) {
|
for (const AstVar* const varp : m_deferredParamVarps) {
|
||||||
BROKEN_RTN(!varp || !varp->brokeExists());
|
BROKEN_RTN(!varp || !varp->brokeExists());
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < VEval::_ENUM_END; ++i) {
|
||||||
|
const AstCFunc* const funcp = m_evalFuncps[i];
|
||||||
|
const AstCFunc* const dumpp = m_dumpTriggersFuncps[i];
|
||||||
|
BROKEN_RTN(funcp && !funcp->brokeExists());
|
||||||
|
BROKEN_RTN(dumpp && !dumpp->brokeExists());
|
||||||
|
// Once created, an entry point has a trigger dump iff it has triggers
|
||||||
|
BROKEN_RTN(funcp && VEval{i}.hasTriggers() && !dumpp);
|
||||||
|
BROKEN_RTN(dumpp && !VEval{i}.hasTriggers());
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -694,13 +736,17 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
|
|||||||
|
|
||||||
asRef = asRef || isDpiOpenArray() || (forFunc && (isWritable() || isRef() || isConstRef()));
|
asRef = asRef || isDpiOpenArray() || (forFunc && (isWritable() || isRef() || isConstRef()));
|
||||||
|
|
||||||
if (forFunc && (isReadOnly() || constRef) && asRef) ostatic = ostatic + "const ";
|
|
||||||
|
|
||||||
string oname;
|
string oname;
|
||||||
if (named) {
|
if (named) {
|
||||||
if (!namespc.empty()) oname += namespc + "::";
|
if (!namespc.empty()) oname += namespc + "::";
|
||||||
oname += VIdProtect::protectIf(name(), protect());
|
oname += VIdProtect::protectIf(name(), protect());
|
||||||
}
|
}
|
||||||
|
if (forFunc && (isReadOnly() || constRef) && asRef) {
|
||||||
|
if (VN_IS(dtypep()->skipRefp(), IfaceRefDType)) {
|
||||||
|
return ostatic + dtypep()->cType("", forFunc, false) + " const &" + oname;
|
||||||
|
}
|
||||||
|
ostatic += "const ";
|
||||||
|
}
|
||||||
return ostatic + dtypep()->cType(oname, forFunc, asRef);
|
return ostatic + dtypep()->cType(oname, forFunc, asRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1179,7 +1225,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packe
|
|||||||
info.m_type = "VlSampleQueue<" + sub.m_type + ">";
|
info.m_type = "VlSampleQueue<" + sub.m_type + ">";
|
||||||
} else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) {
|
} else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) {
|
||||||
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
||||||
info.m_type = "VlClassRef<" + EmitCUtil::prefixNameProtect(adtypep) + ">";
|
const string className = EmitCUtil::prefixNameProtect(adtypep);
|
||||||
|
info.m_type = adtypep->rawPointer() ? className + "*" : "VlClassRef<" + className + ">";
|
||||||
} else if (const auto* const adtypep = VN_CAST(dtypep, IfaceRefDType)) {
|
} else if (const auto* const adtypep = VN_CAST(dtypep, IfaceRefDType)) {
|
||||||
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
||||||
info.m_type = EmitCUtil::prefixNameProtect(adtypep->ifaceViaCellp()) + "*";
|
info.m_type = EmitCUtil::prefixNameProtect(adtypep->ifaceViaCellp()) + "*";
|
||||||
@@ -1401,6 +1448,9 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
|
|||||||
} else if (VN_IS(nodep, WildcardSel)) {
|
} else if (VN_IS(nodep, WildcardSel)) {
|
||||||
nodep = VN_AS(nodep, WildcardSel)->fromp();
|
nodep = VN_AS(nodep, WildcardSel)->fromp();
|
||||||
continue;
|
continue;
|
||||||
|
} else if (VN_IS(nodep, CMethodHard)) {
|
||||||
|
nodep = VN_AS(nodep, CMethodHard)->fromp();
|
||||||
|
continue;
|
||||||
} else if (overMembers && VN_IS(nodep, MemberSel)) {
|
} else if (overMembers && VN_IS(nodep, MemberSel)) {
|
||||||
nodep = VN_AS(nodep, MemberSel)->fromp();
|
nodep = VN_AS(nodep, MemberSel)->fromp();
|
||||||
continue;
|
continue;
|
||||||
@@ -1815,10 +1865,16 @@ void AstNode::dump(std::ostream& str) const {
|
|||||||
#endif
|
#endif
|
||||||
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno()
|
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno()
|
||||||
<< fileline()->firstColumnLetters() << "}";
|
<< fileline()->firstColumnLetters() << "}";
|
||||||
if (user1p()) str << " u1=" << nodeAddr(user1p());
|
const auto dumpUser = [&str](const char* prefix, const VNUser& user) {
|
||||||
if (user2p()) str << " u2=" << nodeAddr(user2p());
|
const std::string s = user.dumpStr([](const void* p) -> std::string {
|
||||||
if (user3p()) str << " u3=" << nodeAddr(user3p());
|
return nodeAddr(reinterpret_cast<const AstNode*>(p));
|
||||||
if (user4p()) str << " u4=" << nodeAddr(user4p());
|
});
|
||||||
|
if (!s.empty()) str << prefix << s;
|
||||||
|
};
|
||||||
|
dumpUser(" u1=", user1u());
|
||||||
|
dumpUser(" u2=", user2u());
|
||||||
|
dumpUser(" u3=", user3u());
|
||||||
|
dumpUser(" u4=", user4u());
|
||||||
if (hasDType()) {
|
if (hasDType()) {
|
||||||
// Final @ so less likely to by accident read it as a nodep
|
// Final @ so less likely to by accident read it as a nodep
|
||||||
if (dtypep() == this) {
|
if (dtypep() == this) {
|
||||||
@@ -1830,6 +1886,7 @@ void AstNode::dump(std::ostream& str) const {
|
|||||||
} else { // V3Broken will throw an error
|
} else { // V3Broken will throw an error
|
||||||
if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
|
if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
|
||||||
}
|
}
|
||||||
|
if (fileline()->erroringOn()) str << " [ERRORING]";
|
||||||
if (name() != "") {
|
if (name() != "") {
|
||||||
if (VN_IS(this, Const)) {
|
if (VN_IS(this, Const)) {
|
||||||
str << " " << name(); // Already quoted
|
str << " " << name(); // Already quoted
|
||||||
@@ -1933,15 +1990,15 @@ void AstAssertCtl::dump(std::ostream& str) const {
|
|||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (ctlType() != VAssertCtlType::_TO_BE_EVALUATED) {
|
if (ctlType() != VAssertCtlType::_TO_BE_EVALUATED) {
|
||||||
str << " [" << ctlType().ascii() << "]";
|
str << " [" << ctlType().ascii() << "]";
|
||||||
str << " [" << ctlAssertTypes().ascii() << "]";
|
str << " [" << assertTypes().ascii() << "]";
|
||||||
str << " [" << ctlDirectiveTypes().ascii() << "]";
|
str << " [" << directiveTypes().ascii() << "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void AstAssertCtl::dumpJson(std::ostream& str) const {
|
void AstAssertCtl::dumpJson(std::ostream& str) const {
|
||||||
if (ctlType() != VAssertCtlType::_TO_BE_EVALUATED) {
|
if (ctlType() != VAssertCtlType::_TO_BE_EVALUATED) {
|
||||||
dumpJsonStr(str, "ctlType", ctlType().ascii());
|
dumpJsonStr(str, "ctlType", ctlType().ascii());
|
||||||
dumpJsonStr(str, "ctlAssertTypes", ctlAssertTypes().ascii());
|
dumpJsonStr(str, "assertTypes", assertTypes().ascii());
|
||||||
dumpJsonStr(str, "ctlDirectiveTypes", ctlDirectiveTypes().ascii());
|
dumpJsonStr(str, "directiveTypes", directiveTypes().ascii());
|
||||||
}
|
}
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
@@ -1977,6 +2034,18 @@ string AstBasicDType::prettyDTypeName(bool) const {
|
|||||||
void AstNodeExpr::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
void AstNodeExpr::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||||
void AstNodeExpr::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstNodeExpr::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||||
|
|
||||||
|
void AstPropSpec::dump(std::ostream& str) const {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
if (propStrength() != VPropStrength::DEFAULT) {
|
||||||
|
str << " [" << VString::upcase(propStrength().ascii()) << "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void AstPropSpec::dumpJson(std::ostream& str) const {
|
||||||
|
if (propStrength() != VPropStrength::DEFAULT)
|
||||||
|
dumpJsonStr(str, "strength", propStrength().ascii());
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
|
||||||
AstConst::~AstConst() {
|
AstConst::~AstConst() {
|
||||||
// Only rare constants carry originating parameter-name metadata. For all other AstConst nodes,
|
// Only rare constants carry originating parameter-name metadata. For all other AstConst nodes,
|
||||||
// the V3Number bit keeps this destructor from touching AstNetlist's side table. When the bit
|
// the V3Number bit keeps this destructor from touching AstNetlist's side table. When the bit
|
||||||
@@ -2022,6 +2091,8 @@ bool AstNodeExpr::isLValue() const {
|
|||||||
return varrefp->access().isWriteOrRW();
|
return varrefp->access().isWriteOrRW();
|
||||||
} else if (const AstMemberSel* const memberselp = VN_CAST(this, MemberSel)) {
|
} else if (const AstMemberSel* const memberselp = VN_CAST(this, MemberSel)) {
|
||||||
return memberselp->access().isWriteOrRW();
|
return memberselp->access().isWriteOrRW();
|
||||||
|
} else if (const AstStructSel* const structselp = VN_CAST(this, StructSel)) {
|
||||||
|
return structselp->fromp()->isLValue();
|
||||||
} else if (const AstSel* const selp = VN_CAST(this, Sel)) {
|
} else if (const AstSel* const selp = VN_CAST(this, Sel)) {
|
||||||
return selp->fromp()->isLValue();
|
return selp->fromp()->isLValue();
|
||||||
} else if (const AstNodeSel* const nodeSelp = VN_CAST(this, NodeSel)) {
|
} else if (const AstNodeSel* const nodeSelp = VN_CAST(this, NodeSel)) {
|
||||||
@@ -2080,6 +2151,7 @@ void AstCell::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void AstCell::dumpJson(std::ostream& str) const {
|
void AstCell::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonStrFunc(str, modName);
|
||||||
dumpJsonStrFunc(str, origName);
|
dumpJsonStrFunc(str, origName);
|
||||||
dumpJsonStrFunc(str, verilogName);
|
dumpJsonStrFunc(str, verilogName);
|
||||||
dumpJsonBoolFuncIf(str, recursive);
|
dumpJsonBoolFuncIf(str, recursive);
|
||||||
@@ -2110,6 +2182,14 @@ void AstCExpr::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonBoolIf(str, "pure", m_pure);
|
dumpJsonBoolIf(str, "pure", m_pure);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
|
void AstCExprUser::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeExpr::dump(str);
|
||||||
|
if (m_pure) str << " [PURE]";
|
||||||
|
}
|
||||||
|
void AstCExprUser::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolIf(str, "pure", m_pure);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
bool AstClass::isCacheableChild(const AstNode* nodep) {
|
bool AstClass::isCacheableChild(const AstNode* nodep) {
|
||||||
return VN_IS(nodep, Var) || VN_IS(nodep, Typedef)
|
return VN_IS(nodep, Var) || VN_IS(nodep, Typedef)
|
||||||
|| (VN_IS(nodep, Constraint) && !VN_AS(nodep, Constraint)->isExternProto())
|
|| (VN_IS(nodep, Constraint) && !VN_AS(nodep, Constraint)->isExternProto())
|
||||||
@@ -2136,26 +2216,32 @@ void AstClass::dump(std::ostream& str) const {
|
|||||||
if (isCovergroup()) str << " [CG]";
|
if (isCovergroup()) str << " [CG]";
|
||||||
if (isExtended()) str << " [EXT]";
|
if (isExtended()) str << " [EXT]";
|
||||||
if (isInterfaceClass()) str << " [IFCCLS]";
|
if (isInterfaceClass()) str << " [IFCCLS]";
|
||||||
if (isVirtual()) str << " [VIRT]";
|
|
||||||
if (useVirtualPublic()) str << " [VIRPUB]";
|
|
||||||
if (isPrintedFrom()) str << " [PRINTED]";
|
if (isPrintedFrom()) str << " [PRINTED]";
|
||||||
|
if (isVirtual()) str << " [VIRT]";
|
||||||
|
if (needRNG()) str << " [NRNG]";
|
||||||
|
if (useVirtualPublic()) str << " [VIRPUB]";
|
||||||
|
if (baseOverride().isAny()) str << " [" << baseOverride().ascii() << "]";
|
||||||
}
|
}
|
||||||
void AstClass::dumpJson(std::ostream& str) const {
|
void AstClass::dumpJson(std::ostream& str) const {
|
||||||
// dumpJsonNumFunc(str, declTokenNum); // Not dumped as adding token changes whole file
|
// dumpJsonNumFunc(str, declTokenNum); // Not dumped as adding token changes whole file
|
||||||
dumpJsonBoolFuncIf(str, isCovergroup);
|
dumpJsonBoolFuncIf(str, isCovergroup);
|
||||||
dumpJsonBoolFuncIf(str, isExtended);
|
dumpJsonBoolFuncIf(str, isExtended);
|
||||||
dumpJsonBoolFuncIf(str, isInterfaceClass);
|
dumpJsonBoolFuncIf(str, isInterfaceClass);
|
||||||
dumpJsonBoolFuncIf(str, isVirtual);
|
|
||||||
dumpJsonBoolFuncIf(str, isPrintedFrom);
|
dumpJsonBoolFuncIf(str, isPrintedFrom);
|
||||||
|
dumpJsonBoolFuncIf(str, isVirtual);
|
||||||
|
dumpJsonBoolFuncIf(str, needRNG);
|
||||||
|
dumpJsonBoolFuncIf(str, useVirtualPublic);
|
||||||
if (baseOverride().isAny()) dumpJsonStr(str, "baseOverride", baseOverride().ascii());
|
if (baseOverride().isAny()) dumpJsonStr(str, "baseOverride", baseOverride().ascii());
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
void AstClassExtends::dump(std::ostream& str) const {
|
void AstClassExtends::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (isImplements()) str << " [IMPLEMENTS]";
|
if (isImplements()) str << " [IMPL]";
|
||||||
|
if (parameterized()) str << " [PAR]";
|
||||||
}
|
}
|
||||||
void AstClassExtends::dumpJson(std::ostream& str) const {
|
void AstClassExtends::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonBoolFuncIf(str, isImplements);
|
dumpJsonBoolFuncIf(str, isImplements);
|
||||||
|
dumpJsonBoolFuncIf(str, parameterized);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
AstClass* AstClassExtends::classOrNullp() const {
|
AstClass* AstClassExtends::classOrNullp() const {
|
||||||
@@ -2181,8 +2267,22 @@ void AstClassRefDType::dump(std::ostream& str) const {
|
|||||||
} else {
|
} else {
|
||||||
str << " -> UNLINKED";
|
str << " -> UNLINKED";
|
||||||
}
|
}
|
||||||
|
if (rawPointer()) str << " [RAWPTR]";
|
||||||
|
}
|
||||||
|
void AstClassRefDType::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, rawPointer);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
void AstClassRefDType::selfTest() {
|
||||||
|
FileLine* const fl = new FileLine{FileLine::commandLineFilename()};
|
||||||
|
AstClassRefDType* const owningp = new AstClassRefDType{fl, nullptr, nullptr};
|
||||||
|
AstClassRefDType* const rawp = new AstClassRefDType{fl, nullptr, nullptr};
|
||||||
|
rawp->rawPointer(true);
|
||||||
|
UASSERT_OBJ(!owningp->sameNode(rawp) && !rawp->sameNode(owningp) && rawp->sameNode(rawp), rawp,
|
||||||
|
"Raw class pointer must have distinct type identity");
|
||||||
|
VL_DO_DANGLING(owningp->deleteTree(), owningp);
|
||||||
|
VL_DO_DANGLING(rawp->deleteTree(), rawp);
|
||||||
}
|
}
|
||||||
void AstClassRefDType::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
|
||||||
void AstClassRefDType::dumpSmall(std::ostream& str) const {
|
void AstClassRefDType::dumpSmall(std::ostream& str) const {
|
||||||
this->AstNodeDType::dumpSmall(str);
|
this->AstNodeDType::dumpSmall(str);
|
||||||
str << "class:" << name();
|
str << "class:" << name();
|
||||||
@@ -2241,11 +2341,21 @@ void AstNodeCoverOrAssert::dumpJson(std::ostream& str) const {
|
|||||||
void AstCover::dump(std::ostream& str) const {
|
void AstCover::dump(std::ostream& str) const {
|
||||||
this->AstNodeCoverOrAssert::dump(str);
|
this->AstNodeCoverOrAssert::dump(str);
|
||||||
if (isCoverSeq()) str << " [COVERSEQ]";
|
if (isCoverSeq()) str << " [COVERSEQ]";
|
||||||
|
if (isSeqEvent()) str << " [SEQEVENT]";
|
||||||
}
|
}
|
||||||
void AstCover::dumpJson(std::ostream& str) const {
|
void AstCover::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonBoolFuncIf(str, isCoverSeq);
|
dumpJsonBoolFuncIf(str, isCoverSeq);
|
||||||
|
dumpJsonBoolFuncIf(str, isSeqEvent);
|
||||||
this->AstNodeCoverOrAssert::dumpJson(str);
|
this->AstNodeCoverOrAssert::dumpJson(str);
|
||||||
}
|
}
|
||||||
|
void AstConstraintForeach::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeForeach::dump(str);
|
||||||
|
if (isSoft()) str << "[SOFT]";
|
||||||
|
}
|
||||||
|
void AstConstraintForeach::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, isSoft);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstClocking::dump(std::ostream& str) const {
|
void AstClocking::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (isDefault()) str << " [DEFAULT]";
|
if (isDefault()) str << " [DEFAULT]";
|
||||||
@@ -2286,7 +2396,26 @@ void AstDisplay::dump(std::ostream& str) const {
|
|||||||
this->AstNodeStmt::dump(str);
|
this->AstNodeStmt::dump(str);
|
||||||
str << " [" << displayType().ascii() << "]";
|
str << " [" << displayType().ascii() << "]";
|
||||||
}
|
}
|
||||||
void AstDisplay::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstDisplay::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonStr(str, "displayType", displayType().ascii());
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
void AstDistItem::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeExpr::dump(str);
|
||||||
|
if (isWhole()) str << " [WHOLE]";
|
||||||
|
}
|
||||||
|
void AstDistItem::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, isWhole);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
void AstDumpCtl::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeStmt::dump(str);
|
||||||
|
str << " [" << ctlType().ascii() << "]";
|
||||||
|
}
|
||||||
|
void AstDumpCtl::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonStr(str, "ctlType", ctlType().ascii());
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstEnumDType::dump(std::ostream& str) const {
|
void AstEnumDType::dump(std::ostream& str) const {
|
||||||
this->AstNodeDType::dump(str);
|
this->AstNodeDType::dump(str);
|
||||||
str << " enum";
|
str << " enum";
|
||||||
@@ -2348,6 +2477,29 @@ void AstGenBlock::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AstNodeIf::dump(std::ostream& str) const {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
if (isBoundsCheck()) str << " [BOUNDS]";
|
||||||
|
}
|
||||||
|
void AstNodeIf::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolIf(str, "isBoundsCheck", isBoundsCheck());
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
void AstIf::dump(std::ostream& str) const {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
str << " " << verilogKwd();
|
||||||
|
if (priorityPragma()) str << " [PRI]";
|
||||||
|
if (uniquePragma()) str << " [UNQ]";
|
||||||
|
if (unique0Pragma()) str << " [UNQ0]";
|
||||||
|
}
|
||||||
|
void AstIf::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonStr(str, "kwd", verilogKwd());
|
||||||
|
dumpJsonBoolIf(str, "priority", priorityPragma());
|
||||||
|
dumpJsonBoolIf(str, "unique", uniquePragma());
|
||||||
|
dumpJsonBoolIf(str, "unique0", unique0Pragma());
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
|
||||||
void AstIfaceRefDType::dump(std::ostream& str) const {
|
void AstIfaceRefDType::dump(std::ostream& str) const {
|
||||||
this->AstNodeDType::dump(str);
|
this->AstNodeDType::dump(str);
|
||||||
if (isPortDecl()) str << " [PORTDECL]";
|
if (isPortDecl()) str << " [PORTDECL]";
|
||||||
@@ -2485,13 +2637,17 @@ const char* AstLoopTest::broken() const {
|
|||||||
|
|
||||||
void AstMemberDType::dump(std::ostream& str) const {
|
void AstMemberDType::dump(std::ostream& str) const {
|
||||||
this->AstNodeDType::dump(str);
|
this->AstNodeDType::dump(str);
|
||||||
if (isConstrainedRand()) str << " [CONSTRAINEDRAND]";
|
if (isConstrainedRand()) str << " [CSRAND]";
|
||||||
|
if (rand().isRandomizable()) str << " [" << rand() << "]";
|
||||||
|
if (lsb()) str << " lsb=" << lsb();
|
||||||
if (name() != "") str << " name=" << name();
|
if (name() != "") str << " name=" << name();
|
||||||
if (tag() != "") str << " tag=" << tag();
|
if (tag() != "") str << " tag=" << tag();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstMemberDType::dumpJson(std::ostream& str) const {
|
void AstMemberDType::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonBoolFuncIf(str, isConstrainedRand);
|
dumpJsonBoolFuncIf(str, isConstrainedRand);
|
||||||
|
if (rand().isRandomizable()) dumpJsonStr(str, "rand", rand().ascii());
|
||||||
|
if (lsb() != 0) dumpJsonStr(str, "lsb", std::to_string(lsb()));
|
||||||
dumpJsonStrFunc(str, name);
|
dumpJsonStrFunc(str, name);
|
||||||
dumpJsonStrFunc(str, tag);
|
dumpJsonStrFunc(str, tag);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
@@ -2584,6 +2740,14 @@ void AstModule::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonBoolFuncIf(str, hasGenericIface);
|
dumpJsonBoolFuncIf(str, hasGenericIface);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
|
void AstMonitorOff::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeStmt::dump(str);
|
||||||
|
if (off()) str << " [OFF]";
|
||||||
|
}
|
||||||
|
void AstMonitorOff::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, off);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstPin::dump(std::ostream& str) const {
|
void AstPin::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (modVarp()) {
|
if (modVarp()) {
|
||||||
@@ -2592,11 +2756,13 @@ void AstPin::dump(std::ostream& str) const {
|
|||||||
} else {
|
} else {
|
||||||
str << " ->UNLINKED";
|
str << " ->UNLINKED";
|
||||||
}
|
}
|
||||||
|
if (param()) str << " [PAR]";
|
||||||
if (!paramPath().empty()) str << " paramPath=" << paramPath();
|
if (!paramPath().empty()) str << " paramPath=" << paramPath();
|
||||||
if (svDotName()) str << " [.n]";
|
if (svDotName()) str << " [.n]";
|
||||||
if (svImplicit()) str << " [.SV]";
|
if (svImplicit()) str << " [.SV]";
|
||||||
}
|
}
|
||||||
void AstPin::dumpJson(std::ostream& str) const {
|
void AstPin::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, param);
|
||||||
dumpJsonBoolFuncIf(str, svDotName);
|
dumpJsonBoolFuncIf(str, svDotName);
|
||||||
dumpJsonBoolFuncIf(str, svImplicit);
|
dumpJsonBoolFuncIf(str, svImplicit);
|
||||||
if (!paramPath().empty()) dumpJsonStr(str, "paramPath", paramPath());
|
if (!paramPath().empty()) dumpJsonStr(str, "paramPath", paramPath());
|
||||||
@@ -2630,7 +2796,14 @@ void AstPrintTimeScale::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
|
void AstPull::dump(std::ostream& str) const {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
if (direction()) str << " [UP]";
|
||||||
|
}
|
||||||
|
void AstPull::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, direction);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstTime::dump(std::ostream& str) const {
|
void AstTime::dump(std::ostream& str) const {
|
||||||
this->AstNodeTermop::dump(str);
|
this->AstNodeTermop::dump(str);
|
||||||
str << " " << timeunit();
|
str << " " << timeunit();
|
||||||
@@ -2655,6 +2828,16 @@ void AstTimeImport::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
|
void AstTracePushPrefix::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeStmt::dump(str);
|
||||||
|
if (m_quotedPrefix) str << " [QUOTE]";
|
||||||
|
str << " [" << prefixType().ascii() << "]";
|
||||||
|
}
|
||||||
|
void AstTracePushPrefix::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, quotedPrefix);
|
||||||
|
dumpJsonStr(str, "prefixType", prefixType().ascii());
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstTypedef::dump(std::ostream& str) const {
|
void AstTypedef::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (attrPublic()) str << " [PUBLIC]";
|
if (attrPublic()) str << " [PUBLIC]";
|
||||||
@@ -2680,6 +2863,14 @@ void AstTypedefFwd::dumpJson(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||||
void AstNodeRange::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstNodeRange::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||||
|
void AstRand::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeExpr::dump(str);
|
||||||
|
if (urandom()) str << " [U]";
|
||||||
|
}
|
||||||
|
void AstRand::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolIf(str, "urandom", urandom());
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstRandSequence::dump(std::ostream& str) const {
|
void AstRandSequence::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " start=" << start();
|
str << " start=" << start();
|
||||||
@@ -2706,8 +2897,18 @@ void AstRange::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonBoolFuncIf(str, fromBracket);
|
dumpJsonBoolFuncIf(str, fromBracket);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
|
void AstNodeReadWriteMem::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeStmt::dump(str);
|
||||||
|
if (isHex()) str << " [HEX]";
|
||||||
|
}
|
||||||
|
void AstNodeReadWriteMem::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, isHex);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstParamTypeDType::dump(std::ostream& str) const {
|
void AstParamTypeDType::dump(std::ostream& str) const {
|
||||||
this->AstNodeDType::dump(str);
|
this->AstNodeDType::dump(str);
|
||||||
|
if (fwdType() != VFwdType::NONE) str << " [" << fwdType().ascii() << "]";
|
||||||
|
str << " [" << varType().ascii() << "]";
|
||||||
if (subDTypep()) {
|
if (subDTypep()) {
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
subDTypep()->dump(str);
|
subDTypep()->dump(str);
|
||||||
@@ -2715,7 +2916,19 @@ void AstParamTypeDType::dump(std::ostream& str) const {
|
|||||||
str << " -> UNLINKED";
|
str << " -> UNLINKED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void AstParamTypeDType::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstParamTypeDType::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonStr(str, "fwdType", fwdType().ascii());
|
||||||
|
dumpJsonStr(str, "varType", varType().ascii());
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
void AstParseTypeDType::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeDType::dump(str);
|
||||||
|
if (fwdType() != VFwdType::NONE) str << " [" << fwdType().ascii() << "]";
|
||||||
|
}
|
||||||
|
void AstParseTypeDType::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonStr(str, "fwdType", fwdType().ascii());
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstRefDType::dump(std::ostream& str) const {
|
void AstRefDType::dump(std::ostream& str) const {
|
||||||
this->AstNodeDType::dump(str);
|
this->AstNodeDType::dump(str);
|
||||||
if (typedefp() || subDTypep()) {
|
if (typedefp() || subDTypep()) {
|
||||||
@@ -2752,15 +2965,25 @@ void AstNodeUOrStructDType::dump(std::ostream& str) const {
|
|||||||
this->AstNodeDType::dump(str);
|
this->AstNodeDType::dump(str);
|
||||||
if (packed()) str << " [PACKED]";
|
if (packed()) str << " [PACKED]";
|
||||||
if (isFourstate()) str << " [4STATE]";
|
if (isFourstate()) str << " [4STATE]";
|
||||||
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
if (isConstrainedRand()) str << " [CSRAND]";
|
||||||
if (emitToString()) str << " [EMITSTR]";
|
if (emitToString()) str << " [EMITSTR]";
|
||||||
|
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
||||||
}
|
}
|
||||||
void AstNodeUOrStructDType::dumpJson(std::ostream& str) const {
|
void AstNodeUOrStructDType::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonBoolFuncIf(str, packed);
|
dumpJsonBoolFuncIf(str, packed);
|
||||||
|
dumpJsonBoolFuncIf(str, isConstrainedRand);
|
||||||
dumpJsonBoolFuncIf(str, isFourstate);
|
dumpJsonBoolFuncIf(str, isFourstate);
|
||||||
dumpJsonBoolFuncIf(str, emitToString);
|
dumpJsonBoolFuncIf(str, emitToString);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
|
void AstUdpTableLine::dump(std::ostream& str) const {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
if (udpIsCombo()) str << " [COMBO]";
|
||||||
|
}
|
||||||
|
void AstUdpTableLine::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, udpIsCombo);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstUnionDType::dump(std::ostream& str) const {
|
void AstUnionDType::dump(std::ostream& str) const {
|
||||||
this->AstNodeUOrStructDType::dump(str);
|
this->AstNodeUOrStructDType::dump(str);
|
||||||
if (isSoft()) str << " [soft]";
|
if (isSoft()) str << " [soft]";
|
||||||
@@ -2872,11 +3095,21 @@ std::vector<AstUnpackArrayDType*> AstUnpackArrayDType::unpackDimensions() {
|
|||||||
}
|
}
|
||||||
return dims;
|
return dims;
|
||||||
}
|
}
|
||||||
|
void AstNBACommitQueueDType::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeDType::dump(str);
|
||||||
|
if (partial()) str << " [PARTIAL]";
|
||||||
|
}
|
||||||
|
void AstNBACommitQueueDType::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, partial);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstNetlist::dump(std::ostream& str) const {
|
void AstNetlist::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
|
if (timescaleSpecified()) str << " [TIMESCALES]";
|
||||||
str << " [" << timeunit() << "/" << timeprecision() << "]";
|
str << " [" << timeunit() << "/" << timeprecision() << "]";
|
||||||
}
|
}
|
||||||
void AstNetlist::dumpJson(std::ostream& str) const {
|
void AstNetlist::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolIf(str, "timescaleSpecified", timescaleSpecified());
|
||||||
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
||||||
dumpJsonStr(str, "timeprecision", timeprecision().ascii());
|
dumpJsonStr(str, "timeprecision", timeprecision().ascii());
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
@@ -2887,13 +3120,13 @@ void AstNetlist::deleteContents() {
|
|||||||
m_constPoolp = nullptr;
|
m_constPoolp = nullptr;
|
||||||
m_dollarUnitPkgp = nullptr;
|
m_dollarUnitPkgp = nullptr;
|
||||||
m_stdPackagep = nullptr;
|
m_stdPackagep = nullptr;
|
||||||
m_evalp = nullptr;
|
|
||||||
m_evalNbap = nullptr;
|
|
||||||
m_dpiExportTriggerp = nullptr;
|
m_dpiExportTriggerp = nullptr;
|
||||||
m_delaySchedulerp = nullptr;
|
m_delaySchedulerp = nullptr;
|
||||||
m_nbaEventp = nullptr;
|
m_nbaEventp = nullptr;
|
||||||
m_nbaEventTriggerp = nullptr;
|
m_nbaEventTriggerp = nullptr;
|
||||||
m_topScopep = nullptr;
|
m_topScopep = nullptr;
|
||||||
|
m_evalFuncps.fill(nullptr);
|
||||||
|
m_dumpTriggersFuncps.fill(nullptr);
|
||||||
if (op1p()) op1p()->unlinkFrBackWithNext()->deleteTree();
|
if (op1p()) op1p()->unlinkFrBackWithNext()->deleteTree();
|
||||||
if (op2p()) op2p()->unlinkFrBackWithNext()->deleteTree();
|
if (op2p()) op2p()->unlinkFrBackWithNext()->deleteTree();
|
||||||
if (op3p()) op3p()->unlinkFrBackWithNext()->deleteTree();
|
if (op3p()) op3p()->unlinkFrBackWithNext()->deleteTree();
|
||||||
@@ -2937,6 +3170,18 @@ AstFuncRef* AstNetlist::stdPackageProcessSelfp(FileLine* flp) const {
|
|||||||
processSelfp->classOrPackagep(v3Global.rootp()->stdPackageProcessp());
|
processSelfp->classOrPackagep(v3Global.rootp()->stdPackageProcessp());
|
||||||
return processSelfp;
|
return processSelfp;
|
||||||
}
|
}
|
||||||
|
void AstNetlist::addEvalStats(const std::string& phase) {
|
||||||
|
if (!v3Global.opt.stats()) return;
|
||||||
|
for (int i = 0; i < VEval::_ENUM_END; ++i) {
|
||||||
|
VEval eval{i};
|
||||||
|
AstCFunc* const funcp = m_evalFuncps[i];
|
||||||
|
if (!funcp) continue;
|
||||||
|
const uint32_t nodes = funcp->nodeCount();
|
||||||
|
const uint32_t instr = V3InstrCount::count(funcp, false);
|
||||||
|
V3Stats::addStat("Size of eval, nodes - '" + eval.tag() + "', " + phase, nodes);
|
||||||
|
V3Stats::addStat("Size of eval, instr - '" + eval.tag() + "', " + phase, instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
void AstNodeModule::dump(std::ostream& str) const {
|
void AstNodeModule::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " L" << level();
|
str << " L" << level();
|
||||||
@@ -2959,6 +3204,7 @@ void AstNodeModule::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonStrFunc(str, origName);
|
dumpJsonStrFunc(str, origName);
|
||||||
dumpJsonStrFunc(str, verilogName);
|
dumpJsonStrFunc(str, verilogName);
|
||||||
dumpJsonNumFunc(str, level);
|
dumpJsonNumFunc(str, level);
|
||||||
|
dumpJsonNumFunc(str, depth);
|
||||||
dumpJsonBoolFuncIf(str, modPublic);
|
dumpJsonBoolFuncIf(str, modPublic);
|
||||||
dumpJsonBoolFuncIf(str, inLibrary);
|
dumpJsonBoolFuncIf(str, inLibrary);
|
||||||
dumpJsonBoolFuncIf(str, ctorVarReset);
|
dumpJsonBoolFuncIf(str, ctorVarReset);
|
||||||
@@ -2970,6 +3216,16 @@ void AstNodeModule::dumpJson(std::ostream& str) const {
|
|||||||
if (libname() != "work") dumpJsonStr(str, "libname=", libname());
|
if (libname() != "work") dumpJsonStr(str, "libname=", libname());
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
|
void AstPExprClause::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeStmt::dump(str);
|
||||||
|
if (pass()) str << " [PASS]";
|
||||||
|
if (vacuous()) str << " [VACUOUS]";
|
||||||
|
}
|
||||||
|
void AstPExprClause::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, pass);
|
||||||
|
dumpJsonBoolFuncIf(str, vacuous);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstPackageExport::dump(std::ostream& str) const {
|
void AstPackageExport::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (packagep()) {
|
if (packagep()) {
|
||||||
@@ -2978,7 +3234,10 @@ void AstPackageExport::dump(std::ostream& str) const {
|
|||||||
str << " ->UNLINKED:" << pkgName();
|
str << " ->UNLINKED:" << pkgName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void AstPackageExport::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstPackageExport::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonStrFunc(str, pkgName);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstPackageImport::dump(std::ostream& str) const {
|
void AstPackageImport::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (packagep()) {
|
if (packagep()) {
|
||||||
@@ -2991,6 +3250,14 @@ void AstPackageImport::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
|||||||
void AstPackageImport::pkgNameFrom() {
|
void AstPackageImport::pkgNameFrom() {
|
||||||
if (packagep()) m_pkgName = packagep()->name();
|
if (packagep()) m_pkgName = packagep()->name();
|
||||||
}
|
}
|
||||||
|
void AstPast::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeExpr::dump(str);
|
||||||
|
if (propertyTiming()) str << " [PROPERTY_TIMING]";
|
||||||
|
}
|
||||||
|
void AstPast::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, propertyTiming);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstPatMember::dump(std::ostream& str) const {
|
void AstPatMember::dump(std::ostream& str) const {
|
||||||
this->AstNodeExpr::dump(str);
|
this->AstNodeExpr::dump(str);
|
||||||
if (isConcat()) str << " [CONCAT]";
|
if (isConcat()) str << " [CONCAT]";
|
||||||
@@ -3025,13 +3292,23 @@ VFormatAttr AstSFormatArg::formatAttrDefauled(const AstSFormatArg* nodep,
|
|||||||
void AstSFormatF::dump(std::ostream& str) const {
|
void AstSFormatF::dump(std::ostream& str) const {
|
||||||
this->AstNodeExpr::dump(str);
|
this->AstNodeExpr::dump(str);
|
||||||
if (exprFormat()) str << " [EXPRFMT]";
|
if (exprFormat()) str << " [EXPRFMT]";
|
||||||
|
if (hidden()) str << " [HID]";
|
||||||
if (optionalFormat()) str << " [OPTFMT]";
|
if (optionalFormat()) str << " [OPTFMT]";
|
||||||
}
|
}
|
||||||
void AstSFormatF::dumpJson(std::ostream& str) const {
|
void AstSFormatF::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
dumpJsonBoolFuncIf(str, exprFormat);
|
dumpJsonBoolFuncIf(str, exprFormat);
|
||||||
|
dumpJsonBoolFuncIf(str, hidden);
|
||||||
dumpJsonBoolFuncIf(str, optionalFormat);
|
dumpJsonBoolFuncIf(str, optionalFormat);
|
||||||
}
|
}
|
||||||
|
void AstSampled::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeExpr::dump(str);
|
||||||
|
if (internal()) str << " [INTERNAL]";
|
||||||
|
}
|
||||||
|
void AstSampled::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, internal);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstSel::dump(std::ostream& str) const {
|
void AstSel::dump(std::ostream& str) const {
|
||||||
this->AstNodeBiop::dump(str);
|
this->AstNodeBiop::dump(str);
|
||||||
str << " widthConst=" << this->widthConst();
|
str << " widthConst=" << this->widthConst();
|
||||||
@@ -3122,6 +3399,15 @@ bool AstWildcardArrayDType::similarDTypeNode(const AstNodeDType* samep) const {
|
|||||||
const AstWildcardArrayDType* const asamep = VN_DBG_AS(samep, WildcardArrayDType);
|
const AstWildcardArrayDType* const asamep = VN_DBG_AS(samep, WildcardArrayDType);
|
||||||
return asamep->subDTypep() && subDTypep()->similarDType(asamep->subDTypep());
|
return asamep->subDTypep() && subDTypep()->similarDType(asamep->subDTypep());
|
||||||
}
|
}
|
||||||
|
void AstUnpackArrayDType::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeDType::dump(str);
|
||||||
|
if (isCompound()) str << " [COMPOUND]";
|
||||||
|
str << " " << declRange();
|
||||||
|
}
|
||||||
|
void AstUnpackArrayDType::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, isCompound);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
bool AstUnpackArrayDType::similarDTypeNode(const AstNodeDType* samep) const {
|
bool AstUnpackArrayDType::similarDTypeNode(const AstNodeDType* samep) const {
|
||||||
const AstUnpackArrayDType* const asamep = VN_DBG_AS(samep, UnpackArrayDType);
|
const AstUnpackArrayDType* const asamep = VN_DBG_AS(samep, UnpackArrayDType);
|
||||||
return hi() == asamep->hi() && rangep()->sameTree(asamep->rangep())
|
return hi() == asamep->hi() && rangep()->sameTree(asamep->rangep())
|
||||||
@@ -3152,6 +3438,14 @@ void AstVoidDType::dumpSmall(std::ostream& str) const {
|
|||||||
this->AstNodeDType::dumpSmall(str);
|
this->AstNodeDType::dumpSmall(str);
|
||||||
str << "void";
|
str << "void";
|
||||||
}
|
}
|
||||||
|
void AstIfaceGenericDType::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeDType::dump(str);
|
||||||
|
if (modportName() != "") str << " mp=" << modportName();
|
||||||
|
}
|
||||||
|
void AstIfaceGenericDType::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonStrFunc(str, modportName);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstIfaceGenericDType::dumpSmall(std::ostream& str) const {
|
void AstIfaceGenericDType::dumpSmall(std::ostream& str) const {
|
||||||
this->AstNodeDType::dumpSmall(str);
|
this->AstNodeDType::dumpSmall(str);
|
||||||
str << "generic_interface";
|
str << "generic_interface";
|
||||||
@@ -3256,6 +3550,7 @@ int AstVarRef::instrCount() const {
|
|||||||
void AstVar::dump(std::ostream& str) const {
|
void AstVar::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (constPoolEntry()) str << " [CONSTPOOL]";
|
if (constPoolEntry()) str << " [CONSTPOOL]";
|
||||||
|
if (covergroupRefMember()) str << " [CGREF]";
|
||||||
if (isSc()) str << " [SC]";
|
if (isSc()) str << " [SC]";
|
||||||
if (isPrimaryIO()) str << (isInout() ? " [PIO]" : (isWritable() ? " [PO]" : " [PI]"));
|
if (isPrimaryIO()) str << (isInout() ? " [PIO]" : (isWritable() ? " [PO]" : " [PI]"));
|
||||||
if (isPrimaryClock()) str << " [PCLK]";
|
if (isPrimaryClock()) str << " [PCLK]";
|
||||||
@@ -3271,7 +3566,7 @@ void AstVar::dump(std::ostream& str) const {
|
|||||||
if (isInternal()) str << " [INTERNAL]";
|
if (isInternal()) str << " [INTERNAL]";
|
||||||
if (isLatched()) str << " [LATCHED]";
|
if (isLatched()) str << " [LATCHED]";
|
||||||
if (isUsedLoopIdx()) str << " [LOOPIDX]";
|
if (isUsedLoopIdx()) str << " [LOOPIDX]";
|
||||||
if (rand().isRandomizable()) str << " [" << rand() << "]";
|
if (rand().isRandomizable()) str << " [" << rand().ascii() << "]";
|
||||||
if (noCReset()) str << " [!CRST]";
|
if (noCReset()) str << " [!CRST]";
|
||||||
if (noReset()) str << " [!RST]";
|
if (noReset()) str << " [!RST]";
|
||||||
if (processQueue()) str << " [PROCQ]";
|
if (processQueue()) str << " [PROCQ]";
|
||||||
@@ -3298,6 +3593,7 @@ void AstVar::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonStrFunc(str, origName);
|
dumpJsonStrFunc(str, origName);
|
||||||
dumpJsonStrFunc(str, verilogName);
|
dumpJsonStrFunc(str, verilogName);
|
||||||
dumpJsonBoolFuncIf(str, constPoolEntry);
|
dumpJsonBoolFuncIf(str, constPoolEntry);
|
||||||
|
dumpJsonBoolFuncIf(str, covergroupRefMember);
|
||||||
dumpJsonBoolFuncIf(str, isSc);
|
dumpJsonBoolFuncIf(str, isSc);
|
||||||
dumpJsonBoolFuncIf(str, isPrimaryIO);
|
dumpJsonBoolFuncIf(str, isPrimaryIO);
|
||||||
dumpJsonBoolFuncIf(str, isPrimaryClock);
|
dumpJsonBoolFuncIf(str, isPrimaryClock);
|
||||||
@@ -3335,6 +3631,7 @@ void AstVar::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonBoolFuncIf(str, hasUserInit);
|
dumpJsonBoolFuncIf(str, hasUserInit);
|
||||||
dumpJsonBoolFuncIf(str, ignorePostWrite);
|
dumpJsonBoolFuncIf(str, ignorePostWrite);
|
||||||
dumpJsonBoolFuncIf(str, ignoreSchedWrite);
|
dumpJsonBoolFuncIf(str, ignoreSchedWrite);
|
||||||
|
if (rand().isRandomizable()) dumpJsonStr(str, "rand", rand().ascii());
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
void AstScope::dump(std::ostream& str) const {
|
void AstScope::dump(std::ostream& str) const {
|
||||||
@@ -3401,7 +3698,7 @@ void AstClassOrPackageRef::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void AstClassOrPackageRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstClassOrPackageRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||||
AstNodeModule* AstClassOrPackageRef::classOrPackageSkipp() const {
|
AstNodeModule* AstClassOrPackageRef::classOrPackageSkipp(const bool doRefs) const {
|
||||||
AstNode* foundp = m_classOrPackageNodep;
|
AstNode* foundp = m_classOrPackageNodep;
|
||||||
AstNode* lastp = nullptr;
|
AstNode* lastp = nullptr;
|
||||||
while (foundp != lastp) {
|
while (foundp != lastp) {
|
||||||
@@ -3409,11 +3706,12 @@ AstNodeModule* AstClassOrPackageRef::classOrPackageSkipp() const {
|
|||||||
if (AstNodeDType* const anodep = VN_CAST(foundp, NodeDType)) {
|
if (AstNodeDType* const anodep = VN_CAST(foundp, NodeDType)) {
|
||||||
foundp = anodep->skipRefOrNullp();
|
foundp = anodep->skipRefOrNullp();
|
||||||
}
|
}
|
||||||
if (const AstTypedef* const anodep = VN_CAST(foundp, Typedef)) {
|
if (doRefs) {
|
||||||
foundp = anodep->subDTypep();
|
if (const AstTypedef* const anodep = VN_CAST(foundp, Typedef)) {
|
||||||
}
|
foundp = anodep->subDTypep();
|
||||||
if (const AstClassRefDType* const anodep = VN_CAST(foundp, ClassRefDType)) {
|
} else if (const AstClassRefDType* const anodep = VN_CAST(foundp, ClassRefDType)) {
|
||||||
foundp = anodep->classp();
|
foundp = anodep->classp();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return VN_CAST(foundp, NodeModule);
|
return VN_CAST(foundp, NodeModule);
|
||||||
@@ -3441,6 +3739,8 @@ void AstNodeFTaskRef::dump(std::ostream& str) const {
|
|||||||
this->AstNodeExpr::dump(str);
|
this->AstNodeExpr::dump(str);
|
||||||
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
||||||
if (containsGenBlock()) str << " [GENBLK]";
|
if (containsGenBlock()) str << " [GENBLK]";
|
||||||
|
if (pli()) str << " [PLI]";
|
||||||
|
if (superReference()) str << " [SUPERREF]";
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
if (dotted() != "") str << ".=" << dotted() << " ";
|
if (dotted() != "") str << ".=" << dotted() << " ";
|
||||||
if (taskp()) {
|
if (taskp()) {
|
||||||
@@ -3452,6 +3752,8 @@ void AstNodeFTaskRef::dump(std::ostream& str) const {
|
|||||||
void AstNodeFTaskRef::dumpJson(std::ostream& str) const {
|
void AstNodeFTaskRef::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonStrFunc(str, dotted);
|
dumpJsonStrFunc(str, dotted);
|
||||||
dumpJsonBoolFuncIf(str, containsGenBlock);
|
dumpJsonBoolFuncIf(str, containsGenBlock);
|
||||||
|
dumpJsonBoolFuncIf(str, pli);
|
||||||
|
dumpJsonBoolFuncIf(str, superReference);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
void AstNodeFTask::dump(std::ostream& str) const {
|
void AstNodeFTask::dump(std::ostream& str) const {
|
||||||
@@ -3473,6 +3775,7 @@ void AstNodeFTask::dump(std::ostream& str) const {
|
|||||||
if (verilogFunction()) str << " [VFUNC]";
|
if (verilogFunction()) str << " [VFUNC]";
|
||||||
if (needProcess()) str << " [NPRC]";
|
if (needProcess()) str << " [NPRC]";
|
||||||
if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]";
|
if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]";
|
||||||
|
if (baseOverride().isAny()) str << " [" << baseOverride().ascii() << "]";
|
||||||
}
|
}
|
||||||
bool AstNodeFTask::isPure() {
|
bool AstNodeFTask::isPure() {
|
||||||
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
||||||
@@ -3538,6 +3841,22 @@ void AstBegin::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonBoolFuncIf(str, needProcess);
|
dumpJsonBoolFuncIf(str, needProcess);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
|
void AstComment::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeStmt::dump(str);
|
||||||
|
if (showAt()) str << " [SHOWAT]";
|
||||||
|
}
|
||||||
|
void AstComment::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, showAt);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
void AstCompareNN::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeExpr::dump(str);
|
||||||
|
if (ignoreCase()) str << " [IGNORECASE]";
|
||||||
|
}
|
||||||
|
void AstCompareNN::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, ignoreCase);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstNodeCoverDecl::dump(std::ostream& str) const {
|
void AstNodeCoverDecl::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (!page().empty()) str << " page=" << page();
|
if (!page().empty()) str << " page=" << page();
|
||||||
@@ -3597,12 +3916,38 @@ void AstCoverInc::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void AstCoverInc::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstCoverInc::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||||
|
void AstDpiExport::dump(std::ostream& str) const {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
if (cname() != "" && cname() != name()) str << " [c=" << cname() << "]";
|
||||||
|
}
|
||||||
|
void AstDpiExport::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonStr(str, "cname", cname());
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
void AstFireEvent::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeStmt::dump(str);
|
||||||
|
if (isDelayed()) str << " [DLY]";
|
||||||
|
}
|
||||||
|
void AstFireEvent::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, isDelayed);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstFork::dump(std::ostream& str) const {
|
void AstFork::dump(std::ostream& str) const {
|
||||||
this->AstNodeBlock::dump(str);
|
this->AstNodeBlock::dump(str);
|
||||||
str << " [" << joinType() << "]";
|
str << " [" << joinType() << "]";
|
||||||
|
if (immediateStart()) str << " [IMMEDIATE]";
|
||||||
}
|
}
|
||||||
void AstFork::dumpJson(std::ostream& str) const {
|
void AstFork::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonStr(str, "joinType", joinType().ascii());
|
dumpJsonStr(str, "joinType", joinType().ascii());
|
||||||
|
dumpJsonBoolFuncIf(str, immediateStart);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
void AstSequence::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeFTask::dump(str);
|
||||||
|
if (isReferenced()) str << " [REFED]";
|
||||||
|
}
|
||||||
|
void AstSequence::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, isReferenced);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
void AstStop::dump(std::ostream& str) const {
|
void AstStop::dump(std::ostream& str) const {
|
||||||
@@ -3615,10 +3960,12 @@ void AstStop::dumpJson(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
void AstTraceDecl::dump(std::ostream& str) const {
|
void AstTraceDecl::dump(std::ostream& str) const {
|
||||||
this->AstNodeStmt::dump(str);
|
this->AstNodeStmt::dump(str);
|
||||||
|
if (inDtypeFunc()) str << " [DT]";
|
||||||
if (codeAssigned()) str << " [code=" << code() << "]";
|
if (codeAssigned()) str << " [code=" << code() << "]";
|
||||||
if (dtypeCallp()) str << " [dtypeCallp=" << dtypeCallp() << "]";
|
if (dtypeCallp()) str << " [dtypeCallp=" << dtypeCallp() << "]";
|
||||||
}
|
}
|
||||||
void AstTraceDecl::dumpJson(std::ostream& str) const {
|
void AstTraceDecl::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, inDtypeFunc);
|
||||||
dumpJsonNumFunc(str, code);
|
dumpJsonNumFunc(str, code);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
@@ -3685,6 +4032,7 @@ void AstCFunc::dump(std::ostream& str) const {
|
|||||||
if (needProcess()) str << " [NPRC]";
|
if (needProcess()) str << " [NPRC]";
|
||||||
if (entryPoint()) str << " [ENTRY]";
|
if (entryPoint()) str << " [ENTRY]";
|
||||||
if (noLife()) str << " [NOLIFE]";
|
if (noLife()) str << " [NOLIFE]";
|
||||||
|
if (!cname().empty() && cname() != name()) str << " [c=" << cname() << "]";
|
||||||
}
|
}
|
||||||
void AstCFunc::dumpJson(std::ostream& str) const {
|
void AstCFunc::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonBoolFuncIf(str, slow);
|
dumpJsonBoolFuncIf(str, slow);
|
||||||
@@ -3700,6 +4048,7 @@ void AstCFunc::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonBoolFuncIf(str, isCoroutine);
|
dumpJsonBoolFuncIf(str, isCoroutine);
|
||||||
dumpJsonBoolFuncIf(str, needProcess);
|
dumpJsonBoolFuncIf(str, needProcess);
|
||||||
dumpJsonBoolFuncIf(str, noLife);
|
dumpJsonBoolFuncIf(str, noLife);
|
||||||
|
dumpJsonStrFunc(str, cname);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
// TODO: maybe try to shorten these flags somehow
|
// TODO: maybe try to shorten these flags somehow
|
||||||
}
|
}
|
||||||
@@ -3746,6 +4095,14 @@ void AstCStmt::dumpJson(std::ostream& str) const {
|
|||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
if (!stmtType().isNone()) dumpJsonStr(str, "stmtType", stmtType().ascii());
|
if (!stmtType().isNone()) dumpJsonStr(str, "stmtType", stmtType().ascii());
|
||||||
}
|
}
|
||||||
|
void AstCStmtUser::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeStmt::dump(str);
|
||||||
|
if (!fromDollarC()) str << " [$C]";
|
||||||
|
}
|
||||||
|
void AstCStmtUser::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFuncIf(str, fromDollarC);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
void AstCUse::dump(std::ostream& str) const {
|
void AstCUse::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " [" << useType() << "]";
|
str << " [" << useType() << "]";
|
||||||
@@ -3776,10 +4133,12 @@ string AstCase::pragmaString() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AstCgOptionAssign::dump(std::ostream& str) const {
|
void AstCgOptionAssign::dump(std::ostream& str) const {
|
||||||
|
str << " [" << optType().ascii() << "]";
|
||||||
if (typeOption()) str << " [TYPEOPT]";
|
if (typeOption()) str << " [TYPEOPT]";
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
}
|
}
|
||||||
void AstCgOptionAssign::dumpJson(std::ostream& str) const {
|
void AstCgOptionAssign::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonStr(str, "optType", optType().ascii());
|
||||||
dumpJsonBoolFuncIf(str, typeOption);
|
dumpJsonBoolFuncIf(str, typeOption);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
@@ -3793,7 +4152,7 @@ void AstDelay::dumpJson(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char* AstDisable::broken() const {
|
const char* AstDisable::broken() const {
|
||||||
BROKEN_RTN((m_targetp && targetRefp()) || ((!m_targetp && !targetRefp())));
|
BROKEN_RTN(!m_targetp && !targetRefp());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
void AstDisable::dump(std::ostream& str) const {
|
void AstDisable::dump(std::ostream& str) const {
|
||||||
@@ -3861,14 +4220,16 @@ void AstCoverpoint::dumpJson(std::ostream& str) const { this->AstNodeFuncCovItem
|
|||||||
|
|
||||||
void AstCoverBin::dump(std::ostream& str) const {
|
void AstCoverBin::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " " << m_type.ascii();
|
str << " " << m_binsType.ascii();
|
||||||
if (m_isArray) str << "[]";
|
if (m_isArray) str << "[]";
|
||||||
|
if (m_isWildcard) str << "[*]";
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstCoverBin::dumpJson(std::ostream& str) const {
|
void AstCoverBin::dumpJson(std::ostream& str) const {
|
||||||
this->AstNode::dumpJson(str);
|
this->AstNode::dumpJson(str);
|
||||||
str << ", \"binsType\": \"" << m_type.ascii() << "\"";
|
dumpJsonBoolIf(str, "isArray", isArray());
|
||||||
if (m_isArray) str << ", \"isArray\": true";
|
dumpJsonBoolIf(str, "isWildcard", isWildcard());
|
||||||
|
str << ", \"binsType\": \"" << binsType().ascii() << "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstCoverTransItem::dump(std::ostream& str) const {
|
void AstCoverTransItem::dump(std::ostream& str) const {
|
||||||
@@ -3891,12 +4252,12 @@ void AstCoverCross::dumpJson(std::ostream& str) const { this->AstNodeFuncCovItem
|
|||||||
|
|
||||||
void AstCoverOption::dump(std::ostream& str) const {
|
void AstCoverOption::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " " << m_type.ascii();
|
str << " " << m_optType.ascii();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstCoverOption::dumpJson(std::ostream& str) const {
|
void AstCoverOption::dumpJson(std::ostream& str) const {
|
||||||
this->AstNode::dumpJson(str);
|
this->AstNode::dumpJson(str);
|
||||||
str << ", \"optionType\": \"" << m_type.ascii() << "\"";
|
str << ", \"optType\": \"" << m_optType.ascii() << "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstCoverpointRef::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
void AstCoverpointRef::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user