Merge branch 'verilator:master' into fix/force-unpacked-bitselect
This commit is contained in:
commit
c9ec8730a9
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
blank_issues_enabled: false
|
||||
|
|
@ -7,18 +7,34 @@ assignees: ''
|
|||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for taking the time to report this.
|
||||
|
||||
Can you please attach an example that shows the issue or missing feature? (Must be openly licensed, completely self-contained so can directly run what you provide. Ideally use test_regress format, see https://veripool.org/guide/latest/contributing.html?highlight=test_regress#reporting-bugs)
|
||||
Please avoid attaching screenshots that show text - you can convert images to text using e.g. https://ocr.space
|
||||
|
||||
Please remove this block when composing, and all other blocks starting with < !--.
|
||||
-->
|
||||
|
||||
Can you please attach an example that shows the issue or missing feature?
|
||||
|
||||
<!-- Please replace this with your answer. Examples must be openly licensed, completely self-contained so can directly run what you provide. Ideally use test_regress format, see https://veripool.org/guide/latest/contributing.html?highlight=test_regress#reporting-bugs -->
|
||||
|
||||
What output from that test indicates it is wrong, and what is the correct or expected output? (Or, please make test self-checking if possible.)
|
||||
|
||||
<!-- Please replace this with your answer -->
|
||||
|
||||
What 'verilator' command line do we use to run your example?
|
||||
|
||||
<!-- Please replace this with your answer -->
|
||||
|
||||
What 'verilator --version' are you using? Did you try it with the git master version? Did you try it with other simulators?
|
||||
|
||||
<!-- Please replace this with your answer -->
|
||||
|
||||
What OS and distribution are you using?
|
||||
|
||||
<!-- Please replace this with your answer -->
|
||||
|
||||
May we assist you in trying to fix this in Verilator yourself?
|
||||
|
||||
(Please avoid attaching screenshots that show text - you can convert images to text using e.g. https://ocr.space)
|
||||
<!-- Please replace this with your answer - then hit "Preview" to see the formatted result before submitting. -->
|
||||
|
|
|
|||
|
|
@ -7,6 +7,14 @@ assignees: ''
|
|||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for taking the time to report this.
|
||||
|
||||
If reporting a bug or requesting a feature please hit BACK on your browser and use a different issue templates.
|
||||
|
||||
Please remove this block when composing, and all other blocks starting with < !--.
|
||||
-->
|
||||
|
||||
How may we help - what is your question?
|
||||
|
||||
(If reporting a bug or requesting a feature please hit BACK on your browser and use a different issue templates.)
|
||||
<!-- Please replace this with your answer - then hit "Preview" to see the formatted result before submitting. -->
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ jobs:
|
|||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: repo/notification
|
||||
name: coverage-pr-notification
|
||||
name: pr-notification
|
||||
|
||||
# Create GitHub issue for failed scheduled jobs
|
||||
# This should always be the last job (we want an issue if anything breaks)
|
||||
|
|
|
|||
|
|
@ -38,11 +38,11 @@ jobs:
|
|||
./configure
|
||||
make venv
|
||||
source .venv/bin/activate
|
||||
make -j 2 format CLANGFORMAT=clang-format-18
|
||||
make -j 4 format CLANGFORMAT=clang-format-18
|
||||
git status
|
||||
- name: Push
|
||||
run: |-
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
git commit . -m "Apply 'make format'" &&
|
||||
git commit . -m "Apply 'make format' [ci skip]" &&
|
||||
git push origin
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ on:
|
|||
paths: ["ci/**", ".github/workflows"]
|
||||
workflow_dispatch:
|
||||
workflow_run:
|
||||
workflows: ["Code coverage"]
|
||||
workflows: ["Code coverage", "RTLMeter"]
|
||||
types: [completed]
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
|
|
@ -35,7 +35,7 @@ jobs:
|
|||
name: Build content
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
coverage-pr-run-ids: ${{ steps.build.outputs.coverage-pr-run-ids }}
|
||||
pr-run-ids: ${{ steps.build.outputs.pr-run-ids }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
|
@ -44,7 +44,7 @@ jobs:
|
|||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
bash -x ./ci/ci-pages.bash
|
||||
./ci/ci-pages.bash
|
||||
ls -lsha
|
||||
tree -L 3 pages
|
||||
- name: Upload pages artifact
|
||||
|
|
@ -83,5 +83,5 @@ jobs:
|
|||
- name: Comment on PR
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
COVERAGE_PR_RUN_IDS: ${{ needs.build.outputs.coverage-pr-run-ids }}
|
||||
run: bash -x ./ci/ci-pages-notify.bash
|
||||
PR_RUN_IDS: ${{ needs.build.outputs.pr-run-ids }}
|
||||
run: ./ci/ci-pages-notify.bash
|
||||
|
|
|
|||
|
|
@ -15,6 +15,14 @@ on:
|
|||
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:
|
||||
|
|
@ -26,8 +34,10 @@ env:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
name: Build
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
outputs:
|
||||
archive: ${{ steps.create-archive.outputs.archive }}
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
|
@ -43,13 +53,17 @@ jobs:
|
|||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ccache
|
||||
key: rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
restore-keys: rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}
|
||||
key: rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
restore-keys: |
|
||||
rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.sha }}-${{ github.run_id }}
|
||||
rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.sha }}
|
||||
rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: repo
|
||||
ref: ${{ inputs.sha }}
|
||||
fetch-depth: 0 # Required for 'git describe' used for 'verilator --version'
|
||||
|
||||
- name: Configure
|
||||
|
|
@ -67,11 +81,16 @@ jobs:
|
|||
run: make install
|
||||
|
||||
- name: Tar up installation
|
||||
run: tar --posix -c -z -f verilator-rtlmeter.tar.gz install
|
||||
id: create-archive
|
||||
run: |
|
||||
SHA=$(git -C repo rev-parse HEAD)
|
||||
ARCHIVE=verilator-$SHA-rtlmeter-${{ inputs.runs-on }}-${{ inputs.cc }}.tar.gz
|
||||
tar --posix -c -z -f $ARCHIVE install
|
||||
echo "archive=$ARCHIVE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Upload Verilator installation archive
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: verilator-rtlmeter.tar.gz
|
||||
name: verilator-rtlmeter-${{ inputs.runs-on }}-${{ inputs.cc }}
|
||||
path: ${{ steps.create-archive.outputs.archive }}
|
||||
name: ${{ steps.create-archive.outputs.archive }}
|
||||
overwrite: true
|
||||
|
|
|
|||
|
|
@ -19,6 +19,15 @@ on:
|
|||
description: "Compiler to use: 'gcc' or 'clang'"
|
||||
type: string
|
||||
required: true
|
||||
verilator-archive-new:
|
||||
description: "Name of the installation archive artifact from reusable-rtlmeter-build, new version"
|
||||
type: string
|
||||
required: true
|
||||
verilator-archive-old:
|
||||
description: "Name of the installation archive artifact from reusable-rtlmeter-build, old version"
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
# Note: The combination of 'cases' and 'run-name' must be unique for all
|
||||
# invocations of this workflow within a run of the parent workflow.
|
||||
# These two are used together to generate a unique results file name.
|
||||
|
|
@ -63,24 +72,6 @@ jobs:
|
|||
sudo apt install ccache mold libfl-dev libjemalloc-dev libsystemc-dev || \
|
||||
sudo apt install ccache mold libfl-dev libjemalloc-dev libsystemc-dev
|
||||
|
||||
- name: Download Verilator installation archive
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: verilator-rtlmeter-${{ inputs.runs-on }}-${{ inputs.cc }}
|
||||
|
||||
- name: Unpack Verilator installation archive
|
||||
run: |
|
||||
tar -x -z -f verilator-rtlmeter.tar.gz
|
||||
echo "${{ github.workspace }}/install/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Use saved ccache
|
||||
if: ${{ env.CCACHE_DISABLE == 0 }}
|
||||
uses: actions/cache@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 }}
|
||||
|
||||
- name: Checkout RTLMeter
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
|
|
@ -91,32 +82,59 @@ jobs:
|
|||
working-directory: rtlmeter
|
||||
run: make venv
|
||||
|
||||
- name: Compile cases
|
||||
- name: Use saved ccache
|
||||
if: ${{ env.CCACHE_DISABLE == 0 }}
|
||||
uses: actions/cache@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
|
||||
########################################################################
|
||||
|
||||
- name: Download Verilator installation archive - new
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: ${{ inputs.verilator-archive-new }}
|
||||
|
||||
- name: Unpack Verilator installation archive - new
|
||||
run: |
|
||||
tar -x -z -f ${{ inputs.verilator-archive-new }}
|
||||
mv install verilator-new
|
||||
|
||||
- name: Compile cases - new
|
||||
working-directory: rtlmeter
|
||||
run: |
|
||||
export PATH="${{ github.workspace }}/verilator-new/bin:$PATH"
|
||||
./rtlmeter run --timeout 60 --verbose --cases='${{inputs.cases}}' --compileArgs='${{inputs.compileArgs}}' --executeArgs='${{inputs.executeArgs}}' --nExecute=0
|
||||
ccache -svv
|
||||
|
||||
- name: Execute cases
|
||||
- name: Execute cases - new
|
||||
working-directory: rtlmeter
|
||||
continue-on-error: true # Do not fail on error, so we can at least save the successful results
|
||||
run: |
|
||||
export PATH="${{ github.workspace }}/verilator-new/bin:$PATH"
|
||||
./rtlmeter run --timeout 60 --verbose --cases='${{inputs.cases}}' --compileArgs='${{inputs.compileArgs}}' --executeArgs='${{inputs.executeArgs}}'
|
||||
|
||||
- name: Collate results
|
||||
- name: Collate results - new
|
||||
id: results
|
||||
working-directory: rtlmeter
|
||||
run: |
|
||||
export PATH="${{ github.workspace }}/verilator-new/bin:$PATH"
|
||||
# Use 'inputs.cases' and 'inputs.run-name' to generate a unique file name
|
||||
hash=$(md5sum <<< '${{ inputs.cases }} ${{ inputs.run-name }}' | awk '{print $1}')
|
||||
echo "hash=${hash}" >> $GITHUB_OUTPUT
|
||||
./rtlmeter collate --runName "${{ inputs.run-name }}" > ../results-${hash}.json
|
||||
|
||||
- name: Report results
|
||||
- name: Report results - new
|
||||
working-directory: rtlmeter
|
||||
run: |
|
||||
export PATH="${{ github.workspace }}/verilator-new/bin:$PATH"
|
||||
./rtlmeter report --steps '*' --metrics '*' ../results-${{ steps.results.outputs.hash }}.json
|
||||
|
||||
- name: Upload results
|
||||
- name: Upload results - new
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: results-${{ steps.results.outputs.hash }}.json
|
||||
|
|
@ -124,7 +142,65 @@ jobs:
|
|||
overwrite: true
|
||||
retention-days: 2
|
||||
|
||||
- name: Report status
|
||||
- name: Report status - new
|
||||
working-directory: rtlmeter
|
||||
run: |- # This will fail the job if any of the runs failed
|
||||
export PATH="${{ github.workspace }}/verilator-new/bin:$PATH"
|
||||
./rtlmeter run --verbose --cases='${{inputs.cases}}' --compileArgs='${{inputs.compileArgs}}' --executeArgs='${{inputs.executeArgs}}'
|
||||
# Clean up for run with old version
|
||||
rm -rf work
|
||||
rm -rf ${{ github.workspace }}/verilator-new
|
||||
|
||||
########################################################################
|
||||
# Run with old Verilator **on same machine for consistency**
|
||||
########################################################################
|
||||
|
||||
- name: Download Verilator installation archive - old
|
||||
if: ${{ inputs.verilator-archive-old != '' }}
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: ${{ inputs.verilator-archive-old }}
|
||||
|
||||
- name: Unpack Verilator installation archive - old
|
||||
if: ${{ inputs.verilator-archive-old != '' }}
|
||||
run: |
|
||||
tar -x -z -f ${{ inputs.verilator-archive-old }}
|
||||
mv install verilator-old
|
||||
|
||||
- name: Compile cases - old
|
||||
if: ${{ inputs.verilator-archive-old != '' }}
|
||||
working-directory: rtlmeter
|
||||
run: |
|
||||
export PATH="${{ github.workspace }}/verilator-old/bin:$PATH"
|
||||
./rtlmeter run --timeout 60 --verbose --cases='${{inputs.cases}}' --compileArgs='${{inputs.compileArgs}}' --executeArgs='${{inputs.executeArgs}}' --nExecute=0
|
||||
ccache -svv
|
||||
|
||||
- name: Execute cases - old
|
||||
if: ${{ inputs.verilator-archive-old != '' }}
|
||||
working-directory: rtlmeter
|
||||
run: |
|
||||
export PATH="${{ github.workspace }}/verilator-old/bin:$PATH"
|
||||
./rtlmeter run --timeout 60 --verbose --cases='${{inputs.cases}}' --compileArgs='${{inputs.compileArgs}}' --executeArgs='${{inputs.executeArgs}}'
|
||||
|
||||
- name: Collate results - old
|
||||
if: ${{ inputs.verilator-archive-old != '' }}
|
||||
working-directory: rtlmeter
|
||||
run: |
|
||||
export PATH="${{ github.workspace }}/verilator-old/bin:$PATH"
|
||||
./rtlmeter collate --runName "${{ inputs.run-name }}" > ../reference-${{ steps.results.outputs.hash }}.json
|
||||
|
||||
- name: Report results - old
|
||||
if: ${{ inputs.verilator-archive-old != '' }}
|
||||
working-directory: rtlmeter
|
||||
run: |
|
||||
export PATH="${{ github.workspace }}/verilator-old/bin:$PATH"
|
||||
./rtlmeter report --steps '*' --metrics '*' ../reference-${{ steps.results.outputs.hash }}.json
|
||||
|
||||
- name: Upload results - old
|
||||
if: ${{ inputs.verilator-archive-old != '' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: reference-${{ steps.results.outputs.hash }}.json
|
||||
name: rtlmeter-${{ inputs.tag }}-reference-${{ steps.results.outputs.hash }}
|
||||
overwrite: true
|
||||
retention-days: 2
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# This name is key to badges in README.rst, so we use the name build
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
name: RTLMeter PR results
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [RTLMeter]
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
|
||||
permissions:
|
||||
actions: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Download report
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: rtlmeter-pr-results
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Download PR number
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: pr-number
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Use the Verilator CI app to post the comment
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
with:
|
||||
app-id: ${{ vars.VERILATOR_CI_ID }}
|
||||
private-key: ${{ secrets.VERILATOR_CI_KEY }}
|
||||
permission-pull-requests: write
|
||||
- name: Comment on PR
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
run: |-
|
||||
ls -la
|
||||
cat report.txt
|
||||
gh pr --repo ${{ github.repository }} comment $(cat pr-number.txt) --body-file report.txt
|
||||
|
|
@ -40,179 +40,229 @@ jobs:
|
|||
(github.event_name == 'workflow_dispatch') ||
|
||||
(github.event_name == 'push')
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
old-sha: ${{ steps.start.outputs.old-sha }}
|
||||
cases: ${{ steps.cases.outputs.cases }}
|
||||
steps:
|
||||
- name: Startup
|
||||
run: echo
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
build-gcc:
|
||||
name: Build GCC
|
||||
- name: Startup
|
||||
id: start
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
[[ "${{ github.event_name }}" == 'pull_request' ]] || exit 0
|
||||
# For a pull request, 'github.sha' is the test merge commit. Its
|
||||
# first parent is the target branch commit it was merged with for this run.
|
||||
OLD_SHA="$(gh api "repos/${{ github.repository }}/commits/${{ github.sha }}" --jq '.parents[0].sha')"
|
||||
echo "old-sha=$OLD_SHA" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Load RTLMeter cases
|
||||
id: cases
|
||||
run: echo "cases=$(ci/ci-rtlmeter-cases.py --event-name ${{ github.event_name }})" >> "$GITHUB_OUTPUT"
|
||||
|
||||
build-gcc-new:
|
||||
name: Build New Verilator - GCC
|
||||
needs: start
|
||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
||||
with:
|
||||
runs-on: ubuntu-24.04
|
||||
cc: gcc
|
||||
sha: ${{ github.sha }}
|
||||
|
||||
build-clang:
|
||||
name: Build Clang
|
||||
build-clang-new:
|
||||
name: Build New Verilator - Clang
|
||||
needs: start
|
||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
||||
with:
|
||||
runs-on: ubuntu-24.04
|
||||
cc: clang
|
||||
sha: ${{ github.sha }}
|
||||
|
||||
build-gcc-old:
|
||||
name: Build Old Verilator - GCC
|
||||
needs: start
|
||||
if: ${{ needs.start.outputs.old-sha != '' }}
|
||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
||||
with:
|
||||
runs-on: ubuntu-24.04
|
||||
cc: gcc
|
||||
sha: ${{ needs.start.outputs.old-sha }}
|
||||
|
||||
build-clang-old:
|
||||
name: Build Old Verilator - Clang
|
||||
needs: start
|
||||
if: ${{ needs.start.outputs.old-sha != '' }}
|
||||
uses: ./.github/workflows/reusable-rtlmeter-build.yml
|
||||
with:
|
||||
runs-on: ubuntu-24.04
|
||||
cc: clang
|
||||
sha: ${{ needs.start.outputs.old-sha }}
|
||||
|
||||
run-gcc:
|
||||
name: Run GCC | ${{ matrix.cases }}
|
||||
needs: build-gcc
|
||||
needs:
|
||||
- start
|
||||
- build-gcc-new
|
||||
- build-gcc-old
|
||||
# Run even if 'build-*-old' was skipped (no old SHA), but not if any
|
||||
# dependency failed, the workflow was cancelled, or 'start' was skipped
|
||||
# (e.g. the workflow was not enabled, so there is nothing to run against).
|
||||
if: ${{ !failure() && !cancelled() && needs.start.result == 'success' }}
|
||||
uses: ./.github/workflows/reusable-rtlmeter-run.yml
|
||||
with:
|
||||
tag: gcc
|
||||
runs-on: ubuntu-24.04
|
||||
cc: gcc
|
||||
verilator-archive-new: ${{ needs.build-gcc-new.outputs.archive }}
|
||||
verilator-archive-old: ${{ needs.build-gcc-old.outputs.archive }}
|
||||
cases: ${{ matrix.cases }}
|
||||
run-name: "gcc"
|
||||
compileArgs: ""
|
||||
executeArgs: ""
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: ${{ github.event == 'schedule' && 2 || 7 }}
|
||||
fail-fast: ${{ github.event_name == 'pull_request' }}
|
||||
max-parallel: 7
|
||||
matrix:
|
||||
cases:
|
||||
- "BlackParrot:1x1:*"
|
||||
- "BlackParrot:4x4:*"
|
||||
- "Caliptra:default:*"
|
||||
- "NVDLA:*"
|
||||
- "OpenPiton:1x1:*"
|
||||
- "OpenPiton:4x4:*"
|
||||
- "OpenTitan:*"
|
||||
- "Servant:serv:*"
|
||||
- "Servant:qerv:*"
|
||||
- "VeeR-EH1:asic*"
|
||||
- "VeeR-EH1:default*"
|
||||
- "VeeR-EH1:hiperf*"
|
||||
- "VeeR-EH2:asic*"
|
||||
- "VeeR-EH2:default*"
|
||||
- "VeeR-EH2:hiperf*"
|
||||
- "VeeR-EL2:asic*"
|
||||
- "VeeR-EL2:default*"
|
||||
- "VeeR-EL2:hiperf*"
|
||||
- "Vortex:mini:*"
|
||||
- "Vortex:sane:*"
|
||||
- "XiangShan:default-chisel3:* !*:linux"
|
||||
- "XiangShan:default-chisel6:* !*:linux"
|
||||
- "XiangShan:mini-chisel3:* !*:linux"
|
||||
- "XiangShan:mini-chisel6:* !*:linux"
|
||||
- "XuanTie-E902:*"
|
||||
- "XuanTie-E906:*"
|
||||
- "XuanTie-C906:*"
|
||||
- "XuanTie-C910:*"
|
||||
cases: ${{ fromJSON(needs.start.outputs.cases)['gcc'] }}
|
||||
|
||||
run-clang:
|
||||
name: Run Clang | ${{ matrix.cases }}
|
||||
needs: build-clang
|
||||
needs:
|
||||
- start
|
||||
- build-clang-new
|
||||
- build-clang-old
|
||||
# Run even if 'build-*-old' was skipped (no old SHA), but not if any
|
||||
# dependency failed, the workflow was cancelled, or 'start' was skipped
|
||||
# (e.g. the workflow was not enabled, so there is nothing to run against).
|
||||
if: ${{ !failure() && !cancelled() && needs.start.result == 'success' }}
|
||||
uses: ./.github/workflows/reusable-rtlmeter-run.yml
|
||||
with:
|
||||
tag: clang
|
||||
runs-on: ubuntu-24.04
|
||||
cc: clang
|
||||
verilator-archive-new: ${{ needs.build-clang-new.outputs.archive }}
|
||||
verilator-archive-old: ${{ needs.build-clang-old.outputs.archive }}
|
||||
cases: ${{ matrix.cases }}
|
||||
run-name: "clang --threads 4"
|
||||
compileArgs: "--threads 4"
|
||||
executeArgs: ""
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: ${{ github.event == 'schedule' && 2 || 7 }}
|
||||
fail-fast: ${{ github.event_name == 'pull_request' }}
|
||||
max-parallel: 7
|
||||
matrix:
|
||||
cases:
|
||||
- "BlackParrot:1x1:*"
|
||||
- "BlackParrot:4x4:*"
|
||||
- "Caliptra:default:*"
|
||||
- "NVDLA:*"
|
||||
- "OpenPiton:1x1:*"
|
||||
- "OpenPiton:4x4:*"
|
||||
- "OpenTitan:*"
|
||||
- "Servant:serv:*"
|
||||
- "Servant:qerv:*"
|
||||
- "VeeR-EH1:asic*"
|
||||
- "VeeR-EH1:default*"
|
||||
- "VeeR-EH1:hiperf*"
|
||||
- "VeeR-EH2:asic*"
|
||||
- "VeeR-EH2:default*"
|
||||
- "VeeR-EH2:hiperf*"
|
||||
- "VeeR-EL2:asic*"
|
||||
- "VeeR-EL2:default*"
|
||||
- "VeeR-EL2:hiperf*"
|
||||
- "Vortex:mini:*"
|
||||
- "Vortex:sane:*"
|
||||
- "XiangShan:default-chisel3:* !*:linux"
|
||||
- "XiangShan:default-chisel6:* !*:linux"
|
||||
- "XiangShan:mini-chisel3:* !*:linux"
|
||||
- "XiangShan:mini-chisel6:* !*:linux"
|
||||
- "XuanTie-E902:*"
|
||||
- "XuanTie-E906:*"
|
||||
- "XuanTie-C906:*"
|
||||
- "XuanTie-C910:*"
|
||||
cases: ${{ fromJSON(needs.start.outputs.cases)['clang'] }}
|
||||
|
||||
run-gcc-hier:
|
||||
name: Run GCC hier | ${{ matrix.cases }}
|
||||
needs: build-gcc
|
||||
needs:
|
||||
- start
|
||||
- build-gcc-new
|
||||
- build-gcc-old
|
||||
# Run even if 'build-*-old' was skipped (no old SHA), but not if any
|
||||
# dependency failed, the workflow was cancelled, or 'start' was skipped
|
||||
# (e.g. the workflow was not enabled, so there is nothing to run against).
|
||||
if: ${{ !failure() && !cancelled() && needs.start.result == 'success' }}
|
||||
uses: ./.github/workflows/reusable-rtlmeter-run.yml
|
||||
with:
|
||||
tag: gcc-hier
|
||||
runs-on: ubuntu-24.04
|
||||
cc: gcc
|
||||
verilator-archive-new: ${{ needs.build-gcc-new.outputs.archive }}
|
||||
verilator-archive-old: ${{ needs.build-gcc-old.outputs.archive }}
|
||||
cases: ${{ matrix.cases }}
|
||||
run-name: "gcc --hierarchical"
|
||||
compileArgs: "--hierarchical"
|
||||
executeArgs: ""
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: ${{ github.event == 'schedule' && 2 || 7 }}
|
||||
fail-fast: ${{ github.event_name == 'pull_request' }}
|
||||
max-parallel: 6
|
||||
matrix:
|
||||
cases:
|
||||
- "BlackParrot:1x1:* !-hier"
|
||||
- "BlackParrot:4x4:* !-hier"
|
||||
- "NVDLA:* !-hier"
|
||||
- "OpenPiton:1x1:* !-hier"
|
||||
- "OpenPiton:4x4:* !-hier"
|
||||
- "OpenPiton:8x8:* !-hier"
|
||||
- "OpenPiton:16x16:dhry !-hier"
|
||||
- "XuanTie-C910:* !-hier"
|
||||
cases: ${{ fromJSON(needs.start.outputs.cases)['gcc-hier'] }}
|
||||
|
||||
combine-results:
|
||||
name: Combine results
|
||||
needs: [run-gcc, run-clang, run-gcc-hier]
|
||||
# Run if any of the dependencies have run, even if failed.
|
||||
# That is: do not run if all skipped, or the workflow was cancelled.
|
||||
if: ${{ (contains(needs.*.result, 'success') || contains(needs.*.result, 'failure')) && !cancelled() }}
|
||||
# Skip if cancelled.
|
||||
# On PRs, run if something succeeded and nothing failed.
|
||||
# On non-PRs, run if anything succeeded or failed (so partial results are still published).
|
||||
if: >-
|
||||
${{ !cancelled() && (
|
||||
(github.event_name == 'pull_request' && (contains(needs.*.result, 'success') && !contains(needs.*.result, 'failure')))
|
||||
|| (github.event_name != 'pull_request' && (contains(needs.*.result, 'success') || contains(needs.*.result, 'failure')))
|
||||
)}}
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
tag: [gcc, clang, gcc-hier]
|
||||
outputs:
|
||||
# The run tags, derived from the 'run-*' dependency job names
|
||||
run-tags: ${{ steps.tags.outputs.tags }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
# 'gh' resolves the repo from git otherwise, but this job has no checkout
|
||||
# of this repo at the workspace root
|
||||
GH_REPO: ${{ github.repository }}
|
||||
steps:
|
||||
# Derive the run tags from the dependency job names ('run-<tag>')
|
||||
- name: Determine run tags
|
||||
id: tags
|
||||
run: echo "tags=$(jq -r 'keys | map(sub("^run-"; "")) | join(" ")' <<< '${{ toJSON(needs) }}')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Checkout RTLMeter
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: "verilator/rtlmeter"
|
||||
path: rtlmeter
|
||||
|
||||
- name: Setup RTLMeter venv
|
||||
working-directory: rtlmeter
|
||||
run: make venv
|
||||
|
||||
- name: Download all results
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: rtlmeter-${{ matrix.tag }}-results-*
|
||||
path: all-results-${{ matrix.tag }}
|
||||
merge-multiple: true
|
||||
run: |
|
||||
for tag in ${{ steps.tags.outputs.tags }}; do
|
||||
mkdir artifacts all-results-$tag
|
||||
gh run download ${{ github.run_id }} --pattern "rtlmeter-$tag-results-*" --dir artifacts
|
||||
mv $(find artifacts -name "*.json") all-results-$tag/
|
||||
rm -rf artifacts
|
||||
done
|
||||
- name: Combine results
|
||||
working-directory: rtlmeter
|
||||
run: |
|
||||
./rtlmeter collate ../all-results-${{ matrix.tag }}/*.json > ../all-results-${{ matrix.tag }}.json
|
||||
for tag in ${{ steps.tags.outputs.tags }}; do
|
||||
./rtlmeter collate ../all-results-$tag/*.json > ../all-results-$tag.json
|
||||
done
|
||||
- name: Upload combined results
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: all-results-${{ matrix.tag }}.json
|
||||
name: all-results-${{ matrix.tag }}
|
||||
path: all-results-*.json
|
||||
name: all-results
|
||||
overwrite: true
|
||||
retention-days: 30
|
||||
|
||||
# The reference (old) results only exist for pull requests, where the
|
||||
# 'build-*-old' jobs run and the run jobs produce '*-reference-*' artifacts.
|
||||
- name: Download reference results
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
for tag in ${{ steps.tags.outputs.tags }}; do
|
||||
mkdir artifacts all-reference-$tag
|
||||
gh run download ${{ github.run_id }} --pattern "rtlmeter-$tag-reference-*" --dir artifacts
|
||||
mv $(find artifacts -name "*.json") all-reference-$tag/
|
||||
rm -rf artifacts
|
||||
done
|
||||
- name: Combine reference results
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
working-directory: rtlmeter
|
||||
run: |
|
||||
for tag in ${{ steps.tags.outputs.tags }}; do
|
||||
./rtlmeter collate ../all-reference-$tag/*.json > ../all-reference-$tag.json
|
||||
done
|
||||
- name: Upload reference results
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: all-reference-*.json
|
||||
name: all-reference
|
||||
overwrite: true
|
||||
retention-days: 30
|
||||
|
||||
|
|
@ -230,9 +280,8 @@ jobs:
|
|||
- name: Download combined results
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: all-results-*
|
||||
name: all-results
|
||||
path: results
|
||||
merge-multiple: true
|
||||
- name: Upload published results
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
|
|
@ -276,7 +325,7 @@ jobs:
|
|||
prepare-pr-results:
|
||||
name: Prepare Pull Request results
|
||||
needs: combine-results
|
||||
if: ${{ github.event_name == 'pull_request' && github.repository == 'verilator/verilator' && contains(needs.*.result, 'success') && !cancelled() }}
|
||||
if: ${{ github.event_name == 'pull_request' && github.repository == 'verilator/verilator' && needs.combine-results.result == 'success' }}
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
actions: read
|
||||
|
|
@ -286,106 +335,51 @@ jobs:
|
|||
with:
|
||||
repository: "verilator/rtlmeter"
|
||||
path: rtlmeter
|
||||
|
||||
- name: Setup RTLMeter venv
|
||||
working-directory: rtlmeter
|
||||
run: make venv
|
||||
- name: Download combined results
|
||||
uses: actions/download-artifact@v8
|
||||
|
||||
- name: Checkout Verilator
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
pattern: all-results-*
|
||||
path: all-results
|
||||
merge-multiple: true
|
||||
- name: Get scheduled run info
|
||||
id: scheduled-info
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
ID=$(gh run --repo ${{ github.repository }} list --workflow RTLMeter --event schedule --status success --limit 1 --json databaseId --jq ".[0].databaseId")
|
||||
echo "id=$ID" >> $GITHUB_OUTPUT
|
||||
URL=$(gh run --repo ${{ github.repository }} view $ID --json url --jq ".url")
|
||||
echo "url=$URL" >> $GITHUB_OUTPUT
|
||||
NUM=$(gh run --repo ${{ github.repository }} view $ID --json number --jq ".number")
|
||||
echo "num=$NUM" >> $GITHUB_OUTPUT
|
||||
DATE=$(gh run --repo ${{ github.repository }} view $ID --json createdAt --jq ".createdAt")
|
||||
echo "date=$DATE" >> $GITHUB_OUTPUT
|
||||
- name: Download scheduled run results
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: published-results
|
||||
path: nightly-results
|
||||
run-id: ${{ steps.scheduled-info.outputs.id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Compare results
|
||||
working-directory: rtlmeter
|
||||
run: |
|
||||
for tag in gcc clang gcc-hier; do
|
||||
ADATA=../nightly-results/all-results-${tag}.json
|
||||
BDATA=../all-results/all-results-${tag}.json
|
||||
touch ../verilate-${tag}.txt
|
||||
touch ../execute-${tag}.txt
|
||||
touch ../cppbuild-${tag}.txt
|
||||
if [[ ! -e $ADATA ]]; then
|
||||
continue
|
||||
fi
|
||||
./rtlmeter compare --cases '* !Example:* !*:hello' --steps "verilate" --metrics "elapsed memory" $ADATA $BDATA > ../verilate-${tag}.txt
|
||||
cat ../verilate-${tag}.txt
|
||||
./rtlmeter compare --cases '* !Example:* !*:hello' --steps "execute" --metrics "speed memory elapsed" $ADATA $BDATA > ../execute-${tag}.txt
|
||||
cat ../execute-${tag}.txt
|
||||
./rtlmeter compare --cases '* !Example:* !*:hello' --steps "cppbuild" --metrics "elapsed memory cpu codeSize" $ADATA $BDATA > ../cppbuild-${tag}.txt
|
||||
cat ../cppbuild-${tag}.txt
|
||||
done
|
||||
path: verilator
|
||||
|
||||
- name: Create report
|
||||
id: report
|
||||
working-directory: verilator
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -x
|
||||
NUM=$(gh run --repo ${{ github.repository }} view ${{ github.run_id }} --json number --jq ".number")
|
||||
URL=$(gh run --repo ${{ github.repository }} view ${{ github.run_id }} --json url --jq ".url")
|
||||
echo -n "Performance metrics for PR workflow [#$NUM]($URL) (B) compared to scheduled run" > report.txt
|
||||
echo -n " [#${{ steps.scheduled-info.outputs.num }}](${{ steps.scheduled-info.outputs.url }}) (A)" >> report.txt
|
||||
echo " from ${{ steps.scheduled-info.outputs.date }}" >> report.txt
|
||||
for tag in gcc clang gcc-hier; do
|
||||
echo "" >> report.txt
|
||||
if [[ $tag == "gcc" ]]; then
|
||||
echo "<details open>" >> report.txt
|
||||
else
|
||||
echo "<details>" >> report.txt
|
||||
fi
|
||||
echo -n "<summary><strong><em>" >> report.txt
|
||||
jq -rj ".[0].runName" all-results/all-results-${tag}.json >> report.txt
|
||||
echo "</em></strong></summary>" >> report.txt
|
||||
awk -v RS= -v tag=${tag} '{print > sprintf("frag-%02d-verilate-%s.txt",NR,tag)}' verilate-${tag}.txt
|
||||
awk -v RS= -v tag=${tag} '{print > sprintf("frag-%02d-execute-%s.txt" ,NR,tag)}' execute-${tag}.txt
|
||||
awk -v RS= -v tag=${tag} '{print > sprintf("frag-$02d-cppbuild-%s.txt",NR,tag)}' cppbuild-${tag}.txt
|
||||
for f in $(ls -1 frag-*-verilate-${tag}.txt | sort) $(ls -1 frag-*-execute-${tag}.txt | sort) $(ls -1 frag-*-cppbuild-${tag}.txt | sort); do
|
||||
if [[ $f == frag-01-verilate-${tag}.txt || $f == frag-01-execute-${tag}.txt ]]; then
|
||||
echo "<details open>" >> report.txt
|
||||
else
|
||||
echo "<details>" >> report.txt
|
||||
fi
|
||||
echo -n "<summary>" >> report.txt
|
||||
head -n 1 $f | tr -d '\n' >> report.txt
|
||||
echo "</summary>" >> report.txt
|
||||
echo '<pre>' >> report.txt
|
||||
tail -n +2 $f >> report.txt
|
||||
echo '</pre>' >> report.txt
|
||||
echo "</details>" >> report.txt
|
||||
done
|
||||
echo "</details>" >> report.txt
|
||||
done
|
||||
cat report.txt
|
||||
ln -s ../rtlmeter rtlmeter
|
||||
gh repo set-default ${{ github.repository }}
|
||||
# Create run report - save status to fail job if the script did
|
||||
STATUS=0
|
||||
ci/ci-rtlmeter-report.bash ${{ github.run_id }} ${{ github.sha }} ${{ needs.combine-results.outputs.run-tags }} || STATUS=$?
|
||||
echo "status=$STATUS" >> "$GITHUB_OUTPUT"
|
||||
# Create the report artifact
|
||||
mkdir ../report-artifact
|
||||
mv rtlmeter-report/report ../report-artifact/
|
||||
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
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: report.txt
|
||||
name: rtlmeter-pr-results
|
||||
- name: Save PR number
|
||||
run: echo ${{ github.event.number }} > pr-number.txt
|
||||
- name: Upload PR number
|
||||
path: report-artifact
|
||||
name: rtlmeter-report
|
||||
|
||||
- name: Upload notification
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: pr-number.txt
|
||||
name: pr-number
|
||||
path: notification-artifact
|
||||
name: pr-notification
|
||||
|
||||
- name: Report status
|
||||
run: exit ${{ steps.report.outputs.status }}
|
||||
|
||||
# Create GitHub issue for failed scheduled jobs
|
||||
# This should always be the last job (we want an issue if anything breaks)
|
||||
|
|
|
|||
22
Changes
22
Changes
|
|
@ -21,6 +21,15 @@ Verilator 5.049 devel
|
|||
|
||||
**Other:**
|
||||
|
||||
* Add `+verilator+log+file` (#4505) (#7645). [Tracy Narine]
|
||||
* Add peak memory usage to `--stats`. [Geza Lore, Testorrent USA, Inc.]
|
||||
* Add error on mixed-initialization (#7352) (#7357).
|
||||
* Add `--coverage-per-instance` (#7636). [Yogish Sekhar]
|
||||
* Add NOTREDOP error on reduction and negation operators (#7417) (#7623) (#7624).
|
||||
* Add hierarchy-aware reporting to `verilator_coverage` (#7657). [Yogish Sekhar]
|
||||
* Improve `--coverage-fsm` (#7490) (#7529) (#7561) (#7573) (#7619). [Yogish Sekhar]
|
||||
* Change `+verilator+seed` to default to 1, and 0 to randomly select (#7325) (#7516). [Miguel]
|
||||
* Change JSON to include parameter constant mnemonics for FSM Coverage (#7531). [Yogish Sekhar]
|
||||
* Support printing enum names for %p and %s (#5523) (#7338 repair) (#7521) (#7527). [Nick Brereton]
|
||||
* Support weak `until` / `until_with` property operators (#7290) (#7548) (#7685). [Yilou Wang]
|
||||
* Support `s_eventually` (#7291) (#7508). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
|
|
@ -44,20 +53,12 @@ Verilator 5.049 devel
|
|||
* Support generic interface arrays (#7604). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support FSM detection in primitive wrappers (#7607). [Yogish Sekhar]
|
||||
* Support busses with mix of pullup/pulldown (#7632). [Lucas Amaral]
|
||||
* Support forceable on unpacked array variables (#7677) (#7678). [Nikolai Kumar]
|
||||
* Support pre/post increment/decrement inside && and || (#7683). [Nick Brereton]
|
||||
* Support streaming into 2-D unpacked arrays (#7686) (#7687). [Paul Swirhun]
|
||||
* Support if/if-else in properties (#7692). [Artur Bieniek, Antmicro Ltd.]
|
||||
* Support process::self().srand() (#7695). [Igor Zaworski, Antmicro Ltd.]
|
||||
* Support MacOS lldb (#7697). [Tracy Narine]
|
||||
* Add `+verilator+log+file` (#4505) (#7645). [Tracy Narine]
|
||||
* Add peak memory usage to `--stats`. [Geza Lore, Testorrent USA, Inc.]
|
||||
* Add error on mixed-initialization (#7352) (#7357).
|
||||
* Add `--coverage-per-instance` (#7636). [Yogish Sekhar]
|
||||
* Add NOTREDOP error on reduction and negation operators (#7417) (#7623) (#7624).
|
||||
* Add hierarchy-aware reporting to `verilator_coverage` (#7657). [Yogish Sekhar]
|
||||
* Improve `--coverage-fsm` (#7490) (#7529) (#7561) (#7573) (#7619). [Yogish Sekhar]
|
||||
* Change `+verilator+seed` to default to 1, and 0 to randomly select (#7325) (#7516). [Miguel]
|
||||
* Change JSON to include parameter constant mnemonics for FSM Coverage (#7531). [Yogish Sekhar]
|
||||
* Optimize emitting to_string() for compiler speedup (#7468). [Jakub Michalski, Antmicro Ltd.]
|
||||
* Optimize additional DFG peephole cases (#7553). [Varun Koyyalagunta, Testorrent USA, Inc.]
|
||||
* Optimize forced signal handling (#7554 partial) (#7572) (#7594) (#7596). [Krzysztof Bieganski, Artur Bieniek, Antmicro Ltd.]
|
||||
|
|
@ -68,6 +69,8 @@ Verilator 5.049 devel
|
|||
* Optimize formatting functions (#7701) (#7702) (#7703). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize DPI import argument passing (#7704). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize runtime assertOn() checks (#7707). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize $countones and $onehot in DFG. [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize procedural loop unrolling. [Geza Lore, Testorrent USA, Inc.]
|
||||
* Fix TSP variable ordering for mtasks (#5342) (#7610). [Muzaffer Kal]
|
||||
* Fix inlining static initializer in V3Gate (#5381) (#7503). [Andrew Nolte] [Geza Lore, Testorrent USA, Inc.]
|
||||
* Fix segmentation fault when using --trace with --lib-create (#7299) (#7518). [anonkey]
|
||||
|
|
@ -96,6 +99,7 @@ Verilator 5.049 devel
|
|||
* Fix internal error on consecutive repetition with N > 256 (#7552) (#7603). [Yilou Wang]
|
||||
* Fix inherited rand array with .size + foreach constraint (#7558) (#7650). [Yilou Wang]
|
||||
* Fix biased bit distribution under value < (1 << N) constraints (#7563) (#7684). [Yilou Wang]
|
||||
* Fix HIERPARAM lint checking (#7570) (#7690). [em2machine]
|
||||
* Fix display of %m in non-first argument (#7574).
|
||||
* Fix floating point compile warning on min/max delays.
|
||||
* Fix force of unpacked arrays (#7579) (#7580). [Zubin Jain]
|
||||
|
|
|
|||
|
|
@ -535,6 +535,7 @@ PY_PROGRAMS = \
|
|||
# Python files, subject to format but not lint
|
||||
PY_FILES = \
|
||||
$(PY_PROGRAMS) \
|
||||
ci/*.py \
|
||||
test_regress/t/*.py \
|
||||
|
||||
# Python files, test_regress tests
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# SPDX-FileCopyrightText: 2025 Geza Lore
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
# Notify PRs via comment that their coverage reports are available
|
||||
# Notify PRs via comment that their workflow reports are available
|
||||
|
||||
# Get the current repo URL - might differ on a fork
|
||||
readonly REPO_URL=$(gh repo view --json url --jq .url)
|
||||
|
|
@ -13,7 +13,7 @@ readonly REPO_URL=$(gh repo view --json url --jq .url)
|
|||
ARTIFACTS_ROOT=artifacts
|
||||
mkdir -p ${ARTIFACTS_ROOT}
|
||||
|
||||
for RUN_ID in ${COVERAGE_PR_RUN_IDS//,/ }; do
|
||||
for RUN_ID in ${PR_RUN_IDS//,/ }; do
|
||||
echo "@@@ Processing run ${RUN_ID}"
|
||||
|
||||
# Create workflow artifacts directory
|
||||
|
|
@ -21,7 +21,7 @@ for RUN_ID in ${COVERAGE_PR_RUN_IDS//,/ }; do
|
|||
mkdir -p ${ARTIFACTS_DIR}
|
||||
|
||||
# Download artifact of this run, if exists
|
||||
gh run download ${RUN_ID} --name coverage-pr-notification --dir ${ARTIFACTS_DIR} || true
|
||||
gh run download ${RUN_ID} --name pr-notification --dir ${ARTIFACTS_DIR} || true
|
||||
ls -lsha ${ARTIFACTS_DIR}
|
||||
|
||||
# Move on if no notification is required
|
||||
|
|
@ -35,7 +35,7 @@ for RUN_ID in ${COVERAGE_PR_RUN_IDS//,/ }; do
|
|||
gh pr comment $(cat ${ARTIFACTS_DIR}/pr-number.txt) --body-file ${ARTIFACTS_DIR}/body.txt
|
||||
|
||||
# Get the artifact ID
|
||||
ARTIFACT_ID=$(gh api "repos/{owner}/{repo}/actions/runs/${RUN_ID}/artifacts" --jq '.artifacts[] | select(.name == "coverage-pr-notification") | .id')
|
||||
ARTIFACT_ID=$(gh api "repos/{owner}/{repo}/actions/runs/${RUN_ID}/artifacts" --jq '.artifacts[] | select(.name == "pr-notification") | .id')
|
||||
|
||||
# Delete it, so we only notify once
|
||||
gh api --method DELETE "repos/{owner}/{repo}/actions/artifacts/${ARTIFACT_ID}"
|
||||
|
|
|
|||
149
ci/ci-pages.bash
149
ci/ci-pages.bash
|
|
@ -5,8 +5,7 @@
|
|||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
# This scipt build the content of the GitHub Pages for the repository.
|
||||
# Currently this only hosts code coverage reports, but it would be possible to
|
||||
# add any other contents to the page in parallel here.
|
||||
# Currently this hosts code coverage reports, and PR RTLMeter detailed reports.
|
||||
|
||||
# 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'),
|
||||
|
|
@ -25,6 +24,9 @@ if [[ -z "$GITHUB_OUTPUT" ]]; then
|
|||
GITHUB_OUTPUT=github-output.txt
|
||||
fi
|
||||
|
||||
# Run IDs of PR jobs processed
|
||||
PR_RUN_IDS=""
|
||||
|
||||
# Populates ${PAGES_ROOT}/coverage-reports
|
||||
compile_coverage_reports() {
|
||||
# We will process all runs up to and including this date. This is chosen to be
|
||||
|
|
@ -42,7 +44,7 @@ compile_coverage_reports() {
|
|||
jq "." completedRuns.json
|
||||
|
||||
# Create artifacts root directory
|
||||
local ARTIFACTS_ROOT=artifacts
|
||||
local ARTIFACTS_ROOT=artifacts-coverage
|
||||
mkdir -p ${ARTIFACTS_ROOT}
|
||||
|
||||
# Create coverage reports root directory
|
||||
|
|
@ -53,9 +55,6 @@ compile_coverage_reports() {
|
|||
local CONTENTS=contents.tmp
|
||||
echo > ${CONTENTS}
|
||||
|
||||
# Run IDs of PR jobs processed
|
||||
local PR_RUN_IDS=""
|
||||
|
||||
# Iterate over all unique event types that triggered the workflows
|
||||
for EVENT in $(jq -r 'map(.event) | sort | unique | .[]' completedRuns.json); do
|
||||
echo "@@@ Processing '${EVENT}' runs"
|
||||
|
|
@ -72,13 +71,7 @@ compile_coverage_reports() {
|
|||
jq "." workflow.json
|
||||
|
||||
# Record run ID of PR job
|
||||
if [[ $EVENT == "pull_request" ]]; then
|
||||
if [[ -z "$PR_RUN_IDS" ]]; then
|
||||
PR_RUN_IDS="$RUN_ID"
|
||||
else
|
||||
PR_RUN_IDS="$PR_RUN_IDS,$RUN_ID"
|
||||
fi
|
||||
fi
|
||||
[[ $EVENT != "pull_request" ]] || PR_RUN_IDS="$PR_RUN_IDS $RUN_ID"
|
||||
|
||||
# Create workflow artifacts directory
|
||||
local ARTIFACTS_DIR=${ARTIFACTS_ROOT}/${RUN_ID}
|
||||
|
|
@ -148,7 +141,7 @@ CONTENTS_TEMPLATE
|
|||
|
||||
<body>
|
||||
$(cat ${CONTENTS})
|
||||
<h4>Assembled $(date --iso-8601=minutes --utc)</h1>
|
||||
<h4>Assembled $(date --iso-8601=minutes --utc)</h4>
|
||||
<body>
|
||||
|
||||
</html>
|
||||
|
|
@ -156,12 +149,136 @@ INDEX_TEMPLATE
|
|||
|
||||
# Report size
|
||||
du -shc ${COVERAGE_ROOT}/*
|
||||
}
|
||||
|
||||
# Set output
|
||||
echo "coverage-pr-run-ids=${PR_RUN_IDS}" >> $GITHUB_OUTPUT
|
||||
# Populates ${PAGES_ROOT}/rtlmeter-reports
|
||||
compile_rtlmeter_reports() {
|
||||
# We will process all runs up to and including this date. This is chosen to be
|
||||
# slightly less than the artifact retention period for simplicity.
|
||||
local OLDEST=$(date --date="28 days ago" --iso-8601=date)
|
||||
|
||||
# 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
|
||||
echo @@@ Recent runs:
|
||||
jq "." recentRuns.json
|
||||
|
||||
# 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
|
||||
echo @@@ Completed with success or failure:
|
||||
jq "." completedRuns.json
|
||||
|
||||
# Create artifacts root directory
|
||||
local ARTIFACTS_ROOT=artifacts-rtlmeter
|
||||
mkdir -p ${ARTIFACTS_ROOT}
|
||||
|
||||
# Create rtlmeter reports root directory
|
||||
local RTLMETER_ROOT=${PAGES_ROOT}/rtlmeter-reports
|
||||
mkdir -p ${RTLMETER_ROOT}
|
||||
|
||||
# Create index page contents fragment
|
||||
local CONTENTS=contents.tmp
|
||||
echo > ${CONTENTS}
|
||||
|
||||
# Iterate over all unique event types that triggered the workflows
|
||||
for EVENT in $(jq -r 'map(.event) | sort | unique | .[]' completedRuns.json); do
|
||||
echo "@@@ Processing '${EVENT}' runs"
|
||||
|
||||
# Emit section header if a report exists with this event type
|
||||
EMIT_SECTION_HEADER=1
|
||||
|
||||
# For each worfklow run that was triggered by this event type
|
||||
for RUN_ID in $(jq ".[] | select(.event == \"${EVENT}\") |.databaseId" completedRuns.json); do
|
||||
echo "@@@ Processing run ${RUN_ID}"
|
||||
|
||||
# Extract the info of this run
|
||||
jq ".[] | select(.databaseId == $RUN_ID)" completedRuns.json > workflow.json
|
||||
jq "." workflow.json
|
||||
|
||||
# Record run ID of PR job
|
||||
[[ $EVENT != "pull_request" ]] || PR_RUN_IDS="$PR_RUN_IDS $RUN_ID"
|
||||
|
||||
# Create workflow artifacts directory
|
||||
local ARTIFACTS_DIR=${ARTIFACTS_ROOT}/${RUN_ID}
|
||||
mkdir -p ${ARTIFACTS_DIR}
|
||||
|
||||
# Download artifacts of this run, if exists
|
||||
gh run download ${RUN_ID} --name rtlmeter-report --dir ${ARTIFACTS_DIR} || true
|
||||
ls -lsha ${ARTIFACTS_DIR}
|
||||
|
||||
# Move on if no RTLMeter report is available
|
||||
if [ ! -d ${ARTIFACTS_DIR}/report ]; then
|
||||
echo "No RTLMeter report found"
|
||||
continue
|
||||
fi
|
||||
echo "RTLMeter report found"
|
||||
|
||||
# Emit section header
|
||||
if [[ -n $EMIT_SECTION_HEADER ]]; then
|
||||
unset EMIT_SECTION_HEADER
|
||||
echo "<h4>RTLMeter reports for '${EVENT}' runs:</h4>" >> ${CONTENTS}
|
||||
fi
|
||||
|
||||
# Create pages subdirectory
|
||||
mv ${ARTIFACTS_DIR}/report ${RTLMETER_ROOT}/${RUN_ID}
|
||||
|
||||
# Add index page content
|
||||
local WORKFLOW_CREATED=$(jq -r '.createdAt' workflow.json)
|
||||
local WOFKRLOW_NUMBER=$(jq -r '.number' workflow.json)
|
||||
cat >> ${CONTENTS} <<CONTENTS_TEMPLATE
|
||||
Run <a href="${RUN_ID}/index.html">#${WOFKRLOW_NUMBER}</a>
|
||||
| GitHub: <a href="${REPO_URL}/actions/runs/${RUN_ID}">${RUN_ID}</a>
|
||||
| started at: ${WORKFLOW_CREATED}
|
||||
CONTENTS_TEMPLATE
|
||||
if [ -e ${ARTIFACTS_DIR}/pr-number.txt ]; then
|
||||
local PRNUMBER=$(cat ${ARTIFACTS_DIR}/pr-number.txt)
|
||||
echo " | Pull request: <a href=\"${REPO_URL}/pull/${PRNUMBER}\">#${PRNUMBER}</a>" >> ${CONTENTS}
|
||||
fi
|
||||
echo "<br>" >> ${CONTENTS}
|
||||
done
|
||||
|
||||
# Section break
|
||||
if [[ -z "$EMIT_SECTION_HEADER" ]]; then
|
||||
echo "<hr>" >> ${CONTENTS}
|
||||
fi
|
||||
done
|
||||
|
||||
# Write rtlmeter report index.html
|
||||
cat > ${RTLMETER_ROOT}/index.html <<INDEX_TEMPLATE
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Verilator CI RTLMeter reports</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: courier, serif;
|
||||
background-color: #f3f3f3;
|
||||
a {
|
||||
color: #008fd7;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
$(cat ${CONTENTS})
|
||||
<h4>Assembled $(date --iso-8601=minutes --utc)</h4>
|
||||
<body>
|
||||
|
||||
</html>
|
||||
INDEX_TEMPLATE
|
||||
|
||||
# Report size
|
||||
du -shc ${RTLMETER_ROOT}/*
|
||||
}
|
||||
|
||||
# Compilie coverage reports
|
||||
compile_coverage_reports;
|
||||
|
||||
# Compile RTLMeter reports
|
||||
compile_rtlmeter_reports;
|
||||
|
||||
# You can build any other content here to be put under ${PAGES_ROOT}
|
||||
|
||||
# Set output to all affected unique PR run IDs (comma separated, no trailing comma)
|
||||
IDS=$(echo ${PR_RUN_IDS} | xargs -n1 | sort -u | paste -sd,)
|
||||
echo "pr-run-ids=${IDS}" >> $GITHUB_OUTPUT
|
||||
|
|
|
|||
|
|
@ -0,0 +1,210 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: RTLMeter cases to run in the rtlmeter.yml CI workflow
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
###############################################################################
|
||||
# Defines the RTLMeter cases to run in CI. This is consumed by the 'start' job
|
||||
# in rtlmeter.yml, which captures the printed JSON and feeds it to the run job
|
||||
# matrices.
|
||||
###############################################################################
|
||||
|
||||
import argparse
|
||||
import json
|
||||
|
||||
# Cases to run for scheduled runs, keyyed by the 'run tag' used in rtlmeter.yml
|
||||
# The associated priority is roughly the number of minutes it takes to run the
|
||||
# job, the emitted job matrix will try to start longest jobs first.
|
||||
|
||||
# Cases to run for non-PR jobs (e.g.: nightly schedule)
|
||||
# fmt: off
|
||||
CASES = {
|
||||
"gcc": [
|
||||
("BlackParrot:1x1:*", 5),
|
||||
("BlackParrot:2x2:*", 14),
|
||||
("BlackParrot:4x4:*", 25),
|
||||
("Caliptra:default:*", 19),
|
||||
("NVDLA:*", 29),
|
||||
("OpenPiton:1x1:*", 4),
|
||||
("OpenPiton:2x2:*", 7),
|
||||
("OpenPiton:4x4:*", 10),
|
||||
("OpenTitan:*", 16),
|
||||
("Servant:qerv:*", 2),
|
||||
("Servant:serv:*", 2),
|
||||
("VeeR-EH1:asic:*", 4),
|
||||
("VeeR-EH1:default:*", 6),
|
||||
("VeeR-EH1:hiperf:*", 5),
|
||||
("VeeR-EH2:asic:*", 13),
|
||||
("VeeR-EH2:default:*", 6),
|
||||
("VeeR-EH2:hiperf:*", 12),
|
||||
("VeeR-EL2:asic:*", 4),
|
||||
("VeeR-EL2:default:*", 4),
|
||||
("VeeR-EL2:hiperf:*", 4),
|
||||
("Vortex:mini:*", 3),
|
||||
("Vortex:sane:*", 6),
|
||||
("XiangShan:default-chisel3:* !*:linux", 31),
|
||||
("XiangShan:default-chisel6:* !*:linux", 28),
|
||||
("XiangShan:mini-chisel3:* !*:linux", 13),
|
||||
("XiangShan:mini-chisel6:* !*:linux", 15),
|
||||
("XuanTie-C906:*", 5),
|
||||
("XuanTie-C910:*", 9),
|
||||
("XuanTie-E902:*", 5),
|
||||
("XuanTie-E906:*", 6),
|
||||
],
|
||||
"clang": [
|
||||
("BlackParrot:1x1:*", 5),
|
||||
("BlackParrot:2x2:*", 9),
|
||||
("BlackParrot:4x4:*", 12),
|
||||
("Caliptra:default:*", 16),
|
||||
("NVDLA:*", 28),
|
||||
("OpenPiton:1x1:*", 5),
|
||||
("OpenPiton:2x2:*", 6),
|
||||
("OpenPiton:4x4:*", 8),
|
||||
("OpenTitan:*", 10),
|
||||
("Servant:qerv:*", 17),
|
||||
("Servant:serv:*", 15),
|
||||
("VeeR-EH1:asic:*", 6),
|
||||
("VeeR-EH1:default:*", 8),
|
||||
("VeeR-EH1:hiperf:*", 5),
|
||||
("VeeR-EH2:asic:*", 9),
|
||||
("VeeR-EH2:default:*", 8),
|
||||
("VeeR-EH2:hiperf:*", 7),
|
||||
("VeeR-EL2:asic:*", 4),
|
||||
("VeeR-EL2:default:*", 5),
|
||||
("VeeR-EL2:hiperf:*", 5),
|
||||
("Vortex:mini:*", 3),
|
||||
("Vortex:sane:*", 5),
|
||||
("XiangShan:default-chisel3:* !*:linux", 21),
|
||||
("XiangShan:default-chisel6:* !*:linux", 19),
|
||||
("XiangShan:mini-chisel3:* !*:linux", 8),
|
||||
("XiangShan:mini-chisel6:* !*:linux", 8),
|
||||
("XuanTie-C906:*", 3),
|
||||
("XuanTie-C910:*", 7),
|
||||
("XuanTie-E902:*", 7),
|
||||
("XuanTie-E906:*", 7),
|
||||
],
|
||||
"gcc-hier": [
|
||||
("BlackParrot:1x1:*", 4),
|
||||
("BlackParrot:2x2:*", 16),
|
||||
("BlackParrot:4x4:*", 25),
|
||||
("NVDLA:*", 25),
|
||||
("OpenPiton:16x16:dhry", 16),
|
||||
("OpenPiton:1x1:*", 4),
|
||||
("OpenPiton:2x2:*", 4),
|
||||
("OpenPiton:4x4:*", 4),
|
||||
("OpenPiton:8x8:*", 6),
|
||||
("XuanTie-C910:*", 7),
|
||||
],
|
||||
}
|
||||
# fmt: on
|
||||
|
||||
# Cases to run for PR jobs
|
||||
# fmt: off
|
||||
CASES_PR = {
|
||||
"gcc": [
|
||||
("BlackParrot:1x1:*", 5),
|
||||
("BlackParrot:4x4:*", 25),
|
||||
("Caliptra:default:*", 19),
|
||||
("NVDLA:*", 29),
|
||||
("OpenPiton:1x1:*", 4),
|
||||
("OpenPiton:4x4:*", 10),
|
||||
("OpenTitan:*", 16),
|
||||
("Servant:qerv:*", 2),
|
||||
("Servant:serv:*", 2),
|
||||
("VeeR-EH1:asic:*", 4),
|
||||
("VeeR-EH1:default:*", 6),
|
||||
("VeeR-EH1:hiperf:*", 5),
|
||||
("VeeR-EH2:asic:*", 13),
|
||||
("VeeR-EH2:default:*", 6),
|
||||
("VeeR-EH2:hiperf:*", 12),
|
||||
("VeeR-EL2:asic:*", 4),
|
||||
("VeeR-EL2:default:*", 4),
|
||||
("VeeR-EL2:hiperf:*", 4),
|
||||
("Vortex:mini:*", 3),
|
||||
("Vortex:sane:*", 6),
|
||||
("XiangShan:default-chisel3:* !*:linux", 31),
|
||||
("XiangShan:default-chisel6:* !*:linux", 28),
|
||||
("XiangShan:mini-chisel3:* !*:linux", 13),
|
||||
("XiangShan:mini-chisel6:* !*:linux", 15),
|
||||
("XuanTie-C906:*", 5),
|
||||
("XuanTie-C910:*", 9),
|
||||
("XuanTie-E902:*", 5),
|
||||
("XuanTie-E906:*", 6),
|
||||
],
|
||||
"clang": [
|
||||
("BlackParrot:1x1:*", 5),
|
||||
("BlackParrot:4x4:*", 12),
|
||||
("Caliptra:default:*", 16),
|
||||
("NVDLA:*", 28),
|
||||
("OpenPiton:1x1:*", 5),
|
||||
("OpenPiton:4x4:*", 8),
|
||||
("OpenTitan:*", 10),
|
||||
("Servant:qerv:*", 17),
|
||||
("Servant:serv:*", 15),
|
||||
("VeeR-EH1:asic:*", 6),
|
||||
("VeeR-EH1:default:*", 8),
|
||||
("VeeR-EH1:hiperf:*", 5),
|
||||
("VeeR-EH2:asic:*", 9),
|
||||
("VeeR-EH2:default:*", 8),
|
||||
("VeeR-EH2:hiperf:*", 7),
|
||||
("VeeR-EL2:asic:*", 4),
|
||||
("VeeR-EL2:default:*", 5),
|
||||
("VeeR-EL2:hiperf:*", 5),
|
||||
("Vortex:mini:*", 3),
|
||||
("Vortex:sane:*", 5),
|
||||
("XiangShan:default-chisel3:* !*:linux", 21),
|
||||
("XiangShan:default-chisel6:* !*:linux", 19),
|
||||
("XiangShan:mini-chisel3:* !*:linux", 8),
|
||||
("XiangShan:mini-chisel6:* !*:linux", 8),
|
||||
("XuanTie-C906:*", 3),
|
||||
("XuanTie-C910:*", 7),
|
||||
("XuanTie-E902:*", 7),
|
||||
("XuanTie-E906:*", 7),
|
||||
],
|
||||
"gcc-hier": [
|
||||
("BlackParrot:1x1:*", 4),
|
||||
("BlackParrot:4x4:*", 25),
|
||||
("NVDLA:*", 25),
|
||||
("OpenPiton:16x16:dhry", 16),
|
||||
("OpenPiton:1x1:*", 4),
|
||||
("OpenPiton:4x4:*", 4),
|
||||
("OpenPiton:8x8:*", 6),
|
||||
("XuanTie-C910:*", 7),
|
||||
],
|
||||
}
|
||||
# fmt: on
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Print the RTLMeter CI cases as JSON, keyed by run tag")
|
||||
parser.add_argument("--event-name",
|
||||
required=True,
|
||||
help="GitHub event name that triggered the workflow")
|
||||
parser.add_argument(
|
||||
"--ci-testing",
|
||||
action="store_true",
|
||||
help="Print only the shortest (lowest priority) case per tag, to reduce CI testing time")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Pull requests use the reduced 'CASES_PR' set, other events (e.g.: the nightly
|
||||
# schedule) use the full 'CASES' set.
|
||||
is_pr = args.event_name == "pull_request"
|
||||
selected = CASES_PR if is_pr else CASES
|
||||
|
||||
cases = {}
|
||||
for tag, entries in selected.items():
|
||||
# Highest priority (longest) first
|
||||
ordered = sorted(entries, key=lambda cp: cp[1], reverse=True)
|
||||
# While tweaking the CI, keep only the shortest (lowest priority) case to minimise churn time
|
||||
if args.ci_testing:
|
||||
ordered = ordered[-1:]
|
||||
# Case filters appended to every case for this tag/event
|
||||
suffix = ""
|
||||
# Filters out the non-hierarchical case variants for the hierarchical job
|
||||
if tag == "gcc-hier":
|
||||
suffix += " !-hier"
|
||||
# Filter out hello tests on pull requests, these just add measurement noise
|
||||
if is_pr:
|
||||
suffix += " !*:hello"
|
||||
cases[tag] = [case + suffix for case, _ in ordered]
|
||||
print(json.dumps(cases, separators=(",", ":")))
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
#!/usr/bin/env bash
|
||||
# DESCRIPTION: Verilator: CI script for 'rtlmeter.yml' PR results
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
# This script builds the content of the response comment posted on PRs
|
||||
# at the end of RTLMeter runs.
|
||||
|
||||
# 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').
|
||||
|
||||
# Trace when running in the CI
|
||||
[ "$GITHUB_ACTIONS" != "true" ] || set -x
|
||||
|
||||
# Arguments:
|
||||
# 1. run ID
|
||||
# 2. SHA of the event that triggered the run (for a PR, the test merge commit)
|
||||
# rest: run tags
|
||||
RUN_ID=$1; shift
|
||||
RUN_SHA=$1; shift
|
||||
RUNS="$@"
|
||||
|
||||
# $VERILATOR_CHECKOUT/ci directory
|
||||
SCRIPT_DIR=$(readlink -f $(dirname ${BASH_SOURCE[0]}))
|
||||
|
||||
# Move into a temporary directory
|
||||
rm -rf rtlmeter-report
|
||||
mkdir rtlmeter-report
|
||||
pushd rtlmeter-report &> /dev/null
|
||||
TMP_DIR=$(readlink -f .)
|
||||
|
||||
# Download the combined results. 'combine-results' uploads a single artifact
|
||||
# for each version, holding the per-tag JSON files (e.g. all-results-gcc.json):
|
||||
# - 'all-results' for the new version
|
||||
# - 'all-reference' for the old reference version
|
||||
mkdir new ref
|
||||
NEW_DIR=$(readlink -f new)
|
||||
REF_DIR=$(readlink -f ref)
|
||||
gh run download ${RUN_ID} --name all-results --dir $NEW_DIR
|
||||
gh run download ${RUN_ID} --name all-reference --dir $REF_DIR
|
||||
|
||||
# Get Some metadata about the runs
|
||||
RUN_URL=$(gh run view $RUN_ID --json url --jq ".url")
|
||||
RUN_NUM=$(gh run view $RUN_ID --json number --jq ".number")
|
||||
|
||||
# Repository owner and name of the default repository, used to build the
|
||||
# GitHub Pages URL of the detailed report. The owner is lowercased, as required
|
||||
# for the '<owner>.github.io' Pages domain. Resolved here, while still in the
|
||||
# default repository's git context (before the 'cd rtlmeter' below).
|
||||
PAGES_OWNER=$(gh repo view --json owner --jq '.owner.login' | tr '[:upper:]' '[:lower:]')
|
||||
PAGES_NAME=$(gh repo view --json name --jq '.name')
|
||||
|
||||
# The 'old' reference was built from the target branch base commit, which is
|
||||
# the first parent of the triggering merge commit (same as the 'start' job in
|
||||
# rtlmeter.yml). Resolved here, while still in the default repository's git
|
||||
# context (before the 'cd rtlmeter' below).
|
||||
REF_SHA=$(gh api "repos/{owner}/{repo}/commits/$RUN_SHA" --jq '.parents[0].sha')
|
||||
|
||||
# Go back to root directory
|
||||
popd &> /dev/null
|
||||
# Go to RTLMeter directory
|
||||
cd rtlmeter
|
||||
|
||||
# Compare results
|
||||
SUMMARY_ARGS=()
|
||||
for r in $RUNS; do
|
||||
CMP_JSON=$TMP_DIR/cmp-$r.json
|
||||
# Gather args for summary script
|
||||
SUMMARY_ARGS+=($NEW_DIR/all-results-$r.json $CMP_JSON)
|
||||
# Create JSON
|
||||
./rtlmeter compare --format json --steps "*" --metrics "*" \
|
||||
$REF_DIR/all-reference-$r.json $NEW_DIR/all-results-$r.json > $CMP_JSON
|
||||
# Also create detailed tables
|
||||
./rtlmeter compare --format ascii --steps 'verilate' --metrics '*' $REF_DIR/all-reference-$r.json $NEW_DIR/all-results-$r.json > $TMP_DIR/verilate-$r.txt
|
||||
./rtlmeter compare --format ascii --steps 'cppbuild' --metrics '*' $REF_DIR/all-reference-$r.json $NEW_DIR/all-results-$r.json > $TMP_DIR/cppbuild-$r.txt
|
||||
./rtlmeter compare --format ascii --steps 'execute' --metrics '*' $REF_DIR/all-reference-$r.json $NEW_DIR/all-results-$r.json > $TMP_DIR/execute-$r.txt
|
||||
# Chop them at new lines, into one table per file
|
||||
awk -v RS= -v prefix=$TMP_DIR/$r-frag '{print > sprintf("%s-verilate-%02d.txt",prefix,NR)}' $TMP_DIR/verilate-$r.txt
|
||||
awk -v RS= -v prefix=$TMP_DIR/$r-frag '{print > sprintf("%s-cppbuild-%02d.txt",prefix,NR)}' $TMP_DIR/cppbuild-$r.txt
|
||||
awk -v RS= -v prefix=$TMP_DIR/$r-frag '{print > sprintf("%s-execute-%02d.txt" ,prefix,NR)}' $TMP_DIR/execute-$r.txt
|
||||
done
|
||||
|
||||
# Create summary, suppress failure, but save the status reported to pass back.
|
||||
STATUS=0
|
||||
venv/bin/python3 $SCRIPT_DIR/ci-rtlmeter-report.py ${SUMMARY_ARGS[@]} > $TMP_DIR/summary.txt || STATUS=$?
|
||||
# Print it
|
||||
cat $TMP_DIR/summary.txt
|
||||
|
||||
# Create notification comment content
|
||||
NOTIFICATION=$TMP_DIR/notification.txt
|
||||
cat > $NOTIFICATION <<NOTIFICATION_TEMPLATE
|
||||
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)
|
||||
- with PR merge commit [${RUN_SHA:0:9}](https://github.com/${PAGES_OWNER}/${PAGES_NAME}/commit/${RUN_SHA}) (B)
|
||||
|
||||
<details open>
|
||||
<summary>Summary of all runs</summary>
|
||||
<pre>
|
||||
$(cat $TMP_DIR/summary.txt)
|
||||
</pre>
|
||||
</details>
|
||||
|
||||
The reported numbers are the geometric means of the ratios of the metrics over all cases,
|
||||
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.
|
||||
|
||||
Detailed report: [${RUN_ID}](https://${PAGES_OWNER}.github.io/${PAGES_NAME}/rtlmeter-reports/${RUN_ID}/index.html)
|
||||
NOTIFICATION_TEMPLATE
|
||||
|
||||
# Create detailed report
|
||||
REPORT=$TMP_DIR/body.html
|
||||
cat > $REPORT <<SUMMARY_TEMPLATE
|
||||
<h3>Summary of all runs</h3>
|
||||
<pre>
|
||||
$(cat $TMP_DIR/summary.txt)
|
||||
</pre>
|
||||
SUMMARY_TEMPLATE
|
||||
echo "<h3>Detailed results</h3>" >> $REPORT
|
||||
for r in $RUNS; do
|
||||
RUN_NAME=$(jq -rj ".[0].runName" $NEW_DIR/all-results-$r.json)
|
||||
echo "<h4>$RUN_NAME</h4>" >> $REPORT
|
||||
for f in $(ls -1 $TMP_DIR/$r-frag-verilate-*.txt | sort) \
|
||||
$(ls -1 $TMP_DIR/$r-frag-cppbuild-*.txt | sort) \
|
||||
$(ls -1 $TMP_DIR/$r-frag-execute-*.txt | sort); do
|
||||
cat >> $REPORT <<DETAIL_TAMPLATE
|
||||
<details>
|
||||
<summary>$(head -n 1 $f | tr -d '\n')</summary>
|
||||
<pre>
|
||||
$(tail -n +2 $f)
|
||||
</pre>
|
||||
</details>
|
||||
DETAIL_TAMPLATE
|
||||
done
|
||||
done
|
||||
|
||||
# Turn the report into a proper HTML page
|
||||
mkdir -p ${TMP_DIR}/report
|
||||
cat > ${TMP_DIR}/report/index.html <<INDEX_TEMPLATE
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Verilator RTLMeter report #${RUN_NUM}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: courier, serif;
|
||||
background-color: #f3f3f3;
|
||||
a {
|
||||
color: #008fd7;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
$(cat ${TMP_DIR}/body.html)
|
||||
</body>
|
||||
|
||||
</html>
|
||||
INDEX_TEMPLATE
|
||||
|
||||
exit $STATUS
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
# DESCRIPTION: Verilator: CI script for 'rtlmeter.yml' PR results
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
###############################################################################
|
||||
# This script runs with the venv of **RTLMeter**
|
||||
###############################################################################
|
||||
|
||||
import sys
|
||||
import json
|
||||
import tabulate
|
||||
from typing import Final, List
|
||||
|
||||
tabulate.PRESERVE_WHITESPACE = True
|
||||
tabulate.MIN_PADDING = 0
|
||||
|
||||
_ASCII_TABLE_FORMAT: Final = tabulate.TableFormat(
|
||||
lineabove=tabulate.Line("╒═", "═", "═╤═", "═╕"),
|
||||
linebelowheader=tabulate.Line("╞═", "═", "═╪═", "═╡"),
|
||||
linebelow=tabulate.Line("╘═", "═", "═╧═", "═╛"),
|
||||
headerrow=tabulate.DataRow("│ ", " │ ", " │"),
|
||||
datarow=tabulate.DataRow("│ ", " │ ", " │"),
|
||||
linebetweenrows=None,
|
||||
padding=0,
|
||||
with_header_hide=None,
|
||||
)
|
||||
|
||||
|
||||
def printTable(table: List[List[str]], **kwargs) -> None:
|
||||
print(tabulate.tabulate(table, tablefmt=_ASCII_TABLE_FORMAT, **kwargs))
|
||||
|
||||
|
||||
# fmt: off
|
||||
stepMetric = (
|
||||
# Step, Metric, Status Brackets
|
||||
("execute", "speed", ("❌", 0.96, "⚠️", 0.98, "✅", 1.02, "💡", 1.04, "⭐")),
|
||||
("execute", "memory", ("❌", 0.90, "⚠️", 0.95, "✅", 1.05, "💡", 1.10, "⭐")),
|
||||
("verilate", "cpu", ("❌", 0.96, "⚠️", 0.98, "✅", 1.02, "💡", 1.04, "⭐")),
|
||||
("verilate", "memory", ("❌", 0.90, "⚠️", 0.95, "✅", 1.05, "💡", 1.10, "⭐")),
|
||||
("cppbuild", "cpu", ("❌", 0.96, "⚠️", 0.98, "✅", 1.02, "💡", 1.04, "⭐")),
|
||||
("cppbuild", "memory", ("❌", 0.90, "⚠️", 0.95, "✅", 1.05, "💡", 1.10, "⭐")),
|
||||
("cppbuild", "codeSize",("❌", 0.96, "⚠️", 0.98, "✅", 1.02, "💡", 1.04, "⭐")),
|
||||
("cppbuild", "elapsed", ("❌", 0.70, "⚠️", 0.85, "✅", 1.15, "💡", 1.30, "⭐")),
|
||||
)
|
||||
|
||||
badgeLegend = [
|
||||
("❌", "Likely regression"),
|
||||
("⚠️", "Possible regression"),
|
||||
("✅", "Within acceptable range"),
|
||||
("💡", "Possible improvement"),
|
||||
("⭐", "Likely improvement"),
|
||||
]
|
||||
# fmt: on
|
||||
|
||||
changedCycles = []
|
||||
table = []
|
||||
badgesToExplain = set()
|
||||
|
||||
for ref, cmp in zip(sys.argv[1::2], sys.argv[2::2]):
|
||||
with open(ref, "r", encoding="utf-8") as f:
|
||||
ref_json = json.load(f)[0]
|
||||
with open(cmp, "r", encoding="utf-8") as f:
|
||||
cmp_json = json.load(f)
|
||||
if table:
|
||||
table.append(tabulate.SEPARATING_LINE)
|
||||
runName = ref_json["runName"]
|
||||
|
||||
# Check simulated cycles match - it's ok to crash if this entry does not exist
|
||||
for entry in cmp_json["execute"]["clocks"]["table"]:
|
||||
case, _, _, (refCycles, _), (newCycles, _), _, _ = entry
|
||||
refCycles = int(refCycles)
|
||||
newCycles = int(newCycles)
|
||||
if refCycles != newCycles:
|
||||
changedCycles.append([runName, case, refCycles, newCycles])
|
||||
|
||||
# Check metrics
|
||||
for step, metric, brackets in stepMetric:
|
||||
if step not in cmp_json:
|
||||
continue
|
||||
data = cmp_json[step]
|
||||
if metric not in data:
|
||||
continue
|
||||
data = data[metric]
|
||||
minGain = float("inf")
|
||||
maxGain = float("-inf")
|
||||
meanGain = 1
|
||||
count = 0
|
||||
for _, _, _, (a, _), (b, _), g, _ in data["table"]:
|
||||
# for wall clock and CPU time, ignore small values that just add noise
|
||||
if metric == "elapsed" or metric == "cpu":
|
||||
if a < 30 or b < 30:
|
||||
continue
|
||||
minGain = min(minGain, g)
|
||||
maxGain = max(maxGain, g)
|
||||
meanGain *= g
|
||||
count += 1
|
||||
if count == 0:
|
||||
continue
|
||||
meanGain = meanGain**(1 / count)
|
||||
|
||||
status = brackets[0]
|
||||
for limit, badge in zip(brackets[1::2], brackets[2::2]):
|
||||
if meanGain >= limit:
|
||||
status = badge
|
||||
badgesToExplain.add(status)
|
||||
|
||||
table.append([
|
||||
runName, step, ref_json["metrics"][metric]["header"], f"{meanGain:.2f}x {status} ",
|
||||
f"{minGain:.2f}x", f"{maxGain:.2f}x", f"{count}"
|
||||
])
|
||||
|
||||
# Print changed cycles if any
|
||||
if changedCycles:
|
||||
print("❌ simulated cycles changed (must be fixed):")
|
||||
printTable(changedCycles,
|
||||
headers=("Run", "Case", "Old Cycles", "New Cycles"),
|
||||
colalign=("left", "left", "right", "right"),
|
||||
disable_numparse=True)
|
||||
print()
|
||||
|
||||
# Print results
|
||||
printTable(
|
||||
table,
|
||||
headers=("Run", "Step", "Metric", "Improvement", "Min", "Max", "Samples"),
|
||||
colalign=("left", "left", "left", "right", "right", "right", "right"),
|
||||
disable_numparse=True,
|
||||
)
|
||||
|
||||
# Explain badges
|
||||
print()
|
||||
for badge, legend in badgeLegend:
|
||||
if badge in badgesToExplain:
|
||||
print(f" {badge} : {legend}")
|
||||
|
||||
# Fail job if status changed
|
||||
sys.exit(0 if not changedCycles else 1)
|
||||
93
configure.ac
93
configure.ac
|
|
@ -421,6 +421,15 @@ AC_DEFUN([_MY_LDLIBS_CHECK_OPT],
|
|||
_MY_LDLIBS_CHECK_IFELSE($2, $1="$$1 $2")
|
||||
])
|
||||
|
||||
AC_DEFUN([_MY_LDLIBS_CHECK_SET],
|
||||
[# _MY_LDLIBS_CHECK_SET(variable, flag) -- Check if linker supports specific
|
||||
# options. If it does, set variable to flag, only if not previously set
|
||||
# (so the first supported flag wins and the rest are not tested).
|
||||
if test "$$1" = ""; then
|
||||
_MY_LDLIBS_CHECK_IFELSE($2, $1="$2")
|
||||
fi
|
||||
])
|
||||
|
||||
# Add the coverage flags early as they influence later checks.
|
||||
if test "$CFG_WITH_DEV_GCOV" = "yes"; then
|
||||
_MY_CXX_CHECK_OPT(CXX,--coverage)
|
||||
|
|
@ -589,11 +598,6 @@ if test "$CFG_ENABLE_PARTIAL_STATIC" = "yes"; then
|
|||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libgcc)
|
||||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libstdc++)
|
||||
_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -Xlinker -gc-sections)
|
||||
LTCMALLOC="-Wl,--whole-archive -l:libtcmalloc_minimal.a -Wl,--no-whole-archive"
|
||||
LJEMALLOC="-Wl,--whole-archive -l:libjemalloc.a -Wl,--no-whole-archive"
|
||||
else
|
||||
LTCMALLOC=-ltcmalloc_minimal
|
||||
LJEMALLOC=-ljemalloc
|
||||
fi
|
||||
AC_SUBST(CFG_LDFLAGS_SRC)
|
||||
AC_SUBST(CFG_LDFLAGS_VERILATED)
|
||||
|
|
@ -609,51 +613,56 @@ _MY_LDLIBS_CHECK_OPT(CFG_LIBS, -latomic)
|
|||
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lbcrypt)
|
||||
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lpsapi)
|
||||
|
||||
# Check if jemalloc is available based on --enable-jemalloc
|
||||
# jemalloc is preferred over tcmalloc when both are available
|
||||
# Figure out which malloc library to use:
|
||||
# - Prefer jemalloc over tcmalloc (it's faster)
|
||||
# - If partial static link enabled, prefer static libraries,
|
||||
# but fall back on dynamic if static is not available
|
||||
|
||||
# Test for jemalloc
|
||||
CFG_HAVE_JEMALLOC=no
|
||||
_MY_LDLIBS_CHECK_IFELSE(
|
||||
$LJEMALLOC,
|
||||
[if test "$CFG_WITH_JEMALLOC" != "no"; then
|
||||
CFG_LIBS="$LJEMALLOC $CFG_LIBS";
|
||||
CFG_HAVE_JEMALLOC=yes;
|
||||
# If using jemalloc, add some extra options to make the compiler not assume
|
||||
# it is using its own versions of the standard library functions
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-malloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-calloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-realloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-free)
|
||||
if test "$CFG_WITH_JEMALLOC" != "no"; then
|
||||
if test "$CFG_ENABLE_PARTIAL_STATIC" = "yes"; then
|
||||
_MY_LDLIBS_CHECK_SET(CFG_LIBS_MALLOC, -Xlinker --whole-archive -l:libjemalloc.a -Xlinker --no-whole-archive)
|
||||
fi
|
||||
_MY_LDLIBS_CHECK_SET(CFG_LIBS_MALLOC, -ljemalloc)
|
||||
if test "$CFG_LIBS_MALLOC" != ""; then
|
||||
CFG_HAVE_JEMALLOC=yes
|
||||
AC_DEFINE([HAVE_JEMALLOC],[1],[Defined if have jemalloc])
|
||||
fi],
|
||||
[if test "$CFG_WITH_JEMALLOC" = "yes"; then
|
||||
AC_MSG_ERROR([--enable-jemalloc was given but test for ${LJEMALLOC} failed])
|
||||
fi])
|
||||
elif test "$CFG_WITH_JEMALLOC" = "yes"; then
|
||||
AC_MSG_ERROR([--enable-jemalloc was given but jemalloc is not available])
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(HAVE_JEMALLOC)
|
||||
|
||||
# Check if tcmalloc is available based on --enable-tcmalloc
|
||||
# Only use tcmalloc if jemalloc was not found/enabled
|
||||
if test "$CFG_HAVE_JEMALLOC" = "yes"; then
|
||||
AC_MSG_NOTICE([jemalloc found, skipping tcmalloc check])
|
||||
else
|
||||
# Test for tcmalloc
|
||||
CFG_HAVE_TCMALLOC=no
|
||||
_MY_LDLIBS_CHECK_IFELSE(
|
||||
$LTCMALLOC,
|
||||
[if test "$CFG_WITH_TCMALLOC" != "no"; then
|
||||
CFG_LIBS="$LTCMALLOC $CFG_LIBS";
|
||||
CFG_HAVE_TCMALLOC=yes;
|
||||
# If using tcmalloc, add some extra options to make the compiler not assume
|
||||
# it is using its own versions of the standard library functions
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-malloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-calloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-realloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-free)
|
||||
if test "$CFG_HAVE_JEMALLOC" = "yes"; then
|
||||
AC_MSG_NOTICE([jemalloc found, skipping check for tcmalloc])
|
||||
elif test "$CFG_WITH_TCMALLOC" != "no"; then
|
||||
if test "$CFG_ENABLE_PARTIAL_STATIC" = "yes"; then
|
||||
_MY_LDLIBS_CHECK_SET(CFG_LIBS_MALLOC, -Xlinker --whole-archive -l:libtcmalloc_minimal.a -Xlinker --no-whole-archive)
|
||||
fi
|
||||
_MY_LDLIBS_CHECK_SET(CFG_LIBS_MALLOC, -ltcmalloc_minimal)
|
||||
if test "$CFG_LIBS_MALLOC" != ""; then
|
||||
CFG_HAVE_TCMALLOC=yes
|
||||
AC_DEFINE([HAVE_TCMALLOC],[1],[Defined if have tcmalloc])
|
||||
fi],
|
||||
[if test "$CFG_WITH_TCMALLOC" = "yes"; then
|
||||
AC_MSG_ERROR([--enable-tcmalloc was given but test for ${LTCMALLOC} failed])
|
||||
fi])
|
||||
elif test "$CFG_WITH_TCMALLOC" = "yes"; then
|
||||
AC_MSG_ERROR([--enable-tcmalloc was given but tcmalloc is not available])
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(HAVE_TCMALLOC)
|
||||
|
||||
if test "$CFG_HAVE_JEMALLOC" = "yes" || test "$CFG_HAVE_TCMALLOC" = "yes"; then
|
||||
# If using custom malloc, add some extra options to make the compiler not assume
|
||||
# it is using its own versions of the standard library functions
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-malloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-calloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-realloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-free)
|
||||
fi
|
||||
|
||||
# Finished with libraries
|
||||
CFG_LIBS="$CFG_LIBS_MALLOC $CFG_LIBS"
|
||||
AC_SUBST(CFG_LIBS)
|
||||
|
||||
# Need C++14 at least
|
||||
|
|
|
|||
|
|
@ -97,10 +97,10 @@ def process() -> None:
|
|||
line,
|
||||
flags=re.IGNORECASE)
|
||||
if m:
|
||||
mid = m.group(2)
|
||||
if ("#" + mid) not in msgs[key]:
|
||||
bug_id = m.group(2)
|
||||
if ("#" + bug_id) not in msgs[key]:
|
||||
# print("K %s" % line)
|
||||
msgs[key] += ' (#' + mid + ')'
|
||||
msgs[key] += ' (#' + bug_id + ')'
|
||||
|
||||
if not msgs:
|
||||
print("No Changes need to be inserted.")
|
||||
|
|
|
|||
|
|
@ -253,8 +253,7 @@ class AssertVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
AstSampled* newSampledExpr(AstNodeExpr* nodep) {
|
||||
AstSampled* const sampledp = new AstSampled{nodep->fileline(), nodep};
|
||||
sampledp->dtypeFrom(nodep);
|
||||
AstSampled* const sampledp = new AstSampled{nodep->fileline(), nodep, nodep->dtypep()};
|
||||
return sampledp;
|
||||
}
|
||||
AstVarRef* newMonitorNumVarRefp(const AstNode* nodep, VAccess access) {
|
||||
|
|
|
|||
|
|
@ -182,8 +182,7 @@ struct BuildResult final {
|
|||
};
|
||||
|
||||
static AstNodeExpr* sampled(AstNodeExpr* exprp) {
|
||||
AstSampled* const sp = new AstSampled{exprp->fileline(), exprp};
|
||||
sp->dtypeFrom(exprp);
|
||||
AstSampled* const sp = new AstSampled{exprp->fileline(), exprp, exprp->dtypep()};
|
||||
return sp;
|
||||
}
|
||||
|
||||
|
|
@ -838,13 +837,14 @@ class SvaNfaBuilder final {
|
|||
BuildResult buildUntil(AstUntil* nodep, SvaStateVertex* entryVtxp, bool isTopLevelStep) {
|
||||
FileLine* const flp = nodep->fileline();
|
||||
if (!isTopLevelStep) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'until' in complex property expression");
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: '" << nodep->verilogKwd()
|
||||
<< "' in complex property expression");
|
||||
return BuildResult::failWithError();
|
||||
}
|
||||
if (nodep->isStrong()) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: s_until"
|
||||
<< (nodep->isOverlapping() ? "_with" : "")
|
||||
<< " (in property expresion)");
|
||||
<< " (in property expression)");
|
||||
return BuildResult::failWithError();
|
||||
}
|
||||
AstNodeExpr* const lhsp = nodep->lhsp();
|
||||
|
|
@ -853,7 +853,8 @@ class SvaNfaBuilder final {
|
|||
return ep->exists([](const AstNodeExpr* np) { return np->isMultiCycleSva(); });
|
||||
};
|
||||
if (hasSeq(lhsp) || hasSeq(rhsp)) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'until' in complex property expression");
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: '" << nodep->verilogKwd()
|
||||
<< "' in complex property expression");
|
||||
return BuildResult::failWithError();
|
||||
}
|
||||
|
||||
|
|
@ -1926,16 +1927,16 @@ class AssertNfaVisitor final : public VNVisitor {
|
|||
|
||||
// Bare `assert property (p until q)` with boolean operands stays on
|
||||
// V3AssertPre's AstLoop lowering, which preserves per-attempt action-block
|
||||
// firings that this NFA's single-bit aggregated state cannot. NFA still
|
||||
// owns strong forms, sequence operands, and any embedding inside a
|
||||
// multi-cycle context (implication consequent, or/and operands, etc.).
|
||||
// firings that this NFA's single-bit aggregated state cannot. Strong bare
|
||||
// forms are also lowered there. NFA still owns sequence operands and any
|
||||
// embedding inside a multi-cycle context (implication consequent, or/and
|
||||
// operands, etc.).
|
||||
static bool isBareTopLevelUntil(AstNode* propp) {
|
||||
AstNode* p = propp;
|
||||
if (AstPropSpec* const specp = VN_CAST(p, PropSpec)) p = specp->propp();
|
||||
while (AstLogNot* const notp = VN_CAST(p, LogNot)) p = notp->lhsp();
|
||||
AstUntil* const untilp = VN_CAST(p, Until);
|
||||
if (!untilp) return false;
|
||||
if (untilp->isStrong()) return false;
|
||||
const auto hasSeq = [](const AstNodeExpr* ep) {
|
||||
return ep->exists([](const AstNodeExpr* np) { return np->isMultiCycleSva(); });
|
||||
};
|
||||
|
|
|
|||
|
|
@ -366,8 +366,8 @@ private:
|
|||
if (skewp->num().is1Step()) {
|
||||
// #1step means the value that is sampled is always the signal's last value
|
||||
// before the clock edge (IEEE 1800-2023 14.4)
|
||||
AstSampled* const sampledp = new AstSampled{flp, exprp->cloneTreePure(false)};
|
||||
sampledp->dtypeFrom(exprp);
|
||||
AstSampled* const sampledp
|
||||
= new AstSampled{flp, exprp->cloneTreePure(false), exprp->dtypep()};
|
||||
AstAssign* const assignp = new AstAssign{flp, refp, sampledp};
|
||||
m_clockingp->addNextHere(new AstAlways{
|
||||
flp, VAlwaysKwd::ALWAYS,
|
||||
|
|
@ -413,7 +413,7 @@ private:
|
|||
}
|
||||
}
|
||||
void visit(AstDelay* nodep) override {
|
||||
m_hasCycleDelay = true;
|
||||
m_hasCycleDelay |= nodep->isCycleDelay();
|
||||
// Only cycle delays are relevant in this stage; also only process once
|
||||
if (!nodep->isCycleDelay()) {
|
||||
if (m_inSynchDrive) {
|
||||
|
|
@ -811,7 +811,6 @@ private:
|
|||
static AstStmtExpr* getProcessAssocArrayDelete(AstVarRef* const refp) {
|
||||
// Constructs refp.delete(std::process::self()) statement
|
||||
FileLine* const flp = refp->fileline();
|
||||
refp->classOrPackagep(v3Global.rootp()->stdPackageProcessp());
|
||||
AstCMethodHard* const deletep = new AstCMethodHard{
|
||||
flp, refp, VCMethod::ASSOC_ERASE, v3Global.rootp()->stdPackageProcessSelfp(flp)};
|
||||
deletep->dtypep(refp->findVoidDType());
|
||||
|
|
@ -819,7 +818,6 @@ private:
|
|||
}
|
||||
static AstNodeExpr* getProcessAssocArraySize(AstVarRef* const refp) {
|
||||
// Constructs refp.size() statement
|
||||
refp->classOrPackagep(v3Global.rootp()->stdPackageProcessp());
|
||||
AstCMethodHard* const sizep
|
||||
= new AstCMethodHard{refp->fileline(), refp, VCMethod::ASSOC_SIZE};
|
||||
sizep->dtypep(refp->findBasicDType(VBasicDTypeKwd::UINT32));
|
||||
|
|
@ -846,7 +844,7 @@ private:
|
|||
|
||||
// Assertion condition check
|
||||
AstLoop* const loopp = new AstLoop{flp};
|
||||
AstNodeExpr* const condp = new AstSampled{flp, nodep->exprp()->unlinkFrBack()};
|
||||
AstNodeExpr* const condp = new AstSampled{flp, nodep->exprp()->unlinkFrBack(), nullptr};
|
||||
loopp->addStmtsp(new AstLoopTest{flp, loopp, new AstLogNot{flp, condp}});
|
||||
loopp->addStmtsp(new AstEventControl{flp, sentreep, nullptr});
|
||||
|
||||
|
|
@ -1300,17 +1298,121 @@ private:
|
|||
}
|
||||
void visit(AstUntil* nodep) override {
|
||||
FileLine* const flp = nodep->fileline();
|
||||
if (m_pexprp) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'until' in complex property expression");
|
||||
nodep->replaceWith(new AstConst{flp, AstConst::BitFalse{}});
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
}
|
||||
UASSERT_OBJ(
|
||||
!m_pexprp, nodep,
|
||||
"'" << nodep->verilogKwd()
|
||||
<< "' in complex property expression should have been rejected by V3AssertNfa");
|
||||
if (nodep->isStrong()) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: s_until"
|
||||
<< (nodep->isOverlapping() ? "_with" : "")
|
||||
<< " (in property expresion)");
|
||||
nodep->replaceWith(new AstConst{flp, AstConst::BitFalse{}});
|
||||
// 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
|
||||
// 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 rawRhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstSampled* const lhsp = new AstSampled{flp, rawLhsp, rawLhsp->dtypep()};
|
||||
AstSampled* const rhsp = new AstSampled{flp, rawRhsp, rawRhsp->dtypep()};
|
||||
AstNodeExpr* finalCondp = rhsp->cloneTreePure(false);
|
||||
if (nodep->isOverlapping()) {
|
||||
finalCondp = new AstLogAnd{flp, lhsp->cloneTreePure(false), finalCondp};
|
||||
}
|
||||
|
||||
// Track active assertion attempts. Only the count is needed to emit final failures.
|
||||
AstVar* const activep = new AstVar{flp, VVarType::MODULETEMP, m_activeNames.get(""),
|
||||
nodep->findBasicDType(VBasicDTypeKwd::UINT32)};
|
||||
activep->lifetime(VLifetime::STATIC_EXPLICIT);
|
||||
m_modp->addStmtsp(activep);
|
||||
|
||||
AstVar* const donep
|
||||
= new AstVar{flp, VVarType::BLOCKTEMP, "__VassertDone", nodep->findBitDType()};
|
||||
donep->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
auto setDone = [&]() {
|
||||
return new AstAssign{flp, new AstVarRef{flp, donep, VAccess::WRITE},
|
||||
new AstConst{flp, AstConst::BitTrue{}}};
|
||||
};
|
||||
|
||||
AstLoop* const loopp = new AstLoop{flp};
|
||||
AstAssign* const decrementVar = new AstAssign{
|
||||
flp, new AstVarRef{flp, activep, VAccess::WRITE},
|
||||
new AstSub{flp, new AstVarRef{flp, activep, VAccess::READ}, new AstConst{flp, 1}}};
|
||||
loopp->addStmtsp(new AstLoopTest{
|
||||
flp, loopp, new AstLogNot{flp, new AstVarRef{flp, donep, VAccess::READ}}});
|
||||
{
|
||||
AstBegin* const passp = new AstBegin{flp, "", nullptr, true};
|
||||
passp->addStmtsp(new AstPExprClause{flp});
|
||||
passp->addStmtsp(decrementVar);
|
||||
passp->addStmtsp(setDone());
|
||||
AstNodeExpr* passCondp = rhsp;
|
||||
if (nodep->isOverlapping()) {
|
||||
passCondp = new AstLogAnd{flp, lhsp->cloneTreePure(false), passCondp};
|
||||
}
|
||||
loopp->addStmtsp(new AstIf{flp, passCondp, passp});
|
||||
}
|
||||
{
|
||||
AstBegin* const failp = new AstBegin{flp, "", nullptr, true};
|
||||
failp->addStmtsp(new AstPExprClause{flp, false});
|
||||
failp->addStmtsp(decrementVar->cloneTree(false));
|
||||
failp->addStmtsp(setDone());
|
||||
loopp->addStmtsp(new AstIf{
|
||||
flp,
|
||||
new AstLogAnd{flp,
|
||||
new AstLogNot{flp, new AstVarRef{flp, donep, VAccess::READ}},
|
||||
new AstLogNot{flp, lhsp}},
|
||||
failp});
|
||||
}
|
||||
AstDelay* const delayp = new AstDelay{flp, new AstConst{flp, 1}, false};
|
||||
delayp->timeunit(m_modp->timeunit());
|
||||
loopp->addStmtsp(new AstIf{
|
||||
flp, new AstLogNot{flp, new AstVarRef{flp, donep, VAccess::READ}}, delayp});
|
||||
|
||||
// Main assertion block
|
||||
AstBegin* const bodyp = new AstBegin{flp, "", nullptr, true};
|
||||
bodyp->addStmtsp(donep);
|
||||
bodyp->addStmtsp(new AstAssign{flp, new AstVarRef{flp, donep, VAccess::WRITE},
|
||||
new AstConst{flp, AstConst::BitFalse{}}});
|
||||
FileLine* const flp = activep->fileline();
|
||||
bodyp->addStmtsp(
|
||||
new AstAssign{flp, new AstVarRef{flp, activep, VAccess::WRITE},
|
||||
new AstAdd{flp, new AstVarRef{flp, activep, VAccess::READ},
|
||||
new AstConst{flp, 1}}});
|
||||
bodyp->addStmtsp(loopp);
|
||||
|
||||
// Validate assertion condition for each active assert
|
||||
AstVar* const activeCountp = new AstVar{flp, VVarType::BLOCKTEMP, "__VassertCount",
|
||||
nodep->findBasicDType(VBasicDTypeKwd::UINT32)};
|
||||
activeCountp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
|
||||
AstAssign* const initActiveCountp
|
||||
= new AstAssign{flp, new AstVarRef{flp, activeCountp, VAccess::WRITE},
|
||||
new AstVarRef{flp, activep, VAccess::READ}};
|
||||
AstLoop* const finalLoopp = new AstLoop{flp};
|
||||
finalLoopp->addStmtsp(
|
||||
new AstLoopTest{flp, finalLoopp,
|
||||
new AstNeq{flp, new AstVarRef{flp, activeCountp, VAccess::READ},
|
||||
new AstConst{flp, 0}}});
|
||||
finalLoopp->addStmtsp(new AstIf{flp, finalCondp, new AstPExprClause{flp},
|
||||
new AstPExprClause{flp, false}});
|
||||
finalLoopp->addStmtsp(
|
||||
new AstAssign{flp, new AstVarRef{flp, activeCountp, VAccess::WRITE},
|
||||
new AstSub{flp, new AstVarRef{flp, activeCountp, VAccess::READ},
|
||||
new AstConst{flp, 1}}});
|
||||
|
||||
// Final assertion block
|
||||
AstBegin* const finalp = new AstBegin{flp, "", nullptr, true};
|
||||
finalp->addStmtsp(activeCountp);
|
||||
finalp->addStmtsp(initActiveCountp);
|
||||
finalp->addStmtsp(finalLoopp);
|
||||
|
||||
AstPExpr* const pexprp = new AstPExpr{flp, bodyp, finalp, nodep->dtypep()};
|
||||
VL_RESTORER(m_pexprp);
|
||||
VL_RESTORER(m_hasCycleDelay);
|
||||
m_pexprp = pexprp;
|
||||
m_hasCycleDelay = false;
|
||||
iterate(bodyp);
|
||||
iterate(finalp);
|
||||
|
||||
UASSERT_OBJ(!m_hasCycleDelay, nodep,
|
||||
"s_until cycle delay should have been handled by V3AssertNfa");
|
||||
|
||||
nodep->replaceWith(pexprp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1369,8 +1471,8 @@ private:
|
|||
iterateNull(nodep->disablep());
|
||||
if (!VN_AS(nodep->backp(), NodeCoverOrAssert)->immediate()) {
|
||||
const AstNodeDType* const propDtp = nodep->propp()->dtypep();
|
||||
nodep->propp(new AstSampled{nodep->fileline(), nodep->propp()->unlinkFrBack()});
|
||||
nodep->propp()->dtypeFrom(propDtp);
|
||||
nodep->propp(new AstSampled{nodep->fileline(), nodep->propp()->unlinkFrBack(),
|
||||
propDtp->dtypep()});
|
||||
}
|
||||
iterate(nodep->propp());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -370,6 +370,24 @@ public:
|
|||
// clang-format on
|
||||
return names[m_e];
|
||||
}
|
||||
// True for attributes that read an operand's type rather than its value, such as $bits.
|
||||
bool isTypeQuery() const {
|
||||
switch (m_e) {
|
||||
case DIM_BITS:
|
||||
case DIM_BITS_OR_NUMBER:
|
||||
case DIM_DIMENSIONS:
|
||||
case DIM_HIGH:
|
||||
case DIM_INCREMENT:
|
||||
case DIM_LEFT:
|
||||
case DIM_LOW:
|
||||
case DIM_RIGHT:
|
||||
case DIM_SIZE:
|
||||
case DIM_UNPK_DIMENSIONS:
|
||||
case TYPEID:
|
||||
case TYPENAME: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
VAttrType()
|
||||
: m_e{ILLEGAL} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
|
|
|
|||
|
|
@ -2519,9 +2519,10 @@ class AstSampled final : public AstNodeExpr {
|
|||
// Verilog $sampled
|
||||
// @astgen op1 := exprp : AstNode<AstNodeExpr|AstPropSpec>
|
||||
public:
|
||||
AstSampled(FileLine* fl, AstNode* exprp)
|
||||
AstSampled(FileLine* fl, AstNode* exprp, AstNodeDType* dtypep)
|
||||
: ASTGEN_SUPER_Sampled(fl) {
|
||||
this->exprp(exprp);
|
||||
this->dtypep(dtypep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSampled;
|
||||
string emitVerilog() override { return "$sampled(%l)"; }
|
||||
|
|
@ -2906,6 +2907,9 @@ public:
|
|||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
string verilogKwd() const override {
|
||||
return (isStrong() ? "s_" : string()) + "until" + (isOverlapping() ? "_with" : "");
|
||||
}
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
|
|
@ -5784,6 +5788,7 @@ public:
|
|||
};
|
||||
class AstOneHot final : public AstNodeUniop {
|
||||
// True if only single bit set in vector
|
||||
// @astgen makeDfgVertex
|
||||
public:
|
||||
AstOneHot(FileLine* fl, AstNodeExpr* lhsp)
|
||||
: ASTGEN_SUPER_OneHot(fl, lhsp) {
|
||||
|
|
@ -5801,6 +5806,7 @@ public:
|
|||
};
|
||||
class AstOneHot0 final : public AstNodeUniop {
|
||||
// True if only single bit, or no bits set in vector
|
||||
// @astgen makeDfgVertex
|
||||
public:
|
||||
AstOneHot0(FileLine* fl, AstNodeExpr* lhsp)
|
||||
: ASTGEN_SUPER_OneHot0(fl, lhsp) {
|
||||
|
|
|
|||
10
src/V3Cfg.h
10
src/V3Cfg.h
|
|
@ -559,13 +559,11 @@ public:
|
|||
|
||||
namespace V3Cfg {
|
||||
|
||||
// Compute AstVars live on entry to given CFG. That is, variables that might
|
||||
// Compute AstVarScopes live on entry to given CFG. That is, variables that might
|
||||
// be read before wholly assigned in the CFG. Returns nullptr if the analysis
|
||||
// failed due to unhandled statements or data types involved in the CFG.
|
||||
// On success, returns a vector of AstVar or AstVarScope nodes live on entry.
|
||||
std::unique_ptr<std::vector<AstVar*>> liveVars(const CfgGraph&);
|
||||
|
||||
// Same as liveVars, but return AstVarScopes insted
|
||||
// failed due to unhandled statements involved in the CFG. The analysis is
|
||||
// conservative and may return variables that are not actually live on entry.
|
||||
// On success, returns a vector of AstVarScope nodes that might be live on entry.
|
||||
std::unique_ptr<std::vector<AstVarScope*>> liveVarScopes(const CfgGraph&);
|
||||
|
||||
} //namespace V3Cfg
|
||||
|
|
|
|||
|
|
@ -25,25 +25,19 @@
|
|||
#include "V3Ast.h"
|
||||
#include "V3Cfg.h"
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
template <bool T_Scoped>
|
||||
class CfgLiveVariables final : VNVisitorConst {
|
||||
// TYPES
|
||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
||||
|
||||
// State associted with each basic block
|
||||
struct BlockState final {
|
||||
// Variables used in block, before a complete assignment in the same block
|
||||
std::unordered_set<Variable*> m_gen;
|
||||
std::unordered_set<AstVarScope*> m_gen;
|
||||
// Variables that are assigned a complete value in the basic block
|
||||
std::unordered_set<Variable*> m_kill;
|
||||
std::unordered_set<Variable*> m_liveIn; // Variables live on entry to the block
|
||||
std::unordered_set<Variable*> m_liveOut; // Variables live on exit from the block
|
||||
std::unordered_set<AstVarScope*> m_kill;
|
||||
std::unordered_set<AstVarScope*> m_liveIn; // Variables live on entry to the block
|
||||
std::unordered_set<AstVarScope*> m_liveOut; // Variables live on exit from the block
|
||||
bool m_isOnWorkList = false; // Block is on work list
|
||||
bool m_wasProcessed = false; // Already processed at least once
|
||||
};
|
||||
|
|
@ -56,14 +50,6 @@ class CfgLiveVariables final : VNVisitorConst {
|
|||
bool m_abort = false; // Abort analysis - unhandled construct
|
||||
|
||||
// METHODS
|
||||
static Variable* getTarget(const AstNodeVarRef* refp) {
|
||||
// TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
return reinterpret_cast<Variable*>(refp->varScopep());
|
||||
} else {
|
||||
return reinterpret_cast<Variable*>(refp->varp());
|
||||
}
|
||||
}
|
||||
|
||||
// This is to match DFG, but can be extended independently - eventually should handle all
|
||||
static bool isSupportedPackedDType(const AstNodeDType* dtypep) {
|
||||
|
|
@ -81,52 +67,41 @@ class CfgLiveVariables final : VNVisitorConst {
|
|||
}
|
||||
|
||||
// Check and return if variable is incompatible
|
||||
bool incompatible(Variable* varp) {
|
||||
if (!isSupportedPackedDType(varp->dtypep())) return true;
|
||||
const AstVar* astVarp = nullptr;
|
||||
// TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
astVarp = reinterpret_cast<AstVarScope*>(varp)->varp();
|
||||
} else {
|
||||
astVarp = reinterpret_cast<AstVar*>(varp);
|
||||
}
|
||||
if (astVarp->ignoreSchedWrite()) return true;
|
||||
bool incompatible(AstVarScope* vscp) {
|
||||
if (!isSupportedPackedDType(vscp->dtypep())) return true;
|
||||
if (vscp->varp()->ignoreSchedWrite()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void updateGen(AstNode* nodep) {
|
||||
UASSERT_OBJ(!m_abort, nodep, "Doing useless work");
|
||||
m_abort = nodep->exists([&](const AstNodeVarRef* refp) {
|
||||
// Cross reference is ambiguous
|
||||
if (VN_IS(refp, VarXRef)) return true;
|
||||
m_abort = nodep->exists([&](const AstVarRef* refp) {
|
||||
// Only care about reads
|
||||
if (refp->access().isWriteOnly()) return false;
|
||||
// Grab referenced variable
|
||||
Variable* const tgtp = getTarget(refp);
|
||||
AstVarScope* const vscp = refp->varScopep();
|
||||
// Bail if not a compatible type
|
||||
if (incompatible(tgtp)) return true;
|
||||
if (incompatible(vscp)) return true;
|
||||
// Add to gen set, if not killed - assume whole variable read
|
||||
if (m_currp->m_kill.count(tgtp)) return false;
|
||||
m_currp->m_gen.emplace(tgtp);
|
||||
if (m_currp->m_kill.count(vscp)) return false;
|
||||
m_currp->m_gen.emplace(vscp);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void updateKill(AstNode* nodep) {
|
||||
UASSERT_OBJ(!m_abort, nodep, "Doing useless work");
|
||||
m_abort = nodep->exists([&](const AstNodeVarRef* refp) {
|
||||
// Cross reference is ambiguous
|
||||
if (VN_IS(refp, VarXRef)) return true;
|
||||
m_abort = nodep->exists([&](const AstVarRef* refp) {
|
||||
// Only care about writes
|
||||
if (refp->access().isReadOnly()) return false;
|
||||
// Grab referenced variable
|
||||
Variable* const tgtp = getTarget(refp);
|
||||
AstVarScope* const vscp = refp->varScopep();
|
||||
// Bail if not a compatible type
|
||||
if (incompatible(tgtp)) return true;
|
||||
if (incompatible(vscp)) return true;
|
||||
// If whole written, add to kill set
|
||||
if (refp->nextp()) return false;
|
||||
if (VN_IS(refp->abovep(), Sel)) return false;
|
||||
m_currp->m_kill.emplace(tgtp);
|
||||
m_currp->m_kill.emplace(vscp);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
|
@ -144,8 +119,8 @@ class CfgLiveVariables final : VNVisitorConst {
|
|||
BlockState& state = m_blockState[bb];
|
||||
|
||||
// liveIn = gen union (liveOut - kill)
|
||||
std::unordered_set<Variable*> liveIn = state.m_gen;
|
||||
for (Variable* const varp : state.m_liveOut) {
|
||||
std::unordered_set<AstVarScope*> liveIn = state.m_gen;
|
||||
for (AstVarScope* const varp : state.m_liveOut) {
|
||||
if (state.m_kill.count(varp)) continue;
|
||||
liveIn.insert(varp);
|
||||
}
|
||||
|
|
@ -219,25 +194,23 @@ class CfgLiveVariables final : VNVisitorConst {
|
|||
}
|
||||
|
||||
public:
|
||||
static std::unique_ptr<std::vector<Variable*>> apply(const CfgGraph& cfg) {
|
||||
static std::unique_ptr<std::vector<AstVarScope*>> apply(const CfgGraph& cfg) {
|
||||
CfgLiveVariables analysis{cfg};
|
||||
// If failed, return nullptr
|
||||
if (analysis.m_abort) return nullptr;
|
||||
// Gather variables live in to the entry blockstd::unique_ptr<std::vector<Variable*>>
|
||||
const std::unordered_set<Variable*>& lin = analysis.m_blockState[cfg.enter()].m_liveIn;
|
||||
std::vector<Variable*>* const resultp = new std::vector<Variable*>{lin.begin(), lin.end()};
|
||||
// Gather variables live in to the entry blockstd::unique_ptr<std::vector<AstVarScope*>>
|
||||
const std::unordered_set<AstVarScope*>& lin = analysis.m_blockState[cfg.enter()].m_liveIn;
|
||||
std::vector<AstVarScope*>* const resultp
|
||||
= new std::vector<AstVarScope*>{lin.begin(), lin.end()};
|
||||
// Sort for stability
|
||||
std::stable_sort(resultp->begin(), resultp->end(), [](Variable* ap, Variable* bp) { //
|
||||
return ap->name() < bp->name();
|
||||
});
|
||||
return std::unique_ptr<std::vector<Variable*>>{resultp};
|
||||
std::stable_sort(resultp->begin(), resultp->end(),
|
||||
[](AstVarScope* ap, AstVarScope* bp) { //
|
||||
return ap->name() < bp->name();
|
||||
});
|
||||
return std::unique_ptr<std::vector<AstVarScope*>>{resultp};
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<std::vector<AstVar*>> V3Cfg::liveVars(const CfgGraph& cfg) {
|
||||
return CfgLiveVariables</* T_Scoped: */ false>::apply(cfg);
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<AstVarScope*>> V3Cfg::liveVarScopes(const CfgGraph& cfg) {
|
||||
return CfgLiveVariables</* T_Scoped: */ true>::apply(cfg);
|
||||
return CfgLiveVariables::apply(cfg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,11 @@ std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
|||
for (const DfgVertex& vtx : m_opVertices) {
|
||||
switch (vtx.type()) {
|
||||
#include "V3Dfg__gen_clone_cases.h" // From ./astgen
|
||||
case VDfgType::CReset: { // LCOV_EXCL_START - No algorithm actually hits this today
|
||||
DfgCReset* const cp = new DfgCReset{*clonep, vtx.fileline(), vtx.dtype()};
|
||||
vtxp2clonep.emplace(&vtx, cp);
|
||||
break;
|
||||
} // LCOV_EXCL_STOP
|
||||
case VDfgType::Sel: {
|
||||
DfgSel* const cp = new DfgSel{*clonep, vtx.fileline(), vtx.dtype()};
|
||||
cp->lsb(vtx.as<DfgSel>()->lsb());
|
||||
|
|
@ -132,11 +137,14 @@ std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
|||
VL_UNREACHABLE;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
vtx.v3fatalSrc("Unhandled operation vertex type: " + vtx.typeName());
|
||||
case VDfgType::AstRd: // LCOV_EXCL_START
|
||||
case VDfgType::Const:
|
||||
case VDfgType::VarArray:
|
||||
case VDfgType::VarPacked: {
|
||||
vtx.v3fatalSrc("Vertex should have been handled above: " + vtx.typeName());
|
||||
VL_UNREACHABLE;
|
||||
break;
|
||||
}
|
||||
} // LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
UASSERT(size() == clonep->size(), "Size of clone should be the same");
|
||||
|
|
@ -618,6 +626,10 @@ void DfgVertex::typeCheck(const DfgGraph& dfg) const {
|
|||
CHECK(isPacked(), "Should be Packed type");
|
||||
return;
|
||||
}
|
||||
case VDfgType::CReset: {
|
||||
CHECK(isPacked() || isArray(), "Should be Packed or Array type");
|
||||
return;
|
||||
}
|
||||
case VDfgType::AstRd: {
|
||||
const DfgAstRd& v = *as<DfgAstRd>();
|
||||
CHECK(v.isPacked() || v.isArray(), "Should be Packed or Array type");
|
||||
|
|
@ -774,7 +786,9 @@ void DfgVertex::typeCheck(const DfgGraph& dfg) const {
|
|||
case VDfgType::LogNot:
|
||||
case VDfgType::RedAnd:
|
||||
case VDfgType::RedOr:
|
||||
case VDfgType::RedXor: {
|
||||
case VDfgType::RedXor:
|
||||
case VDfgType::OneHot:
|
||||
case VDfgType::OneHot0: {
|
||||
CHECK(dtype() == DfgDataType::packed(1), "Should be 1-bit");
|
||||
CHECK(inputp(0)->isPacked(), "Operand should be Packed type");
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -125,6 +125,12 @@ class ColorStronglyConnectedComponents final {
|
|||
|
||||
// Initialize state of operation vertices
|
||||
for (const DfgVertex& vtx : m_dfg.opVertices()) {
|
||||
// If it has no inputs or no outputs, it cannot be part of a non-trivial SCC.
|
||||
if (!vtx.nInputs() || !vtx.hasSinks()) {
|
||||
index(vtx) = 0;
|
||||
component(vtx) = 0;
|
||||
continue;
|
||||
}
|
||||
index(vtx) = UNASSIGNED;
|
||||
component(vtx) = UNASSIGNED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class V3DfgCse final {
|
|||
|
||||
// Special vertices
|
||||
case VDfgType::Const: // LCOV_EXCL_START
|
||||
case VDfgType::CReset:
|
||||
case VDfgType::VarArray:
|
||||
case VDfgType::VarPacked:
|
||||
case VDfgType::AstRd: // LCOV_EXCL_STOP
|
||||
|
|
@ -110,6 +111,8 @@ class V3DfgCse final {
|
|||
case VDfgType::NeqCase:
|
||||
case VDfgType::NeqWild:
|
||||
case VDfgType::Not:
|
||||
case VDfgType::OneHot:
|
||||
case VDfgType::OneHot0:
|
||||
case VDfgType::Or:
|
||||
case VDfgType::Pow:
|
||||
case VDfgType::PowSS:
|
||||
|
|
@ -168,6 +171,7 @@ class V3DfgCse final {
|
|||
|
||||
// Special vertices
|
||||
case VDfgType::Const: return a.as<DfgConst>()->num().isCaseEq(b.as<DfgConst>()->num());
|
||||
case VDfgType::CReset: return false;
|
||||
|
||||
case VDfgType::VarArray:
|
||||
case VDfgType::VarPacked: // CSE does not combine variables
|
||||
|
|
@ -232,6 +236,8 @@ class V3DfgCse final {
|
|||
case VDfgType::NeqCase:
|
||||
case VDfgType::NeqWild:
|
||||
case VDfgType::Not:
|
||||
case VDfgType::OneHot:
|
||||
case VDfgType::OneHot0:
|
||||
case VDfgType::Or:
|
||||
case VDfgType::Pow:
|
||||
case VDfgType::PowSS:
|
||||
|
|
@ -299,6 +305,10 @@ class V3DfgCse final {
|
|||
for (const DfgVertexVar& vtx : dfg.varVertices()) m_hashCache[vtx] = V3Hash{++varHash};
|
||||
// Pre-hash Ast references, these are all unique like variables
|
||||
for (const DfgVertexAst& vtx : dfg.astVertices()) m_hashCache[vtx] = V3Hash{++varHash};
|
||||
// Pre-hash CReset vertices, these are all unique
|
||||
for (const DfgVertex& vtx : dfg.opVertices()) {
|
||||
if (vtx.is<DfgCReset>()) m_hashCache[vtx] = V3Hash{++varHash};
|
||||
}
|
||||
|
||||
// Similarly pre-hash constants for speed. While we don't combine constants, we do want
|
||||
// expressions using the same constants to be combined, so we do need to hash equal
|
||||
|
|
|
|||
|
|
@ -227,6 +227,13 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
void visit(DfgConst* vtxp) override { //
|
||||
m_resultp = new AstConst{vtxp->fileline(), vtxp->num()};
|
||||
}
|
||||
void visit(DfgCReset* vtxp) override {
|
||||
DfgVertex* const sinkp = vtxp->singleSink();
|
||||
UASSERT_OBJ(sinkp, vtxp, "CReset should only have one sink");
|
||||
UASSERT_OBJ(sinkp->is<DfgVertexVar>(), sinkp, "CReset should drive a variable");
|
||||
AstVar* const varp = sinkp->as<DfgVertexVar>()->vscp()->varp();
|
||||
m_resultp = new AstCReset{vtxp->fileline(), varp, false};
|
||||
}
|
||||
|
||||
void visit(DfgRep* vtxp) override {
|
||||
FileLine* const flp = vtxp->fileline();
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ void V3DfgPasses::inlineVars(DfgGraph& dfg) {
|
|||
// Partial driver cannot be inlined
|
||||
if (srcp->is<DfgVertexSplice>()) continue;
|
||||
if (srcp->is<DfgUnitArray>()) continue;
|
||||
// Don't inline CReset
|
||||
if (srcp->is<DfgCReset>()) continue;
|
||||
// Okie dokie, here we go ...
|
||||
vtx.replaceWith(srcp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,11 +138,14 @@ template <> const DfgDataType& resultDType<DfgXor> (const DfgVertex* lhsp
|
|||
|
||||
// Unary constant folding
|
||||
template<typename Vertex> void foldOp(V3Number& out, const V3Number& src);
|
||||
template <> void foldOp<DfgCountOnes> (V3Number& out, const V3Number& src) { out.opCountOnes(src); }
|
||||
template <> void foldOp<DfgExtend> (V3Number& out, const V3Number& src) { out.opAssign(src); }
|
||||
template <> void foldOp<DfgExtendS> (V3Number& out, const V3Number& src) { out.opExtendS(src, src.width()); }
|
||||
template <> void foldOp<DfgLogNot> (V3Number& out, const V3Number& src) { out.opLogNot(src); }
|
||||
template <> void foldOp<DfgNegate> (V3Number& out, const V3Number& src) { out.opNegate(src); }
|
||||
template <> void foldOp<DfgNot> (V3Number& out, const V3Number& src) { out.opNot(src); }
|
||||
template <> void foldOp<DfgOneHot> (V3Number& out, const V3Number& src) { out.opOneHot(src); }
|
||||
template <> void foldOp<DfgOneHot0> (V3Number& out, const V3Number& src) { out.opOneHot0(src); }
|
||||
template <> void foldOp<DfgRedAnd> (V3Number& out, const V3Number& src) { out.opRedAnd(src); }
|
||||
template <> void foldOp<DfgRedOr> (V3Number& out, const V3Number& src) { out.opRedOr(src); }
|
||||
template <> void foldOp<DfgRedXor> (V3Number& out, const V3Number& src) { out.opRedXor(src); }
|
||||
|
|
@ -1155,7 +1158,7 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
|
||||
// Sel from a partial variable (including narrowed vertex)
|
||||
if (DfgVarPacked* const varp = fromp->cast<DfgVarPacked>()) {
|
||||
if (varp->srcp() && !varp->isVolatile()) {
|
||||
if (varp->srcp() && !varp->isVolatile() && !varp->srcp()->is<DfgCReset>()) {
|
||||
// Must be a splice, otherwise it would have been inlined
|
||||
DfgSplicePacked* splicep = varp->srcp()->as<DfgSplicePacked>();
|
||||
DfgVertex* driverp = nullptr;
|
||||
|
|
@ -1193,6 +1196,10 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
// DfgVertexUnary
|
||||
//=========================================================================
|
||||
|
||||
void visit(DfgCountOnes* const vtxp) override {
|
||||
if (foldUnary(vtxp)) return;
|
||||
}
|
||||
|
||||
void visit(DfgExtend* const vtxp) override {
|
||||
if (foldUnary(vtxp)) return;
|
||||
|
||||
|
|
@ -1325,6 +1332,14 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
void visit(DfgOneHot* const vtxp) override {
|
||||
if (foldUnary(vtxp)) return;
|
||||
}
|
||||
|
||||
void visit(DfgOneHot0* const vtxp) override {
|
||||
if (foldUnary(vtxp)) return;
|
||||
}
|
||||
|
||||
void visit(DfgRedOr* const vtxp) override {
|
||||
if (optimizeReduction(vtxp)) return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,9 @@ class V3DfgPushDownSels final {
|
|||
m_stack.push_back(&vtx);
|
||||
}
|
||||
for (DfgConst& vtx : m_dfg.constVertices()) m_stack.push_back(&vtx);
|
||||
for (DfgVertex& vtx : m_dfg.opVertices()) {
|
||||
if (!vtx.nInputs()) m_stack.push_back(&vtx);
|
||||
}
|
||||
|
||||
// Reverse post order number to assign to next vertex
|
||||
uint32_t rpoNext = m_dfg.size();
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ class DfgRegularize final {
|
|||
// No need to add a temporary if the single sink is a variable already
|
||||
if (sink.is<DfgVertexVar>()) return false;
|
||||
|
||||
// CReset always needs to be driving a variable
|
||||
if (aVtx.is<DfgCReset>()) return true;
|
||||
|
||||
// Do not inline expressions into a loop body
|
||||
if (const DfgAstRd* const astRdp = sink.cast<DfgAstRd>()) { return astRdp->inLoop(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -384,6 +384,24 @@ class AstToDfgConverter final : public VNVisitor {
|
|||
nodep->user2p(vtxp);
|
||||
}
|
||||
}
|
||||
void visit(AstCReset* nodep) override {
|
||||
UASSERT_OBJ(m_converting, nodep, "AstToDfg visit called without m_converting");
|
||||
UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex");
|
||||
if (unhandled(nodep)) return;
|
||||
|
||||
const DfgDataType* const dtypep = DfgDataType::fromAst(nodep->dtypep());
|
||||
if (!dtypep) {
|
||||
m_foundUnhandled = true;
|
||||
++m_ctx.m_conv.nonRepDType;
|
||||
return;
|
||||
}
|
||||
|
||||
UASSERT_OBJ(!nodep->constructing(), nodep,
|
||||
"CReset should be non-constructing at this stage");
|
||||
|
||||
DfgVertex* const vtxp = make<DfgCReset>(nodep->fileline(), *dtypep);
|
||||
nodep->user2p(vtxp);
|
||||
}
|
||||
void visit(AstReplicate* nodep) override {
|
||||
UASSERT_OBJ(m_converting, nodep, "AstToDfg visit called without m_converting");
|
||||
UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex");
|
||||
|
|
|
|||
|
|
@ -248,6 +248,14 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class DfgCReset final : public DfgVertexNullary {
|
||||
public:
|
||||
DfgCReset(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype)
|
||||
: DfgVertexNullary{dfg, dfgType(), flp, dtype} {}
|
||||
|
||||
ASTGEN_MEMBERS_DfgCReset;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Unary vertices - 1 inputs
|
||||
|
||||
|
|
|
|||
|
|
@ -2722,10 +2722,14 @@ class ParamVisitor final : public VNVisitor {
|
|||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
void checkParamNotHier(AstNode* valuep) {
|
||||
if (!valuep) return;
|
||||
valuep->foreachAndNext([&](const AstNodeExpr* exprp) {
|
||||
if (const AstVarXRef* const refp = VN_CAST(exprp, VarXRef)) {
|
||||
// Flag hierarchical refs in a parameter value. Single top-down pass.
|
||||
void checkParamNotHierRecurse(AstNode* nodep, bool underTypeQuery = false) {
|
||||
for (; nodep; nodep = nodep->nextp()) {
|
||||
// Refs read only for their type ($bits etc.) are allowed
|
||||
const AstAttrOf* const attrp = VN_CAST(nodep, AttrOf);
|
||||
const bool childUnderQuery
|
||||
= underTypeQuery || (attrp && attrp->attrType().isTypeQuery());
|
||||
if (const AstVarXRef* const refp = VN_CAST(nodep, VarXRef)) {
|
||||
// Allow hierarchical ref to interface params through interface/modport ports
|
||||
// or local interface instances
|
||||
bool isIfaceRef = false;
|
||||
|
|
@ -2735,18 +2739,21 @@ class ParamVisitor final : public VNVisitor {
|
|||
= !refname.empty()
|
||||
&& (m_ifacePortNames.count(refname) || m_ifaceInstCells.count(refname));
|
||||
}
|
||||
|
||||
if (!isIfaceRef) {
|
||||
if (!isIfaceRef && !underTypeQuery) {
|
||||
refp->v3warn(HIERPARAM, "Parameter values cannot use hierarchical values"
|
||||
" (IEEE 1800-2023 6.20.2)");
|
||||
}
|
||||
} else if (const AstNodeFTaskRef* refp = VN_CAST(exprp, NodeFTaskRef)) {
|
||||
} else if (const AstNodeFTaskRef* const refp = VN_CAST(nodep, NodeFTaskRef)) {
|
||||
if (refp->dotted() != "") {
|
||||
refp->v3error("Parameter values cannot call hierarchical functions"
|
||||
" (IEEE 1800-2023 6.20.2)");
|
||||
}
|
||||
}
|
||||
});
|
||||
checkParamNotHierRecurse(nodep->op1p(), childUnderQuery);
|
||||
checkParamNotHierRecurse(nodep->op2p(), childUnderQuery);
|
||||
checkParamNotHierRecurse(nodep->op3p(), childUnderQuery);
|
||||
checkParamNotHierRecurse(nodep->op4p(), childUnderQuery);
|
||||
}
|
||||
}
|
||||
|
||||
// Deparameterize and constify nested interface cells within ifaceModp.
|
||||
|
|
@ -2888,7 +2895,7 @@ class ParamVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstCell* nodep) override {
|
||||
checkParamNotHier(nodep->paramsp());
|
||||
checkParamNotHierRecurse(nodep->paramsp());
|
||||
if (VN_IS(nodep->modp(), Iface)) m_ifaceInstCells.emplace(nodep->name(), nodep);
|
||||
visitCellOrClassRef(nodep, VN_IS(nodep->modp(), Iface));
|
||||
}
|
||||
|
|
@ -2896,7 +2903,7 @@ class ParamVisitor final : public VNVisitor {
|
|||
if (nodep->ifacep()) visitCellOrClassRef(nodep, true);
|
||||
}
|
||||
void visit(AstClassRefDType* nodep) override {
|
||||
checkParamNotHier(nodep->paramsp());
|
||||
checkParamNotHierRecurse(nodep->paramsp());
|
||||
visitCellOrClassRef(nodep, false);
|
||||
}
|
||||
void visit(AstClassOrPackageRef* nodep) override {
|
||||
|
|
@ -2913,7 +2920,7 @@ class ParamVisitor final : public VNVisitor {
|
|||
if (nodep->isIfaceRef()) { m_ifacePortNames.insert(nodep->name()); }
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isParam()) {
|
||||
checkParamNotHier(nodep->valuep());
|
||||
checkParamNotHierRecurse(nodep->valuep());
|
||||
if (!nodep->valuep() && !VN_IS(m_modp, Class)) {
|
||||
nodep->v3error("Parameter without default value is never given value"
|
||||
<< " (IEEE 1800-2023 6.20.1): " << nodep->prettyNameQ());
|
||||
|
|
|
|||
|
|
@ -94,6 +94,69 @@ void V3ParseImp::importIfInStd(FileLine* fileline, const string& id, bool doImpo
|
|||
}
|
||||
}
|
||||
|
||||
AstNodeExpr* V3ParseImp::makePropertyCase(FileLine* flp, AstNodeExpr* exprp, AstCaseItem* itemsp) {
|
||||
AstNodeExpr* resultp = nullptr;
|
||||
AstNodeExpr* matchedp = nullptr;
|
||||
AstNodeExpr* defaultPropp = nullptr;
|
||||
FileLine* defaultFlp = flp;
|
||||
|
||||
if (!itemsp) {
|
||||
flp->v3error("Property case statement with no items");
|
||||
exprp->deleteTree();
|
||||
return new AstConst{flp, AstConst::BitTrue{}};
|
||||
}
|
||||
|
||||
for (AstCaseItem *nextp, *itemp = itemsp; itemp; itemp = nextp) {
|
||||
nextp = VN_AS(itemp->nextp(), CaseItem);
|
||||
AstNodeExpr* const propp = VN_AS(itemp->stmtsp()->unlinkFrBack(), NodeExpr);
|
||||
|
||||
if (itemp->isDefault()) {
|
||||
if (defaultPropp) {
|
||||
itemp->v3error("Multiple default statements in property case statement");
|
||||
defaultPropp->deleteTree();
|
||||
exprp->deleteTree();
|
||||
return new AstConst{flp, AstConst::BitTrue{}};
|
||||
}
|
||||
defaultFlp = itemp->fileline();
|
||||
defaultPropp = propp;
|
||||
continue;
|
||||
}
|
||||
|
||||
AstNodeExpr* itemMatchp = nullptr;
|
||||
for (AstNodeExpr *condNextp, *condp = itemp->condsp(); condp; condp = condNextp) {
|
||||
condNextp = VN_AS(condp->nextp(), NodeExpr);
|
||||
condp->unlinkFrBack();
|
||||
AstNodeExpr* const eqp
|
||||
= new AstEqCase{condp->fileline(), exprp->cloneTreePure(false), condp};
|
||||
itemMatchp = itemMatchp ? new AstLogOr{itemp->fileline(), itemMatchp, eqp} : eqp;
|
||||
}
|
||||
UASSERT_OBJ(itemMatchp, itemp, "Property case item without condition");
|
||||
AstNodeExpr* const guardp
|
||||
= matchedp
|
||||
? new AstLogAnd{itemp->fileline(), itemMatchp->cloneTreePure(false),
|
||||
new AstLogNot{itemp->fileline(), matchedp->cloneTreePure(false)}}
|
||||
: itemMatchp->cloneTreePure(false);
|
||||
AstNodeExpr* const branchp = new AstImplication{itemp->fileline(), guardp, propp, true};
|
||||
resultp = resultp ? new AstSAnd{flp, resultp, branchp} : branchp;
|
||||
matchedp = matchedp ? new AstLogOr{itemp->fileline(), matchedp, itemMatchp} : itemMatchp;
|
||||
}
|
||||
itemsp->deleteTree();
|
||||
|
||||
if (defaultPropp) {
|
||||
if (!matchedp) {
|
||||
exprp->deleteTree();
|
||||
return defaultPropp;
|
||||
}
|
||||
AstNodeExpr* const noMatchp
|
||||
= static_cast<AstNodeExpr*>(new AstLogNot{defaultFlp, matchedp->cloneTreePure(false)});
|
||||
AstNodeExpr* const branchp = new AstImplication{defaultFlp, noMatchp, defaultPropp, true};
|
||||
resultp = new AstSAnd{flp, resultp, branchp};
|
||||
}
|
||||
matchedp->deleteTree();
|
||||
exprp->deleteTree();
|
||||
return resultp;
|
||||
}
|
||||
|
||||
void V3ParseImp::lexPpline(const char* textp) {
|
||||
// Handle lexer `line directive
|
||||
// FileLine* const prevFl = lexFileline();
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@ public:
|
|||
void dumpTokensAhead(int line) VL_MT_DISABLED;
|
||||
static void candidatePli(VSpellCheck* spellerp) VL_MT_DISABLED;
|
||||
void importIfInStd(FileLine* fileline, const string& id, bool doImport);
|
||||
AstNodeExpr* makePropertyCase(FileLine* flp, AstNodeExpr* exprp, AstCaseItem* itemsp);
|
||||
|
||||
private:
|
||||
void preprocDumps(std::ostream& os);
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ class SliceVisitor final : public VNVisitor {
|
|||
UINFO(9, " cloneSliceSel(" << elements << "," << elemIdx << ") " << nodep);
|
||||
AstNodeExpr* const exprp = VN_AS(snodep->exprp(), NodeExpr);
|
||||
AstNodeExpr* const selp = cloneAndSel(exprp, elements, elemIdx, needPure);
|
||||
return new AstSampled{nodep->fileline(), selp};
|
||||
return new AstSampled{nodep->fileline(), selp, nullptr};
|
||||
} else if (AstExprStmt* const snodep = VN_CAST(nodep, ExprStmt)) {
|
||||
UINFO(9, " cloneExprStmt(" << elements << "," << elemIdx << ") " << nodep);
|
||||
AstNodeExpr* const resultSelp
|
||||
|
|
|
|||
153
src/V3Unroll.cpp
153
src/V3Unroll.cpp
|
|
@ -64,16 +64,69 @@ struct UnrollStats final {
|
|||
Stat m_nUnrolledIters{"Unrolled iterations"};
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Variable bindings
|
||||
class UnrolllBindings final {
|
||||
// NODE STATE
|
||||
// AstVarScope::user1() int: index of the binding in m_bindings
|
||||
const VNUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
// Map from AstVarScope::user1() to current variable value, nullptr if not bound - idx 0 unused
|
||||
std::vector<AstConst*> m_curr{nullptr};
|
||||
// Stack of binding checkpoints
|
||||
std::vector<std::vector<AstConst*>> m_checkpoints;
|
||||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
UnrolllBindings() = default;
|
||||
~UnrolllBindings() = default;
|
||||
VL_UNCOPYABLE(UnrolllBindings);
|
||||
VL_UNMOVABLE(UnrolllBindings);
|
||||
|
||||
// METHODS
|
||||
void clear() {
|
||||
m_curr.resize(1);
|
||||
m_checkpoints.clear();
|
||||
AstNode::user1ClearTree();
|
||||
}
|
||||
|
||||
void checkpoint() { m_checkpoints.push_back(m_curr); }
|
||||
|
||||
void revert() {
|
||||
m_curr = std::move(m_checkpoints.back());
|
||||
m_checkpoints.pop_back();
|
||||
}
|
||||
|
||||
void commit() { m_checkpoints.pop_back(); }
|
||||
|
||||
void set(AstVarScope* vscp, AstConst* valp) {
|
||||
if (!vscp->user1()) {
|
||||
vscp->user1(m_curr.size());
|
||||
m_curr.push_back(nullptr);
|
||||
}
|
||||
UINFO(6, "Binding SET " << vscp->name() << " / " << vscp->user1() << " := " << valp);
|
||||
m_curr[vscp->user1()] = valp;
|
||||
}
|
||||
|
||||
AstConst* get(AstVarScope* vscp) {
|
||||
// It's possible after a revert that user1 is set, but the vector is shorter, pad up
|
||||
if (static_cast<size_t>(vscp->user1()) >= m_curr.size()) {
|
||||
m_curr.resize(vscp->user1() + 1, nullptr);
|
||||
}
|
||||
AstConst* const valp = vscp->user1() ? m_curr[vscp->user1()] : nullptr;
|
||||
UINFO(6, "Binding GET " << vscp->name() << " / " << vscp->user1() << " == " << valp);
|
||||
return valp;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Unroll one AstLoop
|
||||
|
||||
class UnrollOneVisitor final : VNVisitor {
|
||||
// NODE STATE
|
||||
// AstVarScope::user1p() AstConst: Value of this AstVarScope
|
||||
const VNUser1InUse m_user1InUse;
|
||||
|
||||
// STATE
|
||||
UnrollStats& m_stats; // Statistics tracking
|
||||
UnrolllBindings& m_bindings; // Variable bindings
|
||||
AstLoop* const m_loopp; // The loop we are trying to unroll
|
||||
AstNode* m_stmtsp = nullptr; // Resulting unrolled statement
|
||||
size_t m_unrolledSize = 0; // Number of nodes in unrolled loop
|
||||
|
|
@ -204,11 +257,11 @@ class UnrollOneVisitor final : VNVisitor {
|
|||
AstVarRef* const refp = VN_CAST(np, VarRef);
|
||||
if (!refp) return;
|
||||
// Ignore if the referenced variable has no binding
|
||||
AstConst* const valp = VN_AS(refp->varScopep()->user1p(), Const);
|
||||
AstConst* const valp = m_bindings.get(refp->varScopep());
|
||||
if (!valp) return;
|
||||
// If writen, remove the binding
|
||||
if (refp->access().isWriteOrRW()) {
|
||||
refp->varScopep()->user1p(nullptr);
|
||||
m_bindings.set(refp->varScopep(), nullptr);
|
||||
return;
|
||||
}
|
||||
// Otherwise add it to the list of variables to substitute
|
||||
|
|
@ -219,7 +272,7 @@ class UnrollOneVisitor final : VNVisitor {
|
|||
// Actually substitute the variables that still have bindings
|
||||
for (AstVarRef* const refp : toSubstitute) {
|
||||
// Pick up bound value
|
||||
AstConst* const valp = VN_AS(refp->varScopep()->user1p(), Const);
|
||||
AstConst* const valp = m_bindings.get(refp->varScopep());
|
||||
// Binding might have been removed after adding to 'toSubstitute'
|
||||
if (!valp) continue;
|
||||
// Substitute it
|
||||
|
|
@ -230,8 +283,9 @@ class UnrollOneVisitor final : VNVisitor {
|
|||
}
|
||||
|
||||
// CONSTRUCTOR
|
||||
UnrollOneVisitor(UnrollStats& stats, AstLoop* loopp)
|
||||
UnrollOneVisitor(UnrollStats& stats, UnrolllBindings& bindings, AstLoop* loopp)
|
||||
: m_stats{stats}
|
||||
, m_bindings{bindings}
|
||||
, m_loopp{loopp} {
|
||||
UASSERT_OBJ(!loopp->contsp(), loopp, "'contsp' only used before LinkJump");
|
||||
// Do not unroll if we are told not to
|
||||
|
|
@ -239,25 +293,9 @@ class UnrollOneVisitor final : VNVisitor {
|
|||
cantUnroll(loopp, m_stats.m_nPragmaDisabled);
|
||||
return;
|
||||
}
|
||||
// Gather variable bindings from the preceding statements
|
||||
for (AstNode *succp = loopp, *currp = loopp->backp(); currp->nextp() == succp;
|
||||
succp = currp, currp = currp->backp()) {
|
||||
AstAssign* const assignp = VN_CAST(currp, Assign);
|
||||
if (!assignp) break;
|
||||
AstConst* const valp = VN_CAST(V3Const::constifyEdit(assignp->rhsp()), Const);
|
||||
if (!valp) break;
|
||||
AstVarRef* const lhsp = VN_CAST(assignp->lhsp(), VarRef);
|
||||
if (!lhsp) break;
|
||||
// Don't bind if volatile
|
||||
if (lhsp->varp()->isForced() || lhsp->varp()->isSigUserRWPublic()) continue;
|
||||
// Don't overwrite a later binding
|
||||
if (lhsp->varScopep()->user1p()) continue;
|
||||
// Set up the binding
|
||||
lhsp->varScopep()->user1p(valp);
|
||||
}
|
||||
// Attempt to unroll the loop
|
||||
const size_t iterLimit
|
||||
= m_unrollFull ? v3Global.opt.unrollLimit() : v3Global.opt.unrollCount();
|
||||
const size_t iterLimit = m_unrollFull ? v3Global.opt.unrollLimit() //
|
||||
: v3Global.opt.unrollCount();
|
||||
size_t iterCount = 0;
|
||||
do {
|
||||
if (iterCount > iterLimit) {
|
||||
|
|
@ -316,7 +354,7 @@ class UnrollOneVisitor final : VNVisitor {
|
|||
AstVarRef* const lhsp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
AstConst* const valp = VN_CAST(V3Const::constifyEdit(nodep->rhsp()), Const);
|
||||
if (lhsp && valp && !lhsp->varp()->isForced() && !lhsp->varp()->isSigUserRWPublic()) {
|
||||
lhsp->varScopep()->user1p(valp);
|
||||
m_bindings.set(lhsp->varScopep(), valp);
|
||||
return;
|
||||
}
|
||||
// Otherwise just like a generic statement
|
||||
|
|
@ -340,12 +378,32 @@ class UnrollOneVisitor final : VNVisitor {
|
|||
// Remove trailing dead code
|
||||
if (nodep->nextp()) pushDeletep(nodep->nextp()->unlinkFrBackWithNext());
|
||||
}
|
||||
void visit(AstLoop* nodep) override {
|
||||
m_bindings.checkpoint();
|
||||
std::pair<AstNode*, bool> pair = UnrollOneVisitor::apply(m_stats, m_bindings, nodep);
|
||||
|
||||
// If failed, revert the bindings and process the loop as a generic statement
|
||||
if (!pair.second) {
|
||||
m_bindings.revert();
|
||||
process(nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
// Commit the bindings and replace the loop with the unrolled code
|
||||
m_bindings.commit();
|
||||
if (pair.first) {
|
||||
nodep->replaceWith(pair.first);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// Unroll the given loop. Returns the resulting statements and the number of
|
||||
// iterations unrolled (0 if unrolling failed);
|
||||
static std::pair<AstNode*, bool> apply(UnrollStats& stats, AstLoop* loopp) {
|
||||
UnrollOneVisitor visitor{stats, loopp};
|
||||
// Unroll the given loop. Returns the resulting statements and a flag indicating success
|
||||
static std::pair<AstNode*, bool> apply(UnrollStats& stats, UnrolllBindings& bindings,
|
||||
AstLoop* loopp) {
|
||||
UnrollOneVisitor visitor{stats, bindings, loopp};
|
||||
// If successfully unrolled, return the resulting list of statements - might be empty
|
||||
if (visitor.m_ok) return {visitor.m_stmtsp, true};
|
||||
// Otherwise delete intermediate results
|
||||
|
|
@ -358,13 +416,40 @@ public:
|
|||
// Unroll all AstLoop statements
|
||||
|
||||
class UnrollAllVisitor final : VNVisitor {
|
||||
// STATE - Statistic tracking
|
||||
UnrollStats m_stats;
|
||||
// STATE
|
||||
UnrollStats m_stats; // Statistic tracking
|
||||
UnrolllBindings m_bindings; // Variable bindings
|
||||
|
||||
// VISIT
|
||||
void visit(AstLoop* nodep) override {
|
||||
// Gather variable bindings from the preceding statements
|
||||
m_bindings.clear();
|
||||
for (AstNode *succp = nodep, *currp = nodep->backp(); true;
|
||||
succp = currp, currp = currp->backp()) {
|
||||
// If the current statement is in higher list, proceed carefully
|
||||
if (currp->nextp() != succp) {
|
||||
// Jump block is OK, there is only one way to get here
|
||||
if (VN_IS(currp, JumpBlock)) continue;
|
||||
// TODO: if?
|
||||
// Otherwise we dont' know the control flow, give up
|
||||
break;
|
||||
}
|
||||
AstAssign* const assignp = VN_CAST(currp, Assign);
|
||||
if (!assignp) break;
|
||||
AstConst* const valp = VN_CAST(V3Const::constifyEdit(assignp->rhsp()), Const);
|
||||
if (!valp) break;
|
||||
AstVarRef* const lhsp = VN_CAST(assignp->lhsp(), VarRef);
|
||||
if (!lhsp) break;
|
||||
// Don't bind if volatile
|
||||
if (lhsp->varp()->isForced() || lhsp->varp()->isSigUserRWPublic()) continue;
|
||||
// Don't overwrite a later binding
|
||||
if (m_bindings.get(lhsp->varScopep())) continue;
|
||||
// Set up the binding
|
||||
m_bindings.set(lhsp->varScopep(), valp);
|
||||
}
|
||||
|
||||
// Attempt to unroll this loop
|
||||
const std::pair<AstNode*, bool> pair = UnrollOneVisitor::apply(m_stats, nodep);
|
||||
const std::pair<AstNode*, bool> pair = UnrollOneVisitor::apply(m_stats, m_bindings, nodep);
|
||||
|
||||
// If failed, carry on with nested loop
|
||||
if (!pair.second) {
|
||||
|
|
|
|||
|
|
@ -1714,6 +1714,13 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
void visit(AstUntil* nodep) override {
|
||||
if (nodep->isStrong()
|
||||
&& (v3Global.opt.timing().isSetFalse() || !v3Global.opt.timing().isSetTrue())) {
|
||||
nodep->v3warn(E_NOTIMING, nodep->verilogKwd() << " requires --timing");
|
||||
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
assertAtExpr(nodep);
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckBool(nodep, "LHS", nodep->lhsp(), BOTH);
|
||||
|
|
@ -1926,6 +1933,25 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (nodep->iffp()) iterateCheckBool(nodep, "iff condition", nodep->iffp(), BOTH);
|
||||
userIterateAndNext(nodep->optionsp(), nullptr);
|
||||
}
|
||||
void visit(AstCoverBin* nodep) override {
|
||||
// Bin range/value entries are self-determined constant expressions (IEEE 1800-2023
|
||||
// 19.5). Width each plain single-value entry self-determined so a referenced
|
||||
// parameter acquires a dtype, then constify so the reference folds to the AstConst
|
||||
// value that V3Covergroup requires. AstInsideRange entries fold their own bounds in
|
||||
// visit(AstInsideRange).
|
||||
for (AstNode *nextp, *itemp = nodep->rangesp(); itemp; itemp = nextp) {
|
||||
nextp = itemp->nextp();
|
||||
if (VN_IS(itemp, InsideRange)) {
|
||||
userIterate(itemp, nullptr);
|
||||
} else {
|
||||
userIterate(itemp, WidthVP{SELF, BOTH}.p());
|
||||
V3Const::constifyEdit(itemp); // itemp may change
|
||||
}
|
||||
}
|
||||
userIterateAndNext(nodep->iffp(), nullptr);
|
||||
userIterateAndNext(nodep->arraySizep(), nullptr);
|
||||
userIterateAndNext(nodep->transp(), nullptr);
|
||||
}
|
||||
void visit(AstPow* nodep) override {
|
||||
// Pow is special, output sign only depends on LHS sign, but
|
||||
// function result depends on both signs
|
||||
|
|
@ -3566,17 +3592,20 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstInsideRange* nodep) override {
|
||||
// Just do each side; AstInside will rip these nodes out later.
|
||||
// When m_vup is null, this range appears outside a normal expression context (e.g.
|
||||
// in a covergroup bin declaration). Pre-fold constant arithmetic in that case
|
||||
// (e.g., AstNegate(Const) -> Const) so children have their types set before widthing.
|
||||
// We cannot do this unconditionally: in a normal 'inside' expression (m_vup set),
|
||||
// range bounds may be enum refs not yet widthed, and constifyEdit would crash.
|
||||
if (!m_vup) {
|
||||
// This range appears outside a normal expression context (e.g. in a covergroup
|
||||
// bin declaration). Width the bounds self-determined first so each bound (and any
|
||||
// referenced parameter) has a dtype, then constify so constant arithmetic is folded
|
||||
// (e.g. AstNegate(Const) -> Const, or a parameter reference -> Const). Folding
|
||||
// preserves the now-present dtype, so no bound reaches V3WidthCommit without one.
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p());
|
||||
userIterateAndNext(nodep->rhsp(), WidthVP{SELF, BOTH}.p());
|
||||
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
|
||||
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
|
||||
} else {
|
||||
userIterateAndNext(nodep->lhsp(), m_vup);
|
||||
userIterateAndNext(nodep->rhsp(), m_vup);
|
||||
}
|
||||
userIterateAndNext(nodep->lhsp(), m_vup);
|
||||
userIterateAndNext(nodep->rhsp(), m_vup);
|
||||
nodep->dtypeFrom(nodep->lhsp());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4531,7 +4531,7 @@ system_f_or_t_expr_call<nodeExprp>: // IEEE: part of system_tf_call (can be tas
|
|||
| yD_ROSE '(' expr ',' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createSenTreeChanged($1, $5)}; }
|
||||
| yD_ROSE_GCLK '(' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; }
|
||||
| yD_RTOI '(' expr ')' { $$ = new AstRToIS{$1, $3}; }
|
||||
| yD_SAMPLED '(' expr ')' { $$ = new AstSampled{$1, $3}; }
|
||||
| yD_SAMPLED '(' expr ')' { $$ = new AstSampled{$1, $3, $3->dtypep()}; }
|
||||
| yD_SFORMATF '(' exprDispList ')' { $$ = new AstSFormatF{$1, AstSFormatF::ExprFormat{}, $3, 'd', false}; }
|
||||
| yD_SHORTREALTOBITS '(' expr ')' { $$ = new AstRealToBits{$1, $3}; UNSUPREAL($1); }
|
||||
| yD_SIGNED '(' expr ')' { $$ = new AstSigned{$1, $3}; }
|
||||
|
|
@ -6678,13 +6678,9 @@ property_spec<propSpecp>: // IEEE: property_spec
|
|||
|
||||
property_exprCaseIf<nodeExprp>: // IEEE: part of property_expr for if/case
|
||||
yCASE '(' expr/*expression_or_dist*/ ')' property_case_itemList yENDCASE
|
||||
{ $$ = new AstConst{$1, AstConst::BitFalse{}};
|
||||
BBUNSUP($<fl>1, "Unsupported: property case expression");
|
||||
DEL($3, $5); }
|
||||
{ $$ = PARSEP->makePropertyCase($1, $3, $5); }
|
||||
| yCASE '(' expr/*expression_or_dist*/ ')' yENDCASE
|
||||
{ $$ = new AstConst{$1, AstConst::BitFalse{}};
|
||||
BBUNSUP($<fl>1, "Unsupported: property case expression");
|
||||
DEL($3); }
|
||||
{ $$ = PARSEP->makePropertyCase($1, $3, nullptr); }
|
||||
| yIF '(' expr/*expression_or_dist*/ ')' pexpr %prec prIF
|
||||
{ $$ = new AstImplication{$1, $3, $5, true}; }
|
||||
| yIF '(' expr/*expression_or_dist*/ ')' pexpr yELSE pexpr
|
||||
|
|
@ -6695,16 +6691,15 @@ property_exprCaseIf<nodeExprp>: // IEEE: part of property_expr for if/case
|
|||
|
||||
property_case_itemList<caseItemp>: // IEEE: {property_case_item}
|
||||
property_case_item { $$ = $1; }
|
||||
| property_case_itemList ',' property_case_item { $$ = addNextNull($1, $3); }
|
||||
| property_case_itemList property_case_item { $$ = addNextNull($1, $2); }
|
||||
;
|
||||
|
||||
property_case_item<caseItemp>: // ==IEEE: property_case_item
|
||||
// // IEEE: expression_or_dist { ',' expression_or_dist } ':' property_statement
|
||||
// // IEEE: expression_or_dist { ',' expression_or_dist } ':' property_expr
|
||||
// // IEEE 1800-2012 changed from property_statement to property_expr
|
||||
// // IEEE 1800-2017 changed to require the semicolon
|
||||
caseCondList ':' pexpr { $$ = new AstCaseItem{$2, $1, $3}; }
|
||||
| caseCondList ':' pexpr ';' { $$ = new AstCaseItem{$2, $1, $3}; }
|
||||
| yDEFAULT pexpr { $$ = new AstCaseItem{$1, nullptr, $2}; }
|
||||
caseCondList ':' pexpr ';' { $$ = new AstCaseItem{$2, $1, $3}; }
|
||||
| yDEFAULT pexpr ';' { $$ = new AstCaseItem{$1, nullptr, $2}; }
|
||||
| yDEFAULT ':' pexpr ';' { $$ = new AstCaseItem{$1, nullptr, $3}; }
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
//END_MODULE_NAME--------------------------------------------------------------
|
||||
|
||||
//See also: https://github.com/twosigma/verilator_support
|
||||
// verilog_format: off
|
||||
// verilator lint_off COMBDLY,INITIALDLY,LATCH,MULTIDRIVEN,UNSIGNED,WIDTH
|
||||
|
||||
// BEGINNING OF MODULE
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
%Warning-DEPRECATED: t/t_clk_first_deprecated.v:12:14: sc_clock is ignored
|
||||
12 | input clk /*verilator sc_clock*/;
|
||||
%Warning-DEPRECATED: t/t_clk_first_deprecated.v:11:14: sc_clock is ignored
|
||||
11 | input clk /*verilator sc_clock*/;
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~
|
||||
... For warning description see https://verilator.org/warn/DEPRECATED?v=latest
|
||||
... Use "/* verilator lint_off DEPRECATED */" and lint_on around source to disable this message.
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
// SPDX-FileCopyrightText: 2003 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t ( /*AUTOARG*/
|
||||
// Inputs
|
||||
module t (
|
||||
clk
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
%Error: t/t_constraint_pure_nonabs_bad.v:8:20: Illegal to have 'pure constraint' in non-abstract class (IEEE 1800-2023 18.5.2)
|
||||
%Error: t/t_constraint_pure_nonabs_bad.v:8:19: Illegal to have 'pure constraint' in non-abstract class (IEEE 1800-2023 18.5.2)
|
||||
: ... note: In instance 't'
|
||||
8 | pure constraint raintBad;
|
||||
| ^~~~~~~~
|
||||
8 | pure constraint raintBad;
|
||||
| ^~~~~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class NonAsbstract;
|
||||
pure constraint raintBad; // Bad: Not in abstract class
|
||||
pure constraint raintBad; // Bad: Not in abstract class
|
||||
endclass
|
||||
|
||||
module t;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
cg.cp.maxv: 2
|
||||
cg.cp.minv: 1
|
||||
cg.cp.negative: 1
|
||||
cg.cp.positive: 3
|
||||
cg.cp.zero: 1
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
import coverage_covergroup_common
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
coverage_covergroup_common.run(test)
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module - parameter/localparam refs in bins
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test: Referencing a parameter/localparam identifier inside a covergroup
|
||||
// `bins` value or range. This previously triggered an internal error
|
||||
// (V3WidthCommit.cpp: No dtype) because the folded constant had no dtype.
|
||||
// Expected: compiles and the bounds behave exactly like numeric literals.
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t #(
|
||||
parameter int PMIN = -100
|
||||
) (
|
||||
input clk
|
||||
);
|
||||
|
||||
localparam int LMAX = 100;
|
||||
|
||||
int signed value;
|
||||
|
||||
covergroup cg;
|
||||
cp: coverpoint value {
|
||||
bins negative = {[PMIN : -1]}; // parameter as range lower bound
|
||||
bins zero = {0};
|
||||
bins positive = {[1 : LMAX]}; // localparam as range upper bound
|
||||
bins maxv = {LMAX}; // localparam as single value
|
||||
bins minv = {PMIN}; // parameter as single value
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
|
||||
case (cyc)
|
||||
0: value <= -100; // Hit negative + minv
|
||||
1: value <= 0; // Hit zero
|
||||
2: value <= 50; // Hit positive
|
||||
3: value <= 100; // Hit positive (dup) + maxv
|
||||
4: begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endcase
|
||||
|
||||
cg_inst.sample();
|
||||
|
||||
// Coverage progression (NBA committed before sample() within always block).
|
||||
// A final sample() also runs on the $finish cycle (value still 100), so the
|
||||
// positive/maxv hit counts are one higher than the number of distinct stimuli.
|
||||
// cyc=0: value=-100 -> negative + minv -> 2/5=40%
|
||||
// cyc=1: value=0 -> zero -> 3/5=60%
|
||||
// cyc=2: value=50 -> positive -> 4/5=80%
|
||||
// cyc=3: value=100 -> positive(dup) + maxv -> 5/5=100%
|
||||
if (cyc == 0) begin
|
||||
`checkr(cg_inst.get_inst_coverage(), 40.0);
|
||||
end
|
||||
if (cyc == 1) begin
|
||||
`checkr(cg_inst.get_inst_coverage(), 60.0);
|
||||
end
|
||||
if (cyc == 2) begin
|
||||
`checkr(cg_inst.get_inst_coverage(), 80.0);
|
||||
end
|
||||
if (cyc == 3) begin
|
||||
`checkr(cg_inst.get_inst_coverage(), 100.0);
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -62,6 +62,13 @@ module t (
|
|||
//verilator lint_on WIDTH
|
||||
`signal(FOLD_UNARY_Extend, tmp_FOLD_UNARY_Extend);
|
||||
`signal(FOLD_UNARY_ExtendS, tmp_FOLD_UNARY_ExtendS);
|
||||
`signal(FOLD_UNARY_CountOnes, $countones(const_a));
|
||||
`signal(FOLD_UNARY_OneHot, $onehot(const_a));
|
||||
`signal(FOLD_UNARY_OneHot0, $onehot0(const_a));
|
||||
`signal(FOLD_UNARY_OneHot_A, $onehot(const_a[0]));
|
||||
`signal(FOLD_UNARY_OneHot_B, $onehot(~const_a[0]));
|
||||
`signal(FOLD_UNARY_OneHot0_A, $onehot0(const_a[0]));
|
||||
`signal(FOLD_UNARY_OneHot0_B, $onehot0(~const_a[0]));
|
||||
|
||||
`signal(FOLD_BINARY_Add, const_a + const_b);
|
||||
`signal(FOLD_BINARY_And, const_a & const_b);
|
||||
|
|
|
|||
|
|
@ -570,4 +570,11 @@ module t (
|
|||
wire logic [7:0] func_3 = pkg::branchy(rand_a[7:0], rand_b[7:0]);
|
||||
`signal(FUNC_3, func_3);
|
||||
|
||||
logic [1:0] via_creset;
|
||||
always_comb begin
|
||||
automatic logic [1:0] a /* = AstCReset */;
|
||||
via_creset = a + 2'd1;
|
||||
end
|
||||
`signal(VIA_CRESET, via_creset);
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -8,12 +8,13 @@
|
|||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
import collections
|
||||
|
||||
test.scenarios('dist')
|
||||
|
||||
Tabs_Exempt_Re = r'(\.out$)|(/fstcpp)|(Makefile)|(\.mk$)|(\.mk\.in$)|test_regress/t/t_preproc\.v|install-sh'
|
||||
|
||||
Unicode_Exempt_Re = r'(Changes$|CONTRIBUTORS$|LICENSES?|contributors.rst$|spelling.txt$)'
|
||||
Unicode_Exempt_Re = r'(Changes$|CONTRIBUTORS$|LICENSES?|contributors.rst$|spelling.txt$|ci-rtlmeter-report.py)'
|
||||
|
||||
|
||||
def get_source_files():
|
||||
|
|
@ -28,6 +29,39 @@ def get_source_files():
|
|||
return files
|
||||
|
||||
|
||||
def check_verilog_indent(filename, contents):
|
||||
# Check for proper spacing
|
||||
# This isn't automated as part of CI action auto-format because .out files
|
||||
# might break as a result
|
||||
indents = collections.defaultdict(int)
|
||||
is_on = True
|
||||
for line in contents.splitlines():
|
||||
if re.search(r'// verilog_format: off', line):
|
||||
is_on = False
|
||||
if re.search(r'// verilog_format: on', line):
|
||||
is_on = True
|
||||
if not is_on:
|
||||
continue
|
||||
# verilog-format puts input/output as double levels, ignore
|
||||
if re.match(r' *(input|output|inout) ', line):
|
||||
continue
|
||||
|
||||
m = re.match(r'^ *', line)
|
||||
num_spaces = m.end() if m else 0
|
||||
if num_spaces > 0:
|
||||
indents[num_spaces] += 1
|
||||
|
||||
# pprint(indents)
|
||||
spacing = 2
|
||||
if (indents[3] + indents[6] + indents[9]) > (indents[2] + indents[4] + indents[6]) * 2:
|
||||
spacing = 3
|
||||
elif indents[2] == 0 and indents[4] > 1: # Hard because two levels of 2-space indents gives 4
|
||||
spacing = 4
|
||||
if spacing != 2:
|
||||
warns[filename] = "Indents should be 2 spaces per level, not what seems to be " + str(
|
||||
spacing) + "/level in: " + filename
|
||||
|
||||
|
||||
if not os.path.exists(test.root + "/.git"):
|
||||
test.skip("Not in a git repository")
|
||||
|
||||
|
|
@ -46,7 +80,7 @@ for filename in sorted(files.keys()):
|
|||
continue # Ignore binary files
|
||||
if contents != "" and contents[-1] != "\n":
|
||||
contents += "\n"
|
||||
warns[filename] = "Missing trailing newline (add one) in " + filename
|
||||
warns[filename] = "Missing trailing newline (add one) in: " + filename
|
||||
if "\r" in contents:
|
||||
contents = re.sub(r'\r', '', contents)
|
||||
warns[filename] = "Carriage returns (remove them) in: " + filename
|
||||
|
|
@ -84,7 +118,7 @@ for filename in sorted(files.keys()):
|
|||
warns[filename] += " (last character is ASCII " + str(ord(line[-1])) + ")"
|
||||
|
||||
if not eol_ws_exempt and re.search(r'\n\n+$', contents): # Regexp repeated above
|
||||
warns[filename] = "Trailing newlines at EOF in " + filename
|
||||
warns[filename] = "Trailing newlines at EOF in: " + filename
|
||||
|
||||
# Unicode checker; should this be done in another file?
|
||||
# No way to auto-fix.
|
||||
|
|
@ -92,7 +126,10 @@ for filename in sorted(files.keys()):
|
|||
m = re.search(r'(([^ \t\r\n\x20-\x7e]).*)', contents)
|
||||
if not unicode_exempt and m:
|
||||
warns[filename] = "Warning: non-ASCII contents '" + m.group(2) + "' at '" + m.group(
|
||||
1) + "' in " + filename
|
||||
1) + "' in: " + filename
|
||||
|
||||
if re.search(r'\.s?vh?$', filename):
|
||||
check_verilog_indent(filename, contents)
|
||||
|
||||
fcount += 1
|
||||
|
||||
|
|
@ -106,7 +143,8 @@ if len(warns):
|
|||
msg += "Updated files with whitespace errors: " + ' '.join(sorted(warns.keys())) + "\n"
|
||||
else:
|
||||
msg += "Files have whitespace errors: " + ' '.join(sorted(warns.keys())) + "\n"
|
||||
msg += "To auto-fix: HARNESS_UPDATE_GOLDEN=1 {command} or --golden\n"
|
||||
msg += "To auto-fix (some): HARNESS_UPDATE_GOLDEN=1 {command} or --golden\n"
|
||||
msg += "If change any Verilog then remember to update .out files too (with --golden)\n"
|
||||
for filename in sorted(warns.keys()):
|
||||
msg += warns[filename] + "\n"
|
||||
test.error(msg)
|
||||
|
|
|
|||
|
|
@ -9,29 +9,26 @@
|
|||
// See t_dpi_accessors.v for details of the test. This file should be included
|
||||
// by the top level module to define all the accessors needed.
|
||||
|
||||
// Use the macros to provide the desire access to our data. First simple
|
||||
// access to the registers, array elements and wires. For consistency with
|
||||
// simulators, we do not attempt to write wires.
|
||||
`RW_ACCESS([0:0], a, {t.i_test_sub.a});
|
||||
`RW_ACCESS([7:0], b, {t.i_test_sub.b});
|
||||
`RW_ACCESS([7:0], mem32, {t.i_test_sub.mem[32]});
|
||||
`R_ACCESS ([0:0], c, {t.i_test_sub.c});
|
||||
`R_ACCESS ([7:0], d, {t.i_test_sub.d});
|
||||
`RW_ACCESS([7:0], e, {t.i_test_sub.e});
|
||||
`RW_ACCESS([7:0], f, {t.i_test_sub.f});
|
||||
// Use the macros to provide the desire access to our data. First simple
|
||||
// access to the registers, array elements and wires. For consistency with
|
||||
// simulators, we do not attempt to write wires.
|
||||
`RW_ACCESS([0:0], a, {t.i_test_sub.a});
|
||||
`RW_ACCESS([7:0], b, {t.i_test_sub.b});
|
||||
`RW_ACCESS([7:0], mem32, {t.i_test_sub.mem[32]});
|
||||
`R_ACCESS([0:0], c, {t.i_test_sub.c});
|
||||
`R_ACCESS([7:0], d, {t.i_test_sub.d});
|
||||
`RW_ACCESS([7:0], e, {t.i_test_sub.e});
|
||||
`RW_ACCESS([7:0], f, {t.i_test_sub.f});
|
||||
|
||||
// Slices of vectors and array elements. For consistency with simulators,
|
||||
// we do not attempt to write wire slices.
|
||||
`RW_ACCESS([3:0], b_slice, {t.i_test_sub.b[3:0]});
|
||||
`RW_ACCESS([4:0], mem32_slice,
|
||||
{t.i_test_sub.mem[32][7:6], t.i_test_sub.mem[32][2:0]});
|
||||
`R_ACCESS([5:0], d_slice, {t.i_test_sub.d[6:1]});
|
||||
// Slices of vectors and array elements. For consistency with simulators,
|
||||
// we do not attempt to write wire slices.
|
||||
`RW_ACCESS([3:0], b_slice, {t.i_test_sub.b[3:0]});
|
||||
`RW_ACCESS([4:0], mem32_slice, {t.i_test_sub.mem[32][7:6], t.i_test_sub.mem[32][2:0]});
|
||||
`R_ACCESS([5:0], d_slice, {t.i_test_sub.d[6:1]});
|
||||
|
||||
// Complex registers, one with distinct read and write. We avoid use of
|
||||
// wires for consistency with simulators.
|
||||
`RW_ACCESS([14:0], l1, {t.i_test_sub.b[3:0],
|
||||
t.i_test_sub.mem[32][7:6],
|
||||
t.i_test_sub.e[6:1],
|
||||
t.i_test_sub.mem[32][2:0]});
|
||||
`R_ACCESS([7:0], l2, {t.i_test_sub.e[7:4], t.i_test_sub.f[3:0]});
|
||||
`W_ACCESS([7:0], l2, {t.i_test_sub.e[5:2], t.i_test_sub.f[5:2]});
|
||||
// Complex registers, one with distinct read and write. We avoid use of
|
||||
// wires for consistency with simulators.
|
||||
`RW_ACCESS([14:0], l1, {t.i_test_sub.b[3:0], t.i_test_sub.mem[32][7:6], t.i_test_sub.e[6:1],
|
||||
t.i_test_sub.mem[32][2:0]});
|
||||
`R_ACCESS([7:0], l2, {t.i_test_sub.e[7:4], t.i_test_sub.f[3:0]});
|
||||
`W_ACCESS([7:0], l2, {t.i_test_sub.e[5:2], t.i_test_sub.f[5:2]});
|
||||
|
|
|
|||
|
|
@ -9,20 +9,22 @@
|
|||
// See t_dpi_accessors.v for details of the test. This file should be included
|
||||
// by the top level module to define the generic accessor macros.
|
||||
|
||||
// verilog_format: off
|
||||
|
||||
// Accessor macros, to keep stuff concise
|
||||
`define R_ACCESS(type_spec, name, expr) \
|
||||
export "DPI-C" function name``_read; \
|
||||
function bit type_spec name``_read; \
|
||||
name``_read = (expr); \
|
||||
endfunction
|
||||
export "DPI-C" function name``_read; \
|
||||
function bit type_spec name``_read; \
|
||||
name``_read = (expr); \
|
||||
endfunction
|
||||
|
||||
`define W_ACCESS(type_spec, name, expr) \
|
||||
export "DPI-C" task name``_write; \
|
||||
task name``_write; \
|
||||
input bit type_spec in; \
|
||||
expr = in; \
|
||||
endtask
|
||||
`define W_ACCESS(type_spec, name, expr) \
|
||||
export "DPI-C" task name``_write; \
|
||||
task name``_write; \
|
||||
input bit type_spec in; \
|
||||
expr = in; \
|
||||
endtask
|
||||
|
||||
`define RW_ACCESS(type_spec, name, expr) \
|
||||
`R_ACCESS (type_spec, name, expr); \
|
||||
`W_ACCESS (type_spec, name, expr)
|
||||
`R_ACCESS (type_spec, name, expr); \
|
||||
`W_ACCESS (type_spec, name, expr)
|
||||
|
|
|
|||
|
|
@ -4,13 +4,16 @@
|
|||
// SPDX-FileCopyrightText: 2026 Nikolai Kumar
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define checkh(g,e) do if ((g) !==(e)) begin $write("%%Error: %s:%0d: got=%x exp=%x\n", `__FILE__,`__LINE__, (g),(e)); $stop; end while(0)
|
||||
|
||||
`ifdef CMT
|
||||
`define FORCEABLE /*verilator forceable*/
|
||||
`define FORCEABLE /*verilator forceable*/
|
||||
`else
|
||||
`define FORCEABLE
|
||||
`define FORCEABLE
|
||||
`endif
|
||||
// verilog_format: on
|
||||
|
||||
module t (input wire clk, output reg [31:0] cyc);
|
||||
initial cyc = 0;
|
||||
always @(posedge clk) cyc <= cyc + 1;
|
||||
|
|
|
|||
|
|
@ -11,204 +11,204 @@ module t (clk);
|
|||
|
||||
logic reset;
|
||||
|
||||
reg [255:0] v2_0;
|
||||
reg [255:0] v1_0;
|
||||
reg [255:0] v1_1;
|
||||
reg [255:0] v1_2;
|
||||
reg [255:0] v1_3;
|
||||
reg [255:0] v1_4;
|
||||
reg [255:0] v1_5;
|
||||
reg [255:0] v1_6;
|
||||
reg [255:0] v1_7;
|
||||
// verilator lint_off MULTIDRIVEN
|
||||
reg [255:0] dummy;
|
||||
// verilator lint_on MULTIDRIVEN
|
||||
reg [255:0] v2_0;
|
||||
reg [255:0] v1_0;
|
||||
reg [255:0] v1_1;
|
||||
reg [255:0] v1_2;
|
||||
reg [255:0] v1_3;
|
||||
reg [255:0] v1_4;
|
||||
reg [255:0] v1_5;
|
||||
reg [255:0] v1_6;
|
||||
reg [255:0] v1_7;
|
||||
// verilator lint_off MULTIDRIVEN
|
||||
reg [255:0] dummy;
|
||||
// verilator lint_on MULTIDRIVEN
|
||||
|
||||
Calculate calc0(.clk(clk), .reset(reset), .v1_0(v1_0), .v1_1(dummy), .v1_2(dummy), .v1_3(dummy), .v1_4(dummy), .v1_5(dummy), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc1(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(v1_1), .v1_2(dummy), .v1_3(dummy), .v1_4(dummy), .v1_5(dummy), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc2(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(v1_2), .v1_3(dummy), .v1_4(dummy), .v1_5(dummy), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc3(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(dummy), .v1_3(v1_3), .v1_4(dummy), .v1_5(dummy), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc4(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(dummy), .v1_3(dummy), .v1_4(v1_4), .v1_5(dummy), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc5(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(dummy), .v1_3(dummy), .v1_4(dummy), .v1_5(v1_5), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc6(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(dummy), .v1_3(dummy), .v1_4(dummy), .v1_5(dummy), .v1_6(v1_6), .v1_7(dummy));
|
||||
Calculate calc7(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(dummy), .v1_3(dummy), .v1_4(dummy), .v1_5(dummy), .v1_6(dummy), .v1_7(v1_7));
|
||||
always @ (posedge clk) v2_0 <= v1_0 + v1_1 + v1_2 + v1_3 + v1_4 + v1_5 + v1_6 + v1_7;
|
||||
Check chk(.clk(clk), .reset(reset), .v2_0(v2_0));
|
||||
Calculate calc0(.clk(clk), .reset(reset), .v1_0(v1_0), .v1_1(dummy), .v1_2(dummy), .v1_3(dummy), .v1_4(dummy), .v1_5(dummy), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc1(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(v1_1), .v1_2(dummy), .v1_3(dummy), .v1_4(dummy), .v1_5(dummy), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc2(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(v1_2), .v1_3(dummy), .v1_4(dummy), .v1_5(dummy), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc3(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(dummy), .v1_3(v1_3), .v1_4(dummy), .v1_5(dummy), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc4(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(dummy), .v1_3(dummy), .v1_4(v1_4), .v1_5(dummy), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc5(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(dummy), .v1_3(dummy), .v1_4(dummy), .v1_5(v1_5), .v1_6(dummy), .v1_7(dummy));
|
||||
Calculate calc6(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(dummy), .v1_3(dummy), .v1_4(dummy), .v1_5(dummy), .v1_6(v1_6), .v1_7(dummy));
|
||||
Calculate calc7(.clk(clk), .reset(reset), .v1_0(dummy), .v1_1(dummy), .v1_2(dummy), .v1_3(dummy), .v1_4(dummy), .v1_5(dummy), .v1_6(dummy), .v1_7(v1_7));
|
||||
always @ (posedge clk) v2_0 <= v1_0 + v1_1 + v1_2 + v1_3 + v1_4 + v1_5 + v1_6 + v1_7;
|
||||
Check chk(.clk(clk), .reset(reset), .v2_0(v2_0));
|
||||
endmodule
|
||||
|
||||
module Check(input clk, output logic reset, input reg [255:0] v2_0);
|
||||
integer cyc=0;
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
`ifdef TEST_VERBOSE
|
||||
$write("[%0t] rst=%0x v0_0=%0x v1_0=%0x result=%0x\n", $time, reset, v0_0, v1_0, v2_0);
|
||||
$write("[%0t] rst=%0x v0_0=%0x v1_0=%0x result=%0x\n", $time, reset, v0_0, v1_0, v2_0);
|
||||
`endif
|
||||
if (cyc==0) begin
|
||||
reset <= 1;
|
||||
end
|
||||
else if (cyc==10) begin
|
||||
reset <= 0;
|
||||
end
|
||||
if (cyc==0) begin
|
||||
reset <= 1;
|
||||
end
|
||||
else if (cyc==10) begin
|
||||
reset <= 0;
|
||||
end
|
||||
`ifndef SIM_CYCLES
|
||||
`define SIM_CYCLES 99
|
||||
`endif
|
||||
else if (cyc==`SIM_CYCLES) begin
|
||||
if (v2_0 != 256'd2017) $stop;
|
||||
$write("VARS=64 WIDTH=256 WORKINGSET=2KB\n");
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
else if (cyc==`SIM_CYCLES) begin
|
||||
if (v2_0 != 256'd2017) $stop;
|
||||
$write("VARS=64 WIDTH=256 WORKINGSET=2KB\n");
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module Calculate(input clk,
|
||||
input reset,
|
||||
output reg [255:0] v1_0,
|
||||
output reg [255:0] v1_1,
|
||||
output reg [255:0] v1_2,
|
||||
output reg [255:0] v1_3,
|
||||
output reg [255:0] v1_4,
|
||||
output reg [255:0] v1_5,
|
||||
output reg [255:0] v1_6,
|
||||
output reg [255:0] v1_7
|
||||
);
|
||||
reg [255:0] v0_0;
|
||||
reg [255:0] v0_1;
|
||||
reg [255:0] v0_2;
|
||||
reg [255:0] v0_3;
|
||||
reg [255:0] v0_4;
|
||||
reg [255:0] v0_5;
|
||||
reg [255:0] v0_6;
|
||||
reg [255:0] v0_7;
|
||||
reg [255:0] v0_8;
|
||||
reg [255:0] v0_9;
|
||||
reg [255:0] v0_10;
|
||||
reg [255:0] v0_11;
|
||||
reg [255:0] v0_12;
|
||||
reg [255:0] v0_13;
|
||||
reg [255:0] v0_14;
|
||||
reg [255:0] v0_15;
|
||||
reg [255:0] v0_16;
|
||||
reg [255:0] v0_17;
|
||||
reg [255:0] v0_18;
|
||||
reg [255:0] v0_19;
|
||||
reg [255:0] v0_20;
|
||||
reg [255:0] v0_21;
|
||||
reg [255:0] v0_22;
|
||||
reg [255:0] v0_23;
|
||||
reg [255:0] v0_24;
|
||||
reg [255:0] v0_25;
|
||||
reg [255:0] v0_26;
|
||||
reg [255:0] v0_27;
|
||||
reg [255:0] v0_28;
|
||||
reg [255:0] v0_29;
|
||||
reg [255:0] v0_30;
|
||||
reg [255:0] v0_31;
|
||||
reg [255:0] v0_32;
|
||||
reg [255:0] v0_33;
|
||||
reg [255:0] v0_34;
|
||||
reg [255:0] v0_35;
|
||||
reg [255:0] v0_36;
|
||||
reg [255:0] v0_37;
|
||||
reg [255:0] v0_38;
|
||||
reg [255:0] v0_39;
|
||||
reg [255:0] v0_40;
|
||||
reg [255:0] v0_41;
|
||||
reg [255:0] v0_42;
|
||||
reg [255:0] v0_43;
|
||||
reg [255:0] v0_44;
|
||||
reg [255:0] v0_45;
|
||||
reg [255:0] v0_46;
|
||||
reg [255:0] v0_47;
|
||||
reg [255:0] v0_48;
|
||||
reg [255:0] v0_49;
|
||||
reg [255:0] v0_50;
|
||||
reg [255:0] v0_51;
|
||||
reg [255:0] v0_52;
|
||||
reg [255:0] v0_53;
|
||||
reg [255:0] v0_54;
|
||||
reg [255:0] v0_55;
|
||||
reg [255:0] v0_56;
|
||||
reg [255:0] v0_57;
|
||||
reg [255:0] v0_58;
|
||||
reg [255:0] v0_59;
|
||||
reg [255:0] v0_60;
|
||||
reg [255:0] v0_61;
|
||||
reg [255:0] v0_62;
|
||||
reg [255:0] v0_63;
|
||||
input reset,
|
||||
output reg [255:0] v1_0,
|
||||
output reg [255:0] v1_1,
|
||||
output reg [255:0] v1_2,
|
||||
output reg [255:0] v1_3,
|
||||
output reg [255:0] v1_4,
|
||||
output reg [255:0] v1_5,
|
||||
output reg [255:0] v1_6,
|
||||
output reg [255:0] v1_7
|
||||
);
|
||||
reg [255:0] v0_0;
|
||||
reg [255:0] v0_1;
|
||||
reg [255:0] v0_2;
|
||||
reg [255:0] v0_3;
|
||||
reg [255:0] v0_4;
|
||||
reg [255:0] v0_5;
|
||||
reg [255:0] v0_6;
|
||||
reg [255:0] v0_7;
|
||||
reg [255:0] v0_8;
|
||||
reg [255:0] v0_9;
|
||||
reg [255:0] v0_10;
|
||||
reg [255:0] v0_11;
|
||||
reg [255:0] v0_12;
|
||||
reg [255:0] v0_13;
|
||||
reg [255:0] v0_14;
|
||||
reg [255:0] v0_15;
|
||||
reg [255:0] v0_16;
|
||||
reg [255:0] v0_17;
|
||||
reg [255:0] v0_18;
|
||||
reg [255:0] v0_19;
|
||||
reg [255:0] v0_20;
|
||||
reg [255:0] v0_21;
|
||||
reg [255:0] v0_22;
|
||||
reg [255:0] v0_23;
|
||||
reg [255:0] v0_24;
|
||||
reg [255:0] v0_25;
|
||||
reg [255:0] v0_26;
|
||||
reg [255:0] v0_27;
|
||||
reg [255:0] v0_28;
|
||||
reg [255:0] v0_29;
|
||||
reg [255:0] v0_30;
|
||||
reg [255:0] v0_31;
|
||||
reg [255:0] v0_32;
|
||||
reg [255:0] v0_33;
|
||||
reg [255:0] v0_34;
|
||||
reg [255:0] v0_35;
|
||||
reg [255:0] v0_36;
|
||||
reg [255:0] v0_37;
|
||||
reg [255:0] v0_38;
|
||||
reg [255:0] v0_39;
|
||||
reg [255:0] v0_40;
|
||||
reg [255:0] v0_41;
|
||||
reg [255:0] v0_42;
|
||||
reg [255:0] v0_43;
|
||||
reg [255:0] v0_44;
|
||||
reg [255:0] v0_45;
|
||||
reg [255:0] v0_46;
|
||||
reg [255:0] v0_47;
|
||||
reg [255:0] v0_48;
|
||||
reg [255:0] v0_49;
|
||||
reg [255:0] v0_50;
|
||||
reg [255:0] v0_51;
|
||||
reg [255:0] v0_52;
|
||||
reg [255:0] v0_53;
|
||||
reg [255:0] v0_54;
|
||||
reg [255:0] v0_55;
|
||||
reg [255:0] v0_56;
|
||||
reg [255:0] v0_57;
|
||||
reg [255:0] v0_58;
|
||||
reg [255:0] v0_59;
|
||||
reg [255:0] v0_60;
|
||||
reg [255:0] v0_61;
|
||||
reg [255:0] v0_62;
|
||||
reg [255:0] v0_63;
|
||||
|
||||
always @ (posedge clk) v0_0 <= reset ? 256'd1 : v0_1;
|
||||
always @ (posedge clk) v0_1 <= reset ? 256'd1 : v0_2;
|
||||
always @ (posedge clk) v0_2 <= reset ? 256'd2 : v0_3;
|
||||
always @ (posedge clk) v0_3 <= reset ? 256'd3 : v0_4;
|
||||
always @ (posedge clk) v0_4 <= reset ? 256'd4 : v0_5;
|
||||
always @ (posedge clk) v0_5 <= reset ? 256'd5 : v0_6;
|
||||
always @ (posedge clk) v0_6 <= reset ? 256'd6 : v0_7;
|
||||
always @ (posedge clk) v0_7 <= reset ? 256'd7 : v0_0;
|
||||
always @ (posedge clk) v0_8 <= reset ? 256'd8 : v0_9;
|
||||
always @ (posedge clk) v0_9 <= reset ? 256'd9 : v0_10;
|
||||
always @ (posedge clk) v0_10 <= reset ? 256'd10 : v0_11;
|
||||
always @ (posedge clk) v0_11 <= reset ? 256'd11 : v0_12;
|
||||
always @ (posedge clk) v0_12 <= reset ? 256'd12 : v0_13;
|
||||
always @ (posedge clk) v0_13 <= reset ? 256'd13 : v0_14;
|
||||
always @ (posedge clk) v0_14 <= reset ? 256'd14 : v0_15;
|
||||
always @ (posedge clk) v0_15 <= reset ? 256'd15 : v0_8;
|
||||
always @ (posedge clk) v0_16 <= reset ? 256'd16 : v0_17;
|
||||
always @ (posedge clk) v0_17 <= reset ? 256'd17 : v0_18;
|
||||
always @ (posedge clk) v0_18 <= reset ? 256'd18 : v0_19;
|
||||
always @ (posedge clk) v0_19 <= reset ? 256'd19 : v0_20;
|
||||
always @ (posedge clk) v0_20 <= reset ? 256'd20 : v0_21;
|
||||
always @ (posedge clk) v0_21 <= reset ? 256'd21 : v0_22;
|
||||
always @ (posedge clk) v0_22 <= reset ? 256'd22 : v0_23;
|
||||
always @ (posedge clk) v0_23 <= reset ? 256'd23 : v0_16;
|
||||
always @ (posedge clk) v0_24 <= reset ? 256'd24 : v0_25;
|
||||
always @ (posedge clk) v0_25 <= reset ? 256'd25 : v0_26;
|
||||
always @ (posedge clk) v0_26 <= reset ? 256'd26 : v0_27;
|
||||
always @ (posedge clk) v0_27 <= reset ? 256'd27 : v0_28;
|
||||
always @ (posedge clk) v0_28 <= reset ? 256'd28 : v0_29;
|
||||
always @ (posedge clk) v0_29 <= reset ? 256'd29 : v0_30;
|
||||
always @ (posedge clk) v0_30 <= reset ? 256'd30 : v0_31;
|
||||
always @ (posedge clk) v0_31 <= reset ? 256'd31 : v0_24;
|
||||
always @ (posedge clk) v0_32 <= reset ? 256'd32 : v0_33;
|
||||
always @ (posedge clk) v0_33 <= reset ? 256'd33 : v0_34;
|
||||
always @ (posedge clk) v0_34 <= reset ? 256'd34 : v0_35;
|
||||
always @ (posedge clk) v0_35 <= reset ? 256'd35 : v0_36;
|
||||
always @ (posedge clk) v0_36 <= reset ? 256'd36 : v0_37;
|
||||
always @ (posedge clk) v0_37 <= reset ? 256'd37 : v0_38;
|
||||
always @ (posedge clk) v0_38 <= reset ? 256'd38 : v0_39;
|
||||
always @ (posedge clk) v0_39 <= reset ? 256'd39 : v0_32;
|
||||
always @ (posedge clk) v0_40 <= reset ? 256'd40 : v0_41;
|
||||
always @ (posedge clk) v0_41 <= reset ? 256'd41 : v0_42;
|
||||
always @ (posedge clk) v0_42 <= reset ? 256'd42 : v0_43;
|
||||
always @ (posedge clk) v0_43 <= reset ? 256'd43 : v0_44;
|
||||
always @ (posedge clk) v0_44 <= reset ? 256'd44 : v0_45;
|
||||
always @ (posedge clk) v0_45 <= reset ? 256'd45 : v0_46;
|
||||
always @ (posedge clk) v0_46 <= reset ? 256'd46 : v0_47;
|
||||
always @ (posedge clk) v0_47 <= reset ? 256'd47 : v0_40;
|
||||
always @ (posedge clk) v0_48 <= reset ? 256'd48 : v0_49;
|
||||
always @ (posedge clk) v0_49 <= reset ? 256'd49 : v0_50;
|
||||
always @ (posedge clk) v0_50 <= reset ? 256'd50 : v0_51;
|
||||
always @ (posedge clk) v0_51 <= reset ? 256'd51 : v0_52;
|
||||
always @ (posedge clk) v0_52 <= reset ? 256'd52 : v0_53;
|
||||
always @ (posedge clk) v0_53 <= reset ? 256'd53 : v0_54;
|
||||
always @ (posedge clk) v0_54 <= reset ? 256'd54 : v0_55;
|
||||
always @ (posedge clk) v0_55 <= reset ? 256'd55 : v0_48;
|
||||
always @ (posedge clk) v0_56 <= reset ? 256'd56 : v0_57;
|
||||
always @ (posedge clk) v0_57 <= reset ? 256'd57 : v0_58;
|
||||
always @ (posedge clk) v0_58 <= reset ? 256'd58 : v0_59;
|
||||
always @ (posedge clk) v0_59 <= reset ? 256'd59 : v0_60;
|
||||
always @ (posedge clk) v0_60 <= reset ? 256'd60 : v0_61;
|
||||
always @ (posedge clk) v0_61 <= reset ? 256'd61 : v0_62;
|
||||
always @ (posedge clk) v0_62 <= reset ? 256'd62 : v0_63;
|
||||
always @ (posedge clk) v0_63 <= reset ? 256'd63 : v0_56;
|
||||
always @ (posedge clk) v0_0 <= reset ? 256'd1 : v0_1;
|
||||
always @ (posedge clk) v0_1 <= reset ? 256'd1 : v0_2;
|
||||
always @ (posedge clk) v0_2 <= reset ? 256'd2 : v0_3;
|
||||
always @ (posedge clk) v0_3 <= reset ? 256'd3 : v0_4;
|
||||
always @ (posedge clk) v0_4 <= reset ? 256'd4 : v0_5;
|
||||
always @ (posedge clk) v0_5 <= reset ? 256'd5 : v0_6;
|
||||
always @ (posedge clk) v0_6 <= reset ? 256'd6 : v0_7;
|
||||
always @ (posedge clk) v0_7 <= reset ? 256'd7 : v0_0;
|
||||
always @ (posedge clk) v0_8 <= reset ? 256'd8 : v0_9;
|
||||
always @ (posedge clk) v0_9 <= reset ? 256'd9 : v0_10;
|
||||
always @ (posedge clk) v0_10 <= reset ? 256'd10 : v0_11;
|
||||
always @ (posedge clk) v0_11 <= reset ? 256'd11 : v0_12;
|
||||
always @ (posedge clk) v0_12 <= reset ? 256'd12 : v0_13;
|
||||
always @ (posedge clk) v0_13 <= reset ? 256'd13 : v0_14;
|
||||
always @ (posedge clk) v0_14 <= reset ? 256'd14 : v0_15;
|
||||
always @ (posedge clk) v0_15 <= reset ? 256'd15 : v0_8;
|
||||
always @ (posedge clk) v0_16 <= reset ? 256'd16 : v0_17;
|
||||
always @ (posedge clk) v0_17 <= reset ? 256'd17 : v0_18;
|
||||
always @ (posedge clk) v0_18 <= reset ? 256'd18 : v0_19;
|
||||
always @ (posedge clk) v0_19 <= reset ? 256'd19 : v0_20;
|
||||
always @ (posedge clk) v0_20 <= reset ? 256'd20 : v0_21;
|
||||
always @ (posedge clk) v0_21 <= reset ? 256'd21 : v0_22;
|
||||
always @ (posedge clk) v0_22 <= reset ? 256'd22 : v0_23;
|
||||
always @ (posedge clk) v0_23 <= reset ? 256'd23 : v0_16;
|
||||
always @ (posedge clk) v0_24 <= reset ? 256'd24 : v0_25;
|
||||
always @ (posedge clk) v0_25 <= reset ? 256'd25 : v0_26;
|
||||
always @ (posedge clk) v0_26 <= reset ? 256'd26 : v0_27;
|
||||
always @ (posedge clk) v0_27 <= reset ? 256'd27 : v0_28;
|
||||
always @ (posedge clk) v0_28 <= reset ? 256'd28 : v0_29;
|
||||
always @ (posedge clk) v0_29 <= reset ? 256'd29 : v0_30;
|
||||
always @ (posedge clk) v0_30 <= reset ? 256'd30 : v0_31;
|
||||
always @ (posedge clk) v0_31 <= reset ? 256'd31 : v0_24;
|
||||
always @ (posedge clk) v0_32 <= reset ? 256'd32 : v0_33;
|
||||
always @ (posedge clk) v0_33 <= reset ? 256'd33 : v0_34;
|
||||
always @ (posedge clk) v0_34 <= reset ? 256'd34 : v0_35;
|
||||
always @ (posedge clk) v0_35 <= reset ? 256'd35 : v0_36;
|
||||
always @ (posedge clk) v0_36 <= reset ? 256'd36 : v0_37;
|
||||
always @ (posedge clk) v0_37 <= reset ? 256'd37 : v0_38;
|
||||
always @ (posedge clk) v0_38 <= reset ? 256'd38 : v0_39;
|
||||
always @ (posedge clk) v0_39 <= reset ? 256'd39 : v0_32;
|
||||
always @ (posedge clk) v0_40 <= reset ? 256'd40 : v0_41;
|
||||
always @ (posedge clk) v0_41 <= reset ? 256'd41 : v0_42;
|
||||
always @ (posedge clk) v0_42 <= reset ? 256'd42 : v0_43;
|
||||
always @ (posedge clk) v0_43 <= reset ? 256'd43 : v0_44;
|
||||
always @ (posedge clk) v0_44 <= reset ? 256'd44 : v0_45;
|
||||
always @ (posedge clk) v0_45 <= reset ? 256'd45 : v0_46;
|
||||
always @ (posedge clk) v0_46 <= reset ? 256'd46 : v0_47;
|
||||
always @ (posedge clk) v0_47 <= reset ? 256'd47 : v0_40;
|
||||
always @ (posedge clk) v0_48 <= reset ? 256'd48 : v0_49;
|
||||
always @ (posedge clk) v0_49 <= reset ? 256'd49 : v0_50;
|
||||
always @ (posedge clk) v0_50 <= reset ? 256'd50 : v0_51;
|
||||
always @ (posedge clk) v0_51 <= reset ? 256'd51 : v0_52;
|
||||
always @ (posedge clk) v0_52 <= reset ? 256'd52 : v0_53;
|
||||
always @ (posedge clk) v0_53 <= reset ? 256'd53 : v0_54;
|
||||
always @ (posedge clk) v0_54 <= reset ? 256'd54 : v0_55;
|
||||
always @ (posedge clk) v0_55 <= reset ? 256'd55 : v0_48;
|
||||
always @ (posedge clk) v0_56 <= reset ? 256'd56 : v0_57;
|
||||
always @ (posedge clk) v0_57 <= reset ? 256'd57 : v0_58;
|
||||
always @ (posedge clk) v0_58 <= reset ? 256'd58 : v0_59;
|
||||
always @ (posedge clk) v0_59 <= reset ? 256'd59 : v0_60;
|
||||
always @ (posedge clk) v0_60 <= reset ? 256'd60 : v0_61;
|
||||
always @ (posedge clk) v0_61 <= reset ? 256'd61 : v0_62;
|
||||
always @ (posedge clk) v0_62 <= reset ? 256'd62 : v0_63;
|
||||
always @ (posedge clk) v0_63 <= reset ? 256'd63 : v0_56;
|
||||
|
||||
always @ (posedge clk) v1_0 <= v0_0 + v0_1 + v0_2 + v0_3 + v0_4 + v0_5 + v0_6 + v0_7;
|
||||
always @ (posedge clk) v1_1 <= v0_8 + v0_9 + v0_10 + v0_11 + v0_12 + v0_13 + v0_14 + v0_15;
|
||||
always @ (posedge clk) v1_2 <= v0_16 + v0_17 + v0_18 + v0_19 + v0_20 + v0_21 + v0_22 + v0_23;
|
||||
always @ (posedge clk) v1_3 <= v0_24 + v0_25 + v0_26 + v0_27 + v0_28 + v0_29 + v0_30 + v0_31;
|
||||
always @ (posedge clk) v1_4 <= v0_32 + v0_33 + v0_34 + v0_35 + v0_36 + v0_37 + v0_38 + v0_39;
|
||||
always @ (posedge clk) v1_5 <= v0_40 + v0_41 + v0_42 + v0_43 + v0_44 + v0_45 + v0_46 + v0_47;
|
||||
always @ (posedge clk) v1_6 <= v0_48 + v0_49 + v0_50 + v0_51 + v0_52 + v0_53 + v0_54 + v0_55;
|
||||
always @ (posedge clk) v1_7 <= v0_56 + v0_57 + v0_58 + v0_59 + v0_60 + v0_61 + v0_62 + v0_63;
|
||||
always @ (posedge clk) v1_0 <= v0_0 + v0_1 + v0_2 + v0_3 + v0_4 + v0_5 + v0_6 + v0_7;
|
||||
always @ (posedge clk) v1_1 <= v0_8 + v0_9 + v0_10 + v0_11 + v0_12 + v0_13 + v0_14 + v0_15;
|
||||
always @ (posedge clk) v1_2 <= v0_16 + v0_17 + v0_18 + v0_19 + v0_20 + v0_21 + v0_22 + v0_23;
|
||||
always @ (posedge clk) v1_3 <= v0_24 + v0_25 + v0_26 + v0_27 + v0_28 + v0_29 + v0_30 + v0_31;
|
||||
always @ (posedge clk) v1_4 <= v0_32 + v0_33 + v0_34 + v0_35 + v0_36 + v0_37 + v0_38 + v0_39;
|
||||
always @ (posedge clk) v1_5 <= v0_40 + v0_41 + v0_42 + v0_43 + v0_44 + v0_45 + v0_46 + v0_47;
|
||||
always @ (posedge clk) v1_6 <= v0_48 + v0_49 + v0_50 + v0_51 + v0_52 + v0_53 + v0_54 + v0_55;
|
||||
always @ (posedge clk) v1_7 <= v0_56 + v0_57 + v0_58 + v0_59 + v0_60 + v0_61 + v0_62 + v0_63;
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
// SPDX-FileCopyrightText: 2003 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define foo bar
|
||||
`ifdef foo
|
||||
`ifdef baz `else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=['--binary'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// $bits() of interface member signals used as a child module parameter value.
|
||||
// $bits reads the type, not the hierarchical value, so it is legal in a
|
||||
// parameter (IEEE 1800-2023 6.20.2 forbids hierarchical values only).
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0)
|
||||
// verilog_format: on
|
||||
|
||||
interface axi_if #(
|
||||
parameter int ID_W = 8,
|
||||
parameter int ADDR_W = 32
|
||||
);
|
||||
logic [ID_W-1:0] AWID;
|
||||
logic [ADDR_W-1:0] AWADDR;
|
||||
logic [7:0] AWLEN;
|
||||
endinterface
|
||||
|
||||
module chkmod #(
|
||||
parameter int PAYLOAD_WIDTH = 1,
|
||||
parameter int EXPECT = 1
|
||||
);
|
||||
initial `checkh(PAYLOAD_WIDTH, EXPECT);
|
||||
endmodule
|
||||
|
||||
module bridge #(
|
||||
parameter int EXPECT = 1
|
||||
) (
|
||||
axi_if axi
|
||||
);
|
||||
// $bits of a concat of interface members
|
||||
chkmod #(
|
||||
.PAYLOAD_WIDTH($bits({axi.AWID, axi.AWADDR, axi.AWLEN})),
|
||||
.EXPECT(EXPECT)
|
||||
) u_concat ();
|
||||
// $bits of a single interface member
|
||||
chkmod #(
|
||||
.PAYLOAD_WIDTH($bits(axi.AWADDR)),
|
||||
.EXPECT(EXPECT - 12 - 8)
|
||||
) u_single ();
|
||||
endmodule
|
||||
|
||||
module t;
|
||||
axi_if #(
|
||||
.ID_W(12),
|
||||
.ADDR_W(64)
|
||||
) if0 (); // 12 + 64 + 8 = 84
|
||||
axi_if #(
|
||||
.ID_W(12),
|
||||
.ADDR_W(16)
|
||||
) if1 (); // 12 + 16 + 8 = 36
|
||||
|
||||
bridge #(.EXPECT(84)) dut0 (.axi(if0));
|
||||
bridge #(.EXPECT(36)) dut1 (.axi(if1));
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
%Error: t/t_lint_in_inc_bad_2.vh:9:7: syntax error, unexpected if, expecting '('
|
||||
9 | if if if;
|
||||
| ^~
|
||||
%Error: t/t_lint_in_inc_bad_2.vh:9:6: syntax error, unexpected if, expecting '('
|
||||
9 | if if if;
|
||||
| ^~
|
||||
t/t_lint_in_inc_bad_1.vh:8:1: ... note: In file included from 't_lint_in_inc_bad_1.vh'
|
||||
t/t_lint_in_inc_bad.v:8:1: ... note: In file included from 't_lint_in_inc_bad.v'
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module x;
|
||||
// Syntax error
|
||||
if if if;
|
||||
// Syntax error
|
||||
if if if;
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
%Warning-LATCH: t/t_lint_latch_bad_3.v:19:1: Latch inferred for signal 'o5' (not all control paths of combinational always assign a value)
|
||||
%Warning-LATCH: t/t_lint_latch_bad_3.v:30:3: Latch inferred for signal 'o5' (not all control paths of combinational always assign a value)
|
||||
: ... Suggest use of always_latch for intentional latches
|
||||
19 | always_comb
|
||||
| ^~~~~~~~~~~
|
||||
30 | always_comb
|
||||
| ^~~~~~~~~~~
|
||||
... For warning description see https://verilator.org/warn/LATCH?v=latest
|
||||
... Use "/* verilator lint_off LATCH */" and lint_on around source to disable this message.
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -4,72 +4,73 @@
|
|||
// SPDX-FileCopyrightText: 2020 Julien Margetts
|
||||
// SPDX-License-Identifier: Unlicense
|
||||
|
||||
module t (/*AUTOARG*/ reset, a, b, c, en, o1, o2, o3, o4, o5);
|
||||
input reset;
|
||||
input a;
|
||||
input b;
|
||||
input c;
|
||||
input en;
|
||||
output reg o1; // Always assigned
|
||||
output reg o2; // "
|
||||
output reg o3; // "
|
||||
output reg o4; // "
|
||||
output reg o5; // Latch
|
||||
module t ( /*AUTOARG*/
|
||||
reset,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
en,
|
||||
o1,
|
||||
o2,
|
||||
o3,
|
||||
o4,
|
||||
o5
|
||||
);
|
||||
input reset;
|
||||
input a;
|
||||
input b;
|
||||
input c;
|
||||
input en;
|
||||
output reg o1; // Always assigned
|
||||
output reg o2; // "
|
||||
output reg o3; // "
|
||||
output reg o4; // "
|
||||
output reg o5; // Latch
|
||||
|
||||
always_comb
|
||||
if (reset)
|
||||
begin
|
||||
o1 = 1'b0;
|
||||
o2 = 1'b0;
|
||||
o3 = 1'b0;
|
||||
o4 = 1'b0;
|
||||
o5 = 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
o1 = 1'b1;
|
||||
if (en)
|
||||
begin
|
||||
always_comb
|
||||
if (reset) begin
|
||||
o1 = 1'b0;
|
||||
o2 = 1'b0;
|
||||
|
||||
if (a)
|
||||
begin
|
||||
o3 = a;
|
||||
o5 = 1'b1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
o3 = ~a;
|
||||
o5 = a;
|
||||
end
|
||||
|
||||
// o3 is not assigned in either path of this if/else
|
||||
// but no latch because always assigned above
|
||||
if (c)
|
||||
begin
|
||||
o2 = a ^ b;
|
||||
o4 = 1'b1;
|
||||
end
|
||||
else
|
||||
o4 = ~a ^ b;
|
||||
|
||||
o2 = 1'b1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
o2 = 1'b1;
|
||||
if (b)
|
||||
begin
|
||||
o3 = ~a | b;
|
||||
o5 = ~b;
|
||||
end
|
||||
else
|
||||
begin
|
||||
o3 = a & ~b;
|
||||
// No assignment to o5, expect Warning-LATCH
|
||||
end
|
||||
o3 = 1'b0;
|
||||
o4 = 1'b0;
|
||||
end
|
||||
end
|
||||
o5 = 1'b0;
|
||||
end
|
||||
else begin
|
||||
o1 = 1'b1;
|
||||
if (en) begin
|
||||
o2 = 1'b0;
|
||||
|
||||
if (a) begin
|
||||
o3 = a;
|
||||
o5 = 1'b1;
|
||||
end
|
||||
else begin
|
||||
o3 = ~a;
|
||||
o5 = a;
|
||||
end
|
||||
|
||||
// o3 is not assigned in either path of this if/else
|
||||
// but no latch because always assigned above
|
||||
if (c) begin
|
||||
o2 = a ^ b;
|
||||
o4 = 1'b1;
|
||||
end
|
||||
else o4 = ~a ^ b;
|
||||
|
||||
o2 = 1'b1;
|
||||
end
|
||||
else begin
|
||||
o2 = 1'b1;
|
||||
if (b) begin
|
||||
o3 = ~a | b;
|
||||
o5 = ~b;
|
||||
end
|
||||
else begin
|
||||
o3 = a & ~b;
|
||||
// No assignment to o5, expect Warning-LATCH
|
||||
end
|
||||
o4 = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module sub;
|
||||
// verilator lint_off WIDTHTRUNC
|
||||
int warn_sub = 64'h1; // Suppressed
|
||||
// verilator lint_off WIDTHTRUNC
|
||||
int warn_sub = 64'h1; // Suppressed
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -5,248 +5,248 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Outputs
|
||||
ign, ign2, ign3, c_wright_32, c_wleft_32, ign4, ign4s,
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
// Outputs
|
||||
ign, ign2, ign3, c_wright_32, c_wleft_32, ign4, ign4s,
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
output [31:0] ign;
|
||||
output [3:0] ign2;
|
||||
output [11:0] ign3;
|
||||
input clk;
|
||||
output [31:0] ign;
|
||||
output [3:0] ign2;
|
||||
output [11:0] ign3;
|
||||
|
||||
parameter [95:0] P6 = 6;
|
||||
localparam P64 = (1 << P6);
|
||||
parameter [95:0] P6 = 6;
|
||||
localparam P64 = (1 << P6);
|
||||
|
||||
// verilator lint_off WIDTH
|
||||
localparam [4:0] PBIG23 = 1'b1 << ~73'b0;
|
||||
localparam [3:0] PBIG29 = 4'b1 << 33'h100000000;
|
||||
// verilator lint_on WIDTH
|
||||
// verilator lint_off WIDTH
|
||||
localparam [4:0] PBIG23 = 1'b1 << ~73'b0;
|
||||
localparam [3:0] PBIG29 = 4'b1 << 33'h100000000;
|
||||
// verilator lint_on WIDTH
|
||||
|
||||
reg [31:0] iright;
|
||||
reg signed [31:0] irights;
|
||||
reg [31:0] ileft;
|
||||
reg [P64-1:0] qright;
|
||||
reg signed [P64-1:0] qrights;
|
||||
reg [P64-1:0] qleft;
|
||||
reg [95:0] wright;
|
||||
reg signed [95:0] wrights;
|
||||
reg [95:0] wleft;
|
||||
reg [31:0] iright;
|
||||
reg signed [31:0] irights;
|
||||
reg [31:0] ileft;
|
||||
reg [P64-1:0] qright;
|
||||
reg signed [P64-1:0] qrights;
|
||||
reg [P64-1:0] qleft;
|
||||
reg [95:0] wright;
|
||||
reg signed [95:0] wrights;
|
||||
reg [95:0] wleft;
|
||||
|
||||
reg [31:0] q_iright;
|
||||
reg signed [31:0] q_irights;
|
||||
reg [31:0] q_ileft;
|
||||
reg [P64-1:0] q_qright;
|
||||
reg signed [P64-1:0] q_qrights;
|
||||
reg [P64-1:0] q_qleft;
|
||||
reg [95:0] q_wright;
|
||||
reg signed [95:0] q_wrights;
|
||||
reg [95:0] q_wleft;
|
||||
reg [31:0] q_iright;
|
||||
reg signed [31:0] q_irights;
|
||||
reg [31:0] q_ileft;
|
||||
reg [P64-1:0] q_qright;
|
||||
reg signed [P64-1:0] q_qrights;
|
||||
reg [P64-1:0] q_qleft;
|
||||
reg [95:0] q_wright;
|
||||
reg signed [95:0] q_wrights;
|
||||
reg [95:0] q_wleft;
|
||||
|
||||
|
||||
reg [31:0] w_iright;
|
||||
reg signed [31:0] w_irights;
|
||||
reg [31:0] w_ileft;
|
||||
reg [P64-1:0] w_qright;
|
||||
reg signed [P64-1:0] w_qrights;
|
||||
reg [P64-1:0] w_qleft;
|
||||
reg [95:0] w_wright;
|
||||
reg signed [95:0] w_wrights;
|
||||
reg [95:0] w_wleft;
|
||||
reg [31:0] w_iright;
|
||||
reg signed [31:0] w_irights;
|
||||
reg [31:0] w_ileft;
|
||||
reg [P64-1:0] w_qright;
|
||||
reg signed [P64-1:0] w_qrights;
|
||||
reg [P64-1:0] w_qleft;
|
||||
reg [95:0] w_wright;
|
||||
reg signed [95:0] w_wrights;
|
||||
reg [95:0] w_wleft;
|
||||
|
||||
reg [31:0] iamt;
|
||||
reg [63:0] qamt;
|
||||
reg [95:0] wamt;
|
||||
reg [31:0] iamt;
|
||||
reg [63:0] qamt;
|
||||
reg [95:0] wamt;
|
||||
|
||||
output reg [95:0] c_wright_32;
|
||||
output reg [95:0] c_wleft_32;
|
||||
output reg [95:0] c_wright_32;
|
||||
output reg [95:0] c_wleft_32;
|
||||
|
||||
reg [63:0] crc = 64'h5aef0c8d_d70a4497;
|
||||
wire [95:0] rand_96 = {crc[63:32] | crc[31:0], crc};
|
||||
reg [63:0] crc = 64'h5aef0c8d_d70a4497;
|
||||
wire [95:0] rand_96 = {crc[63:32] | crc[31:0], crc};
|
||||
|
||||
assign ign = {31'h0, clk} >>> 4'bx; // bug760
|
||||
assign ign2 = {iamt[1:0] >> {22{iamt[5:2]}}, iamt[1:0] << (0 <<< iamt[5:2])}; // bug1174
|
||||
assign ign3 = {iamt[1:0] >> {22{iamt[5:2]}},
|
||||
iamt[1:0] >> {11{iamt[5:2]}},
|
||||
$signed(iamt[1:0]) >>> {22{iamt[5:2]}},
|
||||
$signed(iamt[1:0]) >>> {11{iamt[5:2]}},
|
||||
iamt[1:0] << {22{iamt[5:2]}},
|
||||
iamt[1:0] << {11{iamt[5:2]}}};
|
||||
assign ign = {31'h0, clk} >>> 4'bx; // bug760
|
||||
assign ign2 = {iamt[1:0] >> {22{iamt[5:2]}}, iamt[1:0] << (0 <<< iamt[5:2])}; // bug1174
|
||||
assign ign3 = {iamt[1:0] >> {22{iamt[5:2]}},
|
||||
iamt[1:0] >> {11{iamt[5:2]}},
|
||||
$signed(iamt[1:0]) >>> {22{iamt[5:2]}},
|
||||
$signed(iamt[1:0]) >>> {11{iamt[5:2]}},
|
||||
iamt[1:0] << {22{iamt[5:2]}},
|
||||
iamt[1:0] << {11{iamt[5:2]}}};
|
||||
|
||||
wire [95:0] wamtt = {iamt,iamt,iamt};
|
||||
output wire [95:0] ign4;
|
||||
assign ign4 = wamtt >> {11{iamt[5:2]}};
|
||||
output wire signed [95:0] ign4s;
|
||||
assign ign4s = $signed(wamtt) >>> {11{iamt[5:2]}};
|
||||
wire [95:0] wamtt = {iamt,iamt,iamt};
|
||||
output wire [95:0] ign4;
|
||||
assign ign4 = wamtt >> {11{iamt[5:2]}};
|
||||
output wire signed [95:0] ign4s;
|
||||
assign ign4s = $signed(wamtt) >>> {11{iamt[5:2]}};
|
||||
|
||||
always @* begin
|
||||
iright = 32'h819b018a >> iamt;
|
||||
irights = 32'sh819b018a >>> signed'(iamt);
|
||||
ileft = 32'h819b018a << iamt;
|
||||
qright = 64'hf784bf8f_12734089 >> iamt;
|
||||
qrights = 64'shf784bf8f_12734089 >>> signed'(iamt);
|
||||
qleft = 64'hf784bf8f_12734089 << iamt;
|
||||
wright = 96'hf784bf8f_12734089_190abe48 >> iamt;
|
||||
wrights = 96'shf784bf8f_12734089_190abe48 >>> signed'(iamt);
|
||||
wleft = 96'hf784bf8f_12734089_190abe48 << iamt;
|
||||
always @* begin
|
||||
iright = 32'h819b018a >> iamt;
|
||||
irights = 32'sh819b018a >>> signed'(iamt);
|
||||
ileft = 32'h819b018a << iamt;
|
||||
qright = 64'hf784bf8f_12734089 >> iamt;
|
||||
qrights = 64'shf784bf8f_12734089 >>> signed'(iamt);
|
||||
qleft = 64'hf784bf8f_12734089 << iamt;
|
||||
wright = 96'hf784bf8f_12734089_190abe48 >> iamt;
|
||||
wrights = 96'shf784bf8f_12734089_190abe48 >>> signed'(iamt);
|
||||
wleft = 96'hf784bf8f_12734089_190abe48 << iamt;
|
||||
|
||||
q_iright = 32'h819b018a >> qamt;
|
||||
q_irights = 32'sh819b018a >>> signed'(qamt);
|
||||
q_ileft = 32'h819b018a << qamt;
|
||||
q_qright = 64'hf784bf8f_12734089 >> qamt;
|
||||
q_qrights = 64'shf784bf8f_12734089 >>> signed'(qamt);
|
||||
q_qleft = 64'hf784bf8f_12734089 << qamt;
|
||||
q_wright = 96'hf784bf8f_12734089_190abe48 >> qamt;
|
||||
q_wrights = 96'shf784bf8f_12734089_190abe48 >>> signed'(qamt);
|
||||
q_wleft = 96'hf784bf8f_12734089_190abe48 << qamt;
|
||||
q_iright = 32'h819b018a >> qamt;
|
||||
q_irights = 32'sh819b018a >>> signed'(qamt);
|
||||
q_ileft = 32'h819b018a << qamt;
|
||||
q_qright = 64'hf784bf8f_12734089 >> qamt;
|
||||
q_qrights = 64'shf784bf8f_12734089 >>> signed'(qamt);
|
||||
q_qleft = 64'hf784bf8f_12734089 << qamt;
|
||||
q_wright = 96'hf784bf8f_12734089_190abe48 >> qamt;
|
||||
q_wrights = 96'shf784bf8f_12734089_190abe48 >>> signed'(qamt);
|
||||
q_wleft = 96'hf784bf8f_12734089_190abe48 << qamt;
|
||||
|
||||
w_iright = 32'h819b018a >> wamt;
|
||||
w_irights = 32'sh819b018a >>> signed'(wamt);
|
||||
w_ileft = 32'h819b018a << wamt;
|
||||
w_qright = 64'hf784bf8f_12734089 >> wamt;
|
||||
w_qrights = 64'shf784bf8f_12734089 >>> signed'(wamt);
|
||||
w_qleft = 64'hf784bf8f_12734089 << wamt;
|
||||
w_wright = 96'hf784bf8f_12734089_190abe48 >> wamt;
|
||||
w_wrights = 96'shf784bf8f_12734089_190abe48 >>> signed'(wamt);
|
||||
w_wleft = 96'hf784bf8f_12734089_190abe48 << wamt;
|
||||
w_iright = 32'h819b018a >> wamt;
|
||||
w_irights = 32'sh819b018a >>> signed'(wamt);
|
||||
w_ileft = 32'h819b018a << wamt;
|
||||
w_qright = 64'hf784bf8f_12734089 >> wamt;
|
||||
w_qrights = 64'shf784bf8f_12734089 >>> signed'(wamt);
|
||||
w_qleft = 64'hf784bf8f_12734089 << wamt;
|
||||
w_wright = 96'hf784bf8f_12734089_190abe48 >> wamt;
|
||||
w_wrights = 96'shf784bf8f_12734089_190abe48 >>> signed'(wamt);
|
||||
w_wleft = 96'hf784bf8f_12734089_190abe48 << wamt;
|
||||
|
||||
c_wright_32 = rand_96 >> 32;
|
||||
c_wleft_32 = rand_96 << 32;
|
||||
end
|
||||
c_wright_32 = rand_96 >> 32;
|
||||
c_wleft_32 = rand_96 << 32;
|
||||
end
|
||||
|
||||
integer cyc; initial cyc=1;
|
||||
always @ (posedge clk) begin
|
||||
if (cyc!=0) begin
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]};
|
||||
integer cyc; initial cyc=1;
|
||||
always @ (posedge clk) begin
|
||||
if (cyc!=0) begin
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]};
|
||||
`ifdef TEST_VERBOSE
|
||||
$write("%d %x %x %x %x %x %x\n", cyc, ileft, iright, qleft, qright, wleft, wright);
|
||||
$write("%d %x %x %x %x %x %x\n", cyc, ileft, iright, qleft, qright, wleft, wright);
|
||||
`endif
|
||||
if (cyc==1) begin
|
||||
iamt <= 0;
|
||||
qamt <= 0;
|
||||
wamt <= 0;
|
||||
if (P64 != 64) $stop;
|
||||
if (5'b10110>>2 != 5'b00101) $stop;
|
||||
if (5'b10110>>>2 != 5'b00101) $stop; // Note it cares about sign-ness
|
||||
if (5'b10110<<2 != 5'b11000) $stop;
|
||||
if (5'b10110<<<2 != 5'b11000) $stop;
|
||||
if (5'sb10110>>2 != 5'sb00101) $stop;
|
||||
if (5'sb10110>>>2 != 5'sb11101) $stop;
|
||||
if (5'sb10110<<2 != 5'sb11000) $stop;
|
||||
if (5'sb10110<<<2 != 5'sb11000) $stop;
|
||||
// Allow >64 bit shifts if the shift amount is a constant
|
||||
if ((64'sh458c2de282e30f8b >> 68'sh4) !== 64'sh0458c2de282e30f8) $stop;
|
||||
end
|
||||
if (cyc==2) begin
|
||||
iamt <= 28;
|
||||
qamt <= 28;
|
||||
wamt <= 28;
|
||||
if (ileft != 32'h819b018a) $stop;
|
||||
if (iright != 32'h819b018a) $stop;
|
||||
if (irights != 32'h819b018a) $stop;
|
||||
if (qleft != 64'hf784bf8f_12734089) $stop;
|
||||
if (qright != 64'hf784bf8f_12734089) $stop;
|
||||
if (qrights != 64'hf784bf8f_12734089) $stop;
|
||||
if (wleft != 96'hf784bf8f12734089190abe48) $stop;
|
||||
if (wright != 96'hf784bf8f12734089190abe48) $stop;
|
||||
if (wrights != 96'hf784bf8f12734089190abe48) $stop;
|
||||
end
|
||||
if (cyc==3) begin
|
||||
iamt <= 31;
|
||||
qamt <= 31;
|
||||
wamt <= 31;
|
||||
if (ileft != 32'ha0000000) $stop;
|
||||
if (iright != 32'h8) $stop;
|
||||
if (irights != 32'hfffffff8) $stop;
|
||||
if (qleft != 64'hf127340890000000) $stop;
|
||||
if (qright != 64'h0000000f784bf8f1) $stop;
|
||||
if (qrights != 64'hffffffff784bf8f1) $stop;
|
||||
if (wleft != 96'hf12734089190abe480000000) $stop;
|
||||
if (wright != 96'h0000000f784bf8f127340891) $stop;
|
||||
if (wrights != 96'hffffffff784bf8f127340891) $stop;
|
||||
end
|
||||
if (cyc==4) begin
|
||||
iamt <= 32;
|
||||
qamt <= 32;
|
||||
wamt <= 32;
|
||||
if (ileft != 32'h0) $stop;
|
||||
if (iright != 32'h1) $stop;
|
||||
if (qleft != 64'h8939a04480000000) $stop;
|
||||
if (qright != 64'h00000001ef097f1e) $stop;
|
||||
end
|
||||
if (cyc==5) begin
|
||||
iamt <= 33;
|
||||
qamt <= 33;
|
||||
wamt <= 33;
|
||||
if (ileft != 32'h0) $stop;
|
||||
if (iright != 32'h0) $stop;
|
||||
if (qleft != 64'h1273408900000000) $stop;
|
||||
if (qright != 64'h00000000f784bf8f) $stop;
|
||||
end
|
||||
if (cyc==6) begin
|
||||
iamt <= 64;
|
||||
qamt <= 64;
|
||||
wamt <= 64;
|
||||
if (ileft != 32'h0) $stop;
|
||||
if (iright != 32'h0) $stop;
|
||||
if (qleft != 64'h24e6811200000000) $stop;
|
||||
if (qright != 64'h000000007bc25fc7) $stop;
|
||||
end
|
||||
if (cyc==7) begin
|
||||
iamt <= 128;
|
||||
qamt <= 128;
|
||||
wamt <= 128;
|
||||
if (ileft != 32'h0) $stop;
|
||||
if (iright != 32'h0) $stop;
|
||||
if (qleft != 64'h0) $stop;
|
||||
if (qright != 64'h0) $stop;
|
||||
end
|
||||
if (cyc==8) begin
|
||||
iamt <= 100;
|
||||
qamt <= {32'h10, 32'h0};
|
||||
wamt <= {32'h10, 64'h0};
|
||||
if (ileft != '0) $stop;
|
||||
if (iright != '0) $stop;
|
||||
if (irights != '1) $stop;
|
||||
if (qleft != '0) $stop;
|
||||
if (qright != '0) $stop;
|
||||
if (qrights != '1) $stop;
|
||||
if (wleft != '0) $stop;
|
||||
if (wright != '0) $stop;
|
||||
if (wrights != '1) $stop;
|
||||
end
|
||||
if (cyc==19) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
// General rule to test all q's
|
||||
if (cyc != 0) begin
|
||||
if (ileft != q_ileft) $stop;
|
||||
if (iright != q_iright) $stop;
|
||||
if (irights != q_irights) $stop;
|
||||
if (qleft != q_qleft) $stop;
|
||||
if (qright != q_qright) $stop;
|
||||
if (qrights != q_qrights) $stop;
|
||||
if (wleft != q_wleft) $stop;
|
||||
if (wright != q_wright) $stop;
|
||||
if (wrights != q_wrights) $stop;
|
||||
|
||||
if (ileft != w_ileft) $stop;
|
||||
if (iright != w_iright) $stop;
|
||||
if (irights != w_irights) $stop;
|
||||
if (qleft != w_qleft) $stop;
|
||||
if (qright != w_qright) $stop;
|
||||
if (qrights != w_qrights) $stop;
|
||||
if (wleft != w_wleft) $stop;
|
||||
if (wright != w_wright) $stop;
|
||||
if (wrights != w_wrights) $stop;
|
||||
|
||||
if (c_wright_32 << 32 != {rand_96[95:32], 32'd0}) $stop;
|
||||
if (c_wleft_32 >> 32 != {32'd0, rand_96[63:0]}) $stop;
|
||||
end
|
||||
if (cyc==1) begin
|
||||
iamt <= 0;
|
||||
qamt <= 0;
|
||||
wamt <= 0;
|
||||
if (P64 != 64) $stop;
|
||||
if (5'b10110>>2 != 5'b00101) $stop;
|
||||
if (5'b10110>>>2 != 5'b00101) $stop; // Note it cares about sign-ness
|
||||
if (5'b10110<<2 != 5'b11000) $stop;
|
||||
if (5'b10110<<<2 != 5'b11000) $stop;
|
||||
if (5'sb10110>>2 != 5'sb00101) $stop;
|
||||
if (5'sb10110>>>2 != 5'sb11101) $stop;
|
||||
if (5'sb10110<<2 != 5'sb11000) $stop;
|
||||
if (5'sb10110<<<2 != 5'sb11000) $stop;
|
||||
// Allow >64 bit shifts if the shift amount is a constant
|
||||
if ((64'sh458c2de282e30f8b >> 68'sh4) !== 64'sh0458c2de282e30f8) $stop;
|
||||
end
|
||||
end
|
||||
if (cyc==2) begin
|
||||
iamt <= 28;
|
||||
qamt <= 28;
|
||||
wamt <= 28;
|
||||
if (ileft != 32'h819b018a) $stop;
|
||||
if (iright != 32'h819b018a) $stop;
|
||||
if (irights != 32'h819b018a) $stop;
|
||||
if (qleft != 64'hf784bf8f_12734089) $stop;
|
||||
if (qright != 64'hf784bf8f_12734089) $stop;
|
||||
if (qrights != 64'hf784bf8f_12734089) $stop;
|
||||
if (wleft != 96'hf784bf8f12734089190abe48) $stop;
|
||||
if (wright != 96'hf784bf8f12734089190abe48) $stop;
|
||||
if (wrights != 96'hf784bf8f12734089190abe48) $stop;
|
||||
end
|
||||
if (cyc==3) begin
|
||||
iamt <= 31;
|
||||
qamt <= 31;
|
||||
wamt <= 31;
|
||||
if (ileft != 32'ha0000000) $stop;
|
||||
if (iright != 32'h8) $stop;
|
||||
if (irights != 32'hfffffff8) $stop;
|
||||
if (qleft != 64'hf127340890000000) $stop;
|
||||
if (qright != 64'h0000000f784bf8f1) $stop;
|
||||
if (qrights != 64'hffffffff784bf8f1) $stop;
|
||||
if (wleft != 96'hf12734089190abe480000000) $stop;
|
||||
if (wright != 96'h0000000f784bf8f127340891) $stop;
|
||||
if (wrights != 96'hffffffff784bf8f127340891) $stop;
|
||||
end
|
||||
if (cyc==4) begin
|
||||
iamt <= 32;
|
||||
qamt <= 32;
|
||||
wamt <= 32;
|
||||
if (ileft != 32'h0) $stop;
|
||||
if (iright != 32'h1) $stop;
|
||||
if (qleft != 64'h8939a04480000000) $stop;
|
||||
if (qright != 64'h00000001ef097f1e) $stop;
|
||||
end
|
||||
if (cyc==5) begin
|
||||
iamt <= 33;
|
||||
qamt <= 33;
|
||||
wamt <= 33;
|
||||
if (ileft != 32'h0) $stop;
|
||||
if (iright != 32'h0) $stop;
|
||||
if (qleft != 64'h1273408900000000) $stop;
|
||||
if (qright != 64'h00000000f784bf8f) $stop;
|
||||
end
|
||||
if (cyc==6) begin
|
||||
iamt <= 64;
|
||||
qamt <= 64;
|
||||
wamt <= 64;
|
||||
if (ileft != 32'h0) $stop;
|
||||
if (iright != 32'h0) $stop;
|
||||
if (qleft != 64'h24e6811200000000) $stop;
|
||||
if (qright != 64'h000000007bc25fc7) $stop;
|
||||
end
|
||||
if (cyc==7) begin
|
||||
iamt <= 128;
|
||||
qamt <= 128;
|
||||
wamt <= 128;
|
||||
if (ileft != 32'h0) $stop;
|
||||
if (iright != 32'h0) $stop;
|
||||
if (qleft != 64'h0) $stop;
|
||||
if (qright != 64'h0) $stop;
|
||||
end
|
||||
if (cyc==8) begin
|
||||
iamt <= 100;
|
||||
qamt <= {32'h10, 32'h0};
|
||||
wamt <= {32'h10, 64'h0};
|
||||
if (ileft != '0) $stop;
|
||||
if (iright != '0) $stop;
|
||||
if (irights != '1) $stop;
|
||||
if (qleft != '0) $stop;
|
||||
if (qright != '0) $stop;
|
||||
if (qrights != '1) $stop;
|
||||
if (wleft != '0) $stop;
|
||||
if (wright != '0) $stop;
|
||||
if (wrights != '1) $stop;
|
||||
end
|
||||
if (cyc==19) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
// General rule to test all q's
|
||||
if (cyc != 0) begin
|
||||
if (ileft != q_ileft) $stop;
|
||||
if (iright != q_iright) $stop;
|
||||
if (irights != q_irights) $stop;
|
||||
if (qleft != q_qleft) $stop;
|
||||
if (qright != q_qright) $stop;
|
||||
if (qrights != q_qrights) $stop;
|
||||
if (wleft != q_wleft) $stop;
|
||||
if (wright != q_wright) $stop;
|
||||
if (wrights != q_wrights) $stop;
|
||||
|
||||
if (ileft != w_ileft) $stop;
|
||||
if (iright != w_iright) $stop;
|
||||
if (irights != w_irights) $stop;
|
||||
if (qleft != w_qleft) $stop;
|
||||
if (qright != w_qright) $stop;
|
||||
if (qrights != w_qrights) $stop;
|
||||
if (wleft != w_wleft) $stop;
|
||||
if (wright != w_wright) $stop;
|
||||
if (wrights != w_wrights) $stop;
|
||||
|
||||
if (c_wright_32 << 32 != {rand_96[95:32], 32'd0}) $stop;
|
||||
if (c_wleft_32 >> 32 != {32'd0, rand_96[63:0]}) $stop;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -8,27 +8,24 @@
|
|||
// SPDX-FileCopyrightText: 2021 Dan Petrisko
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module top(/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
module top (
|
||||
input clk
|
||||
);
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish();
|
||||
end
|
||||
always_ff @(posedge clk) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish();
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module faketop(/*AUTOARG*/
|
||||
);
|
||||
module faketop;
|
||||
|
||||
top top();
|
||||
top top ();
|
||||
|
||||
// Stop immediately if this module is instantiated
|
||||
// Stop immediately if this module is instantiated
|
||||
initial begin
|
||||
$stop();
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -51,4 +51,12 @@
|
|||
: ... note: In instance 't'
|
||||
38 | assert property (@(e) s_eventually 1'h1);
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-NOTIMING: t/t_notiming.v:39:31: s_until requires --timing
|
||||
: ... note: In instance 't'
|
||||
39 | assert property (@(e) 1'h1 s_until 1'h1);
|
||||
| ^~~~~~~
|
||||
%Error-NOTIMING: t/t_notiming.v:40:31: s_until_with requires --timing
|
||||
: ... note: In instance 't'
|
||||
40 | assert property (@(e) 1'h1 s_until_with 1'h1);
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ module t;
|
|||
s.get();
|
||||
end
|
||||
assert property (@(e) s_eventually 1'h1);
|
||||
assert property (@(e) 1'h1 s_until 1'h1);
|
||||
assert property (@(e) 1'h1 s_until_with 1'h1);
|
||||
endmodule
|
||||
|
||||
`ifdef VERILATOR_TIMING
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@
|
|||
|
||||
module xx;
|
||||
|
||||
xx // intentional error
|
||||
xx // intentional error
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(timing_loop=True, verilator_flags2=['--assert', '--timing'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
|
||||
int cyc = 0;
|
||||
logic [1:0] sel;
|
||||
logic a;
|
||||
logic b;
|
||||
|
||||
int linear_f = 0;
|
||||
int default_f = 0;
|
||||
int vacuous_f = 0;
|
||||
int delay_f = 0;
|
||||
|
||||
always_comb begin
|
||||
sel = cyc[1:0];
|
||||
a = 1'b1;
|
||||
b = 1'b1;
|
||||
end
|
||||
|
||||
property p_delay(logic [1:0] delay);
|
||||
case (delay)
|
||||
2'd0 : a && b;
|
||||
2'd1 : a ##2 b;
|
||||
2'd2 : a ##4 b;
|
||||
2'd3 : a ##8 b;
|
||||
default: 0;
|
||||
endcase
|
||||
endproperty
|
||||
|
||||
property p_linear_search;
|
||||
case (sel)
|
||||
2'd0 : 1'b0;
|
||||
2'd0, 2'd1 : 1'b1;
|
||||
default 1'b1;
|
||||
endcase
|
||||
endproperty
|
||||
|
||||
property p_default_ignored_during_search;
|
||||
case (sel)
|
||||
default: 1'b0;
|
||||
2'd2 : 1'b1;
|
||||
endcase
|
||||
endproperty
|
||||
|
||||
property p_no_default_vacuous_success;
|
||||
case (sel)
|
||||
2'd0 : 1'b0;
|
||||
endcase
|
||||
endproperty
|
||||
|
||||
property p_only_default;
|
||||
case (sel)
|
||||
default: 1'b1;
|
||||
endcase
|
||||
endproperty
|
||||
|
||||
assert property (@(posedge clk) p_delay(sel)) else delay_f++;
|
||||
assert property (@(posedge clk) p_linear_search) else linear_f++;
|
||||
assert property (@(posedge clk) p_default_ignored_during_search) else default_f++;
|
||||
assert property (@(posedge clk) p_no_default_vacuous_success) else vacuous_f++;
|
||||
assert property (@(posedge clk) p_only_default) else `stop;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
end
|
||||
|
||||
always @(negedge clk) begin
|
||||
if (cyc == 16) begin
|
||||
`checkd(delay_f, 0);
|
||||
`checkd(linear_f, 4);
|
||||
`checkd(default_f, 12);
|
||||
`checkd(vacuous_f, 4);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
%Error: t/t_property_case_bad.v:13:7: Multiple default statements in property case statement
|
||||
13 | default: 1'b0;
|
||||
| ^~~~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: t/t_property_case_bad.v:18:5: Property case statement with no items
|
||||
18 | case (sel)
|
||||
| ^~~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
logic [1:0] sel;
|
||||
|
||||
property p1;
|
||||
case (sel)
|
||||
default: 1'b1;
|
||||
default: 1'b0;
|
||||
endcase
|
||||
endproperty
|
||||
|
||||
property p2;
|
||||
case (sel)
|
||||
endcase
|
||||
endproperty
|
||||
endmodule
|
||||
|
|
@ -1,50 +1,44 @@
|
|||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:26:13: Unsupported: strong (in property expression)
|
||||
26 | strong(a);
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:30:11: Unsupported: weak (in property expression)
|
||||
30 | weak(a);
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:24:11: Unsupported: strong (in property expression)
|
||||
24 | strong(a);
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:58:7: Unsupported: nexttime (in property expression)
|
||||
58 | nexttime a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:62:7: Unsupported: nexttime[] (in property expression)
|
||||
62 | nexttime [2] a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:66:7: Unsupported: s_nexttime (in property expression)
|
||||
66 | s_nexttime a;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:70:7: Unsupported: s_nexttime[] (in property expression)
|
||||
70 | s_nexttime [2] a;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:74:7: Unsupported: nexttime (in property expression)
|
||||
74 | nexttime always a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:78:7: Unsupported: nexttime[] (in property expression)
|
||||
78 | nexttime [2] always a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:82:7: Unsupported: nexttime[] (in property expression)
|
||||
82 | nexttime [2] always a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:86:7: Unsupported: nexttime (in property expression)
|
||||
86 | nexttime s_eventually a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:90:16: Unsupported: s_eventually[] (in property expression)
|
||||
90 | nexttime s_eventually [2:$] always a;
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:90:7: Unsupported: nexttime (in property expression)
|
||||
90 | nexttime s_eventually [2:$] always a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:109:27: Unsupported: property argument data type
|
||||
109 | property p_arg_propery(property inprop);
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:112:27: Unsupported: sequence argument data type
|
||||
112 | property p_arg_seqence(sequence inseq);
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:117:7: Unsupported: property case expression
|
||||
117 | case (a) endcase
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:120:7: Unsupported: property case expression
|
||||
120 | case (a) default: b; endcase
|
||||
| ^~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:28:9: Unsupported: weak (in property expression)
|
||||
28 | weak(a);
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:56:5: Unsupported: nexttime (in property expression)
|
||||
56 | nexttime a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:60:5: Unsupported: nexttime[] (in property expression)
|
||||
60 | nexttime [2] a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:64:5: Unsupported: s_nexttime (in property expression)
|
||||
64 | s_nexttime a;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:68:5: Unsupported: s_nexttime[] (in property expression)
|
||||
68 | s_nexttime [2] a;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:72:5: Unsupported: nexttime (in property expression)
|
||||
72 | nexttime always a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:76:5: Unsupported: nexttime[] (in property expression)
|
||||
76 | nexttime [2] always a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:80:5: Unsupported: nexttime[] (in property expression)
|
||||
80 | nexttime [2] always a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:84:5: Unsupported: nexttime (in property expression)
|
||||
84 | nexttime s_eventually a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:88:14: Unsupported: s_eventually[] (in property expression)
|
||||
88 | nexttime s_eventually [2:$] always a;
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:88:5: Unsupported: nexttime (in property expression)
|
||||
88 | nexttime s_eventually [2:$] always a;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:107:26: Unsupported: property argument data type
|
||||
107 | property p_arg_propery(property inprop);
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:110:26: Unsupported: sequence argument data type
|
||||
110 | property p_arg_seqence(sequence inseq);
|
||||
| ^~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:130:22: Unsupported: Unclocked assertion
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:115:21: Unsupported: Unclocked assertion
|
||||
: ... note: In instance 't'
|
||||
130 | assert property ((s_eventually a) implies (s_eventually a));
|
||||
| ^~~~~~~~~~~~
|
||||
115 | assert property ((s_eventually a) implies (s_eventually a));
|
||||
| ^~~~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:130:47: Unsupported: Unclocked assertion
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:115:46: Unsupported: Unclocked assertion
|
||||
: ... note: In instance 't'
|
||||
130 | assert property ((s_eventually a) implies (s_eventually a));
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:130:4: Unsupported: Unclocked assertion
|
||||
115 | assert property ((s_eventually a) implies (s_eventually a));
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:115:3: Unsupported: Unclocked assertion
|
||||
: ... note: In instance 't'
|
||||
130 | assert property ((s_eventually a) implies (s_eventually a));
|
||||
| ^~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:132:22: Unsupported: Unclocked assertion
|
||||
115 | assert property ((s_eventually a) implies (s_eventually a));
|
||||
| ^~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:117:21: Unsupported: Unclocked assertion
|
||||
: ... note: In instance 't'
|
||||
132 | assert property ((s_eventually a) iff (s_eventually a));
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:132:43: Unsupported: Unclocked assertion
|
||||
117 | assert property ((s_eventually a) iff (s_eventually a));
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:117:42: Unsupported: Unclocked assertion
|
||||
: ... note: In instance 't'
|
||||
132 | assert property ((s_eventually a) iff (s_eventually a));
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:132:4: Unsupported: Unclocked assertion
|
||||
117 | assert property ((s_eventually a) iff (s_eventually a));
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:117:3: Unsupported: Unclocked assertion
|
||||
: ... note: In instance 't'
|
||||
132 | assert property ((s_eventually a) iff (s_eventually a));
|
||||
| ^~~~~~
|
||||
117 | assert property ((s_eventually a) iff (s_eventually a));
|
||||
| ^~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -4,137 +4,122 @@
|
|||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
bit a;
|
||||
bit b;
|
||||
bit c;
|
||||
int cyc = 0;
|
||||
bit a;
|
||||
bit b;
|
||||
bit c;
|
||||
int cyc = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
end
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
end
|
||||
|
||||
`ifdef PARSING_TIME
|
||||
// NOTE this grammar hasn't been checked with other simulators,
|
||||
// is here just to avoid uncovered code lines in the grammar.
|
||||
property p_strong;
|
||||
strong(a);
|
||||
endproperty
|
||||
// NOTE this grammar hasn't been checked with other simulators,
|
||||
// is here just to avoid uncovered code lines in the grammar.
|
||||
property p_strong;
|
||||
strong(a);
|
||||
endproperty
|
||||
|
||||
property p_weak;
|
||||
weak(a);
|
||||
endproperty
|
||||
property p_weak;
|
||||
weak(a);
|
||||
endproperty
|
||||
|
||||
property p_until;
|
||||
a until b;
|
||||
endproperty
|
||||
property p_until;
|
||||
a until b;
|
||||
endproperty
|
||||
|
||||
property p_suntil;
|
||||
a s_until b;
|
||||
endproperty
|
||||
property p_suntil;
|
||||
a s_until b;
|
||||
endproperty
|
||||
|
||||
property p_untilwith;
|
||||
a until_with b;
|
||||
endproperty
|
||||
property p_untilwith;
|
||||
a until_with b;
|
||||
endproperty
|
||||
|
||||
property p_suntilwith;
|
||||
a s_until_with b;
|
||||
endproperty
|
||||
property p_suntilwith;
|
||||
a s_until_with b;
|
||||
endproperty
|
||||
|
||||
property p_poundminuspound1;
|
||||
a #-# b;
|
||||
endproperty
|
||||
property p_poundminuspound1;
|
||||
a #-# b;
|
||||
endproperty
|
||||
|
||||
property p_poundeqpound;
|
||||
a #=# b;
|
||||
endproperty
|
||||
property p_poundeqpound;
|
||||
a #=# b;
|
||||
endproperty
|
||||
|
||||
property p_nexttime;
|
||||
nexttime a;
|
||||
endproperty
|
||||
property p_nexttime;
|
||||
nexttime a;
|
||||
endproperty
|
||||
|
||||
property p_nexttime2;
|
||||
nexttime [2] a;
|
||||
endproperty
|
||||
property p_nexttime2;
|
||||
nexttime [2] a;
|
||||
endproperty
|
||||
|
||||
property p_snexttime;
|
||||
s_nexttime a;
|
||||
endproperty
|
||||
property p_snexttime;
|
||||
s_nexttime a;
|
||||
endproperty
|
||||
|
||||
property p_snexttime2;
|
||||
s_nexttime [2] a;
|
||||
endproperty
|
||||
property p_snexttime2;
|
||||
s_nexttime [2] a;
|
||||
endproperty
|
||||
|
||||
property p_nexttime_always;
|
||||
nexttime always a;
|
||||
endproperty
|
||||
property p_nexttime_always;
|
||||
nexttime always a;
|
||||
endproperty
|
||||
|
||||
property p_nexttime_always2;
|
||||
nexttime [2] always a;
|
||||
endproperty
|
||||
property p_nexttime_always2;
|
||||
nexttime [2] always a;
|
||||
endproperty
|
||||
|
||||
property p_nexttime_eventually2;
|
||||
nexttime [2] always a;
|
||||
endproperty
|
||||
property p_nexttime_eventually2;
|
||||
nexttime [2] always a;
|
||||
endproperty
|
||||
|
||||
property p_nexttime_seventually;
|
||||
nexttime s_eventually a;
|
||||
endproperty
|
||||
property p_nexttime_seventually;
|
||||
nexttime s_eventually a;
|
||||
endproperty
|
||||
|
||||
property p_nexttime_seventually2;
|
||||
nexttime s_eventually [2:$] always a;
|
||||
endproperty
|
||||
property p_nexttime_seventually2;
|
||||
nexttime s_eventually [2:$] always a;
|
||||
endproperty
|
||||
|
||||
property p_accepton;
|
||||
accept_on (a) b;
|
||||
endproperty
|
||||
property p_accepton;
|
||||
accept_on (a) b;
|
||||
endproperty
|
||||
|
||||
property p_syncaccepton;
|
||||
sync_accept_on (a) b;
|
||||
endproperty
|
||||
property p_syncaccepton;
|
||||
sync_accept_on (a) b;
|
||||
endproperty
|
||||
|
||||
property p_rejecton;
|
||||
reject_on (a) b;
|
||||
endproperty
|
||||
property p_rejecton;
|
||||
reject_on (a) b;
|
||||
endproperty
|
||||
|
||||
property p_syncrejecton;
|
||||
sync_reject_on (a) b;
|
||||
endproperty
|
||||
property p_syncrejecton;
|
||||
sync_reject_on (a) b;
|
||||
endproperty
|
||||
|
||||
property p_arg_propery(property inprop);
|
||||
inprop;
|
||||
endproperty
|
||||
property p_arg_seqence(sequence inseq);
|
||||
inseq;
|
||||
endproperty
|
||||
|
||||
property p_case_1;
|
||||
case (a) endcase
|
||||
endproperty
|
||||
property p_case_2;
|
||||
case (a) default: b; endcase
|
||||
endproperty
|
||||
property p_if;
|
||||
if (a) b
|
||||
endproperty
|
||||
property p_ifelse;
|
||||
if (a) b else c
|
||||
endproperty
|
||||
property p_arg_propery(property inprop);
|
||||
inprop;
|
||||
endproperty
|
||||
property p_arg_seqence(sequence inseq);
|
||||
inseq;
|
||||
endproperty
|
||||
`endif
|
||||
|
||||
assert property ((s_eventually a) implies (s_eventually a));
|
||||
assert property ((s_eventually a) implies (s_eventually a));
|
||||
|
||||
assert property ((s_eventually a) iff (s_eventually a));
|
||||
assert property ((s_eventually a) iff (s_eventually a));
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (cyc == 10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
always @(posedge clk) begin
|
||||
if (cyc == 10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(timing_loop=True, verilator_flags2=['--timing'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// s_eventually (strong eventually) inside an interface used to trigger an
|
||||
// internal error in V3Scope ("Can't locate varref scope").
|
||||
|
||||
interface my_if (
|
||||
input logic clk
|
||||
);
|
||||
logic a;
|
||||
assert property (@(posedge clk) s_eventually a);
|
||||
endinterface
|
||||
|
||||
module t ( /*AUTOARG*/);
|
||||
bit clk = 0;
|
||||
initial forever #1 clk = ~clk;
|
||||
|
||||
integer cyc = 0;
|
||||
|
||||
my_if u_if (.clk(clk));
|
||||
|
||||
initial u_if.a = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
u_if.a <= (cyc >= 3);
|
||||
if (cyc == 10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
%Warning-WIDTHTRUNC: t/t_property_sexpr_unsup.v:72:14: Logical operator IMPLICATION expects 1 bit on the RHS, but RHS's CMETHODHARD 'at' generates 8 bits.
|
||||
%Warning-WIDTHTRUNC: t/t_property_sexpr_unsup.v:80:14: Logical operator IMPLICATION expects 1 bit on the RHS, but RHS's CMETHODHARD 'at' generates 8 bits.
|
||||
: ... note: In instance 't.ieee'
|
||||
72 | $rose(a) |-> q[0];
|
||||
80 | $rose(a) |-> q[0];
|
||||
| ^~~
|
||||
... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest
|
||||
... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message.
|
||||
%Warning-WIDTHTRUNC: t/t_property_sexpr_unsup.v:77:29: Logical operator SEXPR expects 1 bit on the exprp, but exprp's CMETHODHARD 'at' generates 8 bits.
|
||||
%Warning-WIDTHTRUNC: t/t_property_sexpr_unsup.v:85:29: Logical operator SEXPR expects 1 bit on the exprp, but exprp's CMETHODHARD 'at' generates 8 bits.
|
||||
: ... note: In instance 't.ieee'
|
||||
77 | ($rose(a), l_b = b) |-> ##[3:10] q[l_b];
|
||||
85 | ($rose(a), l_b = b) |-> ##[3:10] q[l_b];
|
||||
| ^~
|
||||
%Warning-WIDTHTRUNC: t/t_property_sexpr_unsup.v:98:31: Logical operator SEXPR expects 1 bit on the exprp, but exprp's VARREF 'b' generates 32 bits.
|
||||
: ... note: In instance 't.ieee'
|
||||
98 | assert property (@clk not a ##1 b);
|
||||
%Warning-WIDTHTRUNC: t/t_property_sexpr_unsup.v:106:31: Logical operator SEXPR expects 1 bit on the exprp, but exprp's VARREF 'b' generates 32 bits.
|
||||
: ... note: In instance 't.ieee'
|
||||
106 | assert property (@clk not a ##1 b);
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:47:39: Unsupported: 'until' in complex property expression
|
||||
: ... note: In instance 't'
|
||||
|
|
@ -21,16 +21,32 @@
|
|||
: ... note: In instance 't'
|
||||
49 | assert property (@(posedge clk) val until (val ##1 val)) $display("[%0t] sequence in until, fileline:%d", $time, 49);
|
||||
| ^~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:51:39: Unsupported: s_until (in property expresion)
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:51:44: Unsupported: s_until (in property expression)
|
||||
: ... note: In instance 't'
|
||||
51 | assert property (@(posedge clk) val s_until !val) $display("[%0t] s_until, fileline:%d", $time, 51);
|
||||
51 | assert property (@(posedge clk) ##1 (val s_until val)) $display("[%0t] s_until in sequence, fileline:%d", $time, 51);
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:53:39: Unsupported: s_until (in property expression)
|
||||
: ... note: In instance 't'
|
||||
53 | assert property (@(posedge clk) val s_until val s_until val) $display("[%0t] nested s_until, fileline:%d", $time, 53);
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:53:39: Unsupported: s_until_with (in property expresion)
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:55:39: Unsupported: s_until (in property expression)
|
||||
: ... note: In instance 't'
|
||||
53 | assert property (@(posedge clk) val s_until_with val) $display("[%0t] s_until_with, fileline:%d", $time, 53);
|
||||
55 | assert property (@(posedge clk) val s_until (val ##1 val)) $display("[%0t] sequence in until_with, fileline:%d", $time, 55);
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:57:44: Unsupported: s_until_with (in property expression)
|
||||
: ... note: In instance 't'
|
||||
57 | assert property (@(posedge clk) ##1 (val s_until_with val)) $display("[%0t] s_until_with in sequence, fileline:%d", $time, 57);
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:59:39: Unsupported: s_until_with (in property expression)
|
||||
: ... note: In instance 't'
|
||||
59 | assert property (@(posedge clk) val s_until_with val s_until_with val) $display("[%0t] nested s_until_with, fileline:%d", $time, 59);
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:55:40: Unsupported: 'until' in complex property expression
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:61:39: Unsupported: s_until_with (in property expression)
|
||||
: ... note: In instance 't'
|
||||
55 | assert property (@(posedge clk) (val until val) or val) $display("[%0t] until inside or, fileline:%d", $time, 55);
|
||||
61 | assert property (@(posedge clk) val s_until_with (val ##1 val)) $display("[%0t] sequence in until_with, fileline:%d", $time, 61);
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:63:40: Unsupported: 'until' in complex property expression
|
||||
: ... note: In instance 't'
|
||||
63 | assert property (@(posedge clk) (val until val) or val) $display("[%0t] until inside or, fileline:%d", $time, 63);
|
||||
| ^~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -7,16 +7,32 @@
|
|||
: ... note: In instance 't'
|
||||
49 | assert property (@(posedge clk) val until (val ##1 val)) $display("[%0t] sequence in until, fileline:%d", $time, 49);
|
||||
| ^~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:51:39: Unsupported: s_until (in property expresion)
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:51:44: Unsupported: s_until (in property expression)
|
||||
: ... note: In instance 't'
|
||||
51 | assert property (@(posedge clk) val s_until !val) $display("[%0t] s_until, fileline:%d", $time, 51);
|
||||
51 | assert property (@(posedge clk) ##1 (val s_until val)) $display("[%0t] s_until in sequence, fileline:%d", $time, 51);
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:53:39: Unsupported: s_until (in property expression)
|
||||
: ... note: In instance 't'
|
||||
53 | assert property (@(posedge clk) val s_until val s_until val) $display("[%0t] nested s_until, fileline:%d", $time, 53);
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:53:39: Unsupported: s_until_with (in property expresion)
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:55:39: Unsupported: s_until (in property expression)
|
||||
: ... note: In instance 't'
|
||||
53 | assert property (@(posedge clk) val s_until_with val) $display("[%0t] s_until_with, fileline:%d", $time, 53);
|
||||
55 | assert property (@(posedge clk) val s_until (val ##1 val)) $display("[%0t] sequence in until_with, fileline:%d", $time, 55);
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:57:44: Unsupported: s_until_with (in property expression)
|
||||
: ... note: In instance 't'
|
||||
57 | assert property (@(posedge clk) ##1 (val s_until_with val)) $display("[%0t] s_until_with in sequence, fileline:%d", $time, 57);
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:59:39: Unsupported: s_until_with (in property expression)
|
||||
: ... note: In instance 't'
|
||||
59 | assert property (@(posedge clk) val s_until_with val s_until_with val) $display("[%0t] nested s_until_with, fileline:%d", $time, 59);
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:55:40: Unsupported: 'until' in complex property expression
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:61:39: Unsupported: s_until_with (in property expression)
|
||||
: ... note: In instance 't'
|
||||
55 | assert property (@(posedge clk) (val until val) or val) $display("[%0t] until inside or, fileline:%d", $time, 55);
|
||||
61 | assert property (@(posedge clk) val s_until_with (val ##1 val)) $display("[%0t] sequence in until_with, fileline:%d", $time, 61);
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_property_sexpr_unsup.v:63:40: Unsupported: 'until' in complex property expression
|
||||
: ... note: In instance 't'
|
||||
63 | assert property (@(posedge clk) (val until val) or val) $display("[%0t] until inside or, fileline:%d", $time, 63);
|
||||
| ^~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -48,9 +48,17 @@ module t ( /*AUTOARG*/
|
|||
|
||||
assert property (@(posedge clk) val until (val ##1 val)) $display("[%0t] sequence in until, fileline:%d", $time, `__LINE__);
|
||||
|
||||
assert property (@(posedge clk) val s_until !val) $display("[%0t] s_until, fileline:%d", $time, `__LINE__);
|
||||
assert property (@(posedge clk) ##1 (val s_until val)) $display("[%0t] s_until in sequence, fileline:%d", $time, `__LINE__);
|
||||
|
||||
assert property (@(posedge clk) val s_until_with val) $display("[%0t] s_until_with, fileline:%d", $time, `__LINE__);
|
||||
assert property (@(posedge clk) val s_until val s_until val) $display("[%0t] nested s_until, fileline:%d", $time, `__LINE__);
|
||||
|
||||
assert property (@(posedge clk) val s_until (val ##1 val)) $display("[%0t] sequence in until_with, fileline:%d", $time, `__LINE__);
|
||||
|
||||
assert property (@(posedge clk) ##1 (val s_until_with val)) $display("[%0t] s_until_with in sequence, fileline:%d", $time, `__LINE__);
|
||||
|
||||
assert property (@(posedge clk) val s_until_with val s_until_with val) $display("[%0t] nested s_until_with, fileline:%d", $time, `__LINE__);
|
||||
|
||||
assert property (@(posedge clk) val s_until_with (val ##1 val)) $display("[%0t] sequence in until_with, fileline:%d", $time, `__LINE__);
|
||||
|
||||
assert property (@(posedge clk) (val until val) or val) $display("[%0t] until inside or, fileline:%d", $time, `__LINE__);
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,40 @@ module t ( /*AUTOARG*/
|
|||
results[5].passs++;
|
||||
else results[5].fails++;
|
||||
|
||||
assert property (@(posedge clk) 0 s_until 1)
|
||||
results[6].passs++;
|
||||
else results[6].fails++;
|
||||
|
||||
assert property (@(posedge clk) cyc < 5 s_until cyc >= 5)
|
||||
results[7].passs++;
|
||||
else results[7].fails++;
|
||||
|
||||
assert property (@(posedge clk) cyc % 3 == 0 s_until cyc % 5 == 0)
|
||||
results[8].passs++;
|
||||
else results[8].fails++;
|
||||
|
||||
// Check that s_until accepts immediately when RHS is true, even if LHS is false.
|
||||
assert property (@(posedge clk) cyc % 2 == 0 s_until 1)
|
||||
results[9].passs++;
|
||||
else results[9].fails++;
|
||||
|
||||
// Check that s_until_with requires LHS when RHS is true on the same tick.
|
||||
assert property (@(posedge clk) 0 s_until_with 1)
|
||||
results[10].passs++;
|
||||
else results[10].fails++;
|
||||
|
||||
assert property (@(posedge clk) 1 s_until_with cyc >= 5)
|
||||
results[11].passs++;
|
||||
else results[11].fails++;
|
||||
|
||||
assert property (@(posedge clk) cyc <= 5 s_until_with cyc >= 5)
|
||||
results[12].passs++;
|
||||
else results[12].fails++;
|
||||
|
||||
assert property (@(posedge clk) cyc < 5 s_until_with cyc >= 5)
|
||||
results[13].passs++;
|
||||
else results[13].fails++;
|
||||
|
||||
always @(edge clk) begin
|
||||
++cyc;
|
||||
if (cyc == MAX) begin
|
||||
|
|
@ -54,6 +88,14 @@ module t ( /*AUTOARG*/
|
|||
expected[3] = '{0, 7};
|
||||
expected[4] = '{5, 2};
|
||||
expected[5] = '{2, 5};
|
||||
expected[6] = '{0, 7};
|
||||
expected[7] = '{0, 7};
|
||||
expected[8] = '{5, 2};
|
||||
expected[9] = '{0, 7};
|
||||
expected[10] = '{7, 0};
|
||||
expected[11] = '{0, 7};
|
||||
expected[12] = '{4, 3};
|
||||
expected[13] = '{7, 0};
|
||||
`checkh(results, expected);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
|
|
|
|||
|
|
@ -66,122 +66,122 @@ module top();
|
|||
HIJ_struct HIJ;
|
||||
|
||||
initial begin
|
||||
// struct ab
|
||||
ab = '{0, 0}; //constant member by position
|
||||
if (ab.a != 0) $stop;
|
||||
if (ab.b != 0) $stop;
|
||||
// struct ab
|
||||
ab = '{0, 0}; //constant member by position
|
||||
if (ab.a != 0) $stop;
|
||||
if (ab.b != 0) $stop;
|
||||
|
||||
|
||||
ab = '{default: 0}; //default value
|
||||
if (ab.a != 0) $stop;
|
||||
if (ab.b != 0) $stop;
|
||||
ab = '{default: 0}; //default value
|
||||
if (ab.a != 0) $stop;
|
||||
if (ab.b != 0) $stop;
|
||||
|
||||
|
||||
ab = '{int: 1, shortint: 0}; //data type and default value
|
||||
if (ab.a != 1) $stop;
|
||||
if (ab.b != 0) $stop;
|
||||
ab = '{int: 1, shortint: 0}; //data type and default value
|
||||
if (ab.a != 1) $stop;
|
||||
if (ab.b != 0) $stop;
|
||||
|
||||
|
||||
abkey[1:0] = '{'{a:1, b:2}, '{int:2, shortint:3}}; // member: value & data_type: value
|
||||
if (abkey[1].a != 1) $stop;
|
||||
if (abkey[1].b != 2) $stop;
|
||||
if (abkey[0].a != 2) $stop;
|
||||
if (abkey[0].b != 3) $stop;
|
||||
abkey[1:0] = '{'{a:1, b:2}, '{int:2, shortint:3}}; // member: value & data_type: value
|
||||
if (abkey[1].a != 1) $stop;
|
||||
if (abkey[1].b != 2) $stop;
|
||||
if (abkey[0].a != 2) $stop;
|
||||
if (abkey[0].b != 3) $stop;
|
||||
|
||||
|
||||
// struct st
|
||||
st = '{1, 2+k}; //constant member by position
|
||||
if (st.x != 1) $stop;
|
||||
if (st.y != 2+k) $stop;
|
||||
// struct st
|
||||
st = '{1, 2+k}; //constant member by position
|
||||
if (st.x != 1) $stop;
|
||||
if (st.y != 2+k) $stop;
|
||||
|
||||
st = '{x:2, y:3+k}; //member: value
|
||||
if (st.x != 2) $stop;
|
||||
if (st.y != 3+k) $stop;
|
||||
st = '{x:2, y:3+k}; //member: value
|
||||
if (st.x != 2) $stop;
|
||||
if (st.y != 3+k) $stop;
|
||||
|
||||
st = '{int:2, int:3+k}; //data_type: value override
|
||||
if (st.x != 3+k) $stop;
|
||||
if (st.y != 3+k) $stop;
|
||||
st = '{int:2, int:3+k}; //data_type: value override
|
||||
if (st.x != 3+k) $stop;
|
||||
if (st.y != 3+k) $stop;
|
||||
|
||||
|
||||
// struct sa
|
||||
sa = '{default:'1};
|
||||
if (sa.a != '1) $stop;
|
||||
if (sa.b != '1) $stop;
|
||||
if (sa.c != '1) $stop;
|
||||
if (sa.s != '1) $stop;
|
||||
// struct sa
|
||||
sa = '{default:'1};
|
||||
if (sa.a != '1) $stop;
|
||||
if (sa.b != '1) $stop;
|
||||
if (sa.c != '1) $stop;
|
||||
if (sa.s != '1) $stop;
|
||||
|
||||
sa = '{default:'1, int: 5};
|
||||
if (sa.a != '1) $stop;
|
||||
if (sa.b != '1) $stop;
|
||||
if (sa.c != '1) $stop;
|
||||
if (sa.s != 5) $stop;
|
||||
sa = '{default:'1, int: 5};
|
||||
if (sa.a != '1) $stop;
|
||||
if (sa.b != '1) $stop;
|
||||
if (sa.c != '1) $stop;
|
||||
if (sa.s != 5) $stop;
|
||||
|
||||
|
||||
sa = '{default:'1, int: 5, b: 0};
|
||||
if (sa.a != '1) $stop;
|
||||
if (sa.b != 0) $stop;
|
||||
if (sa.c != '1) $stop;
|
||||
if (sa.s != 5) $stop;
|
||||
sa = '{default:'1, int: 5, b: 0};
|
||||
if (sa.a != '1) $stop;
|
||||
if (sa.b != 0) $stop;
|
||||
if (sa.c != '1) $stop;
|
||||
if (sa.s != 5) $stop;
|
||||
|
||||
|
||||
// struct DEF
|
||||
DEF = '{A:1, BC1:'{B:2, C:3}, BC2:'{B:4,C:5}};
|
||||
if (DEF.A != 1) $stop;
|
||||
if (DEF.BC1.B != 2) $stop;
|
||||
if (DEF.BC1.C != 3) $stop;
|
||||
if (DEF.BC2.B != 4) $stop;
|
||||
if (DEF.BC2.C != 5) $stop;
|
||||
// struct DEF
|
||||
DEF = '{A:1, BC1:'{B:2, C:3}, BC2:'{B:4,C:5}};
|
||||
if (DEF.A != 1) $stop;
|
||||
if (DEF.BC1.B != 2) $stop;
|
||||
if (DEF.BC1.C != 3) $stop;
|
||||
if (DEF.BC2.B != 4) $stop;
|
||||
if (DEF.BC2.C != 5) $stop;
|
||||
|
||||
|
||||
DEF = '{int:0, BC1:'{int:10}, BC2:'{default:5}};
|
||||
if (DEF.A != 0) $stop;
|
||||
if (DEF.BC1.B != 10) $stop;
|
||||
if (DEF.BC1.C != 10) $stop;
|
||||
if (DEF.BC2.B != 5) $stop;
|
||||
if (DEF.BC2.C != 5) $stop;
|
||||
DEF = '{int:0, BC1:'{int:10}, BC2:'{default:5}};
|
||||
if (DEF.A != 0) $stop;
|
||||
if (DEF.BC1.B != 10) $stop;
|
||||
if (DEF.BC1.C != 10) $stop;
|
||||
if (DEF.BC2.B != 5) $stop;
|
||||
if (DEF.BC2.C != 5) $stop;
|
||||
|
||||
DEF = '{default:1, BC1:'{int:10}, BC2:'{default:5}};
|
||||
if (DEF.A != 1) $stop;
|
||||
if (DEF.BC1.B != 10) $stop;
|
||||
if (DEF.BC1.C != 10) $stop;
|
||||
if (DEF.BC2.B != 5) $stop;
|
||||
if (DEF.BC2.C != 5) $stop;
|
||||
DEF = '{default:1, BC1:'{int:10}, BC2:'{default:5}};
|
||||
if (DEF.A != 1) $stop;
|
||||
if (DEF.BC1.B != 10) $stop;
|
||||
if (DEF.BC1.C != 10) $stop;
|
||||
if (DEF.BC2.B != 5) $stop;
|
||||
if (DEF.BC2.C != 5) $stop;
|
||||
|
||||
DEF = '{default:10};
|
||||
if (DEF.A != 10) $stop;
|
||||
if (DEF.BC1.B != 10) $stop;
|
||||
if (DEF.BC1.C != 10) $stop;
|
||||
if (DEF.BC2.B != 10) $stop;
|
||||
if (DEF.BC2.C != 10) $stop;
|
||||
DEF = '{default:10};
|
||||
if (DEF.A != 10) $stop;
|
||||
if (DEF.BC1.B != 10) $stop;
|
||||
if (DEF.BC1.C != 10) $stop;
|
||||
if (DEF.BC2.B != 10) $stop;
|
||||
if (DEF.BC2.C != 10) $stop;
|
||||
|
||||
DEF = '{int:10};
|
||||
if (DEF.A != 10) $stop;
|
||||
if (DEF.BC1.B != 10) $stop;
|
||||
if (DEF.BC1.C != 10) $stop;
|
||||
if (DEF.BC2.B != 10) $stop;
|
||||
if (DEF.BC2.C != 10) $stop;
|
||||
DEF = '{int:10};
|
||||
if (DEF.A != 10) $stop;
|
||||
if (DEF.BC1.B != 10) $stop;
|
||||
if (DEF.BC1.C != 10) $stop;
|
||||
if (DEF.BC2.B != 10) $stop;
|
||||
if (DEF.BC2.C != 10) $stop;
|
||||
|
||||
// struct HIJ
|
||||
HIJ = '{int:10, default: 5};
|
||||
if (HIJ.A != 10) $stop;
|
||||
if (HIJ.BC1.B != 10) $stop;
|
||||
if (HIJ.BC1.C != 10) $stop;
|
||||
if (HIJ.BC1.DE1.D != 10) $stop;
|
||||
if (HIJ.BC1.DE1.E != 10) $stop;
|
||||
if (HIJ.BC1.DE1.FG1.F != 10) $stop;
|
||||
if (HIJ.BC1.DE1.FG1.G != 5) $stop;
|
||||
// struct HIJ
|
||||
HIJ = '{int:10, default: 5};
|
||||
if (HIJ.A != 10) $stop;
|
||||
if (HIJ.BC1.B != 10) $stop;
|
||||
if (HIJ.BC1.C != 10) $stop;
|
||||
if (HIJ.BC1.DE1.D != 10) $stop;
|
||||
if (HIJ.BC1.DE1.E != 10) $stop;
|
||||
if (HIJ.BC1.DE1.FG1.F != 10) $stop;
|
||||
if (HIJ.BC1.DE1.FG1.G != 5) $stop;
|
||||
|
||||
HIJ = '{shortint:10, default: 5};
|
||||
if (HIJ.A != 5) $stop;
|
||||
if (HIJ.BC1.B != 5) $stop;
|
||||
if (HIJ.BC1.C != 5) $stop;
|
||||
if (HIJ.BC1.DE1.D != 5) $stop;
|
||||
if (HIJ.BC1.DE1.E != 5) $stop;
|
||||
if (HIJ.BC1.DE1.FG1.F != 5) $stop;
|
||||
if (HIJ.BC1.DE1.FG1.G != 10) $stop;
|
||||
HIJ = '{shortint:10, default: 5};
|
||||
if (HIJ.A != 5) $stop;
|
||||
if (HIJ.BC1.B != 5) $stop;
|
||||
if (HIJ.BC1.C != 5) $stop;
|
||||
if (HIJ.BC1.DE1.D != 5) $stop;
|
||||
if (HIJ.BC1.DE1.E != 5) $stop;
|
||||
if (HIJ.BC1.DE1.FG1.F != 5) $stop;
|
||||
if (HIJ.BC1.DE1.FG1.G != 10) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -52,4 +52,12 @@
|
|||
38 | assert property (@(e) s_eventually 1'h1);
|
||||
| ^~~~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/NOTIMING?v=latest
|
||||
%Error-NOTIMING: t/t_notiming.v:39:31: s_until requires --timing
|
||||
: ... note: In instance 't'
|
||||
39 | assert property (@(e) 1'h1 s_until 1'h1);
|
||||
| ^~~~~~~
|
||||
%Error-NOTIMING: t/t_notiming.v:40:31: s_until_with requires --timing
|
||||
: ... note: In instance 't'
|
||||
40 | assert property (@(e) 1'h1 s_until_with 1'h1);
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -20,6 +20,6 @@ test.compile(verilator_flags2=['--unroll-count 4 --unroll-stmts 9999 --stats -DT
|
|||
test.file_grep(test.stats, r'Optimizations, Loop unrolling, Unrolled loops\s+(\d+)', 5)
|
||||
test.file_grep(test.stats, r'Optimizations, Loop unrolling, Unrolled iterations\s+(\d+)', 25)
|
||||
test.file_grep(test.stats,
|
||||
r'Optimizations, Loop unrolling, Failed - reached --unroll-count\s+(\d+)', 2)
|
||||
r'Optimizations, Loop unrolling, Failed - reached --unroll-count\s+(\d+)', 7)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -31,4 +31,33 @@ loop_6 3
|
|||
loop_6 4
|
||||
loop_6 5
|
||||
stopping loop_6
|
||||
loop_7 0
|
||||
loop_8 0
|
||||
loop_8 1
|
||||
loop_8 2
|
||||
loop_8 3
|
||||
loop_7 1
|
||||
loop_8 0
|
||||
loop_8 1
|
||||
loop_8 2
|
||||
loop_8 3
|
||||
loop_7 2
|
||||
loop_8 0
|
||||
loop_8 1
|
||||
loop_8 2
|
||||
loop_8 3
|
||||
loop_7 3
|
||||
loop_8 0
|
||||
loop_8 1
|
||||
loop_8 2
|
||||
loop_8 3
|
||||
loop_7 4
|
||||
loop_8 0
|
||||
loop_8 1
|
||||
loop_8 2
|
||||
loop_8 3
|
||||
loop_9 0
|
||||
loop_9 1
|
||||
loop_9 2
|
||||
loop_9 3
|
||||
*-* All Finished *-*
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ test.file_grep(test.stats,
|
|||
test.file_grep(test.stats,
|
||||
r'Optimizations, Loop unrolling, Failed - unknown loop condition\s+(\d+)', 0)
|
||||
test.file_grep(test.stats, r'Optimizations, Loop unrolling, Pragma unroll_disable\s+(\d+)', 0)
|
||||
test.file_grep(test.stats, r'Optimizations, Loop unrolling, Unrolled loops\s+(\d+)', 6)
|
||||
test.file_grep(test.stats, r'Optimizations, Loop unrolling, Unrolled iterations\s+(\d+)', 40)
|
||||
test.file_grep(test.stats, r'Optimizations, Loop unrolling, Unrolled loops\s+(\d+)', 13)
|
||||
test.file_grep(test.stats, r'Optimizations, Loop unrolling, Unrolled iterations\s+(\d+)', 77)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ module t;
|
|||
return ++static_loop_cond < 8;
|
||||
endfunction
|
||||
|
||||
int nonConst3 = $c("3");
|
||||
|
||||
initial begin
|
||||
// Basic loop
|
||||
for (int i = 0; i < 3; ++i) begin : loop_0
|
||||
|
|
@ -59,6 +61,22 @@ module t;
|
|||
end
|
||||
end
|
||||
end
|
||||
// Outer condition updated in inner loop
|
||||
begin
|
||||
automatic int i = 0;
|
||||
while (i < 5) begin : loop_7
|
||||
$display("loop_7 %0d", i);
|
||||
for (int j = 0 ; j < 4; ++j) begin : loop_8
|
||||
$display("loop_8 %0d", j);
|
||||
if (j == 3) ++i;
|
||||
end
|
||||
end
|
||||
end
|
||||
// Data dependent break
|
||||
for (int i = 0; i < 5; ++i) begin : loop_9
|
||||
$display("loop_9 %0d", i);
|
||||
if (i == nonConst3) break;
|
||||
end
|
||||
// Done
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module sub;
|
||||
int warn_sub = 64'h1;
|
||||
int warn_sub = 64'h1;
|
||||
endmodule
|
||||
|
|
|
|||
Loading…
Reference in New Issue