diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 497447e6286..fc462a80c4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ # Run functional regression checks name: ci -on: [push, pull_request] +on: [pull_request, workflow_dispatch] jobs: build-riscv-tests: diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml new file mode 100644 index 00000000000..7b5256da98d --- /dev/null +++ b/.github/workflows/integration.yml @@ -0,0 +1,25 @@ +# Copyright 2024 PULP Platform +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# Author: Nils Wistoff + +name: integration +on: [ pull_request, workflow_dispatch ] + +jobs: + cheshire-integration: + runs-on: ubuntu-latest + timeout-minutes: 200 + # Skip on forks due to missing secrets. + if: github.repository == 'pulp-platform/cva6' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) + steps: + - name: Integrate into cheshire + uses: pulp-platform/pulp-actions/integrate@v2.3.0 + with: + ip-name: cva6 + org: pulp-platform + repo: cheshire + base-ref: 4098faa23b8686e7a53936634dfd9fee6e88ede9 + token: ${{ secrets.CHESHIRE_TOKEN }} + lifetime: 14 diff --git a/.github/workflows/pulp-gitlab-ci.yml b/.github/workflows/pulp-gitlab-ci.yml new file mode 100644 index 00000000000..98b3fac7ec9 --- /dev/null +++ b/.github/workflows/pulp-gitlab-ci.yml @@ -0,0 +1,18 @@ +name: pulp-gitlab-ci + +on: [ push, pull_request, workflow_dispatch ] + +jobs: + pulp-gitlab-ci: + runs-on: ubuntu-latest + timeout-minutes: 60 + # Skip on forks or pull requests from forks due to missing secrets. + if: github.repository == 'pulp-platform/cva6' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) + steps: + - name: Check Gitlab CI + uses: pulp-platform/pulp-actions/gitlab-ci@v2.4.5 + with: + domain: iis-git.ee.ethz.ch + repo: github-mirror/cva6 + token: ${{ secrets.GITLAB_TOKEN }} + poll-period: 30 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index ec304f6472c..4c719991001 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -4,9 +4,9 @@ name: 'Close stale issues and PRs' on: - workflow_dispatch: - schedule: - - cron: '30 1 * * *' + workflow_dispatch +# schedule: +# - cron: '30 1 * * *' jobs: stale: diff --git a/.github/workflows/verible.yml b/.github/workflows/verible.yml index b9632a8284a..c8a99fda9b5 100644 --- a/.github/workflows/verible.yml +++ b/.github/workflows/verible.yml @@ -3,8 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 name: Verible -on: - pull_request_target: +on: [push, pull_request, workflow_dispatch] jobs: format: @@ -13,6 +12,8 @@ jobs: checks: write contents: read pull-requests: write + # Skip on forks due to missing secrets. + if: github.repository == 'pulp-platform/cva6' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) steps: - uses: actions/checkout@v3 with: @@ -22,3 +23,4 @@ jobs: github_token: ${{ secrets.GITHUB_TOKEN }} files: '$(find core -regex ".*\.\(v\|sv\)$" | grep -v "^core/include/.*_config_pkg\.sv$")' fail_on_formatting_suggestions: true + reviewdog_reporter: github-check diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c00ec74eca5..e8be072a459 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,692 +1,19 @@ -# Copyright 2022 Thales Silicon Security -# -# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -# You may obtain a copy of the License at https://solderpad.org/licenses/ -# -# Original Author: Yannick Casamatta (yannick.casamatta@thalesgroup.com) - -# Please refer to .gitlab-ci/README.md to add jobs - -# Project maintainers must define following variables to adapt this CI to their runtime environment (Settings > CI/CD > Variables) -# - SETUP_CI_CVV_BRANCH: master (the main branch of CVA6 repository) - -# A git repository named "setup-ci" must be created in the same namespace as cva6 and must contain the following file: -# - 'cva6/core-v-verif-cva6.yml' -# -# This file must at least contain the variables necessary for the execution of -# this pipeline. -# Other elements such as new jobs can be added to overload the associated -# downstream pipeline included in this repository. -# Example can be found in ".gitlab-ci/setup-ci-example/" - -include: - - project: '$CI_PROJECT_NAMESPACE/setup-ci' - ref: '$SETUP_CI_CVV_BRANCH' - file: 'cva6/core-v-verif-cva6.yml' - - local: '.gitlab-ci-custom.yml' - rules: - - exists: - - '.gitlab-ci-custom.yml' - -workflow: - rules: - - if: $CI_PIPELINE_SOURCE == "schedule" - variables: - CI_KIND: verif - - if: $CI_COMMIT_BRANCH == "master" - variables: - CI_KIND: regress - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - variables: - CI_KIND: regress - - if: $CI_COMMIT_BRANCH =~ /.*_PR_.*/ - variables: - CI_KIND: dev - - if: $CI_COMMIT_BRANCH =~ /^dev.*/ - variables: - CI_KIND: dev - - variables: - CI_KIND: none - -variables: - GIT_SUBMODULE_STRATEGY: recursive - DASHBOARD: cva6 - DV_TARGET: cv32a65x - -default: - tags: [$TAGS_RUNNER_SIMU] - artifacts: - when: always - paths: - - artifacts/ - stages: - - setup - - light tests - - heavy tests - - backend tests - - find failures - - report - -.setup_job: - stage: setup - tags: [$TAGS_RUNNER] - variables: - GIT_SUBMODULE_STRATEGY: none - rules: &on_dev - - if: $CI_KIND == "regress" - - if: $CI_KIND == "verif" - - if: $CI_KIND == "dev" - - when: manual - allow_failure: true - -check_env: - extends: - - .setup_job - variables: - GIT_STRATEGY: none - script: - - env - artifacts: - paths: [] - -build_tools: - extends: - - .setup_job - script: - # core-v-verif imports yaml-cpp as a submodule ==> recurse - - git submodule update --init --recursive verif/core-v-verif - - source $SYN_VCS_BASHRC - # ROOT_PROJECT is used by Spike installer and designates the toplevel of core-v-verif tree. - - 'export ROOT_PROJECT=$(pwd)' - # If a local build of Spike is requested, clean up build and installation directories. - - '[ -n "$SPIKE_INSTALL_DIR" -a "$SPIKE_INSTALL_DIR" = "__local__" ] && rm -rf vendor/riscv/riscv-isa-sim/build' - - '[ -n "$SPIKE_INSTALL_DIR" -a "$SPIKE_INSTALL_DIR" = "__local__" ] && rm -rf tools/spike' - # Create default directory corresponding to the artifact path. - - mkdir -p tools/spike - # Set up Spike, whether locally built or pre-installed. - # If initially set to "__local__", SPIKE_INSTALL_DIR will be resolved - # to an absolute path by the installation script. - - source verif/regress/install-spike.sh - # Strip locally built binaries and libraries to reduce artifact size. - - '[ -f $(pwd)/tools/spike/bin/spike ] && strip $(pwd)/tools/spike/bin/spike* $(pwd)/tools/spike/lib/lib*.*' - - mkdir -p artifacts/tools/ - - mv tools/spike artifacts/tools/ - -.copy_spike_artifacts: ©_spike_artifacts - - mkdir -p tools - - mv artifacts/tools/spike tools - - /sbin/ldconfig -N tools/spike/lib - -.fe_smoke_test: - stage: light tests - rules: *on_dev - before_script: - - git -C verif/core-v-verif fetch --unshallow || git -C verif/core-v-verif fetch --all - - !reference [.copy_spike_artifacts] - - rm -rf artifacts/ - - mkdir -p artifacts/{reports,logs} - - python3 .gitlab-ci/scripts/report_fail.py - - echo $SYN_VCS_BASHRC; source $SYN_VCS_BASHRC - -.simu_after_script: &simu_after_script - - for i in $(find verif/sim/out*/[vq]*_sim -type f \( -name "*.csv" -o -name "*.iss" -o -name "*.yaml" \)) ; do tail -10000 $i > artifacts/logs/$(basename $i) ; done - - tail -10000 verif/sim/logfile.log > artifacts/logs/logfile.log - - if [ -n "$SPIKE_TANDEM" ]; then python3 .gitlab-ci/scripts/report_tandem.py verif/sim/out*/"$DV_SIMULATORS"_sim; else python3 .gitlab-ci/scripts/report_simu.py verif/sim/logfile.log; fi - -smoke-tests: - extends: - - .fe_smoke_test - variables: - DASHBOARD_JOB_TITLE: "Smoke test $DV_SIMULATORS $DV_TARGET" - DASHBOARD_JOB_DESCRIPTION: "Short tests to challenge most architectures with most testbenches configurations" - DASHBOARD_SORT_INDEX: 0 - DASHBOARD_JOB_CATEGORY: "Basic" - SPIKE_TANDEM: 1 - COLLECT_SIMU_LOGS: 1 - parallel: - matrix: - - DV_SIMULATORS: ["vcs-testharness", "questa-testharness"] - DV_TARGET: ["cv32a6_imac_sv32", "cv64a6_imafdc_sv39"] - - DV_SIMULATORS: "vcs-uvm" - DV_TARGET: "cv32a65x" - script: - - if [[ $DV_SIMULATORS == *"questa"* ]]; then source $QUESTA_BASHRC; fi - - bash verif/regress/smoke-tests-$DV_TARGET.sh - - !reference [.simu_after_script] - -smoke-gen: - extends: - - .fe_smoke_test - variables: - DASHBOARD_JOB_TITLE: "Smoke Generated test $DV_SIMULATORS" - DASHBOARD_JOB_DESCRIPTION: "Short generated tests to challenge the CVA6-DV on STEP1 configuration" - DASHBOARD_SORT_INDEX: 0 - DASHBOARD_JOB_CATEGORY: "Basic" - DV_SIMULATORS: "vcs-uvm" - COLLECT_SIMU_LOGS: 1 - SPIKE_TANDEM: 1 - script: - - bash verif/regress/smoke-gen_tests.sh - - cp verif/sim/seedlist.yaml artifacts/logs/ - - cp verif/sim/uvm_seed.log artifacts/logs/ - - !reference [.simu_after_script] - -smoke-bench: - extends: - - .fe_smoke_test - variables: - DASHBOARD_JOB_TITLE: "smoke-bench $DV_TARGET" - DASHBOARD_JOB_DESCRIPTION: "Performance indicator" - DASHBOARD_SORT_INDEX: 5 - DASHBOARD_JOB_CATEGORY: "Performance" - SPIKE_TANDEM: 1 - BENCH: "dhrystone" - parallel: - matrix: - - DV_TARGET: "cv32a60x" - - DV_TARGET: "cv32a65x" - script: - - bash verif/regress/"$BENCH"_smoke.sh --no-print - - python3 .gitlab-ci/scripts/report_benchmark.py --"$BENCH"_"$DV_TARGET" verif/sim/out_*/vcs-uvm_sim/"$BENCH"_main.*.log - -smoke-hwconfig: - extends: - - .fe_smoke_test - variables: - DASHBOARD_JOB_TITLE: "HW config $DV_SIMULATORS $DV_HWCONFIG_OPTS" - DASHBOARD_JOB_DESCRIPTION: "Short tests to challenge target configurations" - DASHBOARD_SORT_INDEX: 1 - DASHBOARD_JOB_CATEGORY: "Basic" - DV_SIMULATORS: "vcs-uvm" - SPIKE_TANDEM: 1 - DV_TARGET: "hwconfig" - DV_HWCONFIG_OPTS: "cv32a65x" - script: - - source verif/regress/hwconfig_tests.sh - - python3 .gitlab-ci/scripts/report_pass.py - -hello-pk: - extends: - - .fe_smoke_test - variables: - DASHBOARD_JOB_TITLE: "Hello world with veri-testharness-pk on multiple RTL targets." - DASHBOARD_JOB_DESCRIPTION: "Short tests to challenge target configurations" - DASHBOARD_SORT_INDEX: 1 - DASHBOARD_JOB_CATEGORY: "Basic" - COLLECT_SIMU_LOGS: 1 - script: - - bash verif/regress/veri-testharness-pk-tests.sh - - python3 .gitlab-ci/scripts/report_pass.py - -.synthesis_test: - stage: heavy tests - timeout: 2 hours - before_script: - - !reference [.fe_smoke_test, before_script] - rules: &on_dev_rtl - - if: $CI_KIND == "regress" - - if: $CI_KIND == "verif" - - if: $CI_KIND == "dev" - changes: - paths: - - core/**/* - - corev_apu/**/* - compare_to: master - - when: manual - allow_failure: true - -it-test: - extends: - - .synthesis_test - variables: - DASHBOARD_JOB_TITLE: "Instruction Trace test" - DASHBOARD_JOB_DESCRIPTION: "Test to Challenge the Hardware flow of the Instruction Tracer" - DASHBOARD_SORT_INDEX: 0 - DASHBOARD_JOB_CATEGORY: "Basic" - DV_SIMULATORS: "vcs-testharness" - script: - - python3 .gitlab-ci/scripts/report_fail.py - - bash verif/regress/Instr_tracing_test.sh ../tests/custom/ITI/test_iti_asm.o - - python3 .gitlab-ci/scripts/report_pass.py - - cp -r verif/sim/Instr_tracing_artifact artifacts/ - -spyglass: - extends: - - .synthesis_test - variables: - DV_TARGET: cv32a65x - DASHBOARD_JOB_TITLE: "Report Spyglass Lint Errors" - DASHBOARD_JOB_DESCRIPTION: "Report lint errors and warnings detected by Spyglass" - DASHBOARD_SORT_INDEX: 5 - DASHBOARD_JOB_CATEGORY: "Lint Check" - script: - - echo $SYN_SG_BASHRC; source $SYN_SG_BASHRC - - mkdir -p artifacts/lint_reports - - make -C spyglass design_read - - make -C spyglass lint_check - - mv spyglass/sg_run_results/cva6_sg_reports/cva6_lint_lint_rtl artifacts/lint_reports - - cp spyglass/reference_summary.rpt artifacts/lint_reports - - python3 .gitlab-ci/scripts/report_spyglass_lint.py spyglass/reference_summary.rpt artifacts/lint_reports/cva6_lint_lint_rtl/summary.rpt - -.cvxif-regression: - extends: - - .synthesis_test - variables: - DASHBOARD_JOB_TITLE: "CVXIF non-regression test $DV_SIMULATORS" - DASHBOARD_JOB_DESCRIPTION: "Short tests to challenge most CoreV-X-Interface in testharness" - DASHBOARD_SORT_INDEX: 5 - DASHBOARD_JOB_CATEGORY: "Basic" - COLLECT_SIMU_LOGS: 1 - script: - - bash verif/regress/cvxif_verif_regression.sh - - if [[ $DV_SIMULATORS == *"spike"* ]]; then unset SPIKE_TANDEM; fi # dirty hack to do trace comparison between tandem execution and spike standalone - - !reference [.simu_after_script] - -asic-synthesis: - extends: - - .synthesis_test - tags: [$TAGS_RUNNER_SYNTH] - variables: - DASHBOARD_JOB_TITLE: "ASIC Synthesis $DV_TARGET" - DASHBOARD_JOB_DESCRIPTION: "Synthesis indicator with specific Techno" - DASHBOARD_SORT_INDEX: 5 - DASHBOARD_JOB_CATEGORY: "Synthesis" - PERIOD: "15" - DV_TARGET: cv32a65x - script: - - echo $PERIOD - - echo $DV_TARGET - - source ./verif/sim/setup-env.sh - - git clone ${SYNTH_SCRIPT} ${SYNTH_SCRIPT_PATH} -b ${SYNTH_SCRIPT_BRANCH} - - git -C ${SYNTH_SCRIPT_PATH} checkout cce5ea41 - - cp -r ${SYNTH_SCRIPT_PATH}/cva6/ ../ - - git apply ${SYNTH_SCRIPT_PATH}/patches/*.patch - - echo $SYN_DCSHELL_BASHRC; source $SYN_DCSHELL_BASHRC - - cp -r ${SYNTH_FLOW} ./ - - python3 ${SYNTH_SCRIPT_PATH}/scharm -p configs/modules/CVA6.yml --runner=True --compaign="only-synth" - - export NAND2_AREA=$(cat pd/synth/cva6_${DV_TARGET}/nand2area.txt) - - python3 .gitlab-ci/scripts/report_synth.py pd/synth/cva6_${DV_TARGET}/$PERIOD/reports/cva6_${DV_TARGET}_synth_area.rpt pd/synth/cva6_${DV_TARGET}/$PERIOD/reports/cva6_${DV_TARGET}_synthesis.log - - mv ${SYNTH_SCRIPT_PATH}/artifacts/ artifacts/artifacts_synth/ - - mv pd/synth/cva6_${DV_TARGET}/ artifacts/ - - mv pd/synth/cva6_${DV_TARGET}_synth.v artifacts/ - - mv pd/synth/cva6_${DV_TARGET}_synth.sdf artifacts/ - -fpga-build: - extends: - - .synthesis_test - variables: - DASHBOARD_JOB_TITLE: "FPGA Build $TARGET" - DASHBOARD_JOB_DESCRIPTION: "Test of FPGA build flow" - DASHBOARD_SORT_INDEX: 9 - DASHBOARD_JOB_CATEGORY: "Synthesis" - TARGET: cv32a6_imac_sv32 - script: - - source $VIVADO_SETUP - - source ./verif/sim/setup-env.sh - - mkdir -p artifacts/logs - - make fpga target=$TARGET &> artifacts/logs/logfile.log - - mkdir -p artifacts/reports - - mv corev_apu/fpga/work-fpga/ariane_xilinx.bit artifacts/ariane_xilinx_$TARGET.bit - - python3 .gitlab-ci/scripts/report_fpga.py corev_apu/fpga/reports/ariane.utilization.rpt - -pmp_tests: - timeout : 2 hours - extends: - - .synthesis_test - variables: - DASHBOARD_JOB_TITLE: "PMP $DV_TARGET" - DASHBOARD_JOB_DESCRIPTION: "Physical Memory Protection tests" - DASHBOARD_SORT_INDEX: 2 - DASHBOARD_JOB_CATEGORY: "Test suites" - DV_SIMULATORS: "vcs-uvm" - SPIKE_TANDEM: 1 - script: source verif/regress/pmp_cv32a65x_tests.sh - after_script: *simu_after_script - -.regress_test: - stage: heavy tests - before_script: - - !reference [.fe_smoke_test, before_script] - rules: &on_regress - - if: $CI_KIND == "regress" - - if: $CI_KIND == "verif" - - when: manual - allow_failure: true - -benchmarks: - extends: - - .regress_test - variables: - DASHBOARD_JOB_TITLE: "benchmark $BENCH $ISSUE" - DASHBOARD_JOB_DESCRIPTION: "Performance indicator" - DASHBOARD_SORT_INDEX: 5 - DASHBOARD_JOB_CATEGORY: "Performance" - SPIKE_TANDEM: 1 - parallel: - matrix: - - BENCH: "dhrystone" - ISSUE: "single" - DV_HWCONFIG_OPTS: ["cv32a60x IcacheByteSize=16384 IcacheSetAssoc=8 DcacheByteSize=32768 DcacheSetAssoc=8 BHTEntries=128 NrScoreboardEntries=8 DCacheType=config_pkg::WT"] - - BENCH: "dhrystone" - ISSUE: "dual" - DV_HWCONFIG_OPTS: ["cv32a65x IcacheByteSize=16384 IcacheSetAssoc=8 DcacheByteSize=32768 DcacheSetAssoc=8 BHTEntries=128 NrScoreboardEntries=8 DCacheType=config_pkg::WT"] - - BENCH: "coremark" - ISSUE: "single" - DV_HWCONFIG_OPTS: ["cv32a60x IcacheByteSize=16384 IcacheSetAssoc=8 DcacheByteSize=32768 DcacheSetAssoc=8 BHTEntries=128 NrScoreboardEntries=8 DCacheType=config_pkg::WT"] - - BENCH: "coremark" - ISSUE: "dual" - DV_HWCONFIG_OPTS: ["cv32a65x IcacheByteSize=16384 IcacheSetAssoc=8 DcacheByteSize=32768 DcacheSetAssoc=8 BHTEntries=128 NrScoreboardEntries=8 DCacheType=config_pkg::WT"] - script: - - bash verif/regress/"$BENCH".sh - - python3 .gitlab-ci/scripts/report_benchmark.py --"$BENCH"_"$ISSUE" verif/sim/out_*/vcs-uvm_sim/"$BENCH"_main.*.log - -riscv_arch_test: - extends: - - .regress_test - variables: - DASHBOARD_JOB_TITLE: "arch_test $DV_TARGET" - DASHBOARD_JOB_DESCRIPTION: "Compliance regression suite" - DASHBOARD_SORT_INDEX: 0 - DASHBOARD_JOB_CATEGORY: "Test suites" - DV_SIMULATORS: "vcs-testharness" - SPIKE_TANDEM: 1 - script: source verif/regress/dv-riscv-arch-test.sh - after_script: *simu_after_script - -compliance: - timeout : 2 hours - extends: - - .regress_test - variables: - DASHBOARD_JOB_TITLE: "Compliance $DV_TARGET" - DASHBOARD_JOB_DESCRIPTION: "Compliance regression suite" - DASHBOARD_SORT_INDEX: 2 - DASHBOARD_JOB_CATEGORY: "Test suites" - DV_SIMULATORS: "vcs-testharness" - SPIKE_TANDEM: 1 - script: source verif/regress/dv-riscv-compliance.sh - after_script: *simu_after_script - -riscv-tests-v: - timeout : 2 hours - extends: - - .regress_test - variables: - DASHBOARD_JOB_TITLE: "Riscv-test $DV_TARGET (virtual)" - DASHBOARD_JOB_DESCRIPTION: "Riscv-test regression suite (virtual)" - DASHBOARD_SORT_INDEX: 3 - DASHBOARD_JOB_CATEGORY: "Test suites" - DV_SIMULATORS: "veri-testharness,spike" - DV_TARGET: cv64a6_imafdc_sv39 - DV_TESTLISTS: "../tests/testlist_riscv-tests-$DV_TARGET-v.yaml" - script: source verif/regress/dv-riscv-tests.sh - after_script: *simu_after_script - -riscv-tests-p: - extends: - - .regress_test - variables: - DASHBOARD_JOB_TITLE: "Riscv-test $DV_TARGET (physical)" - DASHBOARD_JOB_DESCRIPTION: "Riscv-test regression suite (physical)" - DASHBOARD_SORT_INDEX: 4 - DASHBOARD_JOB_CATEGORY: "Test suites" - DV_SIMULATORS: "vcs-testharness" - SPIKE_TANDEM: 1 - DV_TESTLISTS: "../tests/testlist_riscv-tests-$DV_TARGET-p.yaml" - script: source verif/regress/dv-riscv-tests.sh - after_script: *simu_after_script - -.verif_test: - extends: - - .regress_test - rules: &on_verif - - if: $CI_KIND == "verif" - allow_failure: true - - when: manual - allow_failure: true - timeout: 6h - -mmu_sv32_tests: - extends: - - .verif_test - variables: - DASHBOARD_JOB_TITLE: "mmu_sv32_tests $DV_TARGET" - DASHBOARD_JOB_DESCRIPTION: "MMU SV32 regression suite" - DASHBOARD_SORT_INDEX: 0 - DASHBOARD_JOB_CATEGORY: "Test suites" - DV_SIMULATORS: "veri-testharness,spike" - DV_TARGET: cv32a6_imac_sv32 - script: source verif/regress/dv-riscv-mmu-sv32-test.sh - after_script: *simu_after_script - -generated_tests: - extends: - - .verif_test - variables: - DASHBOARD_SORT_INDEX: 11 - DASHBOARD_JOB_CATEGORY: "Code Coverage" - SPIKE_TANDEM: 1 - DV_SIMULATORS: "vcs-uvm" - parallel: - matrix: - - list_num: 1 - DASHBOARD_JOB_TITLE: "Generated Random Arithmetic tests" - DASHBOARD_JOB_DESCRIPTION: "Generate Random Arithmetic tests using CVA6-DV" - - list_num: 2 - DASHBOARD_JOB_TITLE: "Generated Hazard Arithmetic tests" - DASHBOARD_JOB_DESCRIPTION: "Generate Hazard register (RAW) Arithmetic tests using CVA6-DV" - - list_num: 3 - DASHBOARD_JOB_TITLE: "Generated Illegal instruction tests" - DASHBOARD_JOB_DESCRIPTION: "Generate Random Illegal instruction tests using CVA6-DV" - - list_num: 4 - DASHBOARD_JOB_TITLE: "Generated MMU tests" - DASHBOARD_JOB_DESCRIPTION: "Generate Random MMU tests using CVA6-DV" - - list_num: 5 - DASHBOARD_JOB_TITLE: "Generated Random Load_store tests" - DASHBOARD_JOB_DESCRIPTION: "Generate Random Load_store tests using CVA6-DV" - - list_num: 6 - DASHBOARD_JOB_TITLE: "Generated Jump tests" - DASHBOARD_JOB_DESCRIPTION: "Generate Random Arithmetic Jump tests using CVA6-DV" - script: - - mkdir -p artifacts/coverage - - source verif/regress/dv-generated-tests.sh - - mv verif/sim/vcs_results/default/vcs.d/simv.vdb artifacts/coverage - - mv verif/sim/seedlist.yaml artifacts/coverage - - mv verif/sim/uvm_seed.log artifacts/coverage - - python3 .gitlab-ci/scripts/report_pass.py - -.generated_xif_tests: - extends: - - .verif_test - variables: - DASHBOARD_SORT_INDEX: 12 - DASHBOARD_JOB_CATEGORY: "Code Coverage" - SPIKE_TANDEM: 1 - DV_SIMULATORS: "vcs-uvm" - parallel: - matrix: - - list_num: 1 - DASHBOARD_JOB_TITLE: "Generated Random xif tests" - DASHBOARD_JOB_DESCRIPTION: "Generate Random tests for cvxif using CVA6-DV" - script: - - mkdir -p artifacts/coverage - - source verif/regress/dv-generated-xif-tests.sh - - mv verif/sim/vcs_results/default/vcs.d/simv.vdb artifacts/coverage - - mv verif/sim/seedlist.yaml artifacts/coverage - - mv verif/sim/uvm_seed.log artifacts/coverage - - python3 .gitlab-ci/scripts/report_pass.py - -directed_isacov-tests: - extends: - - .verif_test - variables: - DASHBOARD_SORT_INDEX: 13 - DASHBOARD_JOB_CATEGORY: "Functional Coverage" - SPIKE_TANDEM: 1 - DV_SIMULATORS: "vcs-uvm" - parallel: - matrix: - - list_num: 0 - DASHBOARD_JOB_TITLE: "Directed tests" - DASHBOARD_JOB_DESCRIPTION: "Execute directed tests to improve functional coverage of ISA" - script: - - mkdir -p artifacts/coverage - - source verif/regress/dv-generated-tests.sh - - mv verif/sim/vcs_results/default/vcs.d/simv.vdb artifacts/coverage - - mv verif/sim/uvm_seed.log artifacts/coverage - - python3 .gitlab-ci/scripts/report_pass.py - -csr_embedded_tests: - extends: - - .verif_test - variables: - DASHBOARD_JOB_TITLE: "csr_embedded test $DV_TARGET" - DASHBOARD_JOB_DESCRIPTION: "CSR Test generated using UVM-REG" - DASHBOARD_SORT_INDEX: 15 - DASHBOARD_JOB_CATEGORY: "CSR tests" - DV_SIMULATORS: "vcs-uvm" - SPIKE_TANDEM: 1 - script: - - mkdir -p artifacts/coverage - - source verif/regress/dv-csr-embedded-tests.sh - - mv verif/sim/vcs_results/default/vcs.d/simv.vdb artifacts/coverage - - mv verif/sim/uvm_seed.log artifacts/coverage - - python3 .gitlab-ci/scripts/report_tandem.py verif/sim/out*/"$DV_SIMULATORS"_sim - -.backend_test: - stage: backend tests - before_script: - - mkdir -p artifacts/{reports,logs} - - python3 .gitlab-ci/scripts/report_fail.py - -simu-gate: - timeout : 4 hours - extends: - - .backend_test - needs: - - build_tools - - asic-synthesis - parallel: - matrix: - - PROG_NAME: ["dhrystone_smoke"] - variables: - DASHBOARD_JOB_TITLE: "Gate Level Simulation $DV_TARGET" - DASHBOARD_JOB_DESCRIPTION: "Tests to check netlist from ASIC synthesis and power consumption over different patterns" - DASHBOARD_SORT_INDEX: 6 - DASHBOARD_JOB_CATEGORY: "Post Synthesis" - DV_TARGET: cv32a65x - TARGET: $DV_TARGET - TOP: "cva6" - SPIKE_TANDEM: 1 - SIMU_PERIOD: "20" # 50 Mhz - PERIOD: "15" # 66 Mhz - script: - - mkdir -p artifacts/{reports,logs} - - git -C verif/core-v-verif fetch --unshallow || git -C verif/core-v-verif fetch --all - - !reference [.copy_spike_artifacts] - - echo $PERIOD - - source ./verif/sim/setup-env.sh - - git clone ${SYNTH_SCRIPT} ${SYNTH_SCRIPT_PATH} -b ${SYNTH_SCRIPT_BRANCH} - - git -C ${SYNTH_SCRIPT_PATH} checkout cce5ea41 - - cp -r ${SYNTH_SCRIPT_PATH}/cva6/ ../ - - git apply ${SYNTH_SCRIPT_PATH}/patches/*.patch - - source verif/regress/install-riscv-tests.sh - - mv artifacts/${TOP}_${DV_TARGET} pd/synth/ - - mv artifacts/${TOP}_${DV_TARGET}_synth.v pd/synth/ - - mv artifacts/${TOP}_${DV_TARGET}_synth.sdf pd/synth/ - - mkdir -p pd/synth/${TOP}_${DV_TARGET}/outputs/ - - export DV_SIMULATORS="spike" - - bash verif/regress/${PROG_NAME}.sh - - cp verif/sim/out_*/directed_tests/*.o verif/sim/testelf.o - - python3 ${SYNTH_SCRIPT_PATH}/scharm -p configs/modules/CVA6.yml --runner=True --compaign="simu-gate" --name=testelf - - grep "Simulation terminated" verif/sim/out_*/*/*.log.iss - - mv ${SYNTH_SCRIPT_PATH}/artifacts/ artifacts/artifacts_gate/ - - rm artifacts/artifacts_gate/*/build/*.fsdb - - mkdir -p verif/sim/out_reports - - mkdir -p artifacts/sim_artifacts - - for i in verif/sim/out*/vcs-uvm-gate*/*; do cp $i $(dirname $(dirname $i))/vcs-uvm_sim/gate.$(basename $i); done - - python3 .gitlab-ci/scripts/report_tandem.py verif/sim/out*/vcs-uvm_sim - -fpga-boot: - extends: - - .backend_test - tags: [$TAGS_RUNNER_FPGA] - needs: - - build_tools - - fpga-build - variables: - DASHBOARD_JOB_TITLE: "FPGA Linux32 Boot " - DASHBOARD_JOB_DESCRIPTION: "Test of Linux 32 bits boot on FPGA Genesys2" - DASHBOARD_SORT_INDEX: 10 - DASHBOARD_JOB_CATEGORY: "Synthesis" - script: - - source ./verif/sim/setup-env.sh - - source $VIVADO2022_SETUP - - mkdir -p corev_apu/fpga/work-fpga - - mv artifacts/ariane_xilinx_cv32a6_imac_sv32.bit corev_apu/fpga/work-fpga/ariane_xilinx.bit - - cd corev_apu/fpga/scripts - - source check_fpga_boot.sh - - cd - - - python3 .gitlab-ci/scripts/report_fpga_boot.py corev_apu/fpga/scripts/fpga_boot.rpt - retry: 1 - -code_coverage-report: - extends: - - .backend_test - needs: - - generated_tests - - directed_isacov-tests -# - generated_xif_tests - - csr_embedded_tests - variables: - DASHBOARD_JOB_TITLE: "Report merge coverage" - DASHBOARD_JOB_DESCRIPTION: "Report merge coverage of generated tests" - DASHBOARD_SORT_INDEX: 14 - DASHBOARD_JOB_CATEGORY: "Code Coverage" - script: - - echo $SYN_VCS_BASHRC; source $SYN_VCS_BASHRC - - mkdir -p artifacts/cov_reports/ - - mkdir -p verif/sim/vcs_results/default/vcs.d - - mv artifacts/coverage/simv.vdb verif/sim/vcs_results/default/vcs.d/ - - mv artifacts/coverage/seedlist.yaml verif/sim/seedlist.yaml - - mv artifacts/coverage/uvm_seed.log verif/sim/uvm_seed.log - - make -C verif/sim generate_cov_dash - - mv verif/sim/urgReport artifacts/cov_reports/ - - python3 .gitlab-ci/scripts/report_coverage.py artifacts/cov_reports/urgReport/hierarchy.txt artifacts/cov_reports/urgReport/"feature.CVA6 Verification Master Plan1.7.-1268999905.txt" - -check gitlab jobs status: - stage: find failures - tags: [$TAGS_RUNNER] - rules: - - if: $DASHBOARD_URL && $CI_KIND != "none" - when: on_failure - variables: - DASHBOARD_JOB_TITLE: "Environment check" - DASHBOARD_JOB_DESCRIPTION: "Detect environment issues" - DASHBOARD_SORT_INDEX: 0 - DASHBOARD_JOB_CATEGORY: "Environment" - GIT_SUBMODULE_STRATEGY: none - script: - - rm -rf artifacts/ - - mkdir -p artifacts/reports - - python3 .gitlab-ci/scripts/report_envfail.py + - nonfree -merge reports: - stage: report - tags: [$TAGS_RUNNER] - variables: - GIT_SUBMODULE_STRATEGY: none - rules: - - if: $DASHBOARD_URL && $CI_KIND != "none" - when: always +init: + stage: nonfree script: - - mkdir -p artifacts/reports - - ls -al artifacts/reports - - python3 .gitlab-ci/scripts/merge_job_reports.py artifacts/reports pipeline_report_$CI_PIPELINE_ID.yml + - git clone git@iis-git.ee.ethz.ch:pulp-restricted/cva6-nonfree.git nonfree + - cd nonfree && git checkout e0cc6f1406ddb0d2e212fccd932aafe40510a44f artifacts: - when: always - paths: - - "artifacts/reports/pipeline_report_$CI_PIPELINE_ID.yml" + paths: [ nonfree/ci.yml ] + +subpipe: + stage: nonfree + needs: [ init ] + trigger: + include: + - artifact: nonfree/ci.yml + job: init + strategy: depend diff --git a/Bender.lock b/Bender.lock new file mode 100644 index 00000000000..3b4260e814d --- /dev/null +++ b/Bender.lock @@ -0,0 +1,80 @@ +packages: + apb: + revision: 77ddf073f194d44b9119949d2421be59789e69ae + version: 0.2.4 + source: + Git: https://github.com/pulp-platform/apb.git + dependencies: + - common_cells + axi: + revision: a256a3b86394fedf19e361047fccfdd7f6ef83e4 + version: 0.39.9 + source: + Git: https://github.com/pulp-platform/axi.git + dependencies: + - common_cells + - common_verification + - tech_cells_generic + axi_riscv_atomics: + revision: 97a1dd2ac643c276880420a0cf8eea697f228aa9 + version: 0.8.3 + source: + Git: https://github.com/pulp-platform/axi_riscv_atomics.git + dependencies: + - axi + - common_cells + - common_verification + clic: + revision: 6515a71eb4ae3b143ab912d265e79832b3179a76 + version: 3.0.0 + source: + Git: https://github.com/pulp-platform/clic.git + dependencies: + - common_cells + - register_interface + common_cells: + revision: 9ca8a7655f741e7dd5736669a20a301325194c28 + version: 1.39.0 + source: + Git: https://github.com/pulp-platform/common_cells + dependencies: + - common_verification + - tech_cells_generic + common_verification: + revision: fb1885f48ea46164a10568aeff51884389f67ae3 + version: 0.2.5 + source: + Git: https://github.com/pulp-platform/common_verification + dependencies: [] + fpnew: + revision: 58ca3c376beb914b2b80b811d4b270c063d4e6f7 + version: null + source: + Git: https://github.com/openhwgroup/cvfpu.git + dependencies: + - common_cells + - fpu_div_sqrt_mvp + fpu_div_sqrt_mvp: + revision: 86e1f558b3c95e91577c41b2fc452c86b04e85ac + version: 1.0.4 + source: + Git: https://github.com/pulp-platform/fpu_div_sqrt_mvp.git + dependencies: + - common_cells + register_interface: + revision: d6e1d4cdaab7870f4faf3f88a1c788eaf5ac129d + version: 0.4.7 + source: + Git: https://github.com/pulp-platform/register_interface.git + dependencies: + - apb + - axi + - common_cells + - common_verification + tech_cells_generic: + revision: 7968dd6e6180df2c644636bc6d2908a49f2190cf + version: 0.2.13 + source: + Git: https://github.com/pulp-platform/tech_cells_generic.git + dependencies: + - common_verification diff --git a/Bender.yml b/Bender.yml index 60fd92c50ee..f0b2d70db4d 100644 --- a/Bender.yml +++ b/Bender.yml @@ -7,12 +7,16 @@ package: # WT_DCACHE dependencies: - axi: { git: "https://github.com/pulp-platform/axi.git", version: 0.31.0 } + axi: { git: "https://github.com/pulp-platform/axi.git", version: 0.39.9 } common_cells: - { git: "https://github.com/pulp-platform/common_cells", version: 1.23.0 } + { git: "https://github.com/pulp-platform/common_cells", version: 1.39.0 } fpnew: { git: "https://github.com/openhwgroup/cvfpu.git", rev: 58ca3c3 } # branch: develop tech_cells_generic: { git: "https://github.com/pulp-platform/tech_cells_generic.git", version: 0.2.13 } + axi_riscv_atomics: { git: "https://github.com/pulp-platform/axi_riscv_atomics.git", version: 0.8.3 } + clic: { git: "https://github.com/pulp-platform/clic.git", version: 3.0.0 } + common_verification: { git: "https://github.com/pulp-platform/common_verification", version: 0.2.5 } + register_interface: { git: https://github.com/pulp-platform/register_interface.git, version: 0.4.7 } export_include_dirs: - core/include @@ -21,6 +25,7 @@ export_include_dirs: sources: - include_dirs: - core/include + - common/local/util files: - core/include/config_pkg.sv # Pick the right configuration by passing the right bender flag. @@ -52,6 +57,30 @@ sources: files: - core/include/cv64a6_imafdch_sv39_wb_config_pkg.sv + - target: cv64a6_imafdchsclic_sv39 + files: + - core/include/cv64a6_imafdchsclic_sv39_config_pkg.sv + + - target: cv64a6_imafdchsclic_sv39_wb + files: + - core/include/cv64a6_imafdchsclic_sv39_wb_config_pkg.sv + + - target: cv64a6_imafdchsclic_sv39_hpdcache_wb + files: + - core/include/cv64a6_imafdchsclic_sv39_hpdcache_wb_config_pkg.sv + + - target: cv64a6_imafdchxhclic_sv39_wb + files: + - core/include/cv64a6_imafdchxhclic_sv39_wb_config_pkg.sv + + - target: cv64a6_splus + files: + - core/include/cv64a6_splus_config_pkg.sv + + - target: cv64a6_imafdchsclic_sv39_hpdcache_wb + files: + - core/include/cv64a6_imafdchsclic_sv39_hpdcache_wb_config_pkg.sv + - target: cv32a6_imac_sv0 files: - core/include/cv32a6_imac_sv0_config_pkg.sv @@ -85,8 +114,13 @@ sources: files: - core/cva6_accel_first_pass_decoder_stub.sv + # CLIC controller + - target: any(cv64a6_imafdchsclic_sv39, cv64a6_imafdchsclic_sv39_hpdcache_wb, cv64a6_imafdchsclic_sv39_wb, cv64a6_imafdchxhclic_sv39_wb) + files: + - core/cva6_clic_controller.sv + # MMU - - target: any(cv64a6_imafdcv_sv39, cv64a6_imafdc_sv39, cv64a6_imafdc_sv39_wb, cv64a6_imafdch_sv39, cv64a6_imafdc_sv39_hpdcache, cv64a6_imafdc_sv39_hpdcache_wb, cv64a6_imafdch_sv39_wb, cv32a6_imac_sv0, cv32a6_imac_sv32, cv32a6_imafc_sv32) + - target: any(cv64a6_imafdcv_sv39, cv64a6_imafdc_sv39, cv64a6_imafdc_sv39_wb, cv64a6_imafdch_sv39, cv64a6_imafdc_sv39_hpdcache, cv64a6_imafdc_sv39_hpdcache_wb, cv64a6_imafdch_sv39_wb, cv64a6_imafdchsclic_sv39, cv64a6_imafdchsclic_sv39_wb, cv64a6_imafdchsclic_sv39_hpdcache_wb, cv64a6_imafdchxhclic_sv39_wb, cv64a6_splus, cv32a6_imac_sv0, cv32a6_imac_sv32, cv32a6_imafc_sv32) files: - core/cva6_mmu/cva6_tlb.sv - core/cva6_mmu/cva6_shared_tlb.sv @@ -124,6 +158,7 @@ sources: - core/ex_stage.sv - core/acc_dispatcher.sv - core/instr_realign.sv + - core/macro_decoder.sv - core/id_stage.sv - core/issue_read_operands.sv - core/issue_stage.sv @@ -162,11 +197,12 @@ sources: - core/cache_subsystem/wt_axi_adapter.sv - core/cache_subsystem/cva6_icache.sv - core/cache_subsystem/tag_cmp.sv - - core/cache_subsystem/cva6_icache_axi_wrapper.sv + - core/cache_subsystem/cache_ctrl.sv + - core/cache_subsystem/amo_alu.sv - core/cache_subsystem/axi_adapter.sv - core/cache_subsystem/miss_handler.sv - - core/cache_subsystem/cache_ctrl.sv - core/cache_subsystem/std_nbdcache.sv + - core/cache_subsystem/cva6_icache_axi_wrapper.sv - core/cache_subsystem/std_cache_subsystem.sv # HPDCache sources - core/cache_subsystem/hpdcache/rtl/src/hpdcache_pkg.sv @@ -186,6 +222,7 @@ sources: - core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_decoder.sv - core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_1hot_to_binary.sv - core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_prio_1hot_encoder.sv + - core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_prio_bin_encoder.sv - core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram.sv - core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram_wbyteenable.sv - core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram_wmask.sv @@ -214,47 +251,42 @@ sources: - core/cache_subsystem/hpdcache/rtl/src/hpdcache_victim_sel.sv - core/cache_subsystem/hpdcache/rtl/src/hpdcache_wbuf.sv - core/cache_subsystem/hpdcache/rtl/src/hpdcache_flush.sv + - core/cache_subsystem/hpdcache/rtl/src/hpdcache_cbuf.sv # HPDCache integration - core/cache_subsystem/cva6_hpdcache_if_adapter.sv - core/cache_subsystem/cva6_hpdcache_subsystem_axi_arbiter.sv - core/cache_subsystem/cva6_hpdcache_subsystem.sv - core/cache_subsystem/cva6_hpdcache_wrapper.sv - # HPDCache SRAM models - - core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv - - core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv - - core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_wmask_1rw.sv + # `tc_sram` wrappers for HPDCache macros + - core/cache_subsystem/hpdcache_tc_sram.sv # Physical Memory Protection - core/pmp/src/pmp.sv - core/pmp/src/pmp_entry.sv - core/pmp/src/pmp_data_if.sv - - include_dirs: - - common/local/util - files: - - common/local/util/sram.sv + # FPGA support stubs: these should never be instantiated (and will throw assertions) + - vendor/pulp-platform/fpga-support/fpga-support-stubs.sv - - target: not(all(fpga, xilinx)) - include_dirs: - - common/local/util - files: - - common/local/util/tc_sram_wrapper.sv - - common/local/util/sram_cache.sv - - common/local/util/tc_sram_wrapper_cache_techno.sv - - - target: all(fpga, xilinx) - include_dirs: - - common/local/util - files: - - common/local/util/sram_cache.sv - - common/local/util/tc_sram_fpga_wrapper.sv - - vendor/pulp-platform/fpga-support/rtl/SyncSpRamBeNx64.sv + # SRAM Wrappers stay tech-independent; we leave technology mapping to tc_sram + - common/local/util/tc_sram_wrapper.sv + - common/local/util/tc_sram_wrapper_cache_techno.sv + - common/local/util/sram_pulp.sv + - common/local/util/sram_cache.sv - target: not(synthesis) - include_dirs: - - core/include - - common/local/util files: # Tracer (behavioral code, not RTL) - core/include/instr_tracer_pkg.sv - common/local/util/instr_tracer.sv + + - target: cva6tb + files: + - test/hw/cva6tb_pkg.sv + - test/hw/cva6tb_regs.sv + - test/hw/cva6tb_sim_console.sv + - test/hw/cva6tb_soc.sv + + - target: all(cva6tb, test_simple) + files: + - test/hw/cva6tb_test_simple.sv diff --git a/CHANGELOG-PULP.md b/CHANGELOG-PULP.md new file mode 100644 index 00000000000..4fbd2f4507a --- /dev/null +++ b/CHANGELOG-PULP.md @@ -0,0 +1,99 @@ +# Changelog +All notable changes to the `pulp` branch of this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## pulp-v2.0.0 - 2025-07-17 +### Added +- vCLIC support + +### Changed +- Rebase onto openhwgroup:cva6:master#2d411b2d (2025-02-20) +- Apply upstream patches adding superscalar configuration options +- Add HPDCache wrappers +- FPU: Upgrade to pulp-v0.2.3 +- fence.t: Support 32-bit XLEN + +### Fixed +- Apply upstream bugfixes mostly regarding H extension +- CLIC WFI resume condition and trap vector base + +## pulp-v1.0.0 - 2024-02-25 +### Changed +- Rebase onto openhwgroup:cva6:master#68f952b4 (2024-02-23) + +## pulp-v0.4.3 - 2023-08-12 +### Changed +- `tech_cells_generic`: Bump v0.2.12 + +## pulp-v0.4.2 - 2023-08-11 +### Changed +- frontend: Do not speculate beyond xret to avoid spurious icache refills +- coherence: Pack Valid/Dirty SRAM + +## pulp-v0.4.1 - 2023-08-03 +### Fixed +- CLIC controller: Fix inferred latch + +## pulp-v0.4.0 - 2023-07-25 +### Added +- Self-invalidation coherence + +### Changed +- Upgrade CLIC to v2.0.0 +- Upgrade AXI RISC-V AMO adapter to v0.8.0 + +### Fixed +- Fix CLIC interrupt behaviour + +## pulp-v0.3.1 - 2023-05-10 +### Changed +- Upgrade FPU to pulp-v0.1.1 + +### Fixed +- Bender.yml: Fix file list for target cv64a6_imafdcsclic_sv39 +- cva6_icache_axi_wrapper: Fix negative repetition multiplier for paddr width > AxiAddrWidth +- cva6_clic_controller: Resolve inferred latch by adding default case +- Bender.lock: Update + +## pulp-v0.3.0 - 2023-05-03 +### Added +- Initial Hypervisor extension (incl. regression tests) + +### Changed +- Upgrade AXI to v0.39.0-beta.2 + +## pulp-v0.2.2 - 2023-04-27 +### Fixed +- `Bender.yml`: Specify version for tech_cells_generic +- `Makefile`: Fix vopt for recent questasim versions + +## pulp-v0.2.1 - 2023-04-17 +### Fixed +- `Bender.yml`: Add cv64a6_imafdcsclic_sv39 target + +## pulp-v0.2.0 - 2023-04-08 +### Added +- CLIC support + +### Fixed +- Verilator 5 compatibility +- `Bender.yml`: Update paths +- Minor tool compatibility issues + +## pulp-v0.1.1 - 2023-03-25 +### Fixed +- Typo in `Bender.yml` + +## pulp-v0.1.0 - 2023-03-24 +### Added +- `fence.t` instruction to support timing channel prevention + +### Changed +- Bumped `master` +- Updated `Bender.yml` + +### Fixed +- Questasim flow +- `icache_axi_wrapper`: Signal widths diff --git a/CODEOWNERS b/CODEOWNERS index 67589d40d8e..98a63f39fab 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,25 +1,3 @@ # Global Owners -* @JeanRochCoulon +* @niwis -# Core - -core/mmu_sv39 @sjthales -core/cvxif_example @Gchauvon -core/cvxif_fu.sv @Gchauvon - -# HPDCache - -core/cache_subsystem/hpdcache @cfuguet -core/cache_subsystem/cva6_hpdcache* @cfuguet -core/include/cv64a6_imafdc_sv39_hpdcache_config_pkg.sv @cfuguet -core/include/cv64a6_imafdc_sv39_hpdcache_wb_config_pkg.sv @cfuguet - -# OpenPiton - -corev_apu/openpiton @Jbalkind -core/cache_subsystem/wt_l15_adapter.sv @Jbalkind -core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv @Jbalkind - -## Documentation - -docs/ @jquevremont diff --git a/CONTRIBUTING-PULP.md b/CONTRIBUTING-PULP.md new file mode 100644 index 00000000000..15c73487bec --- /dev/null +++ b/CONTRIBUTING-PULP.md @@ -0,0 +1,30 @@ +# Contributing to the PULP branch + +> :warning: When opening a PR, **make sure that `pulp-platform:pulp-vx` is selected as base**, not upstream master. + +## General + +Wherever possible, follow the upstream [Contribution Guidelines](https://github.com/openhwgroup/cva6/blob/master/CONTRIBUTING.md). +The default goal for all contributions on the PULP branch is that they can be upstreamed eventually. + + +## Systemlevel modifications + +Some contributions have implications on the interfaces of CVA6, or they require the addition of new regression tests. +This fork uses [Cheshire](https://github.com/pulp-platform/cheshire) as a testharness. +We use the following flow for co-development: + +1. Branch off the current `pulp-vx` branch (the default branch of this fork) and make your modifications. + In the following, we refer to your development branch as `cva6/my-feature`. +2. Branch off Cheshire's `main` branch. We will call this new branch `cheshire/my-feature`. + Point to `cva6/my-feature` in Cheshire's `Bender.lock` and make your systemlevel modifications. +3. In CVA6's `.gitlab-ci.yml`, point the Cheshire ref to `cheshire/my-feature`. +4. Mark your pulp-CVA6 PR ready for review. **The maintainers** will + - review your modifications to CVA6 and Cheshire, + - create a tag on `cheshire/my-feature`, + - merge `cva6/my-feature`, + - create a new release tag for CVA6 (`pulp-vx.y.z`). +5. Point Cheshire's `Bender.yml` and `Bender.lock` to `pulp-vx.y.z`. +6. Open a PR on the Cheshire repo. + +If you have any questions or need support, please contact the maintainers of pulp-CVA6 (see README.md). diff --git a/README.md b/README.md index c7e4ec03fe1..eafbdc9dee4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # CVA6 RISC-V CPU [![Build Status](https://github.com/openhwgroup/cva6/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/openhwgroup/cva6/actions/workflows/ci.yml) [![CVA6 dashboard](https://riscv-ci.pages.thales-invia.fr/dashboard/badge_master.svg)](https://riscv-ci.pages.thales-invia.fr/dashboard/dashboard_cva6.html) [![Documentation Status](https://readthedocs.com/projects/openhw-group-cva6-user-manual/badge/?version=latest)](https://docs.openhwgroup.org/projects/cva6-user-manual/?badge=latest) [![GitHub release](https://img.shields.io/github/release/openhwgroup/cva6?include_prereleases=&sort=semver&color=blue)](https://github.com/openhwgroup/cva6/releases/) +> :warning: **This is a fork of CVA6** intended for PULP development. The upstream repository is hosted on [openhwgroup/cva6](https://github.com/openhwgroup/cva6). This fork is maintained by Nils Wistoff . + CVA6 is a 6-stage, single-issue, in-order CPU which implements the 64-bit RISC-V instruction set. It fully implements I, M, A and C extensions as specified in Volume I: User-Level ISA V 2.3 as well as the draft privilege extension 1.10. It implements three privilege levels M, S, U to fully support a Unix-like operating system. Furthermore, it is compliant to the draft external debug spec 0.13. It has a configurable size, separate TLBs, a hardware PTW and branch-prediction (branch target buffer and branch history table). The primary design goal was on reducing critical path length. diff --git a/common/local/util/sram_pulp.sv b/common/local/util/sram_pulp.sv new file mode 100644 index 00000000000..55599fcc704 --- /dev/null +++ b/common/local/util/sram_pulp.sv @@ -0,0 +1,96 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Author: Florian Zaruba , ETH Zurich +// Michael Schaffner , ETH Zurich +// Nils Wistoff , ETH Zurich +// Date: 15.08.2018 +// Description: generic tc_sram wrapper for CVA6 +// +// Note: the wrapped module contains two different implementations for +// ALTERA and XILINX tools, since these follow different coding styles for +// inferrable RAMS with byte enable. define `FPGA_TARGET_XILINX or +// `FPGA_TARGET_ALTERA in your build environment (default is ALTERA) + +module sram #( + parameter DATA_WIDTH = 64, + parameter BYTE_WIDTH = 8, + parameter USER_WIDTH = 1, + parameter USER_EN = 0, + parameter NUM_WORDS = 1024, + parameter SIM_INIT = "none", + parameter OUT_REGS = 0 // enables output registers in FPGA macro (read lat = 2) +)( + input logic clk_i, + input logic rst_ni, + input logic req_i, + input logic we_i, + input logic [$clog2(NUM_WORDS)-1:0] addr_i, + input logic [USER_WIDTH-1:0] wuser_i, + input logic [DATA_WIDTH-1:0] wdata_i, + input logic [(DATA_WIDTH+BYTE_WIDTH-1)/BYTE_WIDTH-1:0] be_i, + output logic [USER_WIDTH-1:0] ruser_o, + output logic [DATA_WIDTH-1:0] rdata_o +); + + tc_sram #( + .NumWords ( NUM_WORDS ), + .DataWidth ( DATA_WIDTH ), + .ByteWidth ( BYTE_WIDTH ), + .NumPorts ( 32'd1 ), + .Latency ( 32'd1 ), + .SimInit ( SIM_INIT ), + .PrintSimCfg ( 1'b0 ) + ) i_tc_sram ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .req_i ( req_i ), + .we_i ( we_i ), + .be_i ( be_i ), + .wdata_i ( wdata_i ), + .addr_i ( addr_i ), + .rdata_o ( rdata_o ) + ); + + if (USER_EN > 0) begin : gen_mem_user + tc_sram #( + .NumWords ( NUM_WORDS ), + .DataWidth ( DATA_WIDTH ), + .ByteWidth ( BYTE_WIDTH ), + .NumPorts ( 32'd1 ), + .Latency ( 32'd1 ), + .SimInit ( SIM_INIT ), + .PrintSimCfg ( 1'b0 ) + ) i_tc_sram_user ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .req_i ( req_i ), + .we_i ( we_i ), + .be_i ( be_i ), + .wdata_i ( wuser_i ), + .addr_i ( addr_i ), + .rdata_o ( ruser_o ) + ); + + if (USER_WIDTH != DATA_WIDTH) begin : gen_err_data_user_width + $fatal(1, "sram_pulp: USER_WIDTH needs to be equal to DATA_WIDTH (if USER_EN is set)."); + end + + end else begin : gen_mem_user + assign ruser_o = '0; + // synthesis translate_off + begin : i_tc_sram_user + localparam type data_t = logic [DATA_WIDTH-1:0]; + data_t init_val [0:0]; + data_t sram [NUM_WORDS-1:0] /* verilator public_flat */; + end + // synthesis translate_on + end +endmodule : sram diff --git a/common/local/util/tc_sram_wrapper.sv b/common/local/util/tc_sram_wrapper.sv index ae3287d93f9..9c5d7de9e00 100644 --- a/common/local/util/tc_sram_wrapper.sv +++ b/common/local/util/tc_sram_wrapper.sv @@ -34,8 +34,6 @@ module tc_sram_wrapper #( output data_t [NumPorts-1:0] rdata_o // read data ); -// synthesis translate_off - tc_sram #( .NumWords(NumWords), .DataWidth(DataWidth), @@ -55,6 +53,4 @@ module tc_sram_wrapper #( .rdata_o ( rdata_o ) ); -// synthesis translate_on - endmodule diff --git a/common/local/util/tc_sram_wrapper_cache_techno.sv b/common/local/util/tc_sram_wrapper_cache_techno.sv index 31868b5457c..0c125336e3d 100644 --- a/common/local/util/tc_sram_wrapper_cache_techno.sv +++ b/common/local/util/tc_sram_wrapper_cache_techno.sv @@ -38,8 +38,6 @@ module tc_sram_wrapper_cache_techno #( output data_t [NumPorts-1:0] rdata_o // read data ); -// synthesis translate_off - tc_sram #( .NumWords(NumWords), .DataWidth(DataWidth), @@ -59,6 +57,4 @@ module tc_sram_wrapper_cache_techno #( .rdata_o ( rdata_o ) ); -// synthesis translate_on - endmodule diff --git a/core/Flist.cva6 b/core/Flist.cva6 index 58683582e8f..b41dabdf414 100644 --- a/core/Flist.cva6 +++ b/core/Flist.cva6 @@ -220,7 +220,7 @@ ${CVA6_REPO_DIR}/common/local/util/instr_tracer.sv ${CVA6_REPO_DIR}/common/local/util/tc_sram_wrapper.sv ${CVA6_REPO_DIR}/common/local/util/tc_sram_wrapper_cache_techno.sv ${CVA6_REPO_DIR}/vendor/pulp-platform/tech_cells_generic/src/rtl/tc_sram.sv -${CVA6_REPO_DIR}/common/local/util/sram.sv +${CVA6_REPO_DIR}/common/local/util/sram_pulp.sv ${CVA6_REPO_DIR}/common/local/util/sram_cache.sv // MMU diff --git a/core/cache_subsystem/axi_adapter.sv b/core/cache_subsystem/axi_adapter.sv index 3ee65421b7d..25b6f4706b3 100644 --- a/core/cache_subsystem/axi_adapter.sv +++ b/core/cache_subsystem/axi_adapter.sv @@ -27,6 +27,7 @@ module axi_adapter #( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low + output logic busy_o, input logic req_i, input ariane_pkg::ad_req_t type_i, input ariane_pkg::amo_t amo_i, @@ -94,6 +95,9 @@ module axi_adapter #( assign any_outstanding_aw = outstanding_aw_cnt_q != '0; + // Busy if we're not idle or have outstanding writes + assign busy_o = (state_q != IDLE) || any_outstanding_aw; + always_comb begin : axi_fsm // Default assignments axi_req_o.aw_valid = 1'b0; diff --git a/core/cache_subsystem/cache_ctrl.sv b/core/cache_subsystem/cache_ctrl.sv index a76c62e06bc..0db53747848 100644 --- a/core/cache_subsystem/cache_ctrl.sv +++ b/core/cache_subsystem/cache_ctrl.sv @@ -30,9 +30,9 @@ module cache_ctrl ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic flush_i, input logic bypass_i, // enable cache output logic busy_o, + input logic stall_i, // stall new memory requests // Core request ports input dcache_req_i_t req_port_i, output dcache_req_o_t req_port_o, @@ -144,7 +144,7 @@ module cache_ctrl IDLE: begin // a new request arrived - if (req_port_i.data_req && !flush_i) begin + if (req_port_i.data_req && !stall_i) begin // request the cache line - we can do this speculatively req_o = '1; @@ -187,7 +187,7 @@ module cache_ctrl mem_req_d.tag = req_port_i.address_tag; end // we speculatively request another transfer - if (req_port_i.data_req && !flush_i) begin + if (req_port_i.data_req && !stall_i) begin req_o = '1; end // ------------ @@ -195,7 +195,7 @@ module cache_ctrl // ------------ if (|hit_way_i) begin // we can request another cache-line if this was a load - if (req_port_i.data_req && !mem_req_q.we && !flush_i) begin + if (req_port_i.data_req && !mem_req_q.we && !stall_i) begin state_d = WAIT_TAG; // switch back to WAIT_TAG mem_req_d.index = req_port_i.address_index; mem_req_d.id = req_port_i.data_id; @@ -312,15 +312,16 @@ module cache_ctrl addr_o = mem_req_q.index; we_o = 1'b1; - be_o.vldrty = hit_way_q; - // set the correct byte enable be_o.data[cl_offset>>3+:CVA6Cfg.XLEN/8] = mem_req_q.be; - data_o.data[cl_offset+:CVA6Cfg.XLEN] = mem_req_q.wdata; - data_o.tag = mem_req_d.tag; + for (int unsigned i = 0; i < CVA6Cfg.DCACHE_SET_ASSOC; i++) begin + if (hit_way_q[i]) be_o.vldrty[i] = '{valid: 1, dirty: be_o.data}; + end + data_o.data[cl_offset+:CVA6Cfg.XLEN] = mem_req_q.wdata; + data_o.tag = mem_req_d.tag; // ~> change the state - data_o.dirty = 1'b1; - data_o.valid = 1'b1; + data_o.dirty[cl_offset>>3+:CVA6Cfg.XLEN/8] = mem_req_q.be; + data_o.valid = 1'b1; // got a grant ~> this is finished now if (gnt_i) begin @@ -407,7 +408,7 @@ module cache_ctrl req_port_o.data_rvalid = ~mem_req_q.killed; req_port_o.data_rdata = critical_word_i[axi_offset+:CVA6Cfg.XLEN]; // we can make another request - if (req_port_i.data_req && !flush_i) begin + if (req_port_i.data_req && !stall_i) begin // save index, be and we mem_req_d.index = req_port_i.address_index; mem_req_d.id = req_port_i.data_id; diff --git a/core/cache_subsystem/cva6_hpdcache_subsystem.sv b/core/cache_subsystem/cva6_hpdcache_subsystem.sv index a78f6039db3..8a34f9c65fe 100644 --- a/core/cache_subsystem/cva6_hpdcache_subsystem.sv +++ b/core/cache_subsystem/cva6_hpdcache_subsystem.sv @@ -162,6 +162,9 @@ module cva6_hpdcache_subsystem .flush_i (icache_flush_i), .en_i (icache_en_i), .miss_o (icache_miss_o), + .busy_o (), + .stall_i (1'b0), + .init_ni (1'b0), .areq_i (icache_areq_i), .areq_o (icache_areq_o), .dreq_i (icache_dreq_i), @@ -211,6 +214,8 @@ module cva6_hpdcache_subsystem userCfg.mshrSetsPerRam = CVA6Cfg.NrLoadBufEntries < 16 ? 1 : CVA6Cfg.NrLoadBufEntries / 2; userCfg.mshrRamByteEnable = 1'b1; userCfg.mshrUseRegbank = (CVA6Cfg.NrLoadBufEntries < 16); + /*FIXME we should add additional CVA6 config parameters (cbufEntries)*/ + userCfg.cbufEntries = 4; userCfg.refillCoreRspFeedthrough = 1'b1; userCfg.refillFifoDepth = 2 * (CVA6Cfg.DCACHE_LINE_WIDTH / CVA6Cfg.AxiDataWidth); userCfg.wbufDirEntries = CVA6Cfg.WtDcacheWbufDepth; @@ -231,6 +236,7 @@ module cva6_hpdcache_subsystem userCfg.wbEn = (CVA6Cfg.DCacheType == config_pkg::HPDCACHE_WB) || (CVA6Cfg.DCacheType == config_pkg::HPDCACHE_WT_WB); + userCfg.lowLatency = 1'b1; return userCfg; endfunction diff --git a/core/cache_subsystem/cva6_hpdcache_subsystem_axi_arbiter.sv b/core/cache_subsystem/cva6_hpdcache_subsystem_axi_arbiter.sv index 5efc1e8e689..2aef6b9949f 100644 --- a/core/cache_subsystem/cva6_hpdcache_subsystem_axi_arbiter.sv +++ b/core/cache_subsystem/cva6_hpdcache_subsystem_axi_arbiter.sv @@ -281,7 +281,9 @@ module cva6_hpdcache_subsystem_axi_arbiter .mem_req_read_ready_i(mem_req_read_ready_arb), .mem_req_read_valid_o(mem_req_read_valid_arb), - .mem_req_read_o (mem_req_read_arb) + .mem_req_read_o (mem_req_read_arb), + + .gnt_index_o() ); // }}} diff --git a/core/cache_subsystem/cva6_hpdcache_wrapper.sv b/core/cache_subsystem/cva6_hpdcache_wrapper.sv index 7727dc703d0..a6c39a53742 100644 --- a/core/cache_subsystem/cva6_hpdcache_wrapper.sv +++ b/core/cache_subsystem/cva6_hpdcache_wrapper.sv @@ -383,6 +383,9 @@ module cva6_hpdcache_wrapper .mem_resp_read_valid_i(dcache_mem_resp_read_valid_i), .mem_resp_read_i (dcache_mem_resp_read_i), + .mem_resp_read_inval_i('0), + .mem_resp_read_inval_nline_i('0), + .mem_req_write_ready_i(dcache_mem_req_write_ready_i), .mem_req_write_valid_o(dcache_mem_req_write_valid_o), .mem_req_write_o (dcache_mem_req_write_o), diff --git a/core/cache_subsystem/cva6_icache.sv b/core/cache_subsystem/cva6_icache.sv index d84ee26d26f..e022f7191d0 100644 --- a/core/cache_subsystem/cva6_icache.sv +++ b/core/cache_subsystem/cva6_icache.sv @@ -48,6 +48,9 @@ module cva6_icache input logic en_i, /// to performance counter output logic miss_o, + output logic busy_o, + input logic stall_i, + input logic init_ni, // do not init after enabling // address translation requests input icache_areq_t areq_i, output icache_arsp_t areq_o, @@ -129,6 +132,8 @@ module cva6_icache } state_e; state_e state_d, state_q; + assign busy_o = (state_q != IDLE); + /////////////////////////////////////////////////////// // address -> cl_index mapping, interface plumbing /////////////////////////////////////////////////////// @@ -192,7 +197,7 @@ module cva6_icache always_comb begin : p_fsm // default assignment state_d = state_q; - cache_en_d = cache_en_q & en_i;// disabling the cache is always possible, enable needs to go via flush + cache_en_d = (cache_en_q | init_ni) & en_i;// disabling the cache is always possible, enable needs to go via flush if we init flush_en = 1'b0; cmp_en_d = 1'b0; cache_rden = 1'b0; @@ -236,10 +241,10 @@ module cva6_icache cmp_en_d = cache_en_q; // handle pending flushes, or perform cache clear upon enable - if (flush_d || (en_i && !cache_en_q)) begin + if (flush_d || (en_i && !cache_en_q && !init_ni)) begin state_d = FLUSH; // wait for incoming requests - end else begin + end else if (!stall_i) begin // mem requests are for sure invals here if (!mem_rtrn_vld_i) begin dreq_o.ready = 1'b1; diff --git a/core/cache_subsystem/cva6_icache_axi_wrapper.sv b/core/cache_subsystem/cva6_icache_axi_wrapper.sv index c16597e8b31..ea0ce32f02c 100644 --- a/core/cache_subsystem/cva6_icache_axi_wrapper.sv +++ b/core/cache_subsystem/cva6_icache_axi_wrapper.sv @@ -34,6 +34,9 @@ module cva6_icache_axi_wrapper input logic flush_i, // flush the icache, flush and kill have to be asserted together input logic en_i, // enable icache output logic miss_o, // to performance counter + output logic busy_o, + input logic stall_i, + input logic init_ni, // address translation requests input icache_areq_t areq_i, output icache_arsp_t areq_o, @@ -121,6 +124,9 @@ module cva6_icache_axi_wrapper .flush_i (flush_i), .en_i (en_i), .miss_o (miss_o), + .busy_o (busy_o), + .stall_i (stall_i), + .init_ni (init_ni), .areq_i (areq_i), .areq_o (areq_o), .dreq_i (dreq_i), diff --git a/core/cache_subsystem/hpdcache b/core/cache_subsystem/hpdcache index 04de8089698..308a2728641 160000 --- a/core/cache_subsystem/hpdcache +++ b/core/cache_subsystem/hpdcache @@ -1 +1 @@ -Subproject commit 04de80896981527c34fbbd35d7b1ef787a082d7c +Subproject commit 308a2728641209297d9eb7d400f4a58fd48038d0 diff --git a/core/cache_subsystem/hpdcache_tc_sram.sv b/core/cache_subsystem/hpdcache_tc_sram.sv new file mode 100644 index 00000000000..b24e6f9f12b --- /dev/null +++ b/core/cache_subsystem/hpdcache_tc_sram.sv @@ -0,0 +1,105 @@ +// Copyright 2022 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Paul Scheffler + +// Wrappers mapping HPDcache SRAMs to PULP `tc_sram`. + +/// SRAM with one R/W port and no write mask +module hpdcache_sram_1rw #( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2 ** ADDR_SIZE +) ( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + output logic [DATA_SIZE-1:0] rdata +); + tc_sram #( + .NumWords (DEPTH), + .DataWidth(DATA_SIZE), + .ByteWidth(DATA_SIZE), + .NumPorts (1), + .Latency (1) + ) i_tc_sram ( + .clk_i (clk), + .rst_ni (rst_n), + .req_i (cs), + .we_i (we), + .addr_i (addr), + .wdata_i(wdata), + .be_i (1'b1), + .rdata_o(rdata) + ); +endmodule + +/// SRAM with one R/W port and per-byte write mask +module hpdcache_sram_wbyteenable_1rw #( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2 ** ADDR_SIZE +) ( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ ADDR_SIZE-1:0] addr, + input logic [ DATA_SIZE-1:0] wdata, + input logic [DATA_SIZE/8-1:0] wbyteenable, + output logic [ DATA_SIZE-1:0] rdata +); + tc_sram #( + .NumWords (DEPTH), + .DataWidth(DATA_SIZE), + .ByteWidth(8), + .NumPorts (1), + .Latency (1) + ) i_tc_sram ( + .clk_i (clk), + .rst_ni (rst_n), + .req_i (cs), + .we_i (we), + .addr_i (addr), + .wdata_i(wdata), + .be_i (wbyteenable), + .rdata_o(rdata) + ); +endmodule + +/// SRAM with one R/W port and per-bit write mask +module hpdcache_sram_wmask_1rw #( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2 ** ADDR_SIZE +) ( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + input logic [DATA_SIZE-1:0] wmask, + output logic [DATA_SIZE-1:0] rdata +); + tc_sram #( + .NumWords (DEPTH), + .DataWidth(DATA_SIZE), + .ByteWidth(1), + .NumPorts (1), + .Latency (1) + ) i_tc_sram ( + .clk_i (clk), + .rst_ni (rst_n), + .req_i (cs), + .we_i (we), + .addr_i (addr), + .wdata_i(wdata), + .be_i (wmask), + .rdata_o(rdata) + ); +endmodule diff --git a/core/cache_subsystem/miss_handler.sv b/core/cache_subsystem/miss_handler.sv index 6b7bee3848f..157318ce561 100644 --- a/core/cache_subsystem/miss_handler.sv +++ b/core/cache_subsystem/miss_handler.sv @@ -29,10 +29,12 @@ module miss_handler ) ( input logic clk_i, input logic rst_ni, + output logic busy_o, // miss handler or axi is busy input logic flush_i, // flush request output logic flush_ack_o, // acknowledge successful flush output logic miss_o, input logic busy_i, // dcache is busy with something + input logic init_ni, // do not init after reset // Bypass or miss input logic [NR_PORTS-1:0][$bits(miss_req_t)-1:0] miss_req_i, // Bypass handling @@ -164,6 +166,10 @@ module miss_handler logic [ 31:0] halfword; logic [ $clog2(CVA6Cfg.DCACHE_LINE_WIDTH)-1:0] cl_offset; + // Busy signals + logic bypass_axi_busy, miss_axi_busy; + assign busy_o = bypass_axi_busy | miss_axi_busy | (state_q != IDLE); + // ------------------------------ // Cache Management // ------------------------------ @@ -171,7 +177,7 @@ module miss_handler automatic logic [CVA6Cfg.DCACHE_SET_ASSOC-1:0] evict_way, valid_way; for (int unsigned i = 0; i < CVA6Cfg.DCACHE_SET_ASSOC; i++) begin - evict_way[i] = data_i[i].valid & data_i[i].dirty; + evict_way[i] = data_i[i].valid & (|data_i[i].dirty); valid_way[i] = data_i[i].valid; end // ---------------------- @@ -281,10 +287,11 @@ module miss_handler lfsr_enable = 1'b1; evict_way_d = lfsr_oh; // do we need to write back the cache line? - if (data_i[lfsr_bin].dirty) begin + if (|data_i[lfsr_bin].dirty) begin state_d = WB_CACHELINE_MISS; evict_cl_d.tag = data_i[lfsr_bin].tag; evict_cl_d.data = data_i[lfsr_bin].data; + evict_cl_d.dirty = data_i[lfsr_bin].dirty; cnt_d = mshr_q.addr[CVA6Cfg.DCACHE_INDEX_WIDTH-1:0]; // no - we can request a cache line now end else state_d = REQ_CACHELINE; @@ -317,12 +324,15 @@ module miss_handler addr_o = mshr_q.addr[CVA6Cfg.DCACHE_INDEX_WIDTH-1:0]; req_o = evict_way_q; we_o = 1'b1; - be_o = '1; - be_o.vldrty = evict_way_q; + be_o.tag = '1; + be_o.data = '1; + for (int unsigned i = 0; i < CVA6Cfg.DCACHE_SET_ASSOC; i++) begin + if (evict_way_q[i]) be_o.vldrty[i] = '1; + end data_o.tag = mshr_q.addr[CVA6Cfg.DCACHE_TAG_WIDTH+CVA6Cfg.DCACHE_INDEX_WIDTH-1:CVA6Cfg.DCACHE_INDEX_WIDTH]; data_o.data = data_miss_fsm; data_o.valid = 1'b1; - data_o.dirty = 1'b0; + data_o.dirty = '0; // is this a write? if (mshr_q.we) begin @@ -332,7 +342,7 @@ module miss_handler if (mshr_q.be[i]) data_o.data[(cl_offset+i*8)+:8] = mshr_q.wdata[i]; end // its immediately dirty if we write - data_o.dirty = 1'b1; + data_o.dirty[cl_offset>>3+:8] = mshr_q.be; end // reset MSHR mshr_d.valid = 1'b0; @@ -353,7 +363,7 @@ module miss_handler cnt_q[CVA6Cfg.DCACHE_INDEX_WIDTH-1:CVA6Cfg.DCACHE_OFFSET_WIDTH], {{CVA6Cfg.DCACHE_OFFSET_WIDTH} {1'b0}} }; - req_fsm_miss_be = '1; + req_fsm_miss_be = evict_cl_q.dirty; req_fsm_miss_we = 1'b1; req_fsm_miss_wdata = evict_cl_q.data; @@ -365,9 +375,11 @@ module miss_handler we_o = 1'b1; data_o.valid = INVALIDATE_ON_FLUSH ? 1'b0 : 1'b1; // invalidate - be_o.vldrty = evict_way_q; + for (int unsigned i = 0; i < CVA6Cfg.DCACHE_SET_ASSOC; i++) begin + if (evict_way_q[i]) be_o.vldrty[i] = '1; + end // go back to handling the miss or flushing, depending on where we came from - state_d = (state_q == WB_CACHELINE_MISS) ? MISS : FLUSH_REQ_STATUS; + state_d = (state_q == WB_CACHELINE_MISS) ? MISS : FLUSH_REQ_STATUS; end end @@ -423,7 +435,7 @@ module miss_handler be_o.vldrty = '1; cnt_d = cnt_q + (1'b1 << CVA6Cfg.DCACHE_OFFSET_WIDTH); // finished initialization - if (cnt_q[CVA6Cfg.DCACHE_INDEX_WIDTH-1:CVA6Cfg.DCACHE_OFFSET_WIDTH] == CVA6Cfg.DCACHE_NUM_WORDS - 1) + if (cnt_q[CVA6Cfg.DCACHE_INDEX_WIDTH-1:CVA6Cfg.DCACHE_OFFSET_WIDTH] == CVA6Cfg.DCACHE_NUM_WORDS - 1 || init_ni) state_d = IDLE; end // ---------------------- @@ -610,6 +622,7 @@ module miss_handler ) i_bypass_axi_adapter ( .clk_i(clk_i), .rst_ni(rst_ni), + .busy_o(bypass_axi_busy), .req_i(bypass_adapter_req.req), .type_i(bypass_adapter_req.reqtype), .amo_i(bypass_adapter_req.amo), @@ -645,6 +658,7 @@ module miss_handler ) i_miss_axi_adapter ( .clk_i, .rst_ni, + .busy_o (miss_axi_busy), .req_i (req_fsm_miss_valid), .type_i (req_fsm_miss_req), .amo_i (AMO_NONE), diff --git a/core/cache_subsystem/std_cache_subsystem.sv b/core/cache_subsystem/std_cache_subsystem.sv index a38e2e7a7a9..eef4fd7880a 100644 --- a/core/cache_subsystem/std_cache_subsystem.sv +++ b/core/cache_subsystem/std_cache_subsystem.sv @@ -38,6 +38,9 @@ module std_cache_subsystem input logic clk_i, input logic rst_ni, input riscv::priv_lvl_t priv_lvl_i, + output logic busy_o, + input logic stall_i, // stall new memory requests + input logic init_ni, // do not init after reset // I$ input logic icache_en_i, // enable icache (or bypass e.g: in debug mode) input logic icache_flush_i, // flush the icache, flush and kill have to be asserted together @@ -75,6 +78,11 @@ module std_cache_subsystem axi_req_t axi_req_data; axi_rsp_t axi_resp_data; + logic icache_busy; + logic dcache_busy; + + assign busy_o = icache_busy | dcache_busy; + cva6_icache_axi_wrapper #( .CVA6Cfg(CVA6Cfg), .icache_areq_t(icache_areq_t), @@ -92,6 +100,9 @@ module std_cache_subsystem .flush_i (icache_flush_i), .en_i (icache_en_i), .miss_o (icache_miss_o), + .busy_o (icache_busy), + .stall_i (stall_i), + .init_ni (init_ni), .areq_i (icache_areq_i), .areq_o (icache_areq_o), .dreq_i (icache_dreq_i), @@ -119,6 +130,9 @@ module std_cache_subsystem .flush_i (dcache_flush_i), .flush_ack_o (dcache_flush_ack_o), .miss_o (dcache_miss_o), + .busy_o (dcache_busy), + .stall_i (stall_i), + .init_ni (init_ni), .axi_bypass_o(axi_req_bypass), .axi_bypass_i(axi_resp_bypass), .axi_data_o (axi_req_data), diff --git a/core/cache_subsystem/std_nbdcache.sv b/core/cache_subsystem/std_nbdcache.sv index d068e743b28..33e276f7e00 100644 --- a/core/cache_subsystem/std_nbdcache.sv +++ b/core/cache_subsystem/std_nbdcache.sv @@ -31,6 +31,9 @@ module std_nbdcache input logic flush_i, // high until acknowledged output logic flush_ack_o, // send a single cycle acknowledge signal when the cache is flushed output logic miss_o, // we missed on a LD/ST + output logic busy_o, + input logic stall_i, // stall new memory requests + input logic init_ni, // AMOs input amo_req_t amo_req_i, output amo_resp_t amo_resp_o, @@ -49,15 +52,19 @@ module std_nbdcache localparam DCACHE_DIRTY_WIDTH = CVA6Cfg.DCACHE_SET_ASSOC * 2; localparam type cache_line_t = struct packed { - logic [CVA6Cfg.DCACHE_TAG_WIDTH-1:0] tag; // tag array - logic [CVA6Cfg.DCACHE_LINE_WIDTH-1:0] data; // data array - logic valid; // state array - logic dirty; // state array + logic [CVA6Cfg.DCACHE_TAG_WIDTH-1:0] tag; // tag array + logic [CVA6Cfg.DCACHE_LINE_WIDTH-1:0] data; // data array + logic valid; // state array + logic [(CVA6Cfg.DCACHE_LINE_WIDTH-1+7)/8-1:0] dirty; // state array }; + typedef struct packed { + logic [CVA6Cfg.DCACHE_LINE_WIDTH/8-1:0] dirty; + logic valid; + } vldrty_t; localparam type cl_be_t = struct packed { logic [(CVA6Cfg.DCACHE_TAG_WIDTH+7)/8-1:0] tag; // byte enable into tag array logic [(CVA6Cfg.DCACHE_LINE_WIDTH+7)/8-1:0] data; // byte enable into data array - logic [CVA6Cfg.DCACHE_SET_ASSOC-1:0] vldrty; // bit enable into state array (valid for a pair of dirty/valid bits) + vldrty_t [CVA6Cfg.DCACHE_SET_ASSOC-1:0] vldrty; // bit enable into state array (valid for a pair of dirty/valid bits) }; // ------------------------------- @@ -104,6 +111,11 @@ module std_nbdcache cache_line_t wdata_ram; cache_line_t [ CVA6Cfg.DCACHE_SET_ASSOC-1:0] rdata_ram; cl_be_t be_ram; + vldrty_t [ CVA6Cfg.DCACHE_SET_ASSOC-1:0] be_valid_dirty_ram; + + // Busy signals + logic miss_handler_busy; + assign busy_o = |busy | miss_handler_busy; // ------------------ // Cache Controller @@ -119,6 +131,7 @@ module std_nbdcache ) i_cache_ctrl ( .bypass_i (~enable_i), .busy_o (busy[i]), + .stall_i (stall_i | flush_i), // from core .req_port_i(req_ports_i[i]), .req_port_o(req_ports_o[i]), @@ -161,6 +174,7 @@ module std_nbdcache .cache_line_t(cache_line_t), .cl_be_t(cl_be_t) ) i_miss_handler ( + .busy_o (miss_handler_busy), .flush_i (flush_i), .busy_i (|busy), // AMOs @@ -234,21 +248,20 @@ module std_nbdcache // Valid/Dirty Regs // ---------------- - // align each valid/dirty bit pair to a byte boundary in order to leverage byte enable signals. - // note: if you have an SRAM that supports flat bit enables for your target technology, - // you can use it here to save the extra 4x overhead introduced by this workaround. - logic [4*DCACHE_DIRTY_WIDTH-1:0] dirty_wdata, dirty_rdata; + vldrty_t [CVA6Cfg.DCACHE_SET_ASSOC-1:0] dirty_wdata, dirty_rdata; for (genvar i = 0; i < CVA6Cfg.DCACHE_SET_ASSOC; i++) begin - assign dirty_wdata[8*i] = wdata_ram.dirty; - assign dirty_wdata[8*i+1] = wdata_ram.valid; - assign rdata_ram[i].dirty = dirty_rdata[8*i]; - assign rdata_ram[i].valid = dirty_rdata[8*i+1]; + assign dirty_wdata[i] = '{dirty: wdata_ram.dirty, valid: wdata_ram.valid}; + assign rdata_ram[i].dirty = dirty_rdata[i].dirty; + assign rdata_ram[i].valid = dirty_rdata[i].valid; + assign be_valid_dirty_ram[i].valid = be_ram.vldrty[i].valid; + assign be_valid_dirty_ram[i].dirty = be_ram.vldrty[i].dirty; end sram #( .USER_WIDTH(1), - .DATA_WIDTH(4 * DCACHE_DIRTY_WIDTH), + .DATA_WIDTH(CVA6Cfg.DCACHE_SET_ASSOC * $bits(vldrty_t)), + .BYTE_WIDTH(1), .NUM_WORDS (CVA6Cfg.DCACHE_NUM_WORDS) ) valid_dirty_sram ( .clk_i (clk_i), @@ -258,7 +271,7 @@ module std_nbdcache .addr_i (addr_ram[CVA6Cfg.DCACHE_INDEX_WIDTH-1:CVA6Cfg.DCACHE_OFFSET_WIDTH]), .wuser_i('0), .wdata_i(dirty_wdata), - .be_i (be_ram.vldrty), + .be_i (be_valid_dirty_ram), .ruser_o(), .rdata_o(dirty_rdata) ); diff --git a/core/cache_subsystem/wt_cache_subsystem.sv b/core/cache_subsystem/wt_cache_subsystem.sv index 4f40002f482..95700561df3 100644 --- a/core/cache_subsystem/wt_cache_subsystem.sv +++ b/core/cache_subsystem/wt_cache_subsystem.sv @@ -38,6 +38,9 @@ module wt_cache_subsystem ) ( input logic clk_i, input logic rst_ni, + output logic busy_o, + input logic stall_i, // stall new memory requests + input logic init_ni, // I$ input logic icache_en_i, // enable icache (or bypass e.g: in debug mode) input logic icache_flush_i, // flush the icache, flush and kill have to be asserted together @@ -110,9 +113,14 @@ module wt_cache_subsystem logic dcache_adapter_data_req, adapter_dcache_data_ack, adapter_dcache_rtrn_vld; - dcache_req_t dcache_adapter; + dcache_req_t dcache_adapter; dcache_rtrn_t adapter_dcache; + logic icache_busy; + logic dcache_busy; + + assign busy_o = dcache_busy | icache_busy; + cva6_icache #( // use ID 0 for icache reads .CVA6Cfg(CVA6Cfg), @@ -129,6 +137,9 @@ module wt_cache_subsystem .flush_i (icache_flush_i), .en_i (icache_en_i), .miss_o (icache_miss_o), + .busy_o (icache_busy), + .stall_i (stall_i), + .init_ni (init_ni), .areq_i (icache_areq_i), .areq_o (icache_areq_o), .dreq_i (icache_dreq_i), @@ -158,6 +169,9 @@ module wt_cache_subsystem .clk_i (clk_i), .rst_ni (rst_ni), .enable_i (dcache_enable_i), + .busy_o (dcache_busy), + .stall_i (stall_i), + .init_ni (init_ni), .flush_i (dcache_flush_i), .flush_ack_o (dcache_flush_ack_o), .miss_o (dcache_miss_o), diff --git a/core/cache_subsystem/wt_dcache.sv b/core/cache_subsystem/wt_dcache.sv index 76248861597..c5616bcb2ae 100644 --- a/core/cache_subsystem/wt_dcache.sv +++ b/core/cache_subsystem/wt_dcache.sv @@ -35,6 +35,9 @@ module wt_dcache input logic flush_i, // high until acknowledged output logic flush_ack_o, // send a single cycle acknowledge signal when the cache is flushed output logic miss_o, // we missed on a ld/st + output logic busy_o, + input logic stall_i, // stall new memory requests + input logic init_ni, output logic wbuffer_empty_o, output logic wbuffer_not_ni_o, @@ -125,6 +128,13 @@ module wt_dcache // wbuffer <-> memory wbuffer_t [ CVA6Cfg.WtDcacheWbufDepth-1:0] wbuffer_data; + // controllers -> management + logic [ NumPorts-2:0] ctrl_busy; + + // missunit -> management + logic missunit_busy; + + assign busy_o = |ctrl_busy | missunit_busy | ~wbuffer_empty_o; /////////////////////////////////////////////////////// // miss handling unit @@ -144,8 +154,10 @@ module wt_dcache .flush_i (flush_i), .flush_ack_o (flush_ack_o), .miss_o (miss_o), + .busy_o (missunit_busy), .wbuffer_empty_i(wbuffer_empty_o), .cache_en_o (cache_en), + .init_ni (init_ni), // amo interface .amo_req_i (amo_req_i), .amo_resp_o (amo_resp_o), @@ -205,6 +217,8 @@ module wt_dcache .clk_i (clk_i), .rst_ni (rst_ni), .cache_en_i (cache_en), + .busy_o (ctrl_busy[k]), + .stall_i (stall_i), // reqs from core .req_port_i (req_ports_i[k]), .req_port_o (req_ports_o[k]), diff --git a/core/cache_subsystem/wt_dcache_ctrl.sv b/core/cache_subsystem/wt_dcache_ctrl.sv index 61fd7b0317b..0fa31f6fe63 100644 --- a/core/cache_subsystem/wt_dcache_ctrl.sv +++ b/core/cache_subsystem/wt_dcache_ctrl.sv @@ -26,6 +26,8 @@ module wt_dcache_ctrl input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low input logic cache_en_i, + output logic busy_o, + input logic stall_i, // stall new memory requests // core request ports input dcache_req_i_t req_port_i, output dcache_req_o_t req_port_o, @@ -117,6 +119,8 @@ module wt_dcache_ctrl assign rd_ack_d = rd_ack_i; assign rd_tag_only_o = '0; + assign busy_o = (state_q != IDLE); + /////////////////////////////////////////////////////// // main control logic /////////////////////////////////////////////////////// @@ -135,7 +139,7 @@ module wt_dcache_ctrl ////////////////////////////////// // wait for an incoming request IDLE: begin - if (req_port_i.data_req) begin + if (req_port_i.data_req && !stall_i) begin rd_req_o = 1'b1; // if read ack then ack the `req_port_o`, and goto `READ` state if (rd_ack_i) begin diff --git a/core/cache_subsystem/wt_dcache_missunit.sv b/core/cache_subsystem/wt_dcache_missunit.sv index c40491ab45d..0d503b78df5 100644 --- a/core/cache_subsystem/wt_dcache_missunit.sv +++ b/core/cache_subsystem/wt_dcache_missunit.sv @@ -32,9 +32,11 @@ module wt_dcache_missunit input logic flush_i, // flush request, this waits for pending tx (write, read) to finish and will clear the cache output logic flush_ack_o, // send a single cycle acknowledge signal when the cache is flushed output logic miss_o, // we missed on a ld/st + output logic busy_o, // missunit is busy // local cache management signals input logic wbuffer_empty_i, output logic cache_en_o, // local cache enable signal + input logic init_ni, // no init after reset // AMO interface input amo_req_t amo_req_i, output amo_resp_t amo_resp_o, @@ -112,6 +114,7 @@ module wt_dcache_missunit DRAIN, AMO, FLUSH, + INIT, STORE_WAIT, LOAD_WAIT, AMO_WAIT @@ -168,6 +171,8 @@ module wt_dcache_missunit (mask_reads) ? miss_we_i & miss_req_i : miss_req_i; assign miss_is_write = miss_we_i[miss_port_idx]; + assign busy_o = state_q != IDLE; + // read port arbiter lzc #( .WIDTH(NumPorts) @@ -461,8 +466,8 @@ module wt_dcache_missunit amo_resp_o.ack = 1'b0; miss_replay_o = '0; - // disabling cache is possible anytime, enabling goes via flush - enable_d = enable_q & enable_i; + // disabling cache is possible anytime, enabling goes via flush if we init + enable_d = (enable_q | init_ni) & enable_i; flush_ack_d = flush_ack_q; flush_en = 1'b0; amo_sel = 1'b0; @@ -571,6 +576,12 @@ module wt_dcache_missunit end end ////////////////////////////////// + // initialize the cache + INIT: begin + // flush, unless we want to skip init + state_d = (init_ni) ? IDLE : FLUSH; + end + ////////////////////////////////// // send out amo op request AMO: begin if (CVA6Cfg.RVA) begin @@ -610,7 +621,7 @@ module wt_dcache_missunit always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs if (!rst_ni) begin - state_q <= FLUSH; + state_q <= INIT; cnt_q <= '0; enable_q <= '0; flush_ack_q <= '0; diff --git a/core/commit_stage.sv b/core/commit_stage.sv index 1589d2a8ead..a88e82cab0a 100644 --- a/core/commit_stage.sv +++ b/core/commit_stage.sv @@ -80,6 +80,8 @@ module commit_stage output logic fence_i_o, // Flush D$ and pipeline - CONTROLLER output logic fence_o, + // Flush microarchitecture - CONTROLLER + output logic fence_t_o, // Request a pipeline flush - CONTROLLER output logic flush_commit_o, // Flush TLBs and pipeline - CONTROLLER @@ -153,6 +155,7 @@ module commit_stage sfence_vma_o = 1'b0; hfence_vvma_o = 1'b0; hfence_gvma_o = 1'b0; + fence_t_o = 1'b0; csr_write_fflags_o = 1'b0; flush_commit_o = 1'b0; @@ -223,6 +226,16 @@ module commit_stage end end // ------------------ + // FENCE.T Logic + // ------------------ + // fence.t is idempotent so we can safely re-execute it after returning + // from interrupt service routine + if (commit_instr_i[0].op == FENCE_T) begin + commit_ack_o[0] = no_st_pending_i; + // tell the controller to flush the D$ + fence_t_o = no_st_pending_i; + end + // ------------------ // SFENCE.VMA Logic // ------------------ // sfence.vma is idempotent so we can safely re-execute it after returning @@ -318,6 +331,7 @@ module commit_stage if (commit_ack_o[0] && commit_instr_i[1].valid && !halt_i && !(commit_instr_i[0].fu inside {CSR}) + && (commit_instr_i[0].op != FENCE_T) && !flush_dcache_i && !(CVA6Cfg.RVA && instr_0_is_amo) && !single_step_i) begin diff --git a/core/controller.sv b/core/controller.sv index eae7f8f55b7..7c4c1d3629f 100644 --- a/core/controller.sv +++ b/core/controller.sv @@ -25,6 +25,8 @@ module controller input logic rst_ni, // Virtualization mode - CSR_REGFILE input logic v_i, + // Reset microarchitecture - SUBSYSTEM + output logic rst_uarch_no, // Set PC om PC Gen - FRONTEND output logic set_pc_commit_o, // Flush the IF stage - FRONTEND @@ -49,6 +51,12 @@ module controller output logic flush_tlb_vvma_o, // TO_BE_COMPLETED - TO_BE_COMPLETED output logic flush_tlb_gvma_o, + // Reset vector address - SUBSYSTEM + input logic [CVA6Cfg.VLEN-1:0] boot_addr_i, + // Reset vector address - FRONTEND + output logic [CVA6Cfg.VLEN-1:0] rst_addr_o, + // PC of currently commited instruction - EX_STAGE + input logic [CVA6Cfg.VLEN-1:0] pc_commit_i, // Halt request from CSR (WFI instruction) - CSR_REGFILE input logic halt_csr_i, // Halt request from accelerator dispatcher - ACC_DISPATCHER @@ -57,6 +65,22 @@ module controller output logic halt_frontend_o, // Halt signal to commit stage - COMMIT_STAGE output logic halt_o, + // Cache is busy - CACHE + input logic cache_busy_i, + // Let dcache not accept any new requests - CACHE + output logic stall_cache_o, + // Do not init cache - CACHE + output logic cache_init_no, + // Pad cycles of fence.t end relative to time interrupt - CSR_REGFILE + input logic [31:0] fence_t_pad_i, + // Source for time padding (timer_irq / priv mode switch) - CSR_REGFILE + input logic fence_t_src_sel_i, + // Largest recorded execution time of fence.t - CSR_REGFILE + output logic [31:0] fence_t_ceil_o, + // Time interrupt - CLINT + input logic time_irq_i, + // Current privilege level - CSR_REGFILE + input riscv::priv_lvl_t priv_lvl_i, // Return from exception - CSR_REGFILE input logic eret_i, // We got an exception, flush the pipeline - FRONTEND @@ -71,6 +95,8 @@ module controller input logic fence_i_i, // fence in - ACC_DISPATCH input logic fence_i, + // fence.t in - EX_STAGE + input logic fence_t_i, // We got an instruction to flush the TLBs and pipeline - COMMIT_STAGE input logic sfence_vma_i, // TO_BE_COMPLETED - TO_BE_COMPLETED @@ -85,14 +111,41 @@ module controller // active fence - high if we are currently flushing the dcache logic fence_active_d, fence_active_q; - logic flush_dcache; // Added fence_i_active state to track fence.i progress logic fence_i_active_d, fence_i_active_q; + logic flush_dcache; + + // Pad counter + logic [31:0] pad_cnt; + logic [ 3:0] drain_cnt; + logic time_irq_q; + riscv::priv_lvl_t priv_lvl_q; + + // cache init shift register. Keep 'no cache init' asserted for 3 cycles. + logic [2:0] cache_init_d, cache_init_q; + assign cache_init_d[2:1] = cache_init_q[1:0]; + assign cache_init_no = |cache_init_q; + + // address to fetch from after coming out of (uarch) reset + logic [CVA6Cfg.VLEN-1:0] rst_addr_d, rst_addr_q; + assign rst_addr_o = rst_addr_q; + + // fence.t FSM + typedef enum logic [2:0] { + IDLE, + FLUSH_DCACHE, + DRAIN_REQS, + PAD, + RST_UARCH + } fence_t_state_e; + fence_t_state_e fence_t_state_d, fence_t_state_q; + logic [3:0] rst_uarch_cnt_d, rst_uarch_cnt_q; // ------------ // Flush CTRL // ------------ always_comb begin : flush_ctrl + rst_addr_d = rst_addr_q; fence_active_d = fence_active_q; fence_i_active_d = fence_i_active_q; set_pc_commit_o = 1'b0; @@ -211,6 +264,18 @@ module controller flush_tlb_gvma_o = 1'b1; end + // --------------------------------- + // FENCE.T + // --------------------------------- + if (fence_t_i) begin + flush_icache_o = 1'b1; + flush_dcache = 1'b1; + fence_active_d = 1'b1; + + // Save PC to continue from after coming out of reset + rst_addr_d = pc_commit_i + {{CVA6Cfg.VLEN - 3{1'b0}}, 3'b100}; + end + // --------------------------------- // CSR side effects and accelerate port // --------------------------------- @@ -254,24 +319,134 @@ module controller // ---------------------- always_comb begin // halt the core if the fence is active - halt_o = halt_csr_i || halt_acc_i || ((CVA6Cfg.DcacheFlushOnFence || CVA6Cfg.DcacheFlushOnFenceI) && fence_active_q); + halt_o = halt_csr_i || halt_acc_i || ((CVA6Cfg.DcacheFlushOnFence || CVA6Cfg.DcacheFlushOnFenceI) && fence_active_q) || (fence_t_state_q != IDLE); // Halt frontend during fence.i to synchronize ICache/DCache flushes halt_frontend_o = fence_i_active_q; end + // ---------------------- + // Microreset Logic + // ---------------------- + always_comb begin : fence_t_fsm + // Default assignments + fence_t_state_d = fence_t_state_q; + rst_uarch_cnt_d = rst_uarch_cnt_q; + rst_uarch_no = 1'b1; + fence_t_ceil_o = '0; + cache_init_d[0] = 1'b0; + + unique case (fence_t_state_q) + // Idle + IDLE: begin + if (fence_t_i) fence_t_state_d = FLUSH_DCACHE; + end + + // Wait for dcache to acknowledge flush + FLUSH_DCACHE: begin + if (flush_dcache_ack_i) fence_t_state_d = DRAIN_REQS; + end + + // Wait for all pending (external) transactions to complete, + // s.t. we do not violate any handshake protocols. + DRAIN_REQS: begin + // The cache controls our only handshaked interface. + // Wait until it was idle for 16 cycles. + if (drain_cnt == 4'hf) begin + fence_t_state_d = PAD; + fence_t_ceil_o = (pad_cnt == '0) ? '0 : fence_t_pad_i - pad_cnt; + end + end + + // Wait for the padding to complete. + PAD: begin + if (pad_cnt == '0) fence_t_state_d = RST_UARCH; + end + + // Reset microarchitecture + RST_UARCH: begin + rst_uarch_no = 1'b0; + cache_init_d[0] = 1'b1; + + // Return to IDLE after 16 cycles + if (rst_uarch_cnt_q == 4'hf) begin + rst_uarch_cnt_d = 4'b0; + fence_t_state_d = IDLE; + end else begin + rst_uarch_cnt_d = rst_uarch_cnt_q + 1; + end + end + + // We should never reach this state + default: begin + fence_t_state_d = IDLE; + end + endcase + end + + + // Let the caches not accept any new memory requests during fence_t + assign stall_cache_o = (fence_t_state_q != IDLE); + + // Start padding either from CLINT timer interrupt [0] or exetinig leaving U-mode [1] + logic load_pad_cnt; + assign load_pad_cnt = fence_t_src_sel_i ? ((priv_lvl_q == riscv::PRIV_LVL_U) && (priv_lvl_i != riscv::PRIV_LVL_U)) + : (time_irq_i & ~time_irq_q); + + counter #( + .WIDTH (4), + .STICKY_OVERFLOW(0) + ) i_drain_cnt ( + .clk_i, + .rst_ni, + .clear_i (cache_busy_i), // Start counting from 0 when cache is busy + .en_i (drain_cnt != 4'hf), // Stop counting when saturated + .load_i (1'b0), + .down_i (1'b0), + .d_i ('0), + .q_o (drain_cnt), + .overflow_o() + ); + + counter #( + .WIDTH (32), + .STICKY_OVERFLOW(0) + ) i_pad_cnt ( + .clk_i, + .rst_ni, + .clear_i (1'b0), + .en_i (|pad_cnt), // Count until 0 + .load_i (load_pad_cnt), // Start counting on positive edge of time irq + .down_i (1'b1), // Always count down + .d_i (fence_t_pad_i), // Start counting from FENCE_T_CSR value + .q_o (pad_cnt), + .overflow_o() + ); + // ---------------------- // Registers // ---------------------- always_ff @(posedge clk_i or negedge rst_ni) begin if (~rst_ni) begin + fence_t_state_q <= IDLE; + rst_uarch_cnt_q <= 4'b0; fence_active_q <= 1'b0; fence_i_active_q <= 1'b0; flush_dcache_o <= 1'b0; + rst_addr_q <= boot_addr_i; + time_irq_q <= 1'b0; + priv_lvl_q <= riscv::PRIV_LVL_M; + cache_init_q <= '0; end else begin + fence_t_state_q <= fence_t_state_d; fence_active_q <= fence_active_d; fence_i_active_q <= fence_i_active_d; + rst_uarch_cnt_q <= rst_uarch_cnt_d; // register on the flush signal, this signal might be critical flush_dcache_o <= flush_dcache; + rst_addr_q <= rst_addr_d; + time_irq_q <= time_irq_i; + priv_lvl_q <= priv_lvl_i; + cache_init_q <= cache_init_d; end end endmodule diff --git a/core/csr_regfile.sv b/core/csr_regfile.sv index 6d268b8ca41..fb4bae03356 100644 --- a/core/csr_regfile.sv +++ b/core/csr_regfile.sv @@ -142,6 +142,10 @@ module csr_regfile output logic hcbcfe_o, // external interrupt in - SUBSYSTEM input logic [1:0] irq_i, + // interrupt request bit - CLIC + input logic clic_irq_req_i, + // selective hardware vectoring bit - CLIC + input logic clic_irq_shv_i, // inter processor interrupt -> connected to machine mode sw - SUBSYSTEM input logic ipi_i, // debug request in - ID_STAGE @@ -160,12 +164,30 @@ module csr_regfile output logic hu_o, // we are in debug mode -> that will change some decoding - EX_STAGE output logic debug_mode_o, + // CLIC mode - ID_STAGE + output logic clic_mode_o, + // TO_BE_COMPLETED - CLIC_CTRL + output riscv::intstatus_rv_t mintstatus_o, + // TO_BE_COMPLETED - CLIC_CTRL + output logic [7:0] mintthresh_o, + // TO_BE_COMPLETED - CLIC_CTRL + output logic [7:0] sintthresh_o, + // TO_BE_COMPLETED - CLIC_CTRL + output logic [7:0] vsintthresh_o, + // TO_BE_COMPLETED - CLIC_CTRL + output logic clic_irq_ready_o, // we are in single-step mode - COMMIT_STAGE output logic single_step_o, // L1 ICache Enable - CACHE output logic icache_en_o, // L1 DCache Enable - CACHE output logic dcache_en_o, + // Padding time of fence.t relative to time interrupt - CONTROLLER + output logic [31:0] fence_t_pad_o, + // Pad relative to selected source - CONTROLLER + output logic fence_t_src_sel_o, + // Largest recorded fence.t latency - CONTROLLER + input logic [31:0] fence_t_ceil_i, // Accelerator memory consistent mode - ACC_DISPATCHER output logic acc_cons_en_o, // read/write address to performance counter module - PERF_COUNTERS @@ -255,10 +277,13 @@ module csr_regfile logic [CVA6Cfg.XLEN-1:0] dscratch0_q, dscratch0_d; logic [CVA6Cfg.XLEN-1:0] dscratch1_q, dscratch1_d; logic [CVA6Cfg.XLEN-1:0] mtvec_q, mtvec_d; + logic [CVA6Cfg.XLEN-1:0] mtvt_q, mtvt_d; logic [CVA6Cfg.XLEN-1:0] medeleg_q, medeleg_d; logic [CVA6Cfg.XLEN-1:0] mideleg_q, mideleg_d; logic [CVA6Cfg.XLEN-1:0] mip_q, mip_d; logic [CVA6Cfg.XLEN-1:0] mie_q, mie_d; + riscv::intstatus_rv_t mintstatus_q, mintstatus_d; + riscv::intthresh_rv_t mintthresh_q, mintthresh_d; logic [CVA6Cfg.XLEN-1:0] mcounteren_q, mcounteren_d; logic [CVA6Cfg.XLEN-1:0] mscratch_q, mscratch_d; logic [CVA6Cfg.XLEN-1:0] mepc_q, mepc_d; @@ -266,10 +291,14 @@ module csr_regfile logic [CVA6Cfg.XLEN-1:0] mtval_q, mtval_d; logic [CVA6Cfg.XLEN-1:0] mtinst_q, mtinst_d; logic [CVA6Cfg.XLEN-1:0] mtval2_q, mtval2_d; - logic fiom_d, fiom_q; + logic mfiom_d, mfiom_q; + logic sfiom_d, sfiom_q; + logic hfiom_d, hfiom_q; logic [CVA6Cfg.XLEN-1:0] stvec_q, stvec_d; + riscv::intthresh_rv_t sintthresh_q, sintthresh_d; logic [CVA6Cfg.XLEN-1:0] scounteren_q, scounteren_d; + logic [CVA6Cfg.XLEN-1:0] stvt_q, stvt_d; logic [CVA6Cfg.XLEN-1:0] sscratch_q, sscratch_d; logic [CVA6Cfg.XLEN-1:0] sepc_q, sepc_d; logic [CVA6Cfg.XLEN-1:0] scause_q, scause_d; @@ -283,13 +312,18 @@ module csr_regfile logic [CVA6Cfg.XLEN-1:0] htval_q, htval_d; logic [CVA6Cfg.XLEN-1:0] vstvec_q, vstvec_d; + logic [CVA6Cfg.XLEN-1:0] vstvt_q, vstvt_d; logic [CVA6Cfg.XLEN-1:0] vsscratch_q, vsscratch_d; logic [CVA6Cfg.XLEN-1:0] vsepc_q, vsepc_d; logic [CVA6Cfg.XLEN-1:0] vscause_q, vscause_d; logic [CVA6Cfg.XLEN-1:0] vstval_q, vstval_d; + riscv::intthresh_rv_t vsintthresh_q, vsintthresh_d; logic [CVA6Cfg.XLEN-1:0] dcache_q, dcache_d; logic [CVA6Cfg.XLEN-1:0] icache_q, icache_d; + logic [CVA6Cfg.XLEN-1:0] fence_t_pad_q, fence_t_pad_d; + logic [CVA6Cfg.XLEN-1:0] fence_t_sel_q, fence_t_sel_d; + logic [CVA6Cfg.XLEN-1:0] fence_t_ceil_q, fence_t_ceil_d; logic [CVA6Cfg.XLEN-1:0] acc_cons_q, acc_cons_d; logic wfi_d, wfi_q; @@ -367,6 +401,26 @@ module csr_regfile assign vsstatus_extended = '0; end + if (CVA6Cfg.RVSCLIC) begin : gen_clic_csr_signals + assign clic_mode_o = &mtvec_q[1:0]; + assign mintstatus_o = mintstatus_q; + assign mintthresh_o = mintthresh_q.th; + assign sintthresh_o = sintthresh_q.th; + assign clic_irq_ready_o = clic_mode_o & ex_i.valid & ex_i.cause[CVA6Cfg.XLEN-1]; + end else begin : gen_dummy_clic_csr_signals + assign clic_mode_o = 1'b0; + assign mintstatus_o = '0; + assign mintthresh_o = '0; + assign sintthresh_o = '0; + assign clic_irq_ready_o = 1'b0; + end + + if (CVA6Cfg.RVXHCLIC) begin : gen_clic_vsintthresh_signal + assign vsintthresh_o = vsintthresh_q.th; + end else begin : gen_dummy_clic_vsintthresh_signal + assign vsintthresh_o = '0; + end + always_comb begin : csr_read_process // a read access exception can only occur if we attempt to read a CSR which does not exist read_access_exception = 1'b0; @@ -455,15 +509,19 @@ module csr_regfile else read_access_exception = 1'b1; riscv::CSR_VSIE: if (CVA6Cfg.RVH) - csr_rdata = (mie_q & VS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] & hideleg_q) >> 1; + csr_rdata = (CVA6Cfg.RVXHCLIC && clic_mode_o) ? '0 : ((mie_q & VS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] & hideleg_q) >> 1); else read_access_exception = 1'b1; riscv::CSR_VSIP: if (CVA6Cfg.RVH) - csr_rdata = (mip_q & VS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] & hideleg_q) >> 1; + csr_rdata = (CVA6Cfg.RVXHCLIC && clic_mode_o) ? '0 : ((mip_q & VS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] & hideleg_q) >> 1); else read_access_exception = 1'b1; riscv::CSR_VSTVEC: if (CVA6Cfg.RVH) csr_rdata = vstvec_q; else read_access_exception = 1'b1; + riscv::CSR_VSTVT: + if (CVA6Cfg.RVXHCLIC) + csr_rdata = clic_mode_o ? {vstvt_q, 8'b0} : '0; // vstvt reads 0 in CLINT mode + else read_access_exception = 1'b1; riscv::CSR_VSSCRATCH: if (CVA6Cfg.RVH) csr_rdata = vsscratch_q; else read_access_exception = 1'b1; @@ -485,6 +543,10 @@ module csr_regfile end else begin read_access_exception = 1'b1; end + riscv::CSR_VSINTTHRESH: + if (CVA6Cfg.RVXHCLIC) + csr_rdata = clic_mode_o ? {{CVA6Cfg.XLEN - 8{1'b0}}, vsintthresh_q} : '0; // vsintthresh reads 0 in CLINT mode + else read_access_exception = 1'b1; // supervisor registers riscv::CSR_SSTATUS: begin if (CVA6Cfg.RVS) csr_rdata = mstatus_extended & SMODE_STATUS_READ_MASK[CVA6Cfg.XLEN-1:0]; @@ -492,27 +554,62 @@ module csr_regfile end riscv::CSR_SIE: if (CVA6Cfg.RVS) - csr_rdata = (CVA6Cfg.RVH) ? mie_q & mideleg_q & ~HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] : mie_q & mideleg_q; + csr_rdata = clic_mode_o ? '0 : ((CVA6Cfg.RVH) ? mie_q & mideleg_q & ~HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] : mie_q & mideleg_q); else read_access_exception = 1'b1; riscv::CSR_SIP: if (CVA6Cfg.RVS) - csr_rdata = (CVA6Cfg.RVH) ? mip_q & mideleg_q & ~HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] : mip_q & mideleg_q; + csr_rdata = clic_mode_o ? '0 : ((CVA6Cfg.RVH) ? mip_q & mideleg_q & ~HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] : mip_q & mideleg_q); else read_access_exception = 1'b1; riscv::CSR_STVEC: - if (CVA6Cfg.RVS) csr_rdata = stvec_q; + if (CVA6Cfg.RVS) + csr_rdata = clic_mode_o ? {stvec_q[CVA6Cfg.XLEN-1:6], 6'b11} : {stvec_q[CVA6Cfg.XLEN-1:6], 5'b0, stvec_q[0]}; else read_access_exception = 1'b1; + riscv::CSR_SINTSTATUS: begin + if (CVA6Cfg.RVS && CVA6Cfg.RVSCLIC) begin + // sintstatus reads 0 from CLINT mode + // Return a restricted view of mintstatus (sil and uil) + csr_rdata = clic_mode_o ? {{CVA6Cfg.XLEN - 16{1'b0}}, mintstatus_q[15:0]} : '0; + end else begin + read_access_exception = 1'b1; + end + end + riscv::CSR_SINTTHRESH: begin + if (CVA6Cfg.RVS && CVA6Cfg.RVSCLIC) begin + // sintthresh reads 0 from CLINT mode + csr_rdata = clic_mode_o ? {{CVA6Cfg.XLEN - 8{1'b0}}, sintthresh_q} : '0; + end else begin + read_access_exception = 1'b1; + end + end riscv::CSR_SCOUNTEREN: if (CVA6Cfg.RVS) csr_rdata = scounteren_q; else read_access_exception = 1'b1; + riscv::CSR_STVT: begin + if (CVA6Cfg.RVS && CVA6Cfg.RVSCLIC) begin + // stvt reads 0 from CLINT mode + csr_rdata = clic_mode_o ? stvt_q : '0; + end else begin + read_access_exception = 1'b1; + end + end riscv::CSR_SSCRATCH: if (CVA6Cfg.RVS) csr_rdata = sscratch_q; else read_access_exception = 1'b1; riscv::CSR_SEPC: if (CVA6Cfg.RVS) csr_rdata = sepc_q; else read_access_exception = 1'b1; - riscv::CSR_SCAUSE: - if (CVA6Cfg.RVS) csr_rdata = scause_q; - else read_access_exception = 1'b1; + riscv::CSR_SCAUSE: begin + if (CVA6Cfg.RVS) begin + csr_rdata = scause_q; + // In CLIC mode, reading or writing mstatus fields spp/spie in mcause is + // equivalent to reading or writing the homonymous field in mstatus. + if (CVA6Cfg.RVSCLIC && clic_mode_o) begin + csr_rdata[29:27] = {1'b0, mstatus_q.spp, mstatus_q.spie}; + end + end else begin + read_access_exception = 1'b1; + end + end riscv::CSR_STVAL: if (CVA6Cfg.RVS) csr_rdata = stval_q; else read_access_exception = 1'b1; @@ -530,7 +627,7 @@ module csr_regfile end riscv::CSR_SENVCFG: begin if (CVA6Cfg.RVS) begin - csr_rdata = '0 | fiom_q; + csr_rdata = '0 | sfiom_q; if (CVA6Cfg.RVZiCbom) begin csr_rdata[5:4] = scbie_q; csr_rdata[6] = scbcfe_q; @@ -550,13 +647,16 @@ module csr_regfile if (CVA6Cfg.RVH) csr_rdata = hideleg_q; else read_access_exception = 1'b1; riscv::CSR_HIE: - if (CVA6Cfg.RVH) csr_rdata = mie_q & HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0]; + if (CVA6Cfg.RVH) + csr_rdata = (CVA6Cfg.RVXHCLIC && clic_mode_o) ? (mie_q & riscv::MIP_SGEIP) : (mie_q & HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0]); else read_access_exception = 1'b1; riscv::CSR_HIP: - if (CVA6Cfg.RVH) csr_rdata = mip_q & HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0]; + if (CVA6Cfg.RVH) + csr_rdata = (CVA6Cfg.RVXHCLIC && clic_mode_o) ? '0 : (mip_q & HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0]); else read_access_exception = 1'b1; riscv::CSR_HVIP: - if (CVA6Cfg.RVH) csr_rdata = mip_q & VS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0]; + if (CVA6Cfg.RVH) + csr_rdata = (CVA6Cfg.RVXHCLIC && clic_mode_o) ? '0 : (mip_q & VS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0]); else read_access_exception = 1'b1; riscv::CSR_HCOUNTEREN: if (CVA6Cfg.RVH) csr_rdata = hcounteren_q; @@ -568,14 +668,14 @@ module csr_regfile if (CVA6Cfg.RVH) csr_rdata = htinst_q; else read_access_exception = 1'b1; riscv::CSR_HGEIE: - if (CVA6Cfg.RVH) csr_rdata = '0; + if (CVA6Cfg.RVH) csr_rdata = {hgeie_q[CVA6Cfg.XLEN-1:1], 1'b0}; else read_access_exception = 1'b1; riscv::CSR_HGEIP: if (CVA6Cfg.RVH) csr_rdata = '0; else read_access_exception = 1'b1; riscv::CSR_HENVCFG: begin if (CVA6Cfg.RVH) begin - csr_rdata = '0 | {{CVA6Cfg.XLEN - 1{1'b0}}, fiom_q}; + csr_rdata = '0 | {{CVA6Cfg.XLEN - 1{1'b0}}, hfiom_q}; if (CVA6Cfg.RVZiCbom) begin csr_rdata[5:4] = hcbie_q; csr_rdata[6] = hcbcfe_q; @@ -609,14 +709,22 @@ module csr_regfile riscv::CSR_MIDELEG: if (CVA6Cfg.RVS) csr_rdata = mideleg_q; else read_access_exception = 1'b1; - riscv::CSR_MIE: csr_rdata = mie_q; + riscv::CSR_MIE: csr_rdata = clic_mode_o ? '0 : mie_q; riscv::CSR_MTVEC: csr_rdata = mtvec_q; riscv::CSR_MCOUNTEREN: if (CVA6Cfg.RVU) csr_rdata = mcounteren_q; else read_access_exception = 1'b1; + riscv::CSR_MTVT: csr_rdata = mtvt_q; riscv::CSR_MSCRATCH: csr_rdata = mscratch_q; riscv::CSR_MEPC: csr_rdata = mepc_q; - riscv::CSR_MCAUSE: csr_rdata = mcause_q; + riscv::CSR_MCAUSE: begin + csr_rdata = mcause_q; + // In CLIC mode, reading or writing mstatus fields mpp/mpie in mcause is + // equivalent to reading or writing the homonymous field in mstatus. + if (CVA6Cfg.RVSCLIC && clic_mode_o) begin + csr_rdata[29:27] = {mstatus_q.mpp, mstatus_q.mpie}; + end + end riscv::CSR_MTVAL: if (CVA6Cfg.TvalEn) csr_rdata = mtval_q; else csr_rdata = '0; @@ -626,11 +734,27 @@ module csr_regfile riscv::CSR_MTVAL2: if (CVA6Cfg.RVH) csr_rdata = mtval2_q; else read_access_exception = 1'b1; - riscv::CSR_MIP: csr_rdata = mip_q; + riscv::CSR_MIP: csr_rdata = clic_mode_o ? '0 : mip_q; + riscv::CSR_MINTSTATUS: begin + if (CVA6Cfg.RVSCLIC) begin + // mintstatus reads 0 from CLINT mode + csr_rdata = clic_mode_o ? {{CVA6Cfg.XLEN - 32{1'b0}}, mintstatus_q} : '0; + end else begin + read_access_exception = 1'b1; + end + end + riscv::CSR_MINTTHRESH: begin + if (CVA6Cfg.RVSCLIC) begin + // mintthresh reads 0 from CLINT mode + csr_rdata = clic_mode_o ? {{CVA6Cfg.XLEN - 8{1'b0}}, mintthresh_q} : '0; + end else begin + read_access_exception = 1'b1; + end + end riscv::CSR_MENVCFG: begin csr_rdata = '0; if (CVA6Cfg.RVU) begin - csr_rdata = '0 | fiom_q; + csr_rdata = '0 | mfiom_q; end if (CVA6Cfg.RVZiCbom) begin csr_rdata[5:4] = mcbie_q; @@ -846,6 +970,9 @@ module csr_regfile // custom (non RISC-V) cache control riscv::CSR_DCACHE: csr_rdata = dcache_q; riscv::CSR_ICACHE: csr_rdata = icache_q; + riscv::CSR_FENCE_T_PAD: csr_rdata = fence_t_pad_q; + riscv::CSR_FENCE_T_SEL: csr_rdata = fence_t_sel_q; + riscv::CSR_FENCE_T_CEIL: csr_rdata = fence_t_ceil_q; // custom (non RISC-V) accelerator memory consistency mode riscv::CSR_ACC_CONS: begin if (CVA6Cfg.EnableAccelerator) begin @@ -1048,9 +1175,12 @@ module csr_regfile end mip_d = mip_q; mie_d = mie_q; + mintstatus_d = mintstatus_q; + mintthresh_d = mintthresh_q; mepc_d = mepc_q; mcause_d = mcause_q; mcounteren_d = mcounteren_q; + mtvt_d = mtvt_q; mscratch_d = mscratch_q; if (CVA6Cfg.TvalEn) mtval_d = mtval_q; if (CVA6Cfg.RVH) begin @@ -1058,9 +1188,15 @@ module csr_regfile mtval2_d = mtval2_q; end - fiom_d = fiom_q; - dcache_d = dcache_q; - icache_d = icache_q; + fence_t_pad_d = fence_t_pad_q; + fence_t_sel_d = fence_t_sel_q; + fence_t_ceil_d = fence_t_ceil_q; + + mfiom_d = mfiom_q; + sfiom_d = sfiom_q; + hfiom_d = hfiom_q; + dcache_d = dcache_q; + icache_d = icache_q; acc_cons_d = acc_cons_q; if (CVA6Cfg.RVH) begin @@ -1080,11 +1216,18 @@ module csr_regfile en_ld_st_g_translation_d = en_ld_st_g_translation_q; end + if (CVA6Cfg.RVXHCLIC) begin + vstvt_d = vstvt_q; + vsintthresh_d = vsintthresh_q; + end + if (CVA6Cfg.RVS) begin sepc_d = sepc_q; scause_d = scause_q; stvec_d = stvec_q; + sintthresh_d = sintthresh_q; scounteren_d = scounteren_q; + stvt_d = stvt_q; sscratch_d = sscratch_q; stval_d = stval_q; satp_d = satp_q; @@ -1247,13 +1390,19 @@ module csr_regfile end end riscv::CSR_VSIE: - if (CVA6Cfg.RVH) mie_d = (mie_q & ~hideleg_q) | ((csr_wdata << 1) & hideleg_q); - else update_access_exception = 1'b1; + if (CVA6Cfg.RVH) begin + // Writes are legal but ignored in CLIC mode + if (!(CVA6Cfg.RVXHCLIC && clic_mode_o)) + mie_d = (mie_q & ~hideleg_q) | ((csr_wdata << 1) & hideleg_q); + end else update_access_exception = 1'b1; riscv::CSR_VSIP: begin if (CVA6Cfg.RVH) begin - // only the virtual supervisor software interrupt is write-able, iff delegated - mask = CVA6Cfg.XLEN'(riscv::MIP_VSSIP) & hideleg_q; - mip_d = (mip_q & ~mask) | ((csr_wdata << 1) & mask); + // Writes are legal but ignored in CLIC mode + if (!(CVA6Cfg.RVXHCLIC && clic_mode_o)) begin + // only the virtual supervisor software interrupt is write-able, iff delegated + mask = CVA6Cfg.XLEN'(riscv::MIP_VSSIP) & hideleg_q; + mip_d = (mip_q & ~mask) | ((csr_wdata << 1) & mask); + end end else begin update_access_exception = 1'b1; end @@ -1265,6 +1414,12 @@ module csr_regfile update_access_exception = 1'b1; end end + riscv::CSR_VSTVT: begin + if (CVA6Cfg.RVXHCLIC) begin + // Writes are legal but ignored in CLINT mode + if (clic_mode_o) vstvt_d = csr_wdata[CVA6Cfg.XLEN-1:8]; + end else update_access_exception = 1'b1; + end riscv::CSR_VSSCRATCH: if (CVA6Cfg.RVH) vsscratch_d = csr_wdata; else update_access_exception = 1'b1; @@ -1298,6 +1453,12 @@ module csr_regfile update_access_exception = 1'b1; end end + riscv::CSR_VSINTTHRESH: begin + if (CVA6Cfg.RVXHCLIC) begin + // Writes are legal but ignored in CLINT mode + if (clic_mode_o) vsintthresh_d.th = csr_wdata[7:0]; + end else update_access_exception = 1'b1; + end // sstatus is a subset of mstatus - mask it accordingly riscv::CSR_SSTATUS: begin if (CVA6Cfg.RVS) begin @@ -1327,9 +1488,10 @@ module csr_regfile // if the corresponding bit in mideleg is set riscv::CSR_SIE: begin if (CVA6Cfg.RVS) begin - mask = (CVA6Cfg.RVH) ? mideleg_q & ~HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] : mideleg_q; + mask = (CVA6Cfg.RVH) ? mideleg_q & ~HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] : mideleg_q; // the mideleg makes sure only delegate-able register (and therefore also only implemented registers) are written - mie_d = (mie_q & ~mask) | (csr_wdata & mask); + if (!clic_mode_o) mie_d = (mie_q & ~mask) | (csr_wdata & mask); + // In CLIC mode, writes to SIE are ignored. end else begin update_access_exception = 1'b1; end @@ -1337,20 +1499,44 @@ module csr_regfile riscv::CSR_SIP: begin if (CVA6Cfg.RVS) begin - // only the supervisor software interrupt is write-able, iff delegated - mask = CVA6Cfg.XLEN'(riscv::MIP_SSIP) & mideleg_q; - mip_d = (mip_q & ~mask) | (csr_wdata & mask); + // In CLIC mode, writes to SIP are ignored. + if (!clic_mode_o) begin + // only the supervisor software interrupt is write-able, iff delegated + mask = CVA6Cfg.XLEN'(riscv::MIP_SSIP) & mideleg_q; + mip_d = (mip_q & ~mask) | (csr_wdata & mask); + end end else begin update_access_exception = 1'b1; end end riscv::CSR_STVEC: - if (CVA6Cfg.RVS) stvec_d = {csr_wdata[CVA6Cfg.XLEN-1:2], 1'b0, csr_wdata[0]}; + if (CVA6Cfg.RVS) + stvec_d = clic_mode_o ? {csr_wdata[CVA6Cfg.XLEN-1:2], 2'b11} : {csr_wdata[CVA6Cfg.XLEN-1:2], 1'b0, csr_wdata[0]}; else update_access_exception = 1'b1; riscv::CSR_SCOUNTEREN: if (CVA6Cfg.RVS) scounteren_d = {{CVA6Cfg.XLEN - 32{1'b0}}, csr_wdata[31:0]}; else update_access_exception = 1'b1; + riscv::CSR_STVT: begin + if (CVA6Cfg.RVS && CVA6Cfg.RVSCLIC) begin + // Writes are legal but ignored in CLINT mode + if (clic_mode_o) begin + stvt_d = {csr_wdata[CVA6Cfg.XLEN-1:8], 8'b0}; + end + end else begin + update_access_exception = 1'b1; + end + end + riscv::CSR_SINTTHRESH: begin + if (CVA6Cfg.RVS && CVA6Cfg.RVSCLIC) begin + // Writes are legal but ignored in CLINT mode + if (clic_mode_o) begin + sintthresh_d.th = csr_wdata[7:0]; + end + end else begin + update_access_exception = 1'b1; + end + end riscv::CSR_SSCRATCH: if (CVA6Cfg.RVS) sscratch_d = csr_wdata; else update_access_exception = 1'b1; @@ -1386,7 +1572,7 @@ module csr_regfile end riscv::CSR_SENVCFG: begin if (CVA6Cfg.RVS) begin - fiom_d = csr_wdata[0]; + sfiom_d = csr_wdata[0]; if (CVA6Cfg.RVZiCbom) begin unique case (csr_wdata[5:4]) 2'b00: scbie_d = riscv::CBIE_ILLEGAL; @@ -1439,7 +1625,8 @@ module csr_regfile end riscv::CSR_HIE: begin if (CVA6Cfg.RVH) begin - mask = HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0]; + // In CLIC mode only SGEIE bit is writable + mask = (CVA6Cfg.RVXHCLIC && clic_mode_o) ? CVA6Cfg.XLEN'(riscv::MIP_SGEIP) : HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0]; mie_d = (mie_q & ~mask) | (csr_wdata & mask); end else begin update_access_exception = 1'b1; @@ -1447,8 +1634,11 @@ module csr_regfile end riscv::CSR_HIP: begin if (CVA6Cfg.RVH) begin - mask = CVA6Cfg.XLEN'(riscv::MIP_VSSIP); - mip_d = (mip_q & ~mask) | (csr_wdata & mask); + // Writes are legal but ignored in CLIC mode + if (!(CVA6Cfg.RVXHCLIC && clic_mode_o)) begin + mask = CVA6Cfg.XLEN'(riscv::MIP_VSSIP); + mip_d = (mip_q & ~mask) | (csr_wdata & mask); + end end else begin update_access_exception = 1'b1; end @@ -1482,12 +1672,9 @@ module csr_regfile update_access_exception = 1'b1; end end - //TODO Hyp: implement hgeie write - riscv::CSR_HGEIE: begin - if (!CVA6Cfg.RVH) begin - update_access_exception = 1'b1; - end - end + riscv::CSR_HGEIE: + if (CVA6Cfg.RVH) hgeie_d = {csr_wdata[CVA6Cfg.XLEN-1:1], 1'b0}; + else update_access_exception = 1'b1; riscv::CSR_HGATP: begin if (CVA6Cfg.RVH) begin // intercept HGATP writes if in HS-Mode and TVM is enabled @@ -1513,7 +1700,7 @@ module csr_regfile end riscv::CSR_HENVCFG: begin if (CVA6Cfg.RVH) begin - fiom_d = csr_wdata[0]; + hfiom_d = csr_wdata[0]; if (CVA6Cfg.RVZiCbom) begin unique case (csr_wdata[5:4]) 2'b00: hcbie_d = riscv::CBIE_ILLEGAL; @@ -1622,34 +1809,37 @@ module csr_regfile end // mask the register so that unsupported interrupts can never be set riscv::CSR_MIE: begin - if (CVA6Cfg.RVH) begin - mask = HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] - | CVA6Cfg.XLEN'(riscv::MIP_SSIP) - | CVA6Cfg.XLEN'(riscv::MIP_STIP) - | CVA6Cfg.XLEN'(riscv::MIP_SEIP) - | CVA6Cfg.XLEN'(riscv::MIP_MSIP) - | CVA6Cfg.XLEN'(riscv::MIP_MTIP) - | CVA6Cfg.XLEN'(riscv::MIP_MEIP); - end else begin - if (CVA6Cfg.RVS) begin - mask = CVA6Cfg.XLEN'(riscv::MIP_SSIP) + // In CLIC mode, writes to MIE are ignored. + if (!clic_mode_o) begin + if (CVA6Cfg.RVH) begin + mask = HS_DELEG_INTERRUPTS[CVA6Cfg.XLEN-1:0] + | CVA6Cfg.XLEN'(riscv::MIP_SSIP) | CVA6Cfg.XLEN'(riscv::MIP_STIP) | CVA6Cfg.XLEN'(riscv::MIP_SEIP) | CVA6Cfg.XLEN'(riscv::MIP_MSIP) | CVA6Cfg.XLEN'(riscv::MIP_MTIP) | CVA6Cfg.XLEN'(riscv::MIP_MEIP); end else begin - if (CVA6Cfg.SoftwareInterruptEn) begin - mask = CVA6Cfg.XLEN'(riscv::MIP_MSIP) // same shift as MSIE - | CVA6Cfg.XLEN'(riscv::MIP_MTIP) // same shift as MTIE - | CVA6Cfg.XLEN'(riscv::MIP_MEIP); // same shift as MEIE + if (CVA6Cfg.RVS) begin + mask = CVA6Cfg.XLEN'(riscv::MIP_SSIP) + | CVA6Cfg.XLEN'(riscv::MIP_STIP) + | CVA6Cfg.XLEN'(riscv::MIP_SEIP) + | CVA6Cfg.XLEN'(riscv::MIP_MSIP) + | CVA6Cfg.XLEN'(riscv::MIP_MTIP) + | CVA6Cfg.XLEN'(riscv::MIP_MEIP); end else begin - mask = CVA6Cfg.XLEN'(riscv::MIP_MTIP) // same shift as MTIE - | CVA6Cfg.XLEN'(riscv::MIP_MEIP); // same shift as MEIE + if (CVA6Cfg.SoftwareInterruptEn) begin + mask = CVA6Cfg.XLEN'(riscv::MIP_MSIP) // same shift as MSIE + | CVA6Cfg.XLEN'(riscv::MIP_MTIP) // same shift as MTIE + | CVA6Cfg.XLEN'(riscv::MIP_MEIP); // same shift as MEIE + end else begin + mask = CVA6Cfg.XLEN'(riscv::MIP_MTIP) // same shift as MTIE + | CVA6Cfg.XLEN'(riscv::MIP_MEIP); // same shift as MEIE + end end end + mie_d = (mie_q & ~mask) | (csr_wdata & mask); // we only support supervisor and M-mode interrupts end - mie_d = (mie_q & ~mask) | (csr_wdata & mask); // we only support supervisor and M-mode interrupts end riscv::CSR_MTVEC: begin @@ -1659,11 +1849,25 @@ module csr_regfile // we are in vector mode, this implementation requires the additional // alignment constraint of 64 * 4 bytes if (DirVecOnly) mtvec_d = {csr_wdata[CVA6Cfg.XLEN-1:8], 7'b0, DirVecOnly}; + // we are in CLIC mode. + if (CVA6Cfg.RVSCLIC && &csr_wdata[1:0]) + mtvec_d = {csr_wdata[CVA6Cfg.XLEN-1:8], 6'b0, csr_wdata[1:0]}; + end riscv::CSR_MCOUNTEREN: begin if (CVA6Cfg.RVU) mcounteren_d = {{CVA6Cfg.XLEN - 32{1'b0}}, csr_wdata[31:0]}; else update_access_exception = 1'b1; end + riscv::CSR_MTVT: begin + if (CVA6Cfg.RVSCLIC) begin + // Writes are legal but ignored in CLINT mode + if (clic_mode_o) begin + mtvt_d = {csr_wdata[CVA6Cfg.XLEN-1:8], 8'b0}; + end + end else begin + update_access_exception = 1'b1; + end + end riscv::CSR_MSCRATCH: mscratch_d = csr_wdata; riscv::CSR_MEPC: mepc_d = {csr_wdata[CVA6Cfg.XLEN-1:1], 1'b0}; @@ -1678,23 +1882,26 @@ module csr_regfile if (CVA6Cfg.RVH) mtval2_d = csr_wdata; else update_access_exception = 1'b1; riscv::CSR_MIP: begin - if (CVA6Cfg.RVH) begin - mask = CVA6Cfg.XLEN'(riscv::MIP_SSIP) - | CVA6Cfg.XLEN'(riscv::MIP_STIP) - | CVA6Cfg.XLEN'(riscv::MIP_SEIP) - | CVA6Cfg.XLEN'(riscv::MIP_VSSIP); - end else if (CVA6Cfg.RVS) begin - mask = CVA6Cfg.XLEN'(riscv::MIP_SSIP) - | CVA6Cfg.XLEN'(riscv::MIP_STIP) - | CVA6Cfg.XLEN'(riscv::MIP_SEIP); - end else begin - mask = '0; + // In CLIC mode, writes to MIP are ignored. + if (!clic_mode_o) begin + if (CVA6Cfg.RVH) begin + mask = CVA6Cfg.XLEN'(riscv::MIP_SSIP) + | CVA6Cfg.XLEN'(riscv::MIP_STIP) + | CVA6Cfg.XLEN'(riscv::MIP_SEIP) + | CVA6Cfg.XLEN'(riscv::MIP_VSSIP); + end else if (CVA6Cfg.RVS) begin + mask = CVA6Cfg.XLEN'(riscv::MIP_SSIP) + | CVA6Cfg.XLEN'(riscv::MIP_STIP) + | CVA6Cfg.XLEN'(riscv::MIP_SEIP); + end else begin + mask = '0; + end + mip_d = (mip_q & ~mask) | (csr_wdata & mask); end - mip_d = (mip_q & ~mask) | (csr_wdata & mask); end riscv::CSR_MENVCFG: begin if (CVA6Cfg.RVU) begin - fiom_d = csr_wdata[0]; + mfiom_d = csr_wdata[0]; end if (CVA6Cfg.RVZiCbom) begin unique case (csr_wdata[5:4]) @@ -1713,6 +1920,16 @@ module csr_regfile if (CVA6Cfg.PerfCounterEn) mcountinhibit_d = {csr_wdata[MHPMCounterNum+2:2], 1'b0, csr_wdata[0]}; else mcountinhibit_d = '0; + riscv::CSR_MINTTHRESH: begin + if (CVA6Cfg.RVSCLIC) begin + // Writes are legal but ignored in CLINT mode + if (clic_mode_o) begin + mintthresh_d.th = csr_wdata[7:0]; + end + end else begin + update_access_exception = 1'b1; + end + end // performance counters riscv::CSR_MCYCLE: cycle_d[CVA6Cfg.XLEN-1:0] = csr_wdata; riscv::CSR_MCYCLEH: @@ -1825,6 +2042,9 @@ module csr_regfile riscv::CSR_DCACHE: dcache_d = {{CVA6Cfg.XLEN - 1{1'b0}}, csr_wdata[0]}; // enable bit riscv::CSR_ICACHE: icache_d = {{CVA6Cfg.XLEN - 1{1'b0}}, csr_wdata[0]}; // enable bit + riscv::CSR_FENCE_T_PAD: fence_t_pad_d = {{CVA6Cfg.XLEN - 32{1'b0}}, csr_wdata[31:0]}; + riscv::CSR_FENCE_T_SEL: fence_t_sel_d = {{CVA6Cfg.XLEN - 1{1'b0}}, csr_wdata[0]}; + riscv::CSR_FENCE_T_CEIL: fence_t_ceil_d = {{CVA6Cfg.XLEN - 32{1'b0}}, csr_wdata[31:0]}; riscv::CSR_ACC_CONS: begin if (CVA6Cfg.EnableAccelerator) begin acc_cons_d = {{CVA6Cfg.XLEN - 1{1'b0}}, csr_wdata[0]}; // enable bit @@ -2016,10 +2236,11 @@ module csr_regfile // a m-mode trap might be delegated if we are taking it in S mode // first figure out if this was an exception or an interrupt e.g.: look at bit (XLEN-1) // the cause register can only be $clog2(CVA6Cfg.XLEN) bits long (as we only support XLEN exceptions) + // In CLIC mode, xideleg ceases to have effect. if (CVA6Cfg.RVS) begin if ((ex_i.cause[CVA6Cfg.XLEN-1] && mideleg_q[ex_i.cause[$clog2( CVA6Cfg.XLEN - )-1:0]]) || (~ex_i.cause[CVA6Cfg.XLEN-1] && medeleg_q[ex_i.cause[$clog2( + )-1:0]] && ~clic_mode_o) || (~ex_i.cause[CVA6Cfg.XLEN-1] && medeleg_q[ex_i.cause[$clog2( CVA6Cfg.XLEN )-1:0]])) begin // traps never transition from a more-privileged mode to a less privileged mode @@ -2035,6 +2256,9 @@ module csr_regfile trap_to_v = v_q; end end + end else if (ex_i.cause[CVA6Cfg.XLEN-1] && clic_mode_o) begin + trap_to_priv_lvl = riscv::priv_lvl_t'(ex_i.cause[25:24]); + if (CVA6Cfg.RVXHCLIC) trap_to_v = ex_i.cause[26]; end end @@ -2047,7 +2271,12 @@ module csr_regfile // this can either be user or supervisor mode vsstatus_d.spp = priv_lvl_q[0]; // set cause - vscause_d = ex_i.cause[CVA6Cfg.XLEN-1] ? {ex_i.cause[CVA6Cfg.XLEN-1:2], 2'b01} : ex_i.cause; + vscause_d = (~clic_mode_o && ex_i.cause[CVA6Cfg.XLEN-1]) ? {ex_i.cause[CVA6Cfg.XLEN-1:2], 2'b01} : ex_i.cause; + // update the current and previous interrupt level + if (CVA6Cfg.RVXHCLIC && clic_mode_o && ex_i.cause[CVA6Cfg.XLEN-1]) begin + mintstatus_d.vsil = ex_i.cause[23:16]; + vscause_d[23:16] = mintstatus_q.vsil; + end // set epc vsepc_d = {{CVA6Cfg.XLEN - CVA6Cfg.VLEN{pc_i[CVA6Cfg.VLEN-1]}}, pc_i}; // set vstval @@ -2065,6 +2294,11 @@ module csr_regfile mstatus_d.spp = priv_lvl_q[0]; // set cause scause_d = ex_i.cause; + // update the current and previous interrupt level + if (CVA6Cfg.RVSCLIC && clic_mode_o && ex_i.cause[CVA6Cfg.XLEN-1]) begin + mintstatus_d.sil = ex_i.cause[23:16]; + scause_d[23:16] = mintstatus_q.sil; + end // set epc sepc_d = {{CVA6Cfg.XLEN - CVA6Cfg.VLEN{pc_i[CVA6Cfg.VLEN-1]}}, pc_i}; // set mtval or stval @@ -2102,7 +2336,12 @@ module csr_regfile mstatus_d.mpie = mstatus_q.mie; // save the previous privilege mode mstatus_d.mpp = priv_lvl_q; - mcause_d = (break_from_trigger) ? 32'h00000003 : ex_i.cause; + mcause_d = (break_from_trigger) ? {{(CVA6Cfg.XLEN - 8) {1'b0}}, 8'h03} : ex_i.cause; + // update the current and previous interrupt level + if (CVA6Cfg.RVSCLIC && clic_mode_o && ex_i.cause[CVA6Cfg.XLEN-1]) begin + mintstatus_d.mil = ex_i.cause[23:16]; + mcause_d[23:16] = mintstatus_q.mil; + end // set epc mepc_d = {{CVA6Cfg.XLEN - CVA6Cfg.VLEN{pc_i[CVA6Cfg.VLEN-1]}}, pc_i}; // set mtval or stval @@ -2327,6 +2566,9 @@ module csr_regfile mstatus_d.mpv = 1'b0; if (mstatus_q.mpp != riscv::PRIV_LVL_M) mstatus_d.mprv = 1'b0; end + // restore mintstatus + if (CVA6Cfg.RVSCLIC && clic_mode_o && mcause_q[CVA6Cfg.XLEN-1]) + mintstatus_d.mil = mcause_q[23:16]; end if (CVA6Cfg.RVS && sret && ((CVA6Cfg.RVH && !v_q) || !CVA6Cfg.RVH)) begin @@ -2347,6 +2589,9 @@ module csr_regfile hstatus_d.spv = 1'b0; mstatus_d.mprv = 1'b0; end + // restore sintstatus + if (CVA6Cfg.RVSCLIC && clic_mode_o && scause_q[CVA6Cfg.XLEN-1]) + mintstatus_d.sil = scause_q[23:16]; end if (CVA6Cfg.RVH) begin @@ -2361,6 +2606,9 @@ module csr_regfile vsstatus_d.spp = 1'b0; // set spie to 1 vsstatus_d.spie = 1'b1; + // restore vsintstatus + if (CVA6Cfg.RVXHCLIC && clic_mode_o && vscause_q[CVA6Cfg.XLEN-1]) + mintstatus_d.vsil = vscause_q[23:16]; end end @@ -2379,6 +2627,10 @@ module csr_regfile debug_mode_d = 1'b0; end end + + // Update fence.t pad ceiling + if (fence_t_ceil_i > fence_t_ceil_q[31:0]) fence_t_ceil_d[31:0] = fence_t_ceil_i; + end // --------------------------- @@ -2436,6 +2688,8 @@ module csr_regfile end assign irq_ctrl_o.mideleg = (CVA6Cfg.RVS) ? mideleg_q : '0; assign irq_ctrl_o.hideleg = (CVA6Cfg.RVH) ? hideleg_q : '0; + assign irq_ctrl_o.hgeie = (CVA6Cfg.RVH) ? hgeie_q : '0; + assign irq_ctrl_o.vgein = (CVA6Cfg.RVH) ? hstatus_q.vgein : '0; assign irq_ctrl_o.global_enable = ~(CVA6Cfg.DebugEn & debug_mode_q) // interrupts are enabled during single step or we are not stepping // No need to check interrupts during single step if we don't support DEBUG mode @@ -2590,7 +2844,7 @@ module csr_regfile wfi_d = wfi_q; // if there is any (enabled) interrupt pending un-stall the core // also un-stall if we want to enter debug mode - if (|(mip_q & mie_q) || (CVA6Cfg.DebugEn && debug_req_i) || irq_i[1]) begin + if ((CVA6Cfg.DebugEn && debug_req_i) || (!clic_mode_o && (|(mip_q & mie_q) || irq_i[1])) || (CVA6Cfg.RVSCLIC && clic_mode_o && clic_irq_req_i)) begin wfi_d = 1'b0; // or alternatively if there is no exception pending and we are not in debug mode wait here // for the interrupt @@ -2601,10 +2855,20 @@ module csr_regfile // output assignments dependent on privilege mode always_comb begin : priv_output - trap_vector_base_o = {mtvec_q[CVA6Cfg.VLEN-1:2], 2'b0}; + trap_vector_base_o = (CVA6Cfg.RVSCLIC && clic_mode_o && clic_irq_shv_i && ex_i.cause[CVA6Cfg.XLEN-1]) ? {mtvt_q[CVA6Cfg.VLEN-1:8], 8'b0} : {mtvec_q[CVA6Cfg.VLEN-1:2], 2'b0}; // output user mode stvec if (CVA6Cfg.RVS && trap_to_priv_lvl == riscv::PRIV_LVL_S) begin - trap_vector_base_o = (CVA6Cfg.RVH && trap_to_v) ? {vstvec_q[CVA6Cfg.VLEN-1:2], 2'b0} : {stvec_q[CVA6Cfg.VLEN-1:2], 2'b0}; + if (CVA6Cfg.RVSCLIC && clic_mode_o && clic_irq_shv_i && ex_i.cause[CVA6Cfg.XLEN-1]) begin + if (CVA6Cfg.RVSCLIC && trap_to_v) begin + trap_vector_base_o = {vstvt_q[CVA6Cfg.VLEN-1:8], 8'b0}; + end else begin + trap_vector_base_o = {stvt_q[CVA6Cfg.VLEN-1:8], 8'b0}; + end + end else if (CVA6Cfg.RVH && trap_to_v) begin + trap_vector_base_o = {vstvec_q[CVA6Cfg.VLEN-1:2], 2'b0}; + end else begin + trap_vector_base_o = {stvec_q[CVA6Cfg.VLEN-1:2], 2'b0}; + end end // if we are in debug mode jump to a specific address @@ -2617,13 +2881,18 @@ module csr_regfile // we want to spare the costly addition. Furthermore check to which // privilege level we are jumping and whether the vectored mode is // activated for _that_ privilege level. + // Note for CLIC mode: according to the spec, we should actually jump to the address + // stored at trap_vector_base. Since this would have significant HW implications and no + // significant benefit, we conciously diverge from the spec here by jumping to + // trap_vector_base instead. if (ex_i.cause[CVA6Cfg.XLEN-1] && - ((((CVA6Cfg.RVS || CVA6Cfg.RVU) && trap_to_priv_lvl == riscv::PRIV_LVL_M && (!CVA6Cfg.DirectVecOnly && mtvec_q[0])) || (!CVA6Cfg.RVS && !CVA6Cfg.RVU && (!CVA6Cfg.DirectVecOnly && mtvec_q[0]))) - || (CVA6Cfg.RVS && trap_to_priv_lvl == riscv::PRIV_LVL_S && !trap_to_v && stvec_q[0]))) begin + (((((CVA6Cfg.RVS || CVA6Cfg.RVU) && trap_to_priv_lvl == riscv::PRIV_LVL_M && (!CVA6Cfg.DirectVecOnly && mtvec_q[0])) || (!CVA6Cfg.RVS && !CVA6Cfg.RVU && (!CVA6Cfg.DirectVecOnly && mtvec_q[0]))) && ~clic_mode_o) + || (CVA6Cfg.RVS && trap_to_priv_lvl == riscv::PRIV_LVL_S && !trap_to_v && stvec_q[0] && ~clic_mode_o) + || (CVA6Cfg.RVSCLIC && clic_mode_o && clic_irq_shv_i))) begin trap_vector_base_o[7:2] = ex_i.cause[5:0]; end if (ex_i.cause[CVA6Cfg.XLEN-1] && - (CVA6Cfg.RVH && trap_to_priv_lvl == riscv::PRIV_LVL_S && trap_to_v && vstvec_q[0])) begin + (CVA6Cfg.RVH && trap_to_priv_lvl == riscv::PRIV_LVL_S && trap_to_v && vstvec_q[0]) && ~clic_mode_o) begin trap_vector_base_o[7:2] = {ex_i.cause[5:2], 2'b01}; end @@ -2741,6 +3010,8 @@ module csr_regfile `endif assign dcache_en_o = dcache_q[0]; assign acc_cons_en_o = CVA6Cfg.EnableAccelerator ? acc_cons_q[0] : 1'b0; + assign fence_t_pad_o = fence_t_pad_q[31:0]; + assign fence_t_src_sel_o = fence_t_sel_q[0]; // determine if mprv needs to be considered if in debug mode assign mprv = (CVA6Cfg.DebugEn && debug_mode_q && !dcsr_q.mprven) ? 1'b0 : mstatus_q.mprv; @@ -2774,16 +3045,24 @@ module csr_regfile mtvec_q <= '0; mip_q <= {CVA6Cfg.XLEN{1'b0}}; mie_q <= {CVA6Cfg.XLEN{1'b0}}; + mintstatus_q <= 32'b0; + mintthresh_q <= 8'b0; mepc_q <= {CVA6Cfg.XLEN{1'b0}}; mcause_q <= {CVA6Cfg.XLEN{1'b0}}; mcounteren_q <= {CVA6Cfg.XLEN{1'b0}}; + mtvt_q <= {CVA6Cfg.XLEN{1'b0}}; mscratch_q <= {CVA6Cfg.XLEN{1'b0}}; if (CVA6Cfg.TvalEn) mtval_q <= {CVA6Cfg.XLEN{1'b0}}; - fiom_q <= '0; + mfiom_q <= 1'b0; + sfiom_q <= 1'b0; + hfiom_q <= 1'b0; dcache_q <= {{CVA6Cfg.XLEN - 1{1'b0}}, 1'b1}; icache_q <= {{CVA6Cfg.XLEN - 1{1'b0}}, 1'b1}; mcountinhibit_q <= '0; acc_cons_q <= {{CVA6Cfg.XLEN - 1{1'b0}}, CVA6Cfg.EnableAccelerator}; + fence_t_pad_q <= {CVA6Cfg.XLEN{1'b0}}; + fence_t_sel_q <= {CVA6Cfg.XLEN{1'b0}}; + fence_t_ceil_q <= {CVA6Cfg.XLEN{1'b0}}; if (CVA6Cfg.RVZiCbom) begin mcbie_q <= riscv::CBIE_INVAL; mcbcfe_q <= 1'b1; @@ -2803,6 +3082,10 @@ module csr_regfile scbie_q <= riscv::CBIE_INVAL; scbcfe_q <= 1'b1; end + if (CVA6Cfg.RVSCLIC) begin + stvt_q <= {CVA6Cfg.XLEN{1'b0}}; + sintthresh_q <= '0; + end end if (CVA6Cfg.RVH) begin @@ -2830,6 +3113,10 @@ module csr_regfile hcbie_q <= riscv::CBIE_INVAL; hcbcfe_q <= 1'b1; end + if (CVA6Cfg.RVXHCLIC) begin + vstvt_q <= {CVA6Cfg.XLEN{1'b0}}; + vsintthresh_q <= 8'b0; + end end if (CVA6Cfg.SDTRIG) begin scontext_q <= '0; @@ -2872,16 +3159,24 @@ module csr_regfile mtvec_q <= mtvec_d; mip_q <= mip_d; mie_q <= mie_d; + mintstatus_q <= mintstatus_d; + mintthresh_q <= mintthresh_d; mepc_q <= mepc_d; mcause_q <= mcause_d; mcounteren_q <= mcounteren_d; + mtvt_q <= mtvt_d; mscratch_q <= mscratch_d; if (CVA6Cfg.TvalEn) mtval_q <= mtval_d; - fiom_q <= fiom_d; + mfiom_q <= mfiom_d; + sfiom_q <= sfiom_d; + hfiom_q <= hfiom_d; dcache_q <= dcache_d; icache_q <= icache_d; mcountinhibit_q <= mcountinhibit_d; acc_cons_q <= acc_cons_d; + fence_t_pad_q <= fence_t_pad_d; + fence_t_sel_q <= fence_t_sel_d; + fence_t_ceil_q <= fence_t_ceil_d; if (CVA6Cfg.RVZiCbom) begin mcbie_q <= mcbie_d; mcbcfe_q <= mcbcfe_d; @@ -2901,6 +3196,10 @@ module csr_regfile scbie_q <= scbie_d; scbcfe_q <= scbcfe_d; end + if (CVA6Cfg.RVSCLIC) begin + stvt_q <= stvt_d; + sintthresh_q <= sintthresh_d; + end end if (CVA6Cfg.RVH) begin v_q <= v_d; @@ -2928,6 +3227,10 @@ module csr_regfile hcbie_q <= hcbie_d; hcbcfe_q <= hcbcfe_d; end + if (CVA6Cfg.RVXHCLIC) begin + vstvt_q <= vstvt_d; + vsintthresh_q <= vsintthresh_d; + end end if (CVA6Cfg.SDTRIG) begin scontext_q <= scontext_d; @@ -3074,7 +3377,8 @@ module csr_regfile assign rvfi_csr_o.mepc_q = mepc_q; assign rvfi_csr_o.mcause_q = mcause_q; assign rvfi_csr_o.mtval_q = CVA6Cfg.TvalEn ? mtval_q : '0; - assign rvfi_csr_o.fiom_q = fiom_q; + // RVFI historically exposed a single FIOM bit; expose MENVCFG.FIOM. + assign rvfi_csr_o.fiom_q = mfiom_q; assign rvfi_csr_o.mcountinhibit_q = mcountinhibit_q; assign rvfi_csr_o.cycle_q = cycle_q; assign rvfi_csr_o.instret_q = instret_q; diff --git a/core/cva6.sv b/core/cva6.sv index 12684f1e4f6..0209bf71d4a 100644 --- a/core/cva6.sv +++ b/core/cva6.sv @@ -147,6 +147,8 @@ module cva6 logic [CVA6Cfg.XLEN-1:0] mip; logic [CVA6Cfg.XLEN-1:0] mideleg; logic [CVA6Cfg.XLEN-1:0] hideleg; + logic [CVA6Cfg.XLEN-1:0] hgeie; + logic [5:0] vgein; logic sie; logic global_enable; }, @@ -332,6 +334,17 @@ module cva6 input logic time_irq_i, // Debug (async) request - SUBSYSTEM input logic debug_req_i, + // CLIC interface + input logic clic_irq_valid_i, // CLIC interrupt request + input logic [$clog2(CVA6Cfg.CLICNumInterruptSrc)-1:0] clic_irq_id_i, // interrupt source ID + input logic [7:0] clic_irq_level_i, // interrupt level is 8-bit from CLIC spec + input riscv::priv_lvl_t clic_irq_priv_i, // CLIC interrupt privilege level + input logic clic_irq_v_i, // CLIC interrupt virtualization bit (only for vCLIC) + input logic [5:0] clic_irq_vsid_i, // CLIC interrupt Virtual Supervisor ID (only for vCLIC) + input logic clic_irq_shv_i, // selective hardware vectoring bit + output logic clic_irq_ready_o, // core side interrupt hanshake (ready) + input logic clic_kill_req_i, // kill request + output logic clic_kill_ack_o, // kill acknowledge // Probes to build RVFI, can be left open when not used - RVFI output rvfi_probes_t rvfi_probes_o, // CVXIF request - SUBSYSTEM @@ -383,6 +396,7 @@ module cva6 logic [CVA6Cfg.NrCommitPorts-1:0] commit_ack; logic [CVA6Cfg.NrCommitPorts-1:0] commit_macro_ack; logic mbe; // determines the data endian-ness of the processor + logic rst_uarch_n; localparam NumPorts = 4; @@ -587,10 +601,18 @@ module cva6 logic tsr_csr_id; logic hu; irq_ctrl_t irq_ctrl_csr_id; + logic clic_mode; + riscv::intstatus_rv_t mintstatus_csr; + logic [7:0] mintthresh_csr; + logic [7:0] sintthresh_csr; + logic [7:0] vsintthresh_csr; logic dcache_en_csr_nbdcache; logic csr_write_fflags_commit_cs; logic icache_en_csr; logic acc_cons_en_csr; + logic [31:0] fence_t_pad_csr_ctrl; + logic fence_t_src_sel_csr_ctrl; + logic [31:0] fence_t_ceil_csr_ctrl; logic debug_mode; logic single_step_csr_commit; riscv::pmpcfg_t [avoid_neg(CVA6Cfg.NrPMPEntries-1):0] pmpcfg; @@ -635,6 +657,7 @@ module cva6 logic sfence_vma_commit_controller; logic hfence_vvma_commit_controller; logic hfence_gvma_commit_controller; + logic fence_t_commit_controller; logic halt_ctrl; logic halt_frontend; logic halt_csr_ctrl; @@ -643,6 +666,11 @@ module cva6 logic set_debug_pc; logic flush_commit; logic flush_acc; + logic rst_uarch_controller_n; + logic [CVA6Cfg.VLEN-1:0] rst_addr_ctrl_if; + logic busy_cache_ctrl; + logic stall_ctrl_cache; + logic init_ctrl_cache_n; icache_areq_t icache_areq_ex_cache; icache_arsp_t icache_areq_cache_ex; @@ -676,6 +704,20 @@ module cva6 logic inval_valid; logic inval_ready; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + rst_uarch_n <= 1'b0; + end else begin + rst_uarch_n <= rst_uarch_controller_n; + end + end + + // ---------------------- + // CLIC Controller <-> ID + // ---------------------- + logic clic_irq_req_id; + logic [CVA6Cfg.XLEN-1:0] clic_irq_cause_id; + // -------------- // Frontend // -------------- @@ -687,8 +729,8 @@ module cva6 .icache_drsp_t(icache_drsp_t) ) i_frontend ( .clk_i, - .rst_ni, - .boot_addr_i (boot_addr_i[CVA6Cfg.VLEN-1:0]), + .rst_ni (rst_uarch_n), + .boot_addr_i (rst_addr_ctrl_if), .flush_bp_i (1'b0), .flush_i (flush_ctrl_if), // not entirely correct .halt_i (halt_ctrl), @@ -728,7 +770,7 @@ module cva6 .x_compressed_resp_t(x_compressed_resp_t) ) id_stage_i ( .clk_i, - .rst_ni, + .rst_ni (rst_uarch_n), .flush_i(flush_ctrl_if), .debug_req_i, @@ -753,6 +795,9 @@ module cva6 .vs_i (vs), .irq_i (irq_i), .irq_ctrl_i (irq_ctrl_csr_id), + .clic_mode_i (clic_mode), + .clic_irq_req_i (clic_irq_req_id), + .clic_irq_cause_i (clic_irq_cause_id), .debug_mode_i (debug_mode), .tvm_i (tvm_csr_id), .tw_i (tw_csr_id), @@ -867,6 +912,7 @@ module cva6 ) issue_stage_i ( .clk_i, .rst_ni, + .rst_uarch_ni (rst_uarch_n), .sb_full_o (sb_full), .flush_unissued_instr_i (flush_unissued_instr_ctrl_id), .flush_i (flush_ctrl_id), @@ -977,7 +1023,7 @@ module cva6 .cbo_t(cbo_t) ) ex_stage_i ( .clk_i(clk_i), - .rst_ni(rst_ni), + .rst_ni(rst_uarch_n), .debug_mode_i(debug_mode), .flush_i(flush_ctrl_ex), .rs1_forwarding_i(rs1_forwarding_id_ex), @@ -1120,7 +1166,7 @@ module cva6 .scoreboard_entry_t(scoreboard_entry_t) ) commit_stage_i ( .clk_i, - .rst_ni, + .rst_ni (rst_uarch_n), .halt_i (halt_ctrl), .flush_dcache_i (dcache_flush_ctrl_cache), .exception_o (ex_commit), @@ -1153,7 +1199,8 @@ module cva6 .sfence_vma_o (sfence_vma_commit_controller), .hfence_vvma_o (hfence_vvma_commit_controller), .hfence_gvma_o (hfence_gvma_commit_controller), - .break_from_trigger_i(break_from_trigger) + .break_from_trigger_i(break_from_trigger), + .fence_t_o (fence_t_commit_controller) ); assign commit_ack = commit_macro_ack & ~commit_drop_id_commit; @@ -1204,6 +1251,14 @@ module cva6 .fprec_o (fprec_csr_ex), .vs_o (vs), .irq_ctrl_o (irq_ctrl_csr_id), + .clic_mode_o (clic_mode), + .mintstatus_o (mintstatus_csr), + .mintthresh_o (mintthresh_csr), + .sintthresh_o (sintthresh_csr), + .vsintthresh_o (vsintthresh_csr), + .clic_irq_req_i (clic_irq_valid_i), + .clic_irq_shv_i (clic_irq_shv_i), + .clic_irq_ready_o (clic_irq_ready_o), .en_translation_o (enable_translation_csr_ex), .en_g_translation_o (enable_g_translation_csr_ex), .en_ld_st_translation_o (en_ld_st_translation_csr_ex), @@ -1235,6 +1290,9 @@ module cva6 .icache_en_o (icache_en_csr), .dcache_en_o (dcache_en_csr_nbdcache), .acc_cons_en_o (acc_cons_en_csr), + .fence_t_pad_o (fence_t_pad_csr_ctrl), + .fence_t_src_sel_o (fence_t_src_sel_csr_ctrl), + .fence_t_ceil_i (fence_t_ceil_csr_ctrl), .perf_addr_o (addr_csr_perf), .perf_data_o (data_csr_perf), .perf_data_i (data_perf_csr), @@ -1331,11 +1389,23 @@ module cva6 .flush_tlb_o (flush_tlb_ctrl_ex), .flush_tlb_vvma_o (flush_tlb_vvma_ctrl_ex), .flush_tlb_gvma_o (flush_tlb_gvma_ctrl_ex), + .rst_uarch_no (rst_uarch_controller_n), + .rst_addr_o (rst_addr_ctrl_if), + .cache_busy_i (busy_cache_ctrl), + .stall_cache_o (stall_ctrl_cache), + .cache_init_no (init_ctrl_cache_n), + .fence_t_pad_i (fence_t_pad_csr_ctrl), + .fence_t_src_sel_i (fence_t_src_sel_csr_ctrl), + .fence_t_ceil_o (fence_t_ceil_csr_ctrl), + .time_irq_i, + .priv_lvl_i (priv_lvl), .halt_csr_i (halt_csr_ctrl), .halt_acc_i (halt_acc_ctrl), .halt_frontend_o (halt_frontend), .halt_o (halt_ctrl), // control ports + .boot_addr_i (boot_addr_i[CVA6Cfg.VLEN-1:0]), + .pc_commit_i (pc_commit), .eret_i (eret), .ex_valid_i (ex_commit.valid), .set_debug_pc_i (set_debug_pc), @@ -1343,6 +1413,7 @@ module cva6 .flush_csr_i (flush_csr_ctrl), .fence_i_i (fence_i_commit_controller), .fence_i (fence_commit_controller), + .fence_t_i (fence_t_commit_controller), .sfence_vma_i (sfence_vma_commit_controller), .hfence_vvma_i (hfence_vvma_commit_controller), .hfence_gvma_i (hfence_gvma_commit_controller), @@ -1411,7 +1482,10 @@ module cva6 ) i_cache_subsystem ( // to D$ .clk_i (clk_i), - .rst_ni (rst_ni), + .rst_ni (rst_uarch_n), + .busy_o (busy_cache_ctrl), + .stall_i (stall_ctrl_cache), + .init_ni (init_ctrl_cache_n), // I$ .icache_en_i (icache_en_csr), .icache_flush_i (icache_flush_ctrl_cache), @@ -1537,8 +1611,11 @@ module cva6 ) i_cache_subsystem ( // to D$ .clk_i (clk_i), - .rst_ni (rst_ni), + .rst_ni (rst_uarch_n), .priv_lvl_i (priv_lvl), + .busy_o (busy_cache_ctrl), + .stall_i (stall_ctrl_cache), + .init_ni (init_ctrl_cache_n), // I$ .icache_en_i (icache_en_csr), .icache_flush_i (icache_flush_ctrl_cache), @@ -1663,6 +1740,44 @@ module cva6 assign cvxif_req_o = cvxif_req; end : gen_no_accelerator + // ------------------- + // CLIC Controller + // ------------------- + if (CVA6Cfg.RVSCLIC) begin : gen_clic_controller + cva6_clic_controller #( + .CVA6Cfg(CVA6Cfg), + .irq_ctrl_t(irq_ctrl_t) + ) i_clic_controller ( + .clk_i (clk_i), + .rst_ni (rst_ni), + // from CSR file + .priv_lvl_i (priv_lvl), + .v_i (v), + .irq_ctrl_i (irq_ctrl_csr_id), + .mintthresh_i (mintthresh_csr), + .sintthresh_i (sintthresh_csr), + .vsintthresh_i (vsintthresh_csr), + .mintstatus_i (mintstatus_csr), + // from/to CLIC + .clic_irq_valid_i(clic_irq_valid_i), + .clic_irq_ready_i(clic_irq_ready_o), + .clic_irq_id_i (clic_irq_id_i), + .clic_irq_level_i(clic_irq_level_i), + .clic_irq_priv_i (clic_irq_priv_i), + .clic_irq_v_i (clic_irq_v_i), + .clic_irq_vsid_i (clic_irq_vsid_i), + .clic_kill_req_i (clic_kill_req_i), + .clic_kill_ack_o (clic_kill_ack_o), + // to ID stage + .clic_irq_req_o (clic_irq_req_id), + .clic_irq_cause_o(clic_irq_cause_id) + ); + end else begin : gen_dummy_clic_controller + assign clic_kill_ack_o = 1'b0; + assign clic_irq_req_id = 1'b0; + assign clic_irq_cause_id = '0; + end + // ------------------- // Parameter Check // ------------------- @@ -1744,7 +1859,7 @@ module cva6 ) instr_tracer_i ( // .tracer_if(tracer_if), .pck(clk_i), - .rstn(rst_ni), + .rstn(rst_uarch_n), .flush_unissued(flush_unissued_instr_ctrl_id), .flush_all(flush_ctrl_ex), .instruction(fetch_instructions), diff --git a/core/cva6_clic_controller.sv b/core/cva6_clic_controller.sv new file mode 100644 index 00000000000..80af362ac49 --- /dev/null +++ b/core/cva6_clic_controller.sv @@ -0,0 +1,157 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Author: Nils Wistoff + +module cva6_clic_controller #( + parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty, + parameter type irq_ctrl_t = logic +) ( + input logic clk_i, + input logic rst_ni, + // from CSR file + input riscv::priv_lvl_t priv_lvl_i, // current privilege level + input logic v_i, // virtualization mode bit + input irq_ctrl_t irq_ctrl_i, + input logic [7:0] mintthresh_i, // M-mode interrupt threshold + input logic [7:0] sintthresh_i, // S-mode interrupt threshold + input logic [7:0] vsintthresh_i, // VS-mode interrupt threshold + input riscv::intstatus_rv_t mintstatus_i, // interrupt status + // from/to CLIC + input logic clic_irq_valid_i, // interrupt is valid + input logic clic_irq_ready_i, // interrupt is acknowledged + input logic [$clog2(CVA6Cfg.CLICNumInterruptSrc)-1:0] clic_irq_id_i, // interrupt ID + input logic [7:0] clic_irq_level_i, // interrupt level + input riscv::priv_lvl_t clic_irq_priv_i, // interrupt privilege level + input logic clic_irq_v_i, // interrupt virtualization bit + input logic [5:0] clic_irq_vsid_i, // interrupt Virtual Supervisor ID + input logic clic_kill_req_i, // kill request + output logic clic_kill_ack_o, // kill acknowledge + // to ID stage + output logic clic_irq_req_o, + output logic [CVA6Cfg.XLEN-1:0] clic_irq_cause_o +); + // ------- + // Trigger + // ------- + // Check if the interrupt level of the current interrupt exceeds the current + // irq threshold and global interrupt are enabled (otherwise it won't fire). + // The effective interrupt threshold is the maximum of mintstatus.mil and + // mintthresh, because interrupts with higher level have priority. + logic [7:0] max_mthresh, max_sthresh, max_vsthresh; + + logic clic_irq_v; // Interrupt targets virtualization mode + + logic sgeie; // Guest external interrupts at hypervisor level enable (HIE register) + + assign max_mthresh = mintthresh_i > mintstatus_i.mil ? mintthresh_i : mintstatus_i.mil; + assign max_sthresh = sintthresh_i > mintstatus_i.sil ? sintthresh_i : mintstatus_i.sil; + assign max_vsthresh = vsintthresh_i > mintstatus_i.vsil ? vsintthresh_i : mintstatus_i.vsil; + + assign sgeie = (CVA6Cfg.RVH) ? irq_ctrl_i.mie[riscv::IRQ_HS_EXT] : 1'b0; + + // Determine if CLIC interrupt shall be accepted + always_comb begin : clic_irq_accept + clic_irq_req_o = 1'b0; + clic_irq_v = 1'b0; + unique case (priv_lvl_i) + riscv::PRIV_LVL_M: begin + // Take M-mode interrupts with higher level + if (clic_irq_priv_i == riscv::PRIV_LVL_M) begin + clic_irq_req_o = (clic_irq_level_i > max_mthresh) && (clic_irq_valid_i); + end + end + riscv::PRIV_LVL_S: begin + // Take all M-mode interrupts + if (clic_irq_priv_i == riscv::PRIV_LVL_M) begin + clic_irq_req_o = clic_irq_valid_i; + // Take S-mode interrupts with higher level + end else if (clic_irq_priv_i == riscv::PRIV_LVL_S) begin + if (CVA6Cfg.RVH && v_i) begin // Hart currently in VS-mode + if (CVA6Cfg.RVXHCLIC && clic_irq_v_i) begin // Virtual supervisor interrrupt + if (clic_irq_vsid_i == irq_ctrl_i.vgein) begin // VS-mode interrupt is for currently running VS + clic_irq_req_o = (clic_irq_level_i > max_vsthresh) && (clic_irq_valid_i) && irq_ctrl_i.sie; + clic_irq_v = 1'b1; + end else begin // Received interrupt is delegated to a differet VS + // Trap to HS-mode iff HIE.sgeie is set and HGEIE[vsid] is set + clic_irq_req_o = (clic_irq_valid_i) && sgeie && irq_ctrl_i.hgeie[clic_irq_vsid_i]; + end + end else begin // Hypervisor interrupt + clic_irq_req_o = (clic_irq_level_i > max_sthresh) && (clic_irq_valid_i); // HS-mode sie is implicitly enabled in VS-mode + end + end else begin // Hart currently in (H)S-mode + if (CVA6Cfg.RVXHCLIC && clic_irq_v_i) begin // Virtual supervisor interrrupt + // The current custom vCLIC implementation does not provide a way to the hypervisor to set interrupt levels + // to interrupts delegated to VS-mode. The incoming interrupt level is therefore ignored if the hart is running + // in HS-mode and a VS-mode interrupt is taken iff both HIE.sgeie and HGEIE[vsid] bits are set (and interrupts + // are globally enabled at supervisor level (i.e. MSTATUS.sie bit is set) + clic_irq_req_o = (clic_irq_valid_i) && sgeie && irq_ctrl_i.hgeie[clic_irq_vsid_i] && irq_ctrl_i.sie; + end else begin // (Host) Supervisor interrupt + clic_irq_req_o = (clic_irq_level_i > max_sthresh) && (clic_irq_valid_i) && irq_ctrl_i.sie; + end + end + end + end + riscv::PRIV_LVL_U: begin + // Take all M-mode interrupts + if (clic_irq_priv_i == riscv::PRIV_LVL_M) begin + clic_irq_req_o = clic_irq_valid_i; + end else if (clic_irq_priv_i == riscv::PRIV_LVL_S) begin + if (CVA6Cfg.RVH && v_i) begin // Hart currently in VU-mode + if (CVA6Cfg.RVXHCLIC && clic_irq_v_i) begin // Virtual supervisor interrrupt + if (clic_irq_vsid_i == irq_ctrl_i.vgein) begin // VS-mode interrupt is for currently running VS + clic_irq_req_o = clic_irq_valid_i; + clic_irq_v = 1'b1; + end else begin // Received interrupt is delegated to a differet VS + // Trap to HS-mode iff HIE.sgeie is set and HGEIE[vsid] is set + clic_irq_req_o = (clic_irq_valid_i) && sgeie && irq_ctrl_i.hgeie[clic_irq_vsid_i]; + end + end else begin // Hypervisor interrupt + clic_irq_req_o = clic_irq_valid_i; // MSTATUS.sie is implicitly enabled in VU-mode + end + end else begin // Hart currently in U-mode + if (CVA6Cfg.RVXHCLIC && clic_irq_v_i) begin // Virtual supervisor interrrupt + clic_irq_req_o = (clic_irq_valid_i) && sgeie && irq_ctrl_i.hgeie[clic_irq_vsid_i]; // MSTATUS.sie is implicitly enabled in U-mode + end else begin // (Host) Supervisor interrupt + clic_irq_req_o = clic_irq_valid_i; // HS-mode sie is implicitly enabled in U-mode + end + end + end + end + default: ; + endcase + end + + // ------------------ + // Interrupt Packager + // ------------------ + // Pack interrupt cause to be inserted into the pipeline + assign clic_irq_cause_o = { + 1'b1, // This is an irq + {riscv::XLEN - 28{1'b0}}, // XLEN-2...27 + clic_irq_v, // 26: interrupt target virtualization mode + clic_irq_priv_i, // 25..24: interrupt target privilege level + clic_irq_level_i, // to mintstatus.mil + {16 - $clog2(CVA6Cfg.CLICNumInterruptSrc) {1'b0}}, // 15...IDWidth + clic_irq_id_i + }; // to mcause + + // ------------ + // Kill Control + // ------------ + // Track whether an irq was inserted into the pipeline (accepted) but not acknowlegded yet + logic irq_inflight_d, irq_inflight_q; + // Set when accepting irq, clear when acknowledging or killing + assign irq_inflight_d = irq_inflight_q ? ~(clic_irq_ready_i | clic_kill_ack_o) : clic_irq_req_o; + // Acknowledge kill if no irq is inflight and irq is not accepted this cycle + assign clic_kill_ack_o = clic_kill_req_i & ~irq_inflight_q & ~clic_irq_req_o; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + irq_inflight_q <= 1'b0; + end else begin + irq_inflight_q <= irq_inflight_d; + end + end +endmodule diff --git a/core/decoder.sv b/core/decoder.sv index 0a9fccda0f8..ab99a076960 100644 --- a/core/decoder.sv +++ b/core/decoder.sv @@ -60,6 +60,12 @@ module decoder input logic [1:0] irq_i, // Interrupt control status - CSR_REGFILE input irq_ctrl_t irq_ctrl_i, + // TO_BE_COMPLETED - CLIC_CTRL + input logic clic_mode_i, + // TO_BE_COMPLETED - CLIC_CTRL + input logic clic_irq_req_i, + // TO_BE_COMPLETED - CLIC_CTRL + input logic [CVA6Cfg.XLEN-1:0] clic_irq_cause_i, // Current privilege level - CSR_REGFILE input riscv::priv_lvl_t priv_lvl_i, // Current virtualization mode - CSR_REGFILE @@ -1717,6 +1723,17 @@ module decoder instruction_o.rd = instr.utype.rd; end + // Custom instructions + // FENCE.T + riscv::OpcodeCustom0: begin + instruction_o.fu = NONE; + instruction_o.rs1 = '0; + instruction_o.rs2 = '0; + instruction_o.rd = '0; + imm_select = UIMM; + instruction_o.op = ariane_pkg::FENCE_T; + end + default: illegal_instr = 1'b1; endcase end @@ -1896,59 +1913,65 @@ module decoder // we have three interrupt sources: external interrupts, software interrupts, timer interrupts (order of precedence) // for two privilege levels: Supervisor and Machine Mode // Virtual Supervisor Timer Interrupt - if (CVA6Cfg.RVH) begin - if (irq_ctrl_i.mie[riscv::IRQ_VS_TIMER] && irq_ctrl_i.mip[riscv::IRQ_VS_TIMER]) begin - interrupt_cause = INTERRUPTS.VS_TIMER; + if (CVA6Cfg.RVSCLIC && clic_mode_i) begin + if (clic_irq_req_i) begin + interrupt_cause = clic_irq_cause_i; end - // Virtual Supervisor Software Interrupt - if (irq_ctrl_i.mie[riscv::IRQ_VS_SOFT] && irq_ctrl_i.mip[riscv::IRQ_VS_SOFT]) begin - interrupt_cause = INTERRUPTS.VS_SW; - end - // Virtual Supervisor External Interrupt - if (irq_ctrl_i.mie[riscv::IRQ_VS_EXT] && (irq_ctrl_i.mip[riscv::IRQ_VS_EXT])) begin - interrupt_cause = INTERRUPTS.VS_EXT; - end - // Hypervisor Guest External Interrupts - if (irq_ctrl_i.mie[riscv::IRQ_HS_EXT] && irq_ctrl_i.mip[riscv::IRQ_HS_EXT]) begin - interrupt_cause = INTERRUPTS.HS_EXT; + end else begin + if (CVA6Cfg.RVH) begin + if (irq_ctrl_i.mie[riscv::IRQ_VS_TIMER] && irq_ctrl_i.mip[riscv::IRQ_VS_TIMER]) begin + interrupt_cause = INTERRUPTS.VS_TIMER; + end + // Virtual Supervisor Software Interrupt + if (irq_ctrl_i.mie[riscv::IRQ_VS_SOFT] && irq_ctrl_i.mip[riscv::IRQ_VS_SOFT]) begin + interrupt_cause = INTERRUPTS.VS_SW; + end + // Virtual Supervisor External Interrupt + if (irq_ctrl_i.mie[riscv::IRQ_VS_EXT] && (irq_ctrl_i.mip[riscv::IRQ_VS_EXT])) begin + interrupt_cause = INTERRUPTS.VS_EXT; + end + // Hypervisor Guest External Interrupts + if (irq_ctrl_i.mie[riscv::IRQ_HS_EXT] && irq_ctrl_i.mip[riscv::IRQ_HS_EXT]) begin + interrupt_cause = INTERRUPTS.HS_EXT; + end end - end - if (CVA6Cfg.RVS) begin - // Supervisor Timer Interrupt - if (irq_ctrl_i.mie[riscv::IRQ_S_TIMER] && irq_ctrl_i.mip[riscv::IRQ_S_TIMER]) begin - interrupt_cause = INTERRUPTS.S_TIMER; + if (CVA6Cfg.RVS) begin + // Supervisor Timer Interrupt + if (irq_ctrl_i.mie[riscv::IRQ_S_TIMER] && irq_ctrl_i.mip[riscv::IRQ_S_TIMER]) begin + interrupt_cause = INTERRUPTS.S_TIMER; + end + // Supervisor Software Interrupt + if (irq_ctrl_i.mie[riscv::IRQ_S_SOFT] && irq_ctrl_i.mip[riscv::IRQ_S_SOFT]) begin + interrupt_cause = INTERRUPTS.S_SW; + end + // Supervisor External Interrupt + // The logical-OR of the software-writable bit and the signal from the external interrupt controller is + // used to generate external interrupts to the supervisor + if (irq_ctrl_i.mie[riscv::IRQ_S_EXT] && (irq_ctrl_i.mip[riscv::IRQ_S_EXT] | irq_i[ariane_pkg::SupervisorIrq])) begin + interrupt_cause = INTERRUPTS.S_EXT; + end end - // Supervisor Software Interrupt - if (irq_ctrl_i.mie[riscv::IRQ_S_SOFT] && irq_ctrl_i.mip[riscv::IRQ_S_SOFT]) begin - interrupt_cause = INTERRUPTS.S_SW; + // Machine Timer Interrupt + if (irq_ctrl_i.mip[riscv::IRQ_M_TIMER] && irq_ctrl_i.mie[riscv::IRQ_M_TIMER]) begin + interrupt_cause = INTERRUPTS.M_TIMER; end - // Supervisor External Interrupt - // The logical-OR of the software-writable bit and the signal from the external interrupt controller is - // used to generate external interrupts to the supervisor - if (irq_ctrl_i.mie[riscv::IRQ_S_EXT] && (irq_ctrl_i.mip[riscv::IRQ_S_EXT] | irq_i[ariane_pkg::SupervisorIrq])) begin - interrupt_cause = INTERRUPTS.S_EXT; + if (CVA6Cfg.SoftwareInterruptEn) begin + // Machine Mode Software Interrupt + if (irq_ctrl_i.mip[riscv::IRQ_M_SOFT] && irq_ctrl_i.mie[riscv::IRQ_M_SOFT]) begin + interrupt_cause = INTERRUPTS.M_SW; + end end - end - // Machine Timer Interrupt - if (irq_ctrl_i.mip[riscv::IRQ_M_TIMER] && irq_ctrl_i.mie[riscv::IRQ_M_TIMER]) begin - interrupt_cause = INTERRUPTS.M_TIMER; - end - if (CVA6Cfg.SoftwareInterruptEn) begin - // Machine Mode Software Interrupt - if (irq_ctrl_i.mip[riscv::IRQ_M_SOFT] && irq_ctrl_i.mie[riscv::IRQ_M_SOFT]) begin - interrupt_cause = INTERRUPTS.M_SW; + // Machine Mode External Interrupt + if (irq_ctrl_i.mip[riscv::IRQ_M_EXT] && irq_ctrl_i.mie[riscv::IRQ_M_EXT]) begin + interrupt_cause = INTERRUPTS.M_EXT; end end - // Machine Mode External Interrupt - if (irq_ctrl_i.mip[riscv::IRQ_M_EXT] && irq_ctrl_i.mie[riscv::IRQ_M_EXT]) begin - interrupt_cause = INTERRUPTS.M_EXT; - end - if (interrupt_cause[CVA6Cfg.XLEN-1] && irq_ctrl_i.global_enable) begin // However, if bit i in mideleg is set, interrupts are considered to be globally enabled if the hart’s current privilege // mode equals the delegated privilege mode (S or U) and that mode’s interrupt enable bit // (SIE or UIE in mstatus) is set, or if the current privilege mode is less than the delegated privilege mode. - if (irq_ctrl_i.mideleg[interrupt_cause[$clog2(CVA6Cfg.XLEN)-1:0]]) begin + // In CLIC mode, xideleg ceases to have effect. + if (irq_ctrl_i.mideleg[interrupt_cause[$clog2(CVA6Cfg.XLEN)-1:0]] && !clic_mode_i) begin if (CVA6Cfg.RVH) begin : hyp_int_gen if (v_i && irq_ctrl_i.hideleg[interrupt_cause[$clog2(CVA6Cfg.XLEN)-1:0]]) begin if ((irq_ctrl_i.sie && priv_lvl_i == riscv::PRIV_LVL_S) || priv_lvl_i == riscv::PRIV_LVL_U) begin diff --git a/core/id_stage.sv b/core/id_stage.sv index c84faf84317..51b057be03c 100644 --- a/core/id_stage.sv +++ b/core/id_stage.sv @@ -71,6 +71,12 @@ module id_stage #( input logic [1:0] irq_i, // Interrupt control status - CSR_REGFILE input irq_ctrl_t irq_ctrl_i, + // TO_BE_COMPLETED - CLIC_CTRL + input logic clic_mode_i, + // TO_BE_COMPLETED - CLIC_CTRL + input logic clic_irq_req_i, + // TO_BE_COMPLETED - CLIC_CTRL + input logic [CVA6Cfg.XLEN-1:0] clic_irq_cause_i, // Is current mode debug ? - CSR_REGFILE input logic debug_mode_i, // Trap virtual memory - CSR_REGFILE @@ -112,10 +118,10 @@ module id_stage #( ); // ID/ISSUE register stage typedef struct packed { - logic valid; - scoreboard_entry_t sbe; - logic [31:0] orig_instr; - logic is_ctrl_flow; + logic valid; + logic [$bits(scoreboard_entry_t)-1:0] sbe; + logic [31:0] orig_instr; + logic is_ctrl_flow; } issue_struct_t; issue_struct_t [CVA6Cfg.NrIssuePorts-1:0] issue_n, issue_q; // stall required for ZCMP ZCMT CVXIF @@ -328,6 +334,9 @@ module id_stage #( ) decoder_i ( .debug_req_i, .irq_ctrl_i, + .clic_mode_i (clic_mode_i), + .clic_irq_req_i (clic_irq_req_i), + .clic_irq_cause_i (clic_irq_cause_i), .irq_i, .pc_i (fetch_entry_i[i].address), .is_compressed_i (is_compressed_deco[i]), diff --git a/core/include/ariane_pkg.sv b/core/include/ariane_pkg.sv index ee9f95b9e01..0323396b8d8 100644 --- a/core/include/ariane_pkg.sv +++ b/core/include/ariane_pkg.sv @@ -138,13 +138,14 @@ package ariane_pkg; | riscv::HSTATUS_SPV | riscv::HSTATUS_SPVP | riscv::HSTATUS_HU + | riscv::HSTATUS_VGEIN | riscv::HSTATUS_VTVM | riscv::HSTATUS_VTW | riscv::HSTATUS_VTSR; // hypervisor delegable interrupts function automatic logic [31:0] hs_deleg_interrupts(config_pkg::cva6_cfg_t Cfg); - return riscv::MIP_VSSIP | riscv::MIP_VSTIP | riscv::MIP_VSEIP; + return riscv::MIP_VSSIP | riscv::MIP_VSTIP | riscv::MIP_VSEIP | riscv::MIP_SGEIP; endfunction // virtual supervisor delegable interrupts @@ -315,6 +316,7 @@ package ariane_pkg; CSR_READ, CSR_SET, CSR_CLEAR, + FENCE_T, // LSU functions LD, SD, diff --git a/core/include/build_config_pkg.sv b/core/include/build_config_pkg.sv index 6ce88971992..b53e294c3d5 100644 --- a/core/include/build_config_pkg.sv +++ b/core/include/build_config_pkg.sv @@ -75,6 +75,8 @@ package build_config_pkg; cfg.RVZCB = CVA6Cfg.RVZCB; cfg.RVZCMT = CVA6Cfg.RVZCMT; cfg.RVZCMP = CVA6Cfg.RVZCMP; + cfg.RVSCLIC = CVA6Cfg.RVSCLIC; + cfg.RVXHCLIC = CVA6Cfg.RVXHCLIC; cfg.XFVec = CVA6Cfg.XFVec; cfg.CvxifEn = CVA6Cfg.CvxifEn; cfg.CoproType = CVA6Cfg.CoproType; @@ -119,6 +121,7 @@ package build_config_pkg; cfg.PMPEntryReadOnly = CVA6Cfg.PMPEntryReadOnly; cfg.PMPNapotEn = CVA6Cfg.PMPNapotEn; cfg.NOCType = CVA6Cfg.NOCType; + cfg.CLICNumInterruptSrc = CVA6Cfg.CLICNumInterruptSrc; cfg.NrNonIdempotentRules = CVA6Cfg.NrNonIdempotentRules; cfg.NonIdempotentAddrBase = CVA6Cfg.NonIdempotentAddrBase; cfg.NonIdempotentLength = CVA6Cfg.NonIdempotentLength; diff --git a/core/include/config_pkg.sv b/core/include/config_pkg.sv index 744e191ad7f..a7af607f99f 100644 --- a/core/include/config_pkg.sv +++ b/core/include/config_pkg.sv @@ -82,6 +82,10 @@ package config_pkg; bit RVZCMP; // Zcmt RISC-V extension bit RVZCMT; + // CLIC extension + bit RVSCLIC; + // CLIC virtualization extension (vCLIC) + bit RVXHCLIC; // Zicond RISC-V extension bit RVZiCond; // Zicbom RISC-V extension (cache management / CBO) @@ -164,6 +168,8 @@ package config_pkg; copro_type_t CoproType; // NOC bus type noc_type_e NOCType; + // Number of interrupt signals from the CLIC. + int unsigned CLICNumInterruptSrc; // AXI address width int unsigned AxiAddrWidth; // AXI data width @@ -311,6 +317,8 @@ package config_pkg; bit RVZCB; bit RVZCMP; bit RVZCMT; + bit RVSCLIC; + bit RVXHCLIC; bit XFVec; bit CvxifEn; copro_type_t CoproType; @@ -362,6 +370,7 @@ package config_pkg; bit [63:0] PMPEntryReadOnly; bit PMPNapotEn; noc_type_e NOCType; + int unsigned CLICNumInterruptSrc; int unsigned NrNonIdempotentRules; logic [NrMaxRules-1:0][63:0] NonIdempotentAddrBase; logic [NrMaxRules-1:0][63:0] NonIdempotentLength; @@ -452,6 +461,7 @@ package config_pkg; assert (Cfg.NrExecuteRegionRules <= NrMaxRules); assert (Cfg.NrCachedRegionRules <= NrMaxRules); assert (Cfg.NrPMPEntries <= 64); + assert (!(Cfg.RVXHCLIC && (!Cfg.RVH || !Cfg.RVSCLIC))); assert (Cfg.FETCH_WIDTH == 32 || Cfg.FETCH_WIDTH == 64) else $fatal(1, "[frontend] fetch width != not supported"); // Support for disabling MIP.MSIP and MIE.MSIE in Hypervisor and Supervisor mode is not supported diff --git a/core/include/cv32a60x_config_pkg.sv b/core/include/cv32a60x_config_pkg.sv index 641958e69cd..65e314ccd4a 100644 --- a/core/include/cv32a60x_config_pkg.sv +++ b/core/include/cv32a60x_config_pkg.sv @@ -13,6 +13,9 @@ package cva6_config_pkg; localparam CVA6ConfigRvfiTrace = 1; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; + localparam CVA6ConfigAxiIdWidth = 4; // axi_pkg.sv localparam CVA6ConfigAxiAddrWidth = 64; // axi_pkg.sv localparam CVA6ConfigAxiDataWidth = 64; // axi_pkg.sv @@ -47,6 +50,8 @@ package cva6_config_pkg; RVZCMT: bit'(0), RVZCB: bit'(1), RVZCMP: bit'(0), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(0), CvxifEn: bit'(1), CoproType: config_pkg::COPRO_EXAMPLE, diff --git a/core/include/cv32a65x_config_pkg.sv b/core/include/cv32a65x_config_pkg.sv index cc454bd7c9f..ccdae317550 100644 --- a/core/include/cv32a65x_config_pkg.sv +++ b/core/include/cv32a65x_config_pkg.sv @@ -13,6 +13,9 @@ package cva6_config_pkg; localparam CVA6ConfigRvfiTrace = 1; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; + localparam CVA6ConfigAxiIdWidth = 4; // axi_pkg.sv localparam CVA6ConfigAxiAddrWidth = 64; // axi_pkg.sv localparam CVA6ConfigAxiDataWidth = 64; // axi_pkg.sv @@ -47,6 +50,8 @@ package cva6_config_pkg; RVZCMT: bit'(0), RVZCB: bit'(1), RVZCMP: bit'(0), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(0), CvxifEn: bit'(1), CoproType: config_pkg::COPRO_EXAMPLE, @@ -76,6 +81,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(0), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(0), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv b/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv index 143bda40c31..c1c88eaeda9 100644 --- a/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv +++ b/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv @@ -28,6 +28,8 @@ package cva6_config_pkg; localparam CVA6ConfigBExtEn = 0; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigRVZiCond = 0; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -100,6 +102,8 @@ package cva6_config_pkg; RVZCB: bit'(CVA6ConfigZcbExtEn), RVZCMT: bit'(0), RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(CVA6ConfigFVecEn), CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, @@ -129,6 +133,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/cv32a6_imac_sv32_config_pkg.sv b/core/include/cv32a6_imac_sv32_config_pkg.sv index e37153abf5e..a99142d38a1 100644 --- a/core/include/cv32a6_imac_sv32_config_pkg.sv +++ b/core/include/cv32a6_imac_sv32_config_pkg.sv @@ -27,6 +27,8 @@ package cva6_config_pkg; localparam CVA6ConfigHExtEn = 0; // always disabled localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigRVZiCond = 0; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -99,6 +101,8 @@ package cva6_config_pkg; RVZCB: bit'(CVA6ConfigZcbExtEn), RVZCMT: bit'(0), RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(CVA6ConfigFVecEn), CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, @@ -128,6 +132,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(1), NonIdempotentAddrBase: 1024'({64'b0}), NonIdempotentLength: 1024'({64'h8000_0000}), diff --git a/core/include/cv64a6_imafdc_sv39_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_config_pkg.sv index 98d2c6d5aa6..e76d0c2d9e1 100644 --- a/core/include/cv64a6_imafdc_sv39_config_pkg.sv +++ b/core/include/cv64a6_imafdc_sv39_config_pkg.sv @@ -19,7 +19,7 @@ package cva6_config_pkg; localparam CVA6ConfigF8En = 0; localparam CVA6ConfigFVecEn = 0; - localparam CVA6ConfigCvxifEn = 1; + localparam CVA6ConfigCvxifEn = 0; localparam CVA6ConfigCExtEn = 1; localparam CVA6ConfigZcbExtEn = 1; localparam CVA6ConfigZcmpExtEn = 0; @@ -28,6 +28,8 @@ package cva6_config_pkg; localparam CVA6ConfigBExtEn = 1; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -104,6 +106,8 @@ package cva6_config_pkg; RVZCB: bit'(CVA6ConfigZcbExtEn), RVZCMT: bit'(0), RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(CVA6ConfigFVecEn), CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, @@ -133,6 +137,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/cv64a6_imafdc_sv39_hpdcache_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_hpdcache_config_pkg.sv index 58c56d25555..e147701d9d7 100644 --- a/core/include/cv64a6_imafdc_sv39_hpdcache_config_pkg.sv +++ b/core/include/cv64a6_imafdc_sv39_hpdcache_config_pkg.sv @@ -26,7 +26,7 @@ package cva6_config_pkg; localparam CVA6ConfigF8En = 0; localparam CVA6ConfigFVecEn = 0; - localparam CVA6ConfigCvxifEn = 1; + localparam CVA6ConfigCvxifEn = 0; localparam CVA6ConfigCExtEn = 1; localparam CVA6ConfigZcbExtEn = 1; localparam CVA6ConfigZcmpExtEn = 0; @@ -35,6 +35,8 @@ package cva6_config_pkg; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigHExtEn = 0; localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -111,6 +113,8 @@ package cva6_config_pkg; RVZCB: bit'(CVA6ConfigZcbExtEn), RVZCMP: bit'(CVA6ConfigZcmpExtEn), RVZCMT: bit'(0), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(CVA6ConfigFVecEn), CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, @@ -140,6 +144,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/cv64a6_imafdc_sv39_hpdcache_wb_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_hpdcache_wb_config_pkg.sv index 64543a6b2be..7edee14e846 100644 --- a/core/include/cv64a6_imafdc_sv39_hpdcache_wb_config_pkg.sv +++ b/core/include/cv64a6_imafdc_sv39_hpdcache_wb_config_pkg.sv @@ -26,7 +26,7 @@ package cva6_config_pkg; localparam CVA6ConfigF8En = 0; localparam CVA6ConfigFVecEn = 0; - localparam CVA6ConfigCvxifEn = 1; + localparam CVA6ConfigCvxifEn = 0; localparam CVA6ConfigCExtEn = 1; localparam CVA6ConfigZcbExtEn = 1; localparam CVA6ConfigZcmpExtEn = 0; @@ -35,6 +35,8 @@ package cva6_config_pkg; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigHExtEn = 0; localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -113,6 +115,8 @@ package cva6_config_pkg; RVZCB: bit'(CVA6ConfigZcbExtEn), RVZCMP: bit'(CVA6ConfigZcmpExtEn), RVZCMT: bit'(0), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(CVA6ConfigFVecEn), CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, @@ -142,6 +146,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv index 8478a9b11ad..7ca70a9bec8 100644 --- a/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv +++ b/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv @@ -28,6 +28,8 @@ package cva6_config_pkg; localparam CVA6ConfigBExtEn = 0; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigRVZiCond = 0; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -104,6 +106,8 @@ package cva6_config_pkg; RVZCB: bit'(CVA6ConfigZcbExtEn), RVZCMT: bit'(0), RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(CVA6ConfigFVecEn), CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, @@ -133,6 +137,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_L15_BIG_ENDIAN, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/cv64a6_imafdc_sv39_wb_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_wb_config_pkg.sv index 86e7a7f2b59..373b6ab922d 100644 --- a/core/include/cv64a6_imafdc_sv39_wb_config_pkg.sv +++ b/core/include/cv64a6_imafdc_sv39_wb_config_pkg.sv @@ -19,7 +19,7 @@ package cva6_config_pkg; localparam CVA6ConfigF8En = 0; localparam CVA6ConfigFVecEn = 0; - localparam CVA6ConfigCvxifEn = 1; + localparam CVA6ConfigCvxifEn = 0; localparam CVA6ConfigCExtEn = 1; localparam CVA6ConfigZcbExtEn = 1; localparam CVA6ConfigZcmpExtEn = 0; @@ -28,6 +28,8 @@ package cva6_config_pkg; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigHExtEn = 0; localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -104,6 +106,8 @@ package cva6_config_pkg; RVZCB: bit'(CVA6ConfigZcbExtEn), RVZCMT: bit'(0), RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(CVA6ConfigFVecEn), CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, @@ -133,6 +137,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/cv64a6_imafdch_sv39_config_pkg.sv b/core/include/cv64a6_imafdch_sv39_config_pkg.sv index 9442b1133c1..dd06ee4a0d1 100644 --- a/core/include/cv64a6_imafdch_sv39_config_pkg.sv +++ b/core/include/cv64a6_imafdch_sv39_config_pkg.sv @@ -19,7 +19,7 @@ package cva6_config_pkg; localparam CVA6ConfigF8En = 0; localparam CVA6ConfigFVecEn = 0; - localparam CVA6ConfigCvxifEn = 1; + localparam CVA6ConfigCvxifEn = 0; localparam CVA6ConfigCExtEn = 1; localparam CVA6ConfigZcbExtEn = 1; localparam CVA6ConfigZcmpExtEn = 0; @@ -28,6 +28,8 @@ package cva6_config_pkg; localparam CVA6ConfigBExtEn = 1; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -104,6 +106,8 @@ package cva6_config_pkg; RVZCB: bit'(CVA6ConfigZcbExtEn), RVZCMT: bit'(0), RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(CVA6ConfigFVecEn), CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, @@ -133,6 +137,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/cv64a6_imafdch_sv39_wb_config_pkg.sv b/core/include/cv64a6_imafdch_sv39_wb_config_pkg.sv index 485c787b1c8..dba21e84ff0 100644 --- a/core/include/cv64a6_imafdch_sv39_wb_config_pkg.sv +++ b/core/include/cv64a6_imafdch_sv39_wb_config_pkg.sv @@ -19,7 +19,7 @@ package cva6_config_pkg; localparam CVA6ConfigF8En = 0; localparam CVA6ConfigFVecEn = 0; - localparam CVA6ConfigCvxifEn = 1; + localparam CVA6ConfigCvxifEn = 0; localparam CVA6ConfigCExtEn = 1; localparam CVA6ConfigZcbExtEn = 1; localparam CVA6ConfigZcmpExtEn = 0; @@ -28,6 +28,8 @@ package cva6_config_pkg; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigHExtEn = 1; localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -104,6 +106,8 @@ package cva6_config_pkg; RVZCB: bit'(CVA6ConfigZcbExtEn), RVZCMT: bit'(0), RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(CVA6ConfigFVecEn), CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, @@ -133,6 +137,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/cv64a6_imafdchsclic_sv39_config_pkg.sv b/core/include/cv64a6_imafdchsclic_sv39_config_pkg.sv new file mode 100644 index 00000000000..542448c68fb --- /dev/null +++ b/core/include/cv64a6_imafdchsclic_sv39_config_pkg.sv @@ -0,0 +1,182 @@ +// Copyright 2021 Thales DIS design services SAS +// +// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +// You may obtain a copy of the License at https://solderpad.org/licenses/ +// +// Original Author: Jean-Roch COULON - Thales + + +package cva6_config_pkg; + + localparam CVA6ConfigXlen = 64; + + localparam CVA6ConfigRVF = 1; + localparam CVA6ConfigRVD = 1; + localparam CVA6ConfigF16En = 0; + localparam CVA6ConfigF16AltEn = 0; + localparam CVA6ConfigF8En = 0; + localparam CVA6ConfigFVecEn = 0; + + localparam CVA6ConfigCvxifEn = 0; + localparam CVA6ConfigCExtEn = 1; + localparam CVA6ConfigZcbExtEn = 1; + localparam CVA6ConfigZcmpExtEn = 0; + localparam CVA6ConfigAExtEn = 1; + localparam CVA6ConfigHExtEn = 1; + localparam CVA6ConfigBExtEn = 0; + localparam CVA6ConfigVExtEn = 0; + localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 1; + localparam CVA6ConfigXhclicExtEn = 0; + + localparam CVA6ConfigAxiIdWidth = 4; + localparam CVA6ConfigAxiAddrWidth = 64; + localparam CVA6ConfigAxiDataWidth = 64; + localparam CVA6ConfigFetchUserEn = 0; + localparam CVA6ConfigFetchUserWidth = CVA6ConfigXlen; + localparam CVA6ConfigDataUserEn = 0; + localparam CVA6ConfigDataUserWidth = 1; + + localparam CVA6ConfigIcacheByteSize = 16384; + localparam CVA6ConfigIcacheSetAssoc = 4; + localparam CVA6ConfigIcacheLineWidth = 128; + localparam CVA6ConfigDcacheByteSize = 32768; + localparam CVA6ConfigDcacheSetAssoc = 8; + localparam CVA6ConfigDcacheLineWidth = 128; + + localparam CVA6ConfigDcacheFlushOnFence = 1'b0; + localparam CVA6ConfigDcacheFlushOnFenceI = 1'b0; + localparam CVA6ConfigDcacheInvalidateOnFlush = 1'b0; + + localparam CVA6ConfigDcacheIdWidth = 1; + localparam CVA6ConfigMemTidWidth = 2; + + localparam CVA6ConfigWtDcacheWbufDepth = 8; + + localparam CVA6ConfigNrScoreboardEntries = 8; + + localparam CVA6ConfigNrLoadPipeRegs = 1; + localparam CVA6ConfigNrStorePipeRegs = 0; + localparam CVA6ConfigNrLoadBufEntries = 2; + + localparam CVA6ConfigRASDepth = 2; + localparam CVA6ConfigBTBEntries = 32; + localparam CVA6ConfigBHTEntries = 128; + + localparam CVA6ConfigTvalEn = 1; + + localparam CVA6ConfigNrPMPEntries = 8; + + localparam CVA6ConfigPerfCounterEn = 1; + + localparam config_pkg::cache_type_t CVA6ConfigDcacheType = config_pkg::WT; + + localparam CVA6ConfigMmuPresent = 1; + + localparam CVA6ConfigRvfiTrace = 1; + + localparam config_pkg::cva6_user_cfg_t cva6_cfg = '{ + XLEN: unsigned'(CVA6ConfigXlen), + VLEN: unsigned'(64), + FpgaEn: bit'(0), // for Xilinx and Altera + FpgaAlteraEn: bit'(0), // for Altera (only) + TechnoCut: bit'(0), + SuperscalarEn: bit'(0), + ALUBypass: bit'(0), + NrCommitPorts: unsigned'(2), + AxiAddrWidth: unsigned'(CVA6ConfigAxiAddrWidth), + AxiDataWidth: unsigned'(CVA6ConfigAxiDataWidth), + AxiIdWidth: unsigned'(CVA6ConfigAxiIdWidth), + AxiUserWidth: unsigned'(CVA6ConfigDataUserWidth), + MemTidWidth: unsigned'(CVA6ConfigMemTidWidth), + NrLoadBufEntries: unsigned'(CVA6ConfigNrLoadBufEntries), + RVF: bit'(CVA6ConfigRVF), + RVD: bit'(CVA6ConfigRVD), + XF16: bit'(CVA6ConfigF16En), + XF16ALT: bit'(CVA6ConfigF16AltEn), + XF8: bit'(CVA6ConfigF8En), + RVA: bit'(CVA6ConfigAExtEn), + RVB: bit'(CVA6ConfigBExtEn), + ZKN: bit'(0), + RVV: bit'(CVA6ConfigVExtEn), + RVC: bit'(CVA6ConfigCExtEn), + RVH: bit'(CVA6ConfigHExtEn), + RVZCB: bit'(CVA6ConfigZcbExtEn), + RVZCMT: bit'(0), + RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), + XFVec: bit'(CVA6ConfigFVecEn), + CvxifEn: bit'(CVA6ConfigCvxifEn), + CoproType: config_pkg::COPRO_NONE, + RVZiCond: bit'(CVA6ConfigRVZiCond), + RVZiCbom: bit'(0), + RVZicntr: bit'(1), + RVZihpm: bit'(1), + NrScoreboardEntries: unsigned'(CVA6ConfigNrScoreboardEntries), + PerfCounterEn: bit'(CVA6ConfigPerfCounterEn), + MmuPresent: bit'(CVA6ConfigMmuPresent), + RVS: bit'(1), + RVU: bit'(1), + SoftwareInterruptEn: bit'(1), + HaltAddress: 64'h800, + ExceptionAddress: 64'h808, + RASDepth: unsigned'(CVA6ConfigRASDepth), + BTBEntries: unsigned'(CVA6ConfigBTBEntries), + BPType: config_pkg::BHT, + BHTEntries: unsigned'(CVA6ConfigBHTEntries), + BHTHist: unsigned'(3), + DmBaseAddress: 64'h0, + TvalEn: bit'(CVA6ConfigTvalEn), + DirectVecOnly: bit'(0), + NrPMPEntries: unsigned'(CVA6ConfigNrPMPEntries), + PMPCfgRstVal: {64{64'h0}}, + PMPAddrRstVal: {64{64'h0}}, + PMPEntryReadOnly: 64'd0, + PMPNapotEn: bit'(1), + NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), + NrNonIdempotentRules: unsigned'(2), + NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), + NonIdempotentLength: 1024'({64'b0, 64'b0}), + NrExecuteRegionRules: unsigned'(3), + ExecuteRegionAddrBase: 1024'({64'h8000_0000, 64'h1_0000, 64'h0}), + ExecuteRegionLength: 1024'({64'h40000000, 64'h10000, 64'h1000}), + NrCachedRegionRules: unsigned'(1), + CachedRegionAddrBase: 1024'({64'h8000_0000}), + CachedRegionLength: 1024'({64'h40000000}), + MaxOutstandingStores: unsigned'(7), + DebugEn: bit'(1), + SDTRIG: bit'(0), + Mcontrol6: bit'(0), + Icount: bit'(0), + Etrigger: bit'(0), + Itrigger: bit'(0), + AxiBurstWriteEn: bit'(0), + IcacheByteSize: unsigned'(CVA6ConfigIcacheByteSize), + IcacheSetAssoc: unsigned'(CVA6ConfigIcacheSetAssoc), + IcacheLineWidth: unsigned'(CVA6ConfigIcacheLineWidth), + DCacheType: CVA6ConfigDcacheType, + DcacheByteSize: unsigned'(CVA6ConfigDcacheByteSize), + DcacheSetAssoc: unsigned'(CVA6ConfigDcacheSetAssoc), + DcacheLineWidth: unsigned'(CVA6ConfigDcacheLineWidth), + DcacheFlushOnFence: unsigned'(CVA6ConfigDcacheFlushOnFence), + DcacheFlushOnFenceI: unsigned'(CVA6ConfigDcacheFlushOnFenceI), + DcacheInvalidateOnFlush: unsigned'(CVA6ConfigDcacheInvalidateOnFlush), + DataUserEn: unsigned'(CVA6ConfigDataUserEn), + WtDcacheWbufDepth: int'(CVA6ConfigWtDcacheWbufDepth), + FetchUserWidth: unsigned'(CVA6ConfigFetchUserWidth), + FetchUserEn: unsigned'(CVA6ConfigFetchUserEn), + InstrTlbEntries: int'(16), + DataTlbEntries: int'(16), + UseSharedTlb: bit'(0), + SvnapotEn: bit'(0), + SharedTlbDepth: int'(64), + NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs), + NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs), + DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth) + }; + +endpackage diff --git a/core/include/cv64a6_imafdchsclic_sv39_hpdcache_wb_config_pkg.sv b/core/include/cv64a6_imafdchsclic_sv39_hpdcache_wb_config_pkg.sv new file mode 100644 index 00000000000..0174efbfa30 --- /dev/null +++ b/core/include/cv64a6_imafdchsclic_sv39_hpdcache_wb_config_pkg.sv @@ -0,0 +1,192 @@ +// Copyright 2021 Thales DIS design services SAS +// +// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +// You may obtain a copy of the License at https://solderpad.org/licenses/ +// +// Original Author: Jean-Roch COULON - Thales +// +// Copyright 2023 Commissariat a l'Energie Atomique et aux Energies +// Alternatives (CEA) +// +// Author: Cesar Fuguet - CEA +// Date: August, 2023 +// Description: CVA6 configuration package using the HPDcache as cache subsystem (CLIC variant) + + +package cva6_config_pkg; + + localparam CVA6ConfigXlen = 64; + + localparam CVA6ConfigRVF = 1; + localparam CVA6ConfigRVD = 1; + localparam CVA6ConfigF16En = 0; + localparam CVA6ConfigF16AltEn = 0; + localparam CVA6ConfigF8En = 0; + localparam CVA6ConfigFVecEn = 0; + + localparam CVA6ConfigCvxifEn = 0; + localparam CVA6ConfigCExtEn = 1; + localparam CVA6ConfigZcbExtEn = 1; + localparam CVA6ConfigZcmpExtEn = 0; + localparam CVA6ConfigAExtEn = 1; + localparam CVA6ConfigHExtEn = 1; + localparam CVA6ConfigBExtEn = 0; + localparam CVA6ConfigVExtEn = 0; + localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 1; + localparam CVA6ConfigXhclicExtEn = 0; + + localparam CVA6ConfigAxiIdWidth = 4; + localparam CVA6ConfigAxiAddrWidth = 64; + localparam CVA6ConfigAxiDataWidth = 64; + localparam CVA6ConfigFetchUserEn = 0; + localparam CVA6ConfigFetchUserWidth = CVA6ConfigXlen; + localparam CVA6ConfigDataUserEn = 0; + localparam CVA6ConfigDataUserWidth = 1; + + localparam CVA6ConfigIcacheByteSize = 16384; + localparam CVA6ConfigIcacheSetAssoc = 4; + localparam CVA6ConfigIcacheLineWidth = 128; + localparam CVA6ConfigDcacheByteSize = 32768; + localparam CVA6ConfigDcacheSetAssoc = 8; + localparam CVA6ConfigDcacheLineWidth = 128; + + // do not flush Dcache for EVERY fence - dramatic performance impact + // use RVZiCbom to synchronize caches with DMA devices instead + // CAUTION - a configuration with CVA6ConfigDcacheFlushOnFence might be required for different SoCs, e.g., cache-coherent SMP configurations + localparam CVA6ConfigDcacheFlushOnFence = 1'b0; + localparam CVA6ConfigDcacheFlushOnFenceI = 1'b1; + localparam CVA6ConfigDcacheInvalidateOnFlush = 1'b0; + + localparam CVA6ConfigDcacheIdWidth = 3; + localparam CVA6ConfigMemTidWidth = CVA6ConfigAxiIdWidth; + + localparam CVA6ConfigWtDcacheWbufDepth = 7; + + localparam CVA6ConfigNrScoreboardEntries = 8; + + localparam CVA6ConfigNrLoadPipeRegs = 1; + localparam CVA6ConfigNrStorePipeRegs = 0; + localparam CVA6ConfigNrLoadBufEntries = 8; + + localparam CVA6ConfigRASDepth = 2; + localparam CVA6ConfigBTBEntries = 32; + localparam CVA6ConfigBHTEntries = 128; + + localparam CVA6ConfigTvalEn = 1; + + localparam CVA6ConfigNrPMPEntries = 8; + + localparam CVA6ConfigPerfCounterEn = 1; + + localparam config_pkg::cache_type_t CVA6ConfigDcacheType = config_pkg::HPDCACHE_WB; + + localparam CVA6ConfigMmuPresent = 1; + + localparam CVA6ConfigRvfiTrace = 1; + + localparam config_pkg::cva6_user_cfg_t cva6_cfg = '{ + XLEN: unsigned'(CVA6ConfigXlen), + VLEN: unsigned'(64), + FpgaEn: bit'(0), // for Xilinx and Altera + FpgaAlteraEn: bit'(0), // for Altera (only) + TechnoCut: bit'(0), + SuperscalarEn: bit'(0), + ALUBypass: bit'(0), + NrCommitPorts: unsigned'(2), + AxiAddrWidth: unsigned'(CVA6ConfigAxiAddrWidth), + AxiDataWidth: unsigned'(CVA6ConfigAxiDataWidth), + AxiIdWidth: unsigned'(CVA6ConfigAxiIdWidth), + AxiUserWidth: unsigned'(CVA6ConfigDataUserWidth), + MemTidWidth: unsigned'(CVA6ConfigMemTidWidth), + NrLoadBufEntries: unsigned'(CVA6ConfigNrLoadBufEntries), + RVF: bit'(CVA6ConfigRVF), + RVD: bit'(CVA6ConfigRVD), + XF16: bit'(CVA6ConfigF16En), + XF16ALT: bit'(CVA6ConfigF16AltEn), + XF8: bit'(CVA6ConfigF8En), + RVA: bit'(CVA6ConfigAExtEn), + RVB: bit'(CVA6ConfigBExtEn), + ZKN: bit'(0), + RVV: bit'(CVA6ConfigVExtEn), + RVC: bit'(CVA6ConfigCExtEn), + RVH: bit'(CVA6ConfigHExtEn), + RVZCB: bit'(CVA6ConfigZcbExtEn), + RVZCMT: bit'(0), + RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), + XFVec: bit'(CVA6ConfigFVecEn), + CvxifEn: bit'(CVA6ConfigCvxifEn), + CoproType: config_pkg::COPRO_NONE, + RVZiCond: bit'(CVA6ConfigRVZiCond), + RVZiCbom: bit'(1), + RVZicntr: bit'(1), + RVZihpm: bit'(1), + NrScoreboardEntries: unsigned'(CVA6ConfigNrScoreboardEntries), + PerfCounterEn: bit'(CVA6ConfigPerfCounterEn), + MmuPresent: bit'(CVA6ConfigMmuPresent), + RVS: bit'(1), + RVU: bit'(1), + SoftwareInterruptEn: bit'(1), + HaltAddress: 64'h800, + ExceptionAddress: 64'h808, + RASDepth: unsigned'(CVA6ConfigRASDepth), + BTBEntries: unsigned'(CVA6ConfigBTBEntries), + BPType: config_pkg::BHT, + BHTEntries: unsigned'(CVA6ConfigBHTEntries), + BHTHist: unsigned'(3), + DmBaseAddress: 64'h0, + TvalEn: bit'(CVA6ConfigTvalEn), + DirectVecOnly: bit'(0), + NrPMPEntries: unsigned'(CVA6ConfigNrPMPEntries), + PMPCfgRstVal: {64{64'h0}}, + PMPAddrRstVal: {64{64'h0}}, + PMPEntryReadOnly: 64'd0, + PMPNapotEn: bit'(1), + NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), + NrNonIdempotentRules: unsigned'(2), + NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), + NonIdempotentLength: 1024'({64'b0, 64'b0}), + NrExecuteRegionRules: unsigned'(3), + ExecuteRegionAddrBase: 1024'({64'h8000_0000, 64'h1_0000, 64'h0}), + ExecuteRegionLength: 1024'({64'h40000000, 64'h10000, 64'h1000}), + NrCachedRegionRules: unsigned'(1), + CachedRegionAddrBase: 1024'({64'h8000_0000}), + CachedRegionLength: 1024'({64'h40000000}), + MaxOutstandingStores: unsigned'(7), + DebugEn: bit'(1), + SDTRIG: bit'(0), + Mcontrol6: bit'(0), + Icount: bit'(0), + Etrigger: bit'(0), + Itrigger: bit'(0), + AxiBurstWriteEn: bit'(0), + IcacheByteSize: unsigned'(CVA6ConfigIcacheByteSize), + IcacheSetAssoc: unsigned'(CVA6ConfigIcacheSetAssoc), + IcacheLineWidth: unsigned'(CVA6ConfigIcacheLineWidth), + DCacheType: CVA6ConfigDcacheType, + DcacheByteSize: unsigned'(CVA6ConfigDcacheByteSize), + DcacheSetAssoc: unsigned'(CVA6ConfigDcacheSetAssoc), + DcacheLineWidth: unsigned'(CVA6ConfigDcacheLineWidth), + DcacheFlushOnFence: bit'(CVA6ConfigDcacheFlushOnFence), + DcacheFlushOnFenceI: unsigned'(CVA6ConfigDcacheFlushOnFenceI), + DcacheInvalidateOnFlush: bit'(CVA6ConfigDcacheInvalidateOnFlush), + DataUserEn: unsigned'(CVA6ConfigDataUserEn), + WtDcacheWbufDepth: int'(CVA6ConfigWtDcacheWbufDepth), + FetchUserWidth: unsigned'(CVA6ConfigFetchUserWidth), + FetchUserEn: unsigned'(CVA6ConfigFetchUserEn), + InstrTlbEntries: int'(16), + DataTlbEntries: int'(16), + UseSharedTlb: bit'(0), + SvnapotEn: bit'(0), + SharedTlbDepth: int'(64), + NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs), + NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs), + DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth) + }; + +endpackage diff --git a/core/include/cv64a6_imafdchsclic_sv39_wb_config_pkg.sv b/core/include/cv64a6_imafdchsclic_sv39_wb_config_pkg.sv new file mode 100644 index 00000000000..1c5fc65efb7 --- /dev/null +++ b/core/include/cv64a6_imafdchsclic_sv39_wb_config_pkg.sv @@ -0,0 +1,182 @@ +// Copyright 2021 Thales DIS design services SAS +// +// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +// You may obtain a copy of the License at https://solderpad.org/licenses/ +// +// Original Author: Jean-Roch COULON - Thales + + +package cva6_config_pkg; + + localparam CVA6ConfigXlen = 64; + + localparam CVA6ConfigRVF = 1; + localparam CVA6ConfigRVD = 1; + localparam CVA6ConfigF16En = 0; + localparam CVA6ConfigF16AltEn = 0; + localparam CVA6ConfigF8En = 0; + localparam CVA6ConfigFVecEn = 0; + + localparam CVA6ConfigCvxifEn = 0; + localparam CVA6ConfigCExtEn = 1; + localparam CVA6ConfigZcbExtEn = 1; + localparam CVA6ConfigZcmpExtEn = 0; + localparam CVA6ConfigAExtEn = 1; + localparam CVA6ConfigHExtEn = 1; + localparam CVA6ConfigBExtEn = 0; + localparam CVA6ConfigVExtEn = 0; + localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 1; + localparam CVA6ConfigXhclicExtEn = 0; + + localparam CVA6ConfigAxiIdWidth = 4; + localparam CVA6ConfigAxiAddrWidth = 64; + localparam CVA6ConfigAxiDataWidth = 64; + localparam CVA6ConfigFetchUserEn = 0; + localparam CVA6ConfigFetchUserWidth = CVA6ConfigXlen; + localparam CVA6ConfigDataUserEn = 0; + localparam CVA6ConfigDataUserWidth = 1; + + localparam CVA6ConfigIcacheByteSize = 16384; + localparam CVA6ConfigIcacheSetAssoc = 4; + localparam CVA6ConfigIcacheLineWidth = 128; + localparam CVA6ConfigDcacheByteSize = 32768; + localparam CVA6ConfigDcacheSetAssoc = 8; + localparam CVA6ConfigDcacheLineWidth = 128; + + localparam CVA6ConfigDcacheFlushOnFence = 1'b1; + localparam CVA6ConfigDcacheFlushOnFenceI = 1'b1; + localparam CVA6ConfigDcacheInvalidateOnFlush = 1'b0; + + localparam CVA6ConfigDcacheIdWidth = 1; + localparam CVA6ConfigMemTidWidth = 2; + + localparam CVA6ConfigWtDcacheWbufDepth = 8; + + localparam CVA6ConfigNrScoreboardEntries = 8; + + localparam CVA6ConfigNrLoadPipeRegs = 1; + localparam CVA6ConfigNrStorePipeRegs = 0; + localparam CVA6ConfigNrLoadBufEntries = 2; + + localparam CVA6ConfigRASDepth = 2; + localparam CVA6ConfigBTBEntries = 32; + localparam CVA6ConfigBHTEntries = 128; + + localparam CVA6ConfigTvalEn = 1; + + localparam CVA6ConfigNrPMPEntries = 8; + + localparam CVA6ConfigPerfCounterEn = 1; + + localparam config_pkg::cache_type_t CVA6ConfigDcacheType = config_pkg::WB; + + localparam CVA6ConfigMmuPresent = 1; + + localparam CVA6ConfigRvfiTrace = 1; + + localparam config_pkg::cva6_user_cfg_t cva6_cfg = '{ + XLEN: unsigned'(CVA6ConfigXlen), + VLEN: unsigned'(64), + FpgaEn: bit'(0), // for Xilinx and Altera + FpgaAlteraEn: bit'(0), // for Altera (only) + TechnoCut: bit'(0), + SuperscalarEn: bit'(0), + ALUBypass: bit'(0), + NrCommitPorts: unsigned'(2), + AxiAddrWidth: unsigned'(CVA6ConfigAxiAddrWidth), + AxiDataWidth: unsigned'(CVA6ConfigAxiDataWidth), + AxiIdWidth: unsigned'(CVA6ConfigAxiIdWidth), + AxiUserWidth: unsigned'(CVA6ConfigDataUserWidth), + MemTidWidth: unsigned'(CVA6ConfigMemTidWidth), + NrLoadBufEntries: unsigned'(CVA6ConfigNrLoadBufEntries), + RVF: bit'(CVA6ConfigRVF), + RVD: bit'(CVA6ConfigRVD), + XF16: bit'(CVA6ConfigF16En), + XF16ALT: bit'(CVA6ConfigF16AltEn), + XF8: bit'(CVA6ConfigF8En), + RVA: bit'(CVA6ConfigAExtEn), + RVB: bit'(CVA6ConfigBExtEn), + ZKN: bit'(0), + RVV: bit'(CVA6ConfigVExtEn), + RVC: bit'(CVA6ConfigCExtEn), + RVH: bit'(CVA6ConfigHExtEn), + RVZCB: bit'(CVA6ConfigZcbExtEn), + RVZCMT: bit'(0), + RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), + XFVec: bit'(CVA6ConfigFVecEn), + CvxifEn: bit'(CVA6ConfigCvxifEn), + CoproType: config_pkg::COPRO_NONE, + RVZiCond: bit'(CVA6ConfigRVZiCond), + RVZiCbom: bit'(0), + RVZicntr: bit'(1), + RVZihpm: bit'(1), + NrScoreboardEntries: unsigned'(CVA6ConfigNrScoreboardEntries), + PerfCounterEn: bit'(CVA6ConfigPerfCounterEn), + MmuPresent: bit'(CVA6ConfigMmuPresent), + RVS: bit'(1), + RVU: bit'(1), + SoftwareInterruptEn: bit'(1), + HaltAddress: 64'h800, + ExceptionAddress: 64'h808, + RASDepth: unsigned'(CVA6ConfigRASDepth), + BTBEntries: unsigned'(CVA6ConfigBTBEntries), + BPType: config_pkg::BHT, + BHTEntries: unsigned'(CVA6ConfigBHTEntries), + BHTHist: unsigned'(3), + DmBaseAddress: 64'h0, + TvalEn: bit'(CVA6ConfigTvalEn), + DirectVecOnly: bit'(0), + NrPMPEntries: unsigned'(CVA6ConfigNrPMPEntries), + PMPCfgRstVal: {64{64'h0}}, + PMPAddrRstVal: {64{64'h0}}, + PMPEntryReadOnly: 64'd0, + PMPNapotEn: bit'(1), + NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), + NrNonIdempotentRules: unsigned'(2), + NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), + NonIdempotentLength: 1024'({64'b0, 64'b0}), + NrExecuteRegionRules: unsigned'(3), + ExecuteRegionAddrBase: 1024'({64'h8000_0000, 64'h1_0000, 64'h0}), + ExecuteRegionLength: 1024'({64'h40000000, 64'h10000, 64'h1000}), + NrCachedRegionRules: unsigned'(1), + CachedRegionAddrBase: 1024'({64'h8000_0000}), + CachedRegionLength: 1024'({64'h40000000}), + MaxOutstandingStores: unsigned'(7), + DebugEn: bit'(1), + SDTRIG: bit'(0), + Mcontrol6: bit'(0), + Icount: bit'(0), + Etrigger: bit'(0), + Itrigger: bit'(0), + AxiBurstWriteEn: bit'(0), + IcacheByteSize: unsigned'(CVA6ConfigIcacheByteSize), + IcacheSetAssoc: unsigned'(CVA6ConfigIcacheSetAssoc), + IcacheLineWidth: unsigned'(CVA6ConfigIcacheLineWidth), + DCacheType: CVA6ConfigDcacheType, + DcacheByteSize: unsigned'(CVA6ConfigDcacheByteSize), + DcacheSetAssoc: unsigned'(CVA6ConfigDcacheSetAssoc), + DcacheLineWidth: unsigned'(CVA6ConfigDcacheLineWidth), + DcacheFlushOnFence: unsigned'(CVA6ConfigDcacheFlushOnFence), + DcacheFlushOnFenceI: unsigned'(CVA6ConfigDcacheFlushOnFenceI), + DcacheInvalidateOnFlush: unsigned'(CVA6ConfigDcacheInvalidateOnFlush), + DataUserEn: unsigned'(CVA6ConfigDataUserEn), + WtDcacheWbufDepth: int'(CVA6ConfigWtDcacheWbufDepth), + FetchUserWidth: unsigned'(CVA6ConfigFetchUserWidth), + FetchUserEn: unsigned'(CVA6ConfigFetchUserEn), + InstrTlbEntries: int'(16), + DataTlbEntries: int'(16), + UseSharedTlb: bit'(0), + SvnapotEn: bit'(0), + SharedTlbDepth: int'(64), + NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs), + NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs), + DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth) + }; + +endpackage diff --git a/core/include/cv64a6_imafdchxhclic_sv39_wb_config_pkg.sv b/core/include/cv64a6_imafdchxhclic_sv39_wb_config_pkg.sv new file mode 100644 index 00000000000..8d0395ce635 --- /dev/null +++ b/core/include/cv64a6_imafdchxhclic_sv39_wb_config_pkg.sv @@ -0,0 +1,182 @@ +// Copyright 2021 Thales DIS design services SAS +// +// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +// You may obtain a copy of the License at https://solderpad.org/licenses/ +// +// Original Author: Jean-Roch COULON - Thales + + +package cva6_config_pkg; + + localparam CVA6ConfigXlen = 64; + + localparam CVA6ConfigRVF = 1; + localparam CVA6ConfigRVD = 1; + localparam CVA6ConfigF16En = 0; + localparam CVA6ConfigF16AltEn = 0; + localparam CVA6ConfigF8En = 0; + localparam CVA6ConfigFVecEn = 0; + + localparam CVA6ConfigCvxifEn = 0; + localparam CVA6ConfigCExtEn = 1; + localparam CVA6ConfigZcbExtEn = 1; + localparam CVA6ConfigZcmpExtEn = 0; + localparam CVA6ConfigAExtEn = 1; + localparam CVA6ConfigHExtEn = 1; + localparam CVA6ConfigBExtEn = 0; + localparam CVA6ConfigVExtEn = 0; + localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 1; + localparam CVA6ConfigXhclicExtEn = 1; + + localparam CVA6ConfigAxiIdWidth = 4; + localparam CVA6ConfigAxiAddrWidth = 64; + localparam CVA6ConfigAxiDataWidth = 64; + localparam CVA6ConfigFetchUserEn = 0; + localparam CVA6ConfigFetchUserWidth = CVA6ConfigXlen; + localparam CVA6ConfigDataUserEn = 0; + localparam CVA6ConfigDataUserWidth = 1; + + localparam CVA6ConfigIcacheByteSize = 16384; + localparam CVA6ConfigIcacheSetAssoc = 4; + localparam CVA6ConfigIcacheLineWidth = 128; + localparam CVA6ConfigDcacheByteSize = 32768; + localparam CVA6ConfigDcacheSetAssoc = 8; + localparam CVA6ConfigDcacheLineWidth = 128; + + localparam CVA6ConfigDcacheFlushOnFence = 1'b1; + localparam CVA6ConfigDcacheFlushOnFenceI = 1'b1; + localparam CVA6ConfigDcacheInvalidateOnFlush = 1'b0; + + localparam CVA6ConfigDcacheIdWidth = 1; + localparam CVA6ConfigMemTidWidth = 2; + + localparam CVA6ConfigWtDcacheWbufDepth = 8; + + localparam CVA6ConfigNrScoreboardEntries = 8; + + localparam CVA6ConfigNrLoadPipeRegs = 1; + localparam CVA6ConfigNrStorePipeRegs = 0; + localparam CVA6ConfigNrLoadBufEntries = 2; + + localparam CVA6ConfigRASDepth = 2; + localparam CVA6ConfigBTBEntries = 32; + localparam CVA6ConfigBHTEntries = 128; + + localparam CVA6ConfigTvalEn = 1; + + localparam CVA6ConfigNrPMPEntries = 8; + + localparam CVA6ConfigPerfCounterEn = 1; + + localparam config_pkg::cache_type_t CVA6ConfigDcacheType = config_pkg::WB; + + localparam CVA6ConfigMmuPresent = 1; + + localparam CVA6ConfigRvfiTrace = 1; + + localparam config_pkg::cva6_user_cfg_t cva6_cfg = '{ + XLEN: unsigned'(CVA6ConfigXlen), + VLEN: unsigned'(64), + FpgaEn: bit'(0), // for Xilinx and Altera + FpgaAlteraEn: bit'(0), // for Altera (only) + TechnoCut: bit'(0), + SuperscalarEn: bit'(0), + ALUBypass: bit'(0), + NrCommitPorts: unsigned'(2), + AxiAddrWidth: unsigned'(CVA6ConfigAxiAddrWidth), + AxiDataWidth: unsigned'(CVA6ConfigAxiDataWidth), + AxiIdWidth: unsigned'(CVA6ConfigAxiIdWidth), + AxiUserWidth: unsigned'(CVA6ConfigDataUserWidth), + MemTidWidth: unsigned'(CVA6ConfigMemTidWidth), + NrLoadBufEntries: unsigned'(CVA6ConfigNrLoadBufEntries), + RVF: bit'(CVA6ConfigRVF), + RVD: bit'(CVA6ConfigRVD), + XF16: bit'(CVA6ConfigF16En), + XF16ALT: bit'(CVA6ConfigF16AltEn), + XF8: bit'(CVA6ConfigF8En), + RVA: bit'(CVA6ConfigAExtEn), + RVB: bit'(CVA6ConfigBExtEn), + ZKN: bit'(0), + RVV: bit'(CVA6ConfigVExtEn), + RVC: bit'(CVA6ConfigCExtEn), + RVH: bit'(CVA6ConfigHExtEn), + RVZCB: bit'(CVA6ConfigZcbExtEn), + RVZCMT: bit'(0), + RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), + XFVec: bit'(CVA6ConfigFVecEn), + CvxifEn: bit'(CVA6ConfigCvxifEn), + CoproType: config_pkg::COPRO_NONE, + RVZiCond: bit'(CVA6ConfigRVZiCond), + RVZiCbom: bit'(0), + RVZicntr: bit'(1), + RVZihpm: bit'(1), + NrScoreboardEntries: unsigned'(CVA6ConfigNrScoreboardEntries), + PerfCounterEn: bit'(CVA6ConfigPerfCounterEn), + MmuPresent: bit'(CVA6ConfigMmuPresent), + RVS: bit'(1), + RVU: bit'(1), + SoftwareInterruptEn: bit'(1), + HaltAddress: 64'h800, + ExceptionAddress: 64'h808, + RASDepth: unsigned'(CVA6ConfigRASDepth), + BTBEntries: unsigned'(CVA6ConfigBTBEntries), + BPType: config_pkg::BHT, + BHTEntries: unsigned'(CVA6ConfigBHTEntries), + BHTHist: unsigned'(3), + DmBaseAddress: 64'h0, + TvalEn: bit'(CVA6ConfigTvalEn), + DirectVecOnly: bit'(0), + NrPMPEntries: unsigned'(CVA6ConfigNrPMPEntries), + PMPCfgRstVal: {64{64'h0}}, + PMPAddrRstVal: {64{64'h0}}, + PMPEntryReadOnly: 64'd0, + PMPNapotEn: bit'(1), + NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), + NrNonIdempotentRules: unsigned'(2), + NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), + NonIdempotentLength: 1024'({64'b0, 64'b0}), + NrExecuteRegionRules: unsigned'(3), + ExecuteRegionAddrBase: 1024'({64'h8000_0000, 64'h1_0000, 64'h0}), + ExecuteRegionLength: 1024'({64'h40000000, 64'h10000, 64'h1000}), + NrCachedRegionRules: unsigned'(1), + CachedRegionAddrBase: 1024'({64'h8000_0000}), + CachedRegionLength: 1024'({64'h40000000}), + MaxOutstandingStores: unsigned'(7), + DebugEn: bit'(1), + SDTRIG: bit'(0), + Mcontrol6: bit'(0), + Icount: bit'(0), + Etrigger: bit'(0), + Itrigger: bit'(0), + AxiBurstWriteEn: bit'(0), + IcacheByteSize: unsigned'(CVA6ConfigIcacheByteSize), + IcacheSetAssoc: unsigned'(CVA6ConfigIcacheSetAssoc), + IcacheLineWidth: unsigned'(CVA6ConfigIcacheLineWidth), + DCacheType: CVA6ConfigDcacheType, + DcacheByteSize: unsigned'(CVA6ConfigDcacheByteSize), + DcacheSetAssoc: unsigned'(CVA6ConfigDcacheSetAssoc), + DcacheLineWidth: unsigned'(CVA6ConfigDcacheLineWidth), + DcacheFlushOnFence: unsigned'(CVA6ConfigDcacheFlushOnFence), + DcacheFlushOnFenceI: unsigned'(CVA6ConfigDcacheFlushOnFenceI), + DcacheInvalidateOnFlush: unsigned'(CVA6ConfigDcacheInvalidateOnFlush), + DataUserEn: unsigned'(CVA6ConfigDataUserEn), + WtDcacheWbufDepth: int'(CVA6ConfigWtDcacheWbufDepth), + FetchUserWidth: unsigned'(CVA6ConfigFetchUserWidth), + FetchUserEn: unsigned'(CVA6ConfigFetchUserEn), + InstrTlbEntries: int'(16), + DataTlbEntries: int'(16), + UseSharedTlb: bit'(0), + SvnapotEn: bit'(0), + SharedTlbDepth: int'(64), + NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs), + NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs), + DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth) + }; + +endpackage diff --git a/core/include/cv64a6_imafdcv_sv39_config_pkg.sv b/core/include/cv64a6_imafdcv_sv39_config_pkg.sv index dca6634bc74..ae2731e3eb4 100644 --- a/core/include/cv64a6_imafdcv_sv39_config_pkg.sv +++ b/core/include/cv64a6_imafdcv_sv39_config_pkg.sv @@ -30,6 +30,8 @@ package cva6_config_pkg; localparam CVA6ConfigHExtEn = 0; localparam CVA6ConfigVExtEn = 1; localparam CVA6ConfigRVZiCond = 0; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -106,6 +108,8 @@ package cva6_config_pkg; RVZCB: bit'(CVA6ConfigZcbExtEn), RVZCMP: bit'(CVA6ConfigZcmpExtEn), RVZCMT: bit'(0), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), XFVec: bit'(CVA6ConfigFVecEn), CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, @@ -135,6 +139,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/cv64a6_splus_config_pkg.sv b/core/include/cv64a6_splus_config_pkg.sv new file mode 100644 index 00000000000..2c2b32855dc --- /dev/null +++ b/core/include/cv64a6_splus_config_pkg.sv @@ -0,0 +1,190 @@ +// Copyright 2021 Thales DIS design services SAS +// +// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +// You may obtain a copy of the License at https://solderpad.org/licenses/ +// +// Original Author: Jean-Roch COULON - Thales +// +// Copyright 2023 Commissariat a l'Energie Atomique et aux Energies +// Alternatives (CEA) +// +// Author: Enrico Zelioli +// Description: CVA6S+ configuration + + +package cva6_config_pkg; + + localparam CVA6ConfigXlen = 64; + + localparam CVA6ConfigRVF = 1; + localparam CVA6ConfigRVD = 1; + localparam CVA6ConfigF16En = 0; + localparam CVA6ConfigF16AltEn = 0; + localparam CVA6ConfigF8En = 0; + localparam CVA6ConfigFVecEn = 0; + + localparam CVA6ConfigCvxifEn = 0; + localparam CVA6ConfigCExtEn = 1; + localparam CVA6ConfigZcbExtEn = 1; + localparam CVA6ConfigZcmpExtEn = 0; + localparam CVA6ConfigAExtEn = 1; + localparam CVA6ConfigBExtEn = 1; + localparam CVA6ConfigVExtEn = 0; + localparam CVA6ConfigHExtEn = 0; + localparam CVA6ConfigRVZiCond = 1; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; + + localparam CVA6ConfigAxiIdWidth = 4; + localparam CVA6ConfigAxiAddrWidth = 64; + localparam CVA6ConfigAxiDataWidth = 64; + localparam CVA6ConfigFetchUserEn = 0; + localparam CVA6ConfigFetchUserWidth = CVA6ConfigXlen; + localparam CVA6ConfigDataUserEn = 0; + localparam CVA6ConfigDataUserWidth = CVA6ConfigXlen; + + localparam CVA6ConfigIcacheByteSize = 16384; + localparam CVA6ConfigIcacheSetAssoc = 4; + localparam CVA6ConfigIcacheLineWidth = 128; + localparam CVA6ConfigDcacheByteSize = 32768; + localparam CVA6ConfigDcacheSetAssoc = 8; + localparam CVA6ConfigDcacheLineWidth = 128; + // do not flush Dcache for EVERY fence - dramatic performance impact + // use RVZiCbom to synchronize caches with DMA devices instead + // CAUTION - a configuration with CVA6ConfigDcacheFlushOnFence might be required for different SoCs, e.g., cache-coherent SMP configurations + localparam CVA6ConfigDcacheFlushOnFence = 1'b0; + localparam CVA6ConfigDcacheFlushOnFenceI = 1'b1; + localparam CVA6ConfigDcacheInvalidateOnFlush = 1'b0; + + localparam CVA6ConfigDcacheIdWidth = 3; + localparam CVA6ConfigMemTidWidth = CVA6ConfigAxiIdWidth; + + localparam CVA6ConfigWtDcacheWbufDepth = 7; + + localparam CVA6ConfigNrScoreboardEntries = 8; + + localparam CVA6ConfigNrLoadPipeRegs = 1; + localparam CVA6ConfigNrStorePipeRegs = 0; + localparam CVA6ConfigNrLoadBufEntries = 8; + + localparam CVA6ConfigRASDepth = 2; + localparam CVA6ConfigBTBEntries = 32; + localparam CVA6ConfigBHTEntries = 128; + + localparam CVA6ConfigTvalEn = 1; + + localparam CVA6ConfigNrPMPEntries = 8; + + localparam CVA6ConfigPerfCounterEn = 1; + + localparam config_pkg::cache_type_t CVA6ConfigDcacheType = config_pkg::HPDCACHE_WB; + + localparam CVA6ConfigMmuPresent = 1; + + localparam CVA6ConfigRvfiTrace = 1; + + localparam config_pkg::cva6_user_cfg_t cva6_cfg = '{ + XLEN: unsigned'(CVA6ConfigXlen), + VLEN: unsigned'(64), + FpgaEn: bit'(0), // for Xilinx and Altera + FpgaAlteraEn: bit'(0), // for Altera (only) + TechnoCut: bit'(0), + SuperscalarEn: bit'(1), + ALUBypass: bit'(1), + NrCommitPorts: unsigned'(2), + AxiAddrWidth: unsigned'(CVA6ConfigAxiAddrWidth), + AxiDataWidth: unsigned'(CVA6ConfigAxiDataWidth), + AxiIdWidth: unsigned'(CVA6ConfigAxiIdWidth), + AxiUserWidth: unsigned'(CVA6ConfigDataUserWidth), + MemTidWidth: unsigned'(CVA6ConfigMemTidWidth), + NrLoadBufEntries: unsigned'(CVA6ConfigNrLoadBufEntries), + RVF: bit'(CVA6ConfigRVF), + RVD: bit'(CVA6ConfigRVD), + XF16: bit'(CVA6ConfigF16En), + XF16ALT: bit'(CVA6ConfigF16AltEn), + XF8: bit'(CVA6ConfigF8En), + RVA: bit'(CVA6ConfigAExtEn), + RVB: bit'(CVA6ConfigBExtEn), + ZKN: bit'(1), + RVV: bit'(CVA6ConfigVExtEn), + RVC: bit'(CVA6ConfigCExtEn), + RVH: bit'(CVA6ConfigHExtEn), + RVZCB: bit'(CVA6ConfigZcbExtEn), + RVZCMP: bit'(CVA6ConfigZcmpExtEn), + RVZCMT: bit'(0), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), + XFVec: bit'(CVA6ConfigFVecEn), + CvxifEn: bit'(CVA6ConfigCvxifEn), + CoproType: config_pkg::COPRO_NONE, + RVZiCond: bit'(CVA6ConfigRVZiCond), + RVZiCbom: bit'(1), + RVZicntr: bit'(1), + RVZihpm: bit'(1), + NrScoreboardEntries: unsigned'(CVA6ConfigNrScoreboardEntries), + PerfCounterEn: bit'(CVA6ConfigPerfCounterEn), + MmuPresent: bit'(CVA6ConfigMmuPresent), + RVS: bit'(1), + RVU: bit'(1), + SoftwareInterruptEn: bit'(1), + HaltAddress: 64'h800, + ExceptionAddress: 64'h808, + RASDepth: unsigned'(CVA6ConfigRASDepth), + BTBEntries: unsigned'(CVA6ConfigBTBEntries), + BPType: config_pkg::BHT, + BHTEntries: unsigned'(CVA6ConfigBHTEntries), + BHTHist: unsigned'(3), + DmBaseAddress: 64'h0, + TvalEn: bit'(CVA6ConfigTvalEn), + DirectVecOnly: bit'(0), + NrPMPEntries: unsigned'(CVA6ConfigNrPMPEntries), + PMPCfgRstVal: {64{64'h0}}, + PMPAddrRstVal: {64{64'h0}}, + PMPEntryReadOnly: 64'd0, + PMPNapotEn: bit'(1), + NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), + NrNonIdempotentRules: unsigned'(2), + NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), + NonIdempotentLength: 1024'({64'b0, 64'b0}), + NrExecuteRegionRules: unsigned'(3), + ExecuteRegionAddrBase: 1024'({64'h8000_0000, 64'h1_0000, 64'h0}), + ExecuteRegionLength: 1024'({64'h40000000, 64'h10000, 64'h1000}), + NrCachedRegionRules: unsigned'(1), + CachedRegionAddrBase: 1024'({64'h8000_0000}), + CachedRegionLength: 1024'({64'h40000000}), + MaxOutstandingStores: unsigned'(7), + DebugEn: bit'(1), + SDTRIG: bit'(0), + Mcontrol6: bit'(0), + Icount: bit'(0), + Etrigger: bit'(0), + Itrigger: bit'(0), + AxiBurstWriteEn: bit'(0), + IcacheByteSize: unsigned'(CVA6ConfigIcacheByteSize), + IcacheSetAssoc: unsigned'(CVA6ConfigIcacheSetAssoc), + IcacheLineWidth: unsigned'(CVA6ConfigIcacheLineWidth), + DCacheType: CVA6ConfigDcacheType, + DcacheByteSize: unsigned'(CVA6ConfigDcacheByteSize), + DcacheSetAssoc: unsigned'(CVA6ConfigDcacheSetAssoc), + DcacheLineWidth: unsigned'(CVA6ConfigDcacheLineWidth), + DcacheFlushOnFence: bit'(CVA6ConfigDcacheFlushOnFence), + DcacheFlushOnFenceI: unsigned'(CVA6ConfigDcacheFlushOnFenceI), + DcacheInvalidateOnFlush: bit'(CVA6ConfigDcacheInvalidateOnFlush), + DataUserEn: unsigned'(CVA6ConfigDataUserEn), + WtDcacheWbufDepth: int'(CVA6ConfigWtDcacheWbufDepth), + FetchUserWidth: unsigned'(CVA6ConfigFetchUserWidth), + FetchUserEn: unsigned'(CVA6ConfigFetchUserEn), + InstrTlbEntries: int'(16), + DataTlbEntries: int'(16), + UseSharedTlb: bit'(0), + SvnapotEn: bit'(0), + SharedTlbDepth: int'(64), + NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs), + NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs), + DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth) + }; + +endpackage diff --git a/core/include/deprecated_packages/cv32a6_embedded_config_pkg_deprecated.sv b/core/include/deprecated_packages/cv32a6_embedded_config_pkg_deprecated.sv index 33b3c7e1f7b..756b953b83e 100644 --- a/core/include/deprecated_packages/cv32a6_embedded_config_pkg_deprecated.sv +++ b/core/include/deprecated_packages/cv32a6_embedded_config_pkg_deprecated.sv @@ -27,6 +27,8 @@ package cva6_config_pkg; localparam CVA6ConfigBExtEn = 1; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigRVZiCond = 0; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -106,6 +108,8 @@ package cva6_config_pkg; CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, RVZiCond: bit'(CVA6ConfigRVZiCond), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), RVZicntr: bit'(1), RVZiCbom: bit'(0), RVZihpm: bit'(1), @@ -131,6 +135,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/deprecated_packages/cv32a6_imac_sv0_config_pkg.sv b/core/include/deprecated_packages/cv32a6_imac_sv0_config_pkg.sv index 90b20d6caa5..846c7f39649 100644 --- a/core/include/deprecated_packages/cv32a6_imac_sv0_config_pkg.sv +++ b/core/include/deprecated_packages/cv32a6_imac_sv0_config_pkg.sv @@ -28,6 +28,8 @@ package cva6_config_pkg; localparam CVA6ConfigBExtEn = 0; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigRVZiCond = 0; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -104,6 +106,8 @@ package cva6_config_pkg; CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, RVZiCond: bit'(CVA6ConfigRVZiCond), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), RVZicntr: bit'(1), RVZiCbom: bit'(0), RVZihpm: bit'(1), @@ -129,6 +133,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/deprecated_packages/cv32a6_imafc_sv32_config_pkg.sv b/core/include/deprecated_packages/cv32a6_imafc_sv32_config_pkg.sv index d65bf85a665..e0f0aca5fd7 100644 --- a/core/include/deprecated_packages/cv32a6_imafc_sv32_config_pkg.sv +++ b/core/include/deprecated_packages/cv32a6_imafc_sv32_config_pkg.sv @@ -28,6 +28,8 @@ package cva6_config_pkg; localparam CVA6ConfigBExtEn = 0; localparam CVA6ConfigVExtEn = 0; localparam CVA6ConfigRVZiCond = 0; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -104,6 +106,8 @@ package cva6_config_pkg; CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, RVZiCond: bit'(CVA6ConfigRVZiCond), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), RVZicntr: bit'(1), RVZiCbom: bit'(0), RVZihpm: bit'(1), @@ -129,6 +133,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_AXI4_ATOP, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/deprecated_packages/cv64a6_imadfcv_sv39_polara_config_pkg.sv b/core/include/deprecated_packages/cv64a6_imadfcv_sv39_polara_config_pkg.sv index 2588a431361..e88596eec5e 100644 --- a/core/include/deprecated_packages/cv64a6_imadfcv_sv39_polara_config_pkg.sv +++ b/core/include/deprecated_packages/cv64a6_imadfcv_sv39_polara_config_pkg.sv @@ -28,6 +28,8 @@ package cva6_config_pkg; localparam CVA6ConfigHExtEn = 0; localparam CVA6ConfigVExtEn = 1; localparam CVA6ConfigRVZiCond = 0; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -108,6 +110,8 @@ package cva6_config_pkg; CvxifEn: bit'(CVA6ConfigCvxifEn), CoproType: config_pkg::COPRO_NONE, RVZiCond: bit'(CVA6ConfigRVZiCond), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), RVZicntr: bit'(1), RVZiCbom: bit'(0), RVZihpm: bit'(1), @@ -133,6 +137,7 @@ package cva6_config_pkg; PMPEntryReadOnly: 64'd0, PMPNapotEn: bit'(1), NOCType: config_pkg::NOC_TYPE_L15_BIG_ENDIAN, + CLICNumInterruptSrc: unsigned'(256), NrNonIdempotentRules: unsigned'(2), NonIdempotentAddrBase: 1024'({64'b0, 64'b0}), NonIdempotentLength: 1024'({64'b0, 64'b0}), diff --git a/core/include/deprecated_packages/cv64a6_mmu_config_pkg.sv b/core/include/deprecated_packages/cv64a6_mmu_config_pkg.sv index ccfba97e2ea..df523fd5e6e 100644 --- a/core/include/deprecated_packages/cv64a6_mmu_config_pkg.sv +++ b/core/include/deprecated_packages/cv64a6_mmu_config_pkg.sv @@ -14,6 +14,9 @@ package cva6_config_pkg; localparam CVA6ConfigBExtEn = 1; // UVM localparam CVA6ConfigRvfiTrace = 1; + localparam CVA6ConfigSclicExtEn = 0; + localparam CVA6ConfigXhclicExtEn = 0; + localparam CVA6ConfigAxiIdWidth = 4; // axi_pkg.sv localparam CVA6ConfigAxiAddrWidth = 64; // axi_pkg.sv localparam CVA6ConfigAxiDataWidth = 64; // axi_pkg.sv @@ -58,6 +61,8 @@ package cva6_config_pkg; CvxifEn: bit'(1), CoproType: config_pkg::COPRO_NONE, RVZiCond: bit'(0), + RVSCLIC: bit'(CVA6ConfigSclicExtEn), + RVXHCLIC: bit'(CVA6ConfigXhclicExtEn), RVZicntr: bit'(1), RVZiCbom: bit'(0), RVZihpm: bit'(1), diff --git a/core/include/riscv_pkg.sv b/core/include/riscv_pkg.sv index 519da62c7a1..eb5c2366812 100644 --- a/core/include/riscv_pkg.sv +++ b/core/include/riscv_pkg.sv @@ -139,6 +139,15 @@ package riscv; logic fiom; // fence of I/O implies memory } envcfg_rv_t; + typedef struct packed { + logic [7:0] mil; + logic [7:0] vsil; + logic [7:0] sil; + logic [7:0] uil; + } intstatus_rv_t; + + typedef struct packed {logic [7:0] th;} intthresh_rv_t; + // -------------------- // Instruction Types // -------------------- @@ -408,23 +417,27 @@ package riscv; CSR_VSSTATUS = 12'h200, CSR_VSIE = 12'h204, CSR_VSTVEC = 12'h205, + CSR_VSTVT = 12'h207, CSR_VSSCRATCH = 12'h240, CSR_VSEPC = 12'h241, CSR_VSCAUSE = 12'h242, CSR_VSTVAL = 12'h243, CSR_VSIP = 12'h244, + CSR_VSINTTHRESH = 12'h247, CSR_VSATP = 12'h280, // Supervisor Mode CSRs CSR_SSTATUS = 12'h100, CSR_SIE = 12'h104, CSR_STVEC = 12'h105, CSR_SCOUNTEREN = 12'h106, + CSR_STVT = 12'h107, CSR_SENVCFG = 12'h10A, CSR_SSCRATCH = 12'h140, CSR_SEPC = 12'h141, CSR_SCAUSE = 12'h142, CSR_STVAL = 12'h143, CSR_SIP = 12'h144, + CSR_SINTTHRESH = 12'h147, CSR_SATP = 12'h180, // Hypervisor-extended Supervisor Mode CSRs CSR_HSTATUS = 12'h600, @@ -483,11 +496,14 @@ package riscv; CSR_MHPM_EVENT_29 = 12'h33D, //Reserved CSR_MHPM_EVENT_30 = 12'h33E, //Reserved CSR_MHPM_EVENT_31 = 12'h33F, //Reserved + CSR_MTVT = 12'h307, CSR_MSCRATCH = 12'h340, CSR_MEPC = 12'h341, CSR_MCAUSE = 12'h342, CSR_MTVAL = 12'h343, CSR_MIP = 12'h344, + CSR_MINTSTATUS = 12'h346, + CSR_MINTTHRESH = 12'h347, CSR_MTINST = 12'h34A, CSR_MTVAL2 = 12'h34B, CSR_MENVCFG = 12'h30A, @@ -645,6 +661,9 @@ package riscv; CSR_ICACHE = 12'h7C0, // Accelerator memory consistency (platform specific) CSR_ACC_CONS = 12'h7C2, + CSR_FENCE_T_PAD = 12'h7C3, + CSR_FENCE_T_SEL = 12'h7C4, + CSR_FENCE_T_CEIL = 12'h7C5, // Triggers CSR_TSELECT = 12'h7A0, CSR_TDATA1 = 12'h7A1, @@ -723,7 +742,9 @@ package riscv; CSR_HPM_COUNTER_28H = 12'hC9C, // reserved CSR_HPM_COUNTER_29H = 12'hC9D, // reserved CSR_HPM_COUNTER_30H = 12'hC9E, // reserved - CSR_HPM_COUNTER_31H = 12'hC9F // reserved + CSR_HPM_COUNTER_31H = 12'hC9F, // reserved + // CLIC CSRs (Supervisor Mode) + CSR_SINTSTATUS = 12'hDB1 } csr_reg_t; localparam logic [63:0] SSTATUS_UIE = 'h00000001; diff --git a/core/issue_read_operands.sv b/core/issue_read_operands.sv index d6eb7f1c44f..9380caa039f 100644 --- a/core/issue_read_operands.sv +++ b/core/issue_read_operands.sv @@ -33,6 +33,7 @@ module issue_read_operands input logic clk_i, // Asynchronous reset active low - SUBSYSTEM input logic rst_ni, + input logic rst_uarch_ni, // Prevent from issuing - CONTROLLER input logic flush_i, // Stall inserted by Acc dispatcher - ACC_DISPATCHER @@ -799,8 +800,8 @@ module issue_read_operands end // FU select, assert the correct valid out signal (in the next cycle) // This needs to be like this to make verilator happy. I know it's ugly. - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin + always_ff @(posedge clk_i or negedge rst_uarch_ni) begin + if (!rst_uarch_ni) begin alu_valid_q <= '0; aes_valid_q <= '0; lsu_valid_q <= '0; @@ -1062,8 +1063,8 @@ module issue_read_operands assign alu_bypass_n = &issue_ack_o ? alu_bypass : '0; - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin + always_ff @(posedge clk_i or negedge rst_uarch_ni) begin + if (!rst_uarch_ni) begin fu_data_q <= '0; if (CVA6Cfg.RVH) begin tinst_q <= '0; diff --git a/core/issue_stage.sv b/core/issue_stage.sv index 09cbeeb862f..8e234263785 100644 --- a/core/issue_stage.sv +++ b/core/issue_stage.sv @@ -33,6 +33,8 @@ module issue_stage input logic clk_i, // Asynchronous reset active low - SUBSYSTEM input logic rst_ni, + // Microreset active low - CONTROLLER + input logic rst_uarch_ni, // Is scoreboard full - PERF_COUNTERS output logic sb_full_o, // Prevent from issuing - CONTROLLER @@ -209,7 +211,7 @@ module issue_stage .scoreboard_entry_t(scoreboard_entry_t) ) i_scoreboard ( .clk_i, - .rst_ni, + .rst_ni (rst_uarch_ni), .sb_full_o (sb_full_o), .flush_unissued_instr_i, .flush_i, @@ -257,6 +259,7 @@ module issue_stage ) i_issue_read_operands ( .clk_i, .rst_ni, + .rst_uarch_ni, .flush_i (flush_unissued_instr_i), .stall_i, .issue_instr_i (issue_instr_sb_iro), diff --git a/corev_apu/fpga/src/ariane_xilinx.sv b/corev_apu/fpga/src/ariane_xilinx.sv index 52f825de8ec..6dc4a4046d4 100644 --- a/corev_apu/fpga/src/ariane_xilinx.sv +++ b/corev_apu/fpga/src/ariane_xilinx.sv @@ -644,6 +644,7 @@ axi_adapter #( ) i_dm_axi_master ( .clk_i ( clk ), .rst_ni ( rst_n ), + .busy_o ( ), .req_i ( dm_master_req ), .type_i ( ariane_pkg::SINGLE_REQ ), .amo_i ( ariane_pkg::AMO_NONE ), diff --git a/corev_apu/src/ariane.sv b/corev_apu/src/ariane.sv index 536d070fcef..b011b03ae8c 100644 --- a/corev_apu/src/ariane.sv +++ b/corev_apu/src/ariane.sv @@ -101,6 +101,14 @@ module ariane import ariane_pkg::*; #( .ipi_i ( ipi_i ), .time_irq_i ( time_irq_i ), .debug_req_i ( debug_req_i ), + .clic_irq_valid_i ( 1'b0 ), + .clic_irq_id_i ( '0 ), + .clic_irq_level_i ( '0 ), + .clic_irq_priv_i ( riscv::PRIV_LVL_M ), + .clic_irq_shv_i ( 1'b0 ), + .clic_irq_ready_o ( ), + .clic_kill_req_i ( 1'b0 ), + .clic_kill_ack_o ( ), .rvfi_probes_o ( rvfi_probes_o ), .cvxif_req_o ( cvxif_req ), .cvxif_resp_i ( cvxif_resp ), diff --git a/corev_apu/tb/ariane_tb.cpp b/corev_apu/tb/ariane_tb.cpp index 3653eaa5164..ea9d787c918 100644 --- a/corev_apu/tb/ariane_tb.cpp +++ b/corev_apu/tb/ariane_tb.cpp @@ -332,12 +332,12 @@ int main(int argc, char **argv) { // Preload memory. #if (VERILATOR_VERSION_INTEGER >= 5000000) // Verilator v5: Use rootp pointer and .data() accessor. -#define MEM top->rootp->ariane_testharness__DOT__i_sram__DOT__gen_cut__BRA__0__KET____DOT__i_tc_sram_wrapper__DOT__i_tc_sram__DOT__sram.m_storage -#define MEM_USER top->rootp->ariane_testharness__DOT__i_sram__DOT__gen_cut__BRA__0__KET____DOT__gen_mem_user__DOT__i_tc_sram_wrapper_user__DOT__i_tc_sram__DOT__sram.m_storage +#define MEM top->rootp->ariane_testharness__DOT__i_sram__DOT__i_tc_sram__DOT__sram.m_storage +#define MEM_USER top->rootp->ariane_testharness__DOT__i_sram__DOT__gen_mem_user__DOT__i_tc_sram_user__DOT__sram.m_storage #else // Verilator v4 -#define MEM top->ariane_testharness__DOT__i_sram__DOT__gen_cut__BRA__0__KET____DOT__i_tc_sram_wrapper__DOT__i_tc_sram__DOT__sram -#define MEM_USER top->ariane_testharness__DOT__i_sram__DOT__gen_cut__BRA__0__KET____DOT__gen_mem_user__DOT__i_tc_sram_wrapper_user__DOT__i_tc_sram__DOT__sram +#define MEM top->ariane_testharness__DOT__i_sram__DOT__i_tc_sram__DOT__sram +#define MEM_USER top->ariane_testharness__DOT__i_sram__DOT__gen_mem_user__DOT__i_tc_sram_user__DOT__sram #endif long long addr; long long len; diff --git a/corev_apu/tb/ariane_tb.sv b/corev_apu/tb/ariane_tb.sv index 22e32765127..d14cab83cbb 100644 --- a/corev_apu/tb/ariane_tb.sv +++ b/corev_apu/tb/ariane_tb.sv @@ -20,8 +20,8 @@ import uvm_pkg::*; `include "uvm_macros.svh" `include "rvfi_types.svh" -`define MAIN_MEM(P) dut.i_sram.gen_cut[0].i_tc_sram_wrapper.i_tc_sram.init_val[(``P``)] -`define USER_MEM(P) dut.i_sram.gen_cut[0].gen_mem_user.i_tc_sram_wrapper_user.i_tc_sram.init_val[(``P``)] +`define MAIN_MEM(P) dut.i_sram.i_tc_sram.init_val[(``P``)] +`define USER_MEM(P) dut.i_sram.gen_mem_user.i_tc_sram_user.init_val[(``P``)] `ifndef READ_ELF_T `define READ_ELF_T diff --git a/corev_apu/tb/ariane_testharness.sv b/corev_apu/tb/ariane_testharness.sv index e4e3236392e..ec95efec032 100644 --- a/corev_apu/tb/ariane_testharness.sv +++ b/corev_apu/tb/ariane_testharness.sv @@ -318,6 +318,7 @@ module ariane_testharness #( ) i_dm_axi_master ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .busy_o ( ), .req_i ( dm_master_req ), .type_i ( ariane_pkg::SINGLE_REQ ), .amo_i ( ariane_pkg::AMO_NONE ), diff --git a/corev_apu/tb/common/tb_dcache_pkg.sv b/corev_apu/tb/common/tb_dcache_pkg.sv index 0597824453b..a65993a739a 100644 --- a/corev_apu/tb/common/tb_dcache_pkg.sv +++ b/corev_apu/tb/common/tb_dcache_pkg.sv @@ -36,7 +36,7 @@ package tb_pkg; parameter ERROR_CNT_STOP_LEVEL = 1; // use 1 for debugging. 0 runs the complete simulation... // tb_readport sequences - typedef enum logic [2:0] { RANDOM_SEQ, LINEAR_SEQ, BURST_SEQ, IDLE_SEQ, WRAP_SEQ, SET_SEQ, CONST_SEQ } seq_t; + typedef enum logic [2:0] { RANDOM_SEQ, LINEAR_SEQ, BURST_SEQ, IDLE_SEQ, WRAP_SEQ, SET_SEQ, CONST_SEQ, HALF_SEQ } seq_t; typedef enum logic [1:0] { OTHER, BYPASS, CACHED } port_type_t; diff --git a/corev_apu/tb/common/tb_writeport.sv b/corev_apu/tb/common/tb_writeport.sv index 82cc10bbee1..3913d16b68d 100644 --- a/corev_apu/tb/common/tb_writeport.sv +++ b/corev_apu/tb/common/tb_writeport.sv @@ -33,6 +33,8 @@ program tb_writeport import tb_pkg::*; import ariane_pkg::*; #( input logic rst_ni, // to testbench master + input logic half_i, + input logic [1:0] max_size_i, ref string test_name_i, input logic [6:0] req_rate_i, input seq_t seq_type_i, @@ -66,13 +68,13 @@ program tb_writeport import tb_pkg::*; import ariane_pkg::*; #( automatic logic [CVA6Cfg.XLEN/8-1:0] be; automatic logic [1:0] size; - void'(randomize(size) with {size <= $clog2(CVA6Cfg.XLEN/8);}); + void'(randomize(size) with {size >= 2'b00; size <= max_size_i; size <= $clog2(CVA6Cfg.XLEN/8);}); // align to size, set correct byte enables be = '0; unique case(size) - 2'b00: be[paddr[2:0] +: 1] = '1; - 2'b01: be[paddr[2:1]<<1 +: 2] = '1; - 2'b10: be[paddr[2:2]<<2 +: 4] = '1; + 2'b00: be[int'(paddr[2:0]) +: 1] = '1; + 2'b01: be[int'(paddr[2:1]<<1) +: 2] = '1; + 2'b10: be[int'(paddr[2:2]<<2) +: 4] = '1; 2'b11: be = '1; default: ; endcase @@ -112,6 +114,7 @@ program tb_writeport import tb_pkg::*; import ariane_pkg::*; #( dut_req_port_o.data_req = 1'b1; // generate random address void'(randomize(paddr) with {paddr >= 0; paddr < (MemWords<<$clog2(CVA6Cfg.XLEN/8));}); + if (seq_type_i == HALF_SEQ) paddr[int'(max_size_i)] = half_i; applyRandData(); `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) end @@ -281,6 +284,11 @@ program tb_writeport import tb_pkg::*; import ariane_pkg::*; #( $display("%s> start random sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); genRandReq(); end + HALF_SEQ: begin + $display("%s> start half random sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); + $display("%s> half = %b and max size = %b", PortName, half_i, max_size_i); + genRandReq(); + end LINEAR_SEQ: begin $display("%s> start linear sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); genSeqWrite(); diff --git a/corev_apu/tb/tb_wb_dcache/Makefile b/corev_apu/tb/tb_wb_dcache/Makefile index 81c6d411cd1..de6df0fafec 100755 --- a/corev_apu/tb/tb_wb_dcache/Makefile +++ b/corev_apu/tb/tb_wb_dcache/Makefile @@ -20,7 +20,7 @@ src := $(shell xargs printf '\n%s' < $(src-list) | cut -b 1-) compile_flag += +cover+i_dut -incr -64 -nologo -svinputport=compat -override_timescale 1ns/1ps -suppress 2583 -suppress 13262 -suppress 2986 +cover sim_opts += -64 -coverage -classdebug -voptargs="+acc" questa_version ?= ${QUESTASIM_VERSION} -incdir += ../common/ ../../../vendor/pulp-platform/axi/include/ +incdir += ../common/ ../../../vendor/pulp-platform/axi/include/ ../../../vendor/pulp-platform/common_cells/include/ # Iterate over all include directories and write them with +incdir+ prefixed # +incdir+ works for Verilator and QuestaSim diff --git a/corev_apu/tb/tb_wb_dcache/hdl/tb.sv b/corev_apu/tb/tb_wb_dcache/hdl/tb.sv index 9cba78c7db5..41e27665e3a 100644 --- a/corev_apu/tb/tb_wb_dcache/hdl/tb.sv +++ b/corev_apu/tb/tb_wb_dcache/hdl/tb.sv @@ -118,6 +118,8 @@ module tb import ariane_pkg::*; import std_cache_pkg::*; import tb_pkg::*; #( seq_t [2:0] seq_type; logic [3:0] seq_done; logic [6:0] req_rate[2:0]; + logic half; + logic [1:0] max_size; logic seq_run, seq_last; logic end_of_sim; @@ -259,6 +261,37 @@ module tb import ariane_pkg::*; import std_cache_pkg::*; import tb_pkg::*; #( `APPL_WAIT_CYC(clk_i, 1) endtask : flushCache + //integer fd = $fopen("extern_write.txt","w"); + // Write directly the tb memory + function automatic void external_writer(int unsigned pos, int unsigned half); + automatic logic[7:0] val; + for (int k=0; k requests to cached region should use cache port, + // those to uncached regions should use bypass port + bypass_mem_port.set_region(0, CachedAddrBeg - 1); + data_mem_port.set_region(CachedAddrBeg, cva6_config_pkg::MemBytes - 1); + + runSeq(0,nWriteVectors,0); + external_writer(int'(max_size),int'(!half)); + flushCache(); + tb_mem_port_t::check_mem(); + + ////////////////////////////////////////////// + test_name = "TEST 20 -- random write on half memory(MSB) and external writer on the other half -- max size = 64b -- enabled cache + tlb, mem contentions + invalidations"; + + // Config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + max_size = 2'b11; + half = 1; + seq_type = '{HALF_SEQ, RANDOM_SEQ, RANDOM_SEQ}; + req_rate = '{default:50}; + + // cache enabled ~> requests to cached region should use cache port, + // those to uncached regions should use bypass port + bypass_mem_port.set_region(0, CachedAddrBeg - 1); + data_mem_port.set_region(CachedAddrBeg, cva6_config_pkg::MemBytes - 1); + + runSeq(0,nWriteVectors,0); + external_writer(int'(max_size),int'(!half)); + flushCache(); + tb_mem_port_t::check_mem(); + + ////////////////////////////////////////////// + test_name = "TEST 21 -- random write on half memory(LSB) and external writer on the other half -- max size = 32b -- enabled cache + tlb, mem contentions + invalidations"; + + // Config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + max_size = 2'b10; + half = 0; + seq_type = '{HALF_SEQ, RANDOM_SEQ, RANDOM_SEQ}; + req_rate = '{default:50}; + + // cache enabled ~> requests to cached region should use cache port, + // those to uncached regions should use bypass port + bypass_mem_port.set_region(0, CachedAddrBeg - 1); + data_mem_port.set_region(CachedAddrBeg, cva6_config_pkg::MemBytes - 1); + + runSeq(0,nWriteVectors,0); + external_writer(int'(max_size),int'(!half)); + flushCache(); + tb_mem_port_t::check_mem(); + + ////////////////////////////////////////////// + test_name = "TEST 22 -- random write on half memory(MSB) and external writer on the other half -- max size = 32b -- enabled cache + tlb, mem contentions + invalidations"; + + // Config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + max_size = 2'b10; + half = 1; + seq_type = '{HALF_SEQ, RANDOM_SEQ, RANDOM_SEQ}; + req_rate = '{default:50}; + + // cache enabled ~> requests to cached region should use cache port, + // those to uncached regions should use bypass port + bypass_mem_port.set_region(0, CachedAddrBeg - 1); + data_mem_port.set_region(CachedAddrBeg, cva6_config_pkg::MemBytes - 1); + + runSeq(0,nWriteVectors,0); + external_writer(int'(max_size),int'(!half)); + flushCache(); + tb_mem_port_t::check_mem(); + + ////////////////////////////////////////////// + test_name = "TEST 23 -- random write on half memory(LSB) and external writer on the other half -- max size = 16b -- enabled cache + tlb, mem contentions + invalidations"; + + // Config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + max_size = 2'b01; + half = 0; + seq_type = '{HALF_SEQ, RANDOM_SEQ, RANDOM_SEQ}; + req_rate = '{default:50}; + + // cache enabled ~> requests to cached region should use cache port, + // those to uncached regions should use bypass port + bypass_mem_port.set_region(0, CachedAddrBeg - 1); + data_mem_port.set_region(CachedAddrBeg, cva6_config_pkg::MemBytes - 1); + + runSeq(0,nWriteVectors,0); + external_writer(int'(max_size),int'(!half)); + flushCache(); + tb_mem_port_t::check_mem(); + + ////////////////////////////////////////////// + test_name = "TEST 24 -- random write on half memory(MSB) and external writer on the other half -- max size = 16b -- enabled cache + tlb, mem contentions + invalidations"; + + // Config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + max_size = 2'b01; + half = 1; + seq_type = '{HALF_SEQ, RANDOM_SEQ, RANDOM_SEQ}; + req_rate = '{default:50}; + + // cache enabled ~> requests to cached region should use cache port, + // those to uncached regions should use bypass port + bypass_mem_port.set_region(0, CachedAddrBeg - 1); + data_mem_port.set_region(CachedAddrBeg, cva6_config_pkg::MemBytes - 1); + + runSeq(0,nWriteVectors,0); + external_writer(int'(max_size),int'(!half)); + flushCache(); + tb_mem_port_t::check_mem(); + + ////////////////////////////////////////////// + test_name = "TEST 25 -- random write on half memory(LSB) and external writer on the other half -- max size = 8b -- enabled cache + tlb, mem contentions + invalidations"; + + // Config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + max_size = 2'b00; + half = 0; + seq_type = '{HALF_SEQ, RANDOM_SEQ, RANDOM_SEQ}; + req_rate = '{default:50}; + + // cache enabled ~> requests to cached region should use cache port, + // those to uncached regions should use bypass port + bypass_mem_port.set_region(0, CachedAddrBeg - 1); + data_mem_port.set_region(CachedAddrBeg, cva6_config_pkg::MemBytes - 1); + + runSeq(0,nWriteVectors,0); + external_writer(int'(max_size),int'(!half)); + flushCache(); + tb_mem_port_t::check_mem(); + + ////////////////////////////////////////////// + test_name = "TEST 26 -- random write on half memory(MSB) and external writer on the other half -- max size = 8b -- enabled cache + tlb, mem contentions + invalidations"; + + // Config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + max_size = 2'b00; + half = 1; + seq_type = '{HALF_SEQ, RANDOM_SEQ, RANDOM_SEQ}; + req_rate = '{default:50}; + + // cache enabled ~> requests to cached region should use cache port, + // those to uncached regions should use bypass port + bypass_mem_port.set_region(0, CachedAddrBeg - 1); + data_mem_port.set_region(CachedAddrBeg, cva6_config_pkg::MemBytes - 1); + + runSeq(0,nWriteVectors,1); + external_writer(int'(max_size),int'(!half)); + flushCache(); + tb_mem_port_t::check_mem(); + + ////////////////////////////////////////////// + end_of_sim = 1; $display("TB> end test sequences"); tb_mem_port_t::report_mem(); diff --git a/corev_apu/tb/tb_wb_dcache/tb.list b/corev_apu/tb/tb_wb_dcache/tb.list index 8e67d1e4c58..3b914549698 100644 --- a/corev_apu/tb/tb_wb_dcache/tb.list +++ b/corev_apu/tb/tb_wb_dcache/tb.list @@ -39,12 +39,23 @@ hdl/cv64a6_config_pkg.sv ../../../vendor/pulp-platform/common_cells/src/stream_demux.sv ../../../core/cache_subsystem/axi_adapter.sv ../../../common/local/util/sram.sv +../../../common/local/util/tc_sram_wrapper.sv +../../src/tech_cells_generic/src/rtl/tc_sram.sv ../../../vendor/pulp-platform/axi_riscv_atomics/src/axi_res_tbl.sv ../../../vendor/pulp-platform/axi_riscv_atomics/src/axi_riscv_amos.sv ../../../vendor/pulp-platform/axi_riscv_atomics/src/axi_riscv_amos_alu.sv ../../../vendor/pulp-platform/axi_riscv_atomics/src/axi_riscv_lrsc.sv ../../../vendor/pulp-platform/axi_riscv_atomics/src/axi_riscv_atomics.sv ../../../vendor/pulp-platform/axi_riscv_atomics/src/axi_riscv_atomics_wrap.sv +../../../common/submodules/common_cells/src/id_queue.sv +../../../common/submodules/common_cells/src/stream_fork.sv +../../../common/submodules/common_cells/src/stream_filter.sv +../../../common/submodules/common_cells/src/fall_through_register.sv +../../../common/submodules/common_cells/src/stream_register.sv +../../../common/submodules/common_cells/src/spill_register_flushable.sv +../../../common/submodules/common_cells/src/spill_register.sv +../../../common/submodules/common_cells/src/onehot_to_bin.sv +../../axi/src/axi_multicut.sv ../common/tb_dcache_pkg.sv ../common/tb_readport.sv diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 00000000000..64aa18e76ce --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,3 @@ +.python-version +.venv/ + diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 00000000000..4401db52e62 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,137 @@ +# Copyright 2026 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Enrico Zelioli + +# Variables +MAKEFILE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +ROOT_DIR := $(abspath $(MAKEFILE_DIR)/..) +TEST_DIR := $(ROOT_DIR)/test +VSIM_DIR := $(TEST_DIR)/vsim +VERILATOR_DIR := $(TEST_DIR)/verilator + +# Tools +BENDER ?= bender --suppress E31 -d $(ROOT_DIR) +QUESTA ?= questa-2023.4 +VERILATOR ?= verilator + +# Target CVA6 configuration +CVA6_CONFIG ?= cv64a6_imafdchsclic_sv39_wb +HEXFILE ?= $(TEST_DIR)/sw/out/hello.hex +MAX_CYCLES ?= 10000 +TEST ?= test_simple +ALLOWED_TESTS := test_simple + +ifeq ($(filter $(TEST),$(ALLOWED_TESTS)),) +$(error TEST must be one of: $(ALLOWED_TESTS) (got '$(TEST)')) +endif + +.PHONY: default +default: info + +.PHONY: clean +clean: vsim-clean verilator-clean + +.PHONY: info +info: + @echo "########################## INFO ##########################" + @echo "MAKEFILE_DIR : $(MAKEFILE_DIR)" + @echo "ROOT_DIR : $(ROOT_DIR)" + @echo "TEST_DIR : $(TEST_DIR)" + @echo "VSIM_DIR : $(VSIM_DIR)" + @echo "VERILATOR_DIR : $(VERILATOR_DIR)" + @echo "##########################################################" + +################################## +############ Bender ############## +################################## + +BENDER_FLAGS := -t rtl -t simulation -t cva6 -t $(CVA6_CONFIG) -t cva6tb -t $(TEST) + +ifeq ($(ZERO_SIM_MEM),1) +BENDER_FLAGS += -D ZERO_SIM_MEM +endif + +$(ROOT_DIR)/Bender.lock: + $(BENDER) checkout + touch $@ + +################################## +########## QuestaSim ############# +################################## + +VSIM_BUILD_DIR := $(VSIM_DIR)/build + +# C++ compiler path +# Caution: Questasim requires this to point to the *actual* compiler install path +CXX_PATH := $(shell which $(CXX)) + +# Silence warning 13314 on input ports defaulting to 'wire' due to -svinputport=relaxed +# Silence warning 2583 on extra checking for conflicts between processes is done at vopt time +VLOG_FLAGS := -timescale 1ns/1ps -suppress 13314 -suppress 2583 +VOPT_FLAGS := -suppress 3009 -suppress 8386 -suppress 7061 -error 7 -cpppath $(CXX_PATH) +VOPT_FLAGS += +acc + +$(VSIM_BUILD_DIR): + @mkdir -p $(VSIM_BUILD_DIR) + +$(VSIM_BUILD_DIR)/vsim_compile.tcl: $(ROOT_DIR)/Bender.lock | $(VSIM_BUILD_DIR) + $(BENDER) script vsim $(BENDER_FLAGS) --vlog-arg="$(VLOG_FLAGS)" > $@ + @echo 'vopt $(VOPT_FLAGS) test -o test_opt' >> $@ + +$(VSIM_BUILD_DIR)/vsim_compile.log: $(VSIM_BUILD_DIR)/vsim_compile.tcl + cd $(VSIM_BUILD_DIR) && $(QUESTA) vsim -c -do "quit -code [source $<]" | tee $@ + +$(VSIM_BUILD_DIR)/vsim_compile.err: $(VSIM_BUILD_DIR)/vsim_compile.log + @echo "--- QuestaSim compilation report ---" > $@ + @echo "Errors:" >> $@ + @grep "Error:" $< >> $@ || true + @echo "" >> $@ + @echo "Warnings:" >> $@ + @grep "Warning:" $< >> $@ || true + @cat $@ + +.PHONY: vsim-build +vsim-build: $(VSIM_BUILD_DIR)/vsim_compile.err + +.PHONY: vsim-run +vsim-run: $(VSIM_BUILD_DIR)/vsim_compile.err + cd $(VSIM_BUILD_DIR) && $(QUESTA) vsim -c -wlf cva6tb.wlf -do "log -r /test/*; run -all; quit" test_opt +binary=$(abspath $(HEXFILE)) +MaxCycles=$(MAX_CYCLES) + +.PHONY: vsim-clean +vsim-clean: + rm -rf $(VSIM_BUILD_DIR) + +################################## +########## Verilator ############# +################################## + +VERILATOR_BUILD_DIR := $(VERILATOR_DIR)/build +VERILATOR_LOG_DIR := $(VERILATOR_DIR)/logs +VERILATOR_FLIST := $(VERILATOR_DIR)/cva6tb.flist +VERILATOR_WARNINGS := -Wall -Wno-fatal -Wno-style -Wno-BLKANDNBLK -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-WIDTHCONCAT -Wno-ASCRANGE -Wno-IMPLICITSTATIC +VERILATOR_FLAGS := --binary -j 0 --Mdir $(VERILATOR_BUILD_DIR) $(VERILATOR_WARNINGS) -O3 -f $(VERILATOR_FLIST) --assert --timing \ + --trace-fst --trace-structs --trace-threads 2 --x-assign fast --x-initial fast + +$(VERILATOR_LOG_DIR): + @mkdir -p $(VERILATOR_LOG_DIR) + +$(VERILATOR_FLIST): $(ROOT_DIR)/Bender.lock + $(BENDER) script verilator $(BENDER_FLAGS) -t verilator > $@ + +$(VERILATOR_BUILD_DIR)/Vtest: $(VERILATOR_FLIST) | $(VERILATOR_LOG_DIR) + cd $(VERILATOR_DIR) && $(VERILATOR) $(VERILATOR_FLAGS) --top-module test | tee $(VERILATOR_LOG_DIR)/build.log + +.PHONY: verilator-build +verilator-build: $(VERILATOR_BUILD_DIR)/Vtest + +.PHONY: verilator-run +verilator-run: $(VERILATOR_BUILD_DIR)/Vtest | $(VERILATOR_LOG_DIR) + cd $(VERILATOR_DIR) && ./$(notdir $(VERILATOR_BUILD_DIR))/Vtest +binary=$(abspath $(HEXFILE)) +MaxCycles=$(MAX_CYCLES) | tee $(VERILATOR_LOG_DIR)/$(basename $(notdir $(HEXFILE))).log + +.PHONY: verilator-clean +verilator-clean: + rm -rf $(VERILATOR_BUILD_DIR) $(VERILATOR_LOG_DIR) + rm -f $(VERILATOR_FLIST) + cd $(VERILATOR_DIR) && rm -f *.fst *.fst.hier *.flist *.json *.dasm *.csv diff --git a/test/hw/cva6tb_pkg.sv b/test/hw/cva6tb_pkg.sv new file mode 100644 index 00000000000..7a7d1175d46 --- /dev/null +++ b/test/hw/cva6tb_pkg.sv @@ -0,0 +1,161 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Author: Enrico Zelioli + +package cva6tb_pkg; + + `include "axi/typedef.svh" + `include "register_interface/typedef.svh" + `include "rvfi_types.svh" + + import ariane_pkg::*; + + // CVA6 configuration struct + localparam config_pkg::cva6_user_cfg_t CVA6UserCfg = cva6_config_pkg::cva6_cfg; + localparam config_pkg::cva6_cfg_t CVA6Cfg = build_config_pkg::build_config(CVA6UserCfg); + + //////////////////////////// + // Test SoC configuration // + //////////////////////////// + + localparam int unsigned AxiXbarMasters = 1; + localparam int unsigned AxiXbarSlaves = 3; + localparam int unsigned AxiSlvIdWidth = CVA6UserCfg.AxiIdWidth + $clog2(AxiXbarMasters); + localparam int unsigned AxiXbarAddrRules = 3; + localparam int unsigned AxiSlvIdErrSlv = 0; + localparam int unsigned AxiSlvIdReg = 1; + localparam int unsigned AxiSlvIdSimMem = 2; + + localparam int unsigned RegbusOutNum = 4; + localparam int unsigned RegbusRulesNum = 4; + localparam int unsigned RegbusErrId = 0; + localparam int unsigned RegbusPCRsId = 1; + localparam int unsigned RegbusConsoleId = 2; + localparam int unsigned RegbusClicId = 3; + + localparam int unsigned NumClicIrqs = 256; + + // AXI xbar configuration + localparam axi_pkg::xbar_cfg_t AxiXbarCfg = '{ + NoSlvPorts: AxiXbarMasters, + NoMstPorts: AxiXbarSlaves, + MaxMstTrans: 24, + MaxSlvTrans: 24, + FallThrough: 0, + LatencyMode: axi_pkg::CUT_ALL_PORTS, + PipelineStages: 0, + AxiIdWidthSlvPorts: CVA6UserCfg.AxiIdWidth, + AxiIdUsedSlvPorts: CVA6UserCfg.AxiIdWidth, + UniqueIds: 0, + AxiAddrWidth: CVA6UserCfg.AxiAddrWidth, + AxiDataWidth: CVA6UserCfg.AxiDataWidth, + NoAddrRules: AxiXbarAddrRules, + default: '0 + }; + + ////////////////////// + // Type definitions // + ////////////////////// + + localparam type rvfi_instr_t = `RVFI_INSTR_T(CVA6Cfg); + localparam type rvfi_csr_elmt_t = `RVFI_CSR_ELMT_T(CVA6Cfg); + localparam type rvfi_csr_t = `RVFI_CSR_T(CVA6Cfg, rvfi_csr_elmt_t); + localparam type rvfi_probes_instr_t = `RVFI_PROBES_INSTR_T(CVA6Cfg); + localparam type rvfi_probes_csr_t = `RVFI_PROBES_CSR_T(CVA6Cfg); + localparam type rvfi_probes_t = struct packed { + rvfi_probes_csr_t csr; + rvfi_probes_instr_t instr; + }; + + localparam type axi_addr_t = logic [CVA6UserCfg.AxiAddrWidth-1:0]; + localparam type axi_data_t = logic [CVA6UserCfg.AxiDataWidth-1:0]; + localparam type axi_strb_t = logic [CVA6UserCfg.AxiDataWidth/8-1:0]; + localparam type axi_mst_id_t = logic [CVA6UserCfg.AxiIdWidth-1:0]; + localparam type axi_slv_id_t = logic [AxiSlvIdWidth-1:0]; + localparam type axi_user_t = logic [CVA6UserCfg.AxiUserWidth-1:0]; + + `AXI_TYPEDEF_ALL(axi_mst, axi_addr_t, axi_mst_id_t, axi_data_t, axi_strb_t, axi_user_t); + `AXI_TYPEDEF_ALL(axi_slv, axi_addr_t, axi_slv_id_t, axi_data_t, axi_strb_t, axi_user_t); + typedef axi_mst_resp_t axi_mst_rsp_t; + typedef axi_slv_resp_t axi_slv_rsp_t; + + localparam type reg_addr_t = logic [31:0]; + localparam type reg_idx_t = logic [cf_math_pkg::idx_width(RegbusOutNum)-1:0]; + + `REG_BUS_TYPEDEF_ALL(reg, reg_addr_t, logic [31:0], logic [3:0]) + + // Type for address map entries + typedef struct packed { + logic [5:0] idx; + axi_addr_t start_addr; + axi_addr_t end_addr; + } addr_rule_t; + + // Type for regbus address map entries + typedef struct packed { + logic [5:0] idx; + reg_addr_t start_addr; + reg_addr_t end_addr; + } reg_addr_rule_t; + + ////////////////////////// + // Test SoC address map // + ////////////////////////// + + localparam addr_rule_t [AxiXbarAddrRules-1:0] AxiMap = { + addr_rule_t'{ idx: AxiSlvIdErrSlv, start_addr: 32'h0000_0000, end_addr: 32'h0FFF_FFFF }, // AXI error slave + addr_rule_t'{ idx: AxiSlvIdReg, start_addr: 32'h1000_0000, end_addr: 32'h100F_FFFF }, // Regbus + addr_rule_t'{ idx: AxiSlvIdSimMem, start_addr: 32'h8000_0000, end_addr: 32'h8FFF_FFFF } // AXI Sim Mem + }; + + localparam reg_addr_rule_t [RegbusRulesNum-1:0] RegbusMap = { + reg_addr_rule_t'{ idx: RegbusErrId, start_addr: 32'h0000_0000, end_addr: 32'h0FFF_FFFF }, // Regbus error slave + reg_addr_rule_t'{ idx: RegbusPCRsId, start_addr: 32'h1000_0000, end_addr: 32'h1000_0FFF }, // Platform Control Registers + reg_addr_rule_t'{ idx: RegbusConsoleId, start_addr: 32'h1000_1000, end_addr: 32'h1000_1FFF }, // Sim console + reg_addr_rule_t'{ idx: RegbusClicId, start_addr: 32'h1004_0000, end_addr: 32'h1006_FFFF } // CLIC + }; + + ////////////////////// + // Helper functions // + ////////////////////// + + function automatic void log(string msg); + $display("@%t | [TB ] %s", $realtime, msg); + endfunction + + function automatic void setup(); + $display("==========================================="); + $display("======== CVA6 standalone testbench ========"); + $display("==========================================="); + // Time format + $timeformat(-9, 0, "ns", 9); // 1: scale (ns=-9), 2: decimals, 3: suffix, 4: print-field width + // Waveform logging + `ifdef VERILATOR + $dumpfile($sformatf("cva6tb.fst")); + $dumpvars; + `endif + endfunction + + function automatic void cleanup(); + $display("==========================================="); + $display("============ End of simulation ============"); + $display("==========================================="); + `ifdef VERILATOR + $dumpflush; + `endif + $finish; + endfunction + + function automatic void pass(); + log("**SIMULATION PASSED**"); + cleanup(); + endfunction + + function automatic void fail(); + log("**SIMULATION FAILED**"); + cleanup(); + endfunction + +endpackage diff --git a/test/hw/cva6tb_regs.sv b/test/hw/cva6tb_regs.sv new file mode 100644 index 00000000000..0e20f4c6519 --- /dev/null +++ b/test/hw/cva6tb_regs.sv @@ -0,0 +1,79 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Author: Enrico Zelioli + +package cva6tb_regs_pkg; + localparam int unsigned NumRegs = 16; + localparam int unsigned RegAddrWidth = $clog2(NumRegs); + + localparam logic [RegAddrWidth-1:0] BootaddrRegOffset = 4'h0; // Boot address register + localparam logic [RegAddrWidth-1:0] EOCRegOffset = 4'h1; // End Of Computation register +endpackage + +module cva6tb_regs #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic +) ( + input logic clk_i, + input logic rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + output logic [31:0] boot_addr_o +); + + import cva6tb_regs_pkg::*; + + logic [31:0] control_regs [NumRegs]; + logic [NumRegs-1:0] reg_select; + logic [31:0] write_mask; + + assign boot_addr_o = control_regs[BootaddrRegOffset]; + + // Register selection logic + genvar i; + generate + for (i = 0; i < NumRegs; i++) begin : gen_reg_select + assign reg_select[i] = (reg_req_i.addr[(RegAddrWidth+2)-1:2] == i); + end + endgenerate + + // Write bitmask + genvar j; + generate + for (j = 0; j < 4; j++) begin : gen_write_mask + assign write_mask[j*8 +: 8] = {8{reg_req_i.wstrb[j]}}; + end + endgenerate + + // Read logic + always_comb begin + reg_rsp_o = '0; + reg_rsp_o.ready = 1'b1; + reg_rsp_o.error = 1'b0; + reg_rsp_o.rdata = 32'd0; + for (int i = 0; i < NumRegs; i++) begin + if (reg_select[i]) begin + reg_rsp_o.rdata = control_regs[i]; + end + end + end + + // Register read/write logic + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + for (int i = 0; i < NumRegs; i++) begin + control_regs[i] <= 32'd0; + end + control_regs[BootaddrRegOffset] <= 32'h8000_0000; + end else begin + for (int i = 0; i < NumRegs; i++) begin + if (reg_req_i.valid && reg_req_i.write && reg_select[i]) begin + control_regs[i] <= (control_regs[i] & ~write_mask) | (reg_req_i.wdata & write_mask); + end + end + end + end + +endmodule diff --git a/test/hw/cva6tb_sim_console.sv b/test/hw/cva6tb_sim_console.sv new file mode 100644 index 00000000000..f30f51ea0cf --- /dev/null +++ b/test/hw/cva6tb_sim_console.sv @@ -0,0 +1,42 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Author: Enrico Zelioli +// +// Simulation console + +`include "common_cells/registers.svh" + +module cva6tb_sim_console #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic +) ( + input logic clk_i, + input logic rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o +); + + string buffer = ""; + + assign reg_rsp_o = reg_rsp_t'{ + rdata: '0, + error: 1'b0, + ready: 1'b1 + }; + + initial begin + forever @(posedge clk_i) begin + if (reg_req_i.valid && reg_req_i.write && (reg_req_i.addr[4:0] == 5'h0)) begin + if (reg_req_i.wdata[7:0] == 8'h0A) begin + $display("@%t | [CON] %s", $realtime, buffer); + buffer = ""; + end else begin + buffer = {buffer, reg_req_i.wdata[7:0]}; + end + end + end + end + +endmodule diff --git a/test/hw/cva6tb_soc.sv b/test/hw/cva6tb_soc.sv new file mode 100644 index 00000000000..3cd57a7fca0 --- /dev/null +++ b/test/hw/cva6tb_soc.sv @@ -0,0 +1,366 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Author: Enrico Zelioli +// +// Testbench SoC + +module cva6tb_soc + import ariane_pkg::*; + import cva6tb_pkg::*; +#( + parameter time ApplDelay = 0ps, + parameter time AcqDelay = 0ps +)( + input logic clk_i, + input logic rst_ni, + input logic [NumClicIrqs-1:0] clic_irqs_i +); + + logic clk; + logic rst_n; + logic [31:0] cva6_boot_addr; + rvfi_probes_t rvfi_probes; + + axi_mst_req_t axi_core_req; + axi_mst_rsp_t axi_core_rsp; + axi_slv_req_t axi_err_req; + axi_slv_rsp_t axi_err_rsp; + axi_slv_req_t axi_reg_req; + axi_slv_rsp_t axi_reg_rsp; + axi_slv_req_t axi_amo_req; + axi_slv_rsp_t axi_amo_rsp; + axi_slv_req_t axi_mem_req; + axi_slv_rsp_t axi_mem_rsp; + axi_mst_req_t [AxiXbarMasters-1:0] axi_mst_reqs; + axi_mst_rsp_t [AxiXbarMasters-1:0] axi_mst_rsps; + axi_slv_req_t [ AxiXbarSlaves-1:0] axi_slv_reqs; + axi_slv_rsp_t [ AxiXbarSlaves-1:0] axi_slv_rsps; + + logic clic_irq_valid, clic_irq_ready; + logic clic_irq_kill_req, clic_irq_kill_ack; + logic clic_irq_shv; + logic [7:0] clic_irq_id; + logic [7:0] clic_irq_level; + logic [1:0] clic_irq_priv; + logic clic_irq_v; + logic [5:0] clic_irq_vsid; + + reg_req_t reg_pcr_req; + reg_rsp_t reg_pcr_rsp; + reg_req_t reg_console_req; + reg_rsp_t reg_console_rsp; + reg_req_t reg_clic_req; + reg_rsp_t reg_clic_rsp; + reg_req_t reg_err_req; + reg_rsp_t reg_err_rsp; + reg_req_t reg_in_req; + reg_rsp_t reg_in_rsp; + reg_req_t [RegbusOutNum-1:0] reg_out_reqs; + reg_rsp_t [RegbusOutNum-1:0] reg_out_rsps; + + reg_idx_t reg_select; + reg_idx_t default_reg_idx; + + function automatic void load_hex(); + string binary_path; + if ($value$plusargs("binary=%s", binary_path)) begin + log($sformatf("Running program \"%s\"", binary_path)); + $readmemh(binary_path, i_axi_sim_mem.mem); + end else begin + log("WARNING: no binary path provided"); + end + endfunction + + assign clk = clk_i; + assign rst_n = rst_ni; + + assign default_reg_idx = (RegbusErrId); + + assign axi_mst_reqs[0] = axi_core_req; + assign axi_core_rsp = axi_mst_rsps[0]; + + assign axi_err_req = axi_slv_reqs[AxiSlvIdErrSlv]; + assign axi_slv_rsps[AxiSlvIdErrSlv] = axi_err_rsp; + + assign axi_reg_req = axi_slv_reqs[AxiSlvIdReg]; + assign axi_slv_rsps[AxiSlvIdReg] = axi_reg_rsp; + + assign axi_amo_req = axi_slv_reqs[AxiSlvIdSimMem]; + assign axi_slv_rsps[AxiSlvIdSimMem] = axi_amo_rsp; + + assign reg_err_req = reg_out_reqs[RegbusErrId]; + assign reg_out_rsps[RegbusErrId] = reg_err_rsp; + + assign reg_pcr_req = reg_out_reqs[RegbusPCRsId]; + assign reg_out_rsps[RegbusPCRsId] = reg_pcr_rsp; + + assign reg_console_req = reg_out_reqs[RegbusConsoleId]; + assign reg_out_rsps[RegbusConsoleId] = reg_console_rsp; + + assign reg_clic_req = reg_out_reqs[RegbusClicId]; + assign reg_out_rsps[RegbusClicId] = reg_clic_rsp; + + cva6 #( + .CVA6Cfg ( CVA6Cfg ), + .rvfi_probes_instr_t ( rvfi_probes_instr_t ), + .rvfi_probes_csr_t ( rvfi_probes_csr_t ), + .rvfi_probes_t ( rvfi_probes_t ), + .axi_ar_chan_t ( axi_mst_ar_chan_t ), + .axi_aw_chan_t ( axi_mst_aw_chan_t ), + .axi_w_chan_t ( axi_mst_w_chan_t ), + .b_chan_t ( axi_mst_b_chan_t ), + .r_chan_t ( axi_mst_r_chan_t ), + .noc_req_t ( axi_mst_req_t ), + .noc_resp_t ( axi_mst_rsp_t ) + ) i_cva6 ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .boot_addr_i ( {32'h0, cva6_boot_addr} ), + .hart_id_i ( 64'h0 ), + .irq_i ( '0 ), + .ipi_i ( '0 ), + .time_irq_i ( '0 ), + .debug_req_i ( '0 ), + .clic_irq_valid_i ( clic_irq_valid ), + .clic_irq_id_i ( clic_irq_id ), + .clic_irq_level_i ( clic_irq_level ), + .clic_irq_priv_i ( riscv::priv_lvl_t'(clic_irq_priv) ), + .clic_irq_v_i ( clic_irq_v ), + .clic_irq_vsid_i ( clic_irq_vsid ), + .clic_irq_shv_i ( clic_irq_shv ), + .clic_irq_ready_o ( clic_irq_ready ), + .clic_kill_req_i ( clic_irq_kill_req ), + .clic_kill_ack_o ( clic_irq_kill_ack ), + .rvfi_probes_o ( rvfi_probes ), + .cvxif_req_o ( /* Not connected */ ), + .cvxif_resp_i ( '0 ), + .noc_req_o ( axi_core_req ), + .noc_resp_i ( axi_core_rsp ) + ); + + // CLIC interrupt controller + clic #( + .N_SOURCE ( NumClicIrqs ), + .INTCTLBITS ( 8 ), + .reg_req_t ( reg_req_t ), + .reg_rsp_t ( reg_rsp_t ), + .SSCLIC ( 1 ), + .USCLIC ( 0 ), + .VSCLIC ( 1 ), + .N_VSCTXTS ( 4 ), + .VSPRIO ( 1 ), + .VSPRIO_W ( 1 ) + ) i_clic ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .reg_req_i ( reg_clic_req ), + .reg_rsp_o ( reg_clic_rsp ), + .intr_src_i ( clic_irqs_i ), + .irq_valid_o ( clic_irq_valid ), + .irq_ready_i ( clic_irq_ready ), + .irq_id_o ( clic_irq_id ), + .irq_level_o ( clic_irq_level ), + .irq_shv_o ( clic_irq_shv ), + .irq_priv_o ( clic_irq_priv ), + .irq_v_o ( clic_irq_v ), + .irq_vsid_o ( clic_irq_vsid ), + .irq_kill_req_o ( clic_irq_kill_req ), + .irq_kill_ack_i ( clic_irq_kill_ack ) + ); + + // AXI interconnect + axi_xbar #( + .Cfg ( AxiXbarCfg ), + .ATOPs ( 1 ), + .Connectivity ( '1 ), + .slv_aw_chan_t ( axi_mst_aw_chan_t ), + .mst_aw_chan_t ( axi_slv_aw_chan_t ), + .w_chan_t ( axi_mst_w_chan_t ), + .slv_b_chan_t ( axi_mst_b_chan_t ), + .mst_b_chan_t ( axi_slv_b_chan_t ), + .slv_ar_chan_t ( axi_mst_ar_chan_t ), + .mst_ar_chan_t ( axi_slv_ar_chan_t ), + .slv_r_chan_t ( axi_mst_r_chan_t ), + .mst_r_chan_t ( axi_slv_r_chan_t ), + .slv_req_t ( axi_mst_req_t ), + .slv_resp_t ( axi_mst_rsp_t ), + .mst_req_t ( axi_slv_req_t ), + .mst_resp_t ( axi_slv_rsp_t ), + .rule_t ( addr_rule_t ) + ) i_axi_xbar ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .test_i ( '0 ), + .slv_ports_req_i ( axi_mst_reqs ), + .slv_ports_resp_o ( axi_mst_rsps ), + .mst_ports_req_o ( axi_slv_reqs ), + .mst_ports_resp_i ( axi_slv_rsps ), + .addr_map_i ( AxiMap ), + .en_default_mst_port_i ( {AxiXbarMasters{1'b1}} ), + .default_mst_port_i ( {AxiXbarMasters{2'b0}} ) + ); + + // AXI error slave + axi_err_slv #( + .AxiIdWidth ( AxiSlvIdWidth ), + .axi_req_t ( axi_slv_req_t ), + .axi_resp_t ( axi_slv_rsp_t ) + ) i_axi_err_slv ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .test_i ( '0 ), + .slv_req_i ( axi_err_req ), + .slv_resp_o ( axi_err_rsp ) + ); + + // Convert from AXI to reg protocol + axi_to_reg_v2 #( + .AxiAddrWidth ( CVA6UserCfg.AxiAddrWidth ), + .AxiDataWidth ( CVA6UserCfg.AxiDataWidth ), + .AxiIdWidth ( AxiSlvIdWidth ), + .AxiUserWidth ( CVA6UserCfg.AxiUserWidth ), + .RegDataWidth ( 32 ), + .CutMemReqs ( 0 ), + .axi_req_t ( axi_slv_req_t ), + .axi_rsp_t ( axi_slv_rsp_t ), + .reg_req_t ( reg_req_t ), + .reg_rsp_t ( reg_rsp_t ) + ) i_axi_to_reg_v2 ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .axi_req_i ( axi_reg_req ), + .axi_rsp_o ( axi_reg_rsp ), + .reg_req_o ( reg_in_req ), + .reg_rsp_i ( reg_in_rsp ), + .reg_id_o ( ), + .busy_o ( ) + ); + + // Non-matching addresses are directed to an error slave + addr_decode #( + .NoIndices ( RegbusOutNum ), + .NoRules ( RegbusRulesNum ), + .addr_t ( reg_addr_t ), + .rule_t ( reg_addr_rule_t ) + ) i_reg_demux_decode ( + .addr_i ( reg_in_req.addr ), + .addr_map_i ( RegbusMap ), + .idx_o ( reg_select ), + .dec_valid_o ( ), + .dec_error_o ( ), + .en_default_idx_i ( 1'b1 ), + .default_idx_i ( default_reg_idx ) + ); + + reg_demux #( + .NoPorts ( RegbusOutNum ), + .req_t ( reg_req_t ), + .rsp_t ( reg_rsp_t ) + ) i_reg_demux ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .in_select_i ( reg_select ), + .in_req_i ( reg_in_req ), + .in_rsp_o ( reg_in_rsp ), + .out_req_o ( reg_out_reqs ), + .out_rsp_i ( reg_out_rsps ) + ); + + reg_err_slv #( + .DW ( 32 ), + .ERR_VAL ( 32'hBADCAB1E ), + .req_t ( reg_req_t ), + .rsp_t ( reg_rsp_t ) + ) i_reg_err_slv ( + .req_i ( reg_err_req ), + .rsp_o ( reg_err_rsp ) + ); + + // Platform control registers + cva6tb_regs #( + .reg_req_t ( reg_req_t ), + .reg_rsp_t ( reg_rsp_t ) + ) i_regs ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .reg_req_i ( reg_pcr_req ), + .reg_rsp_o ( reg_pcr_rsp ), + .boot_addr_o ( cva6_boot_addr ) + ); + + // Sim console + cva6tb_sim_console #( + .reg_req_t ( reg_req_t ), + .reg_rsp_t ( reg_rsp_t ) + ) i_sim_console ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .reg_req_i ( reg_console_req ), + .reg_rsp_o ( reg_console_rsp ) + ); + + // RISC-V atomics filter + axi_riscv_atomics_structs #( + .AxiAddrWidth ( CVA6UserCfg.AxiAddrWidth ), + .AxiDataWidth ( CVA6UserCfg.AxiDataWidth ), + .AxiIdWidth ( AxiSlvIdWidth ), + .AxiUserWidth ( CVA6UserCfg.AxiUserWidth ), + .AxiMaxReadTxns ( 24 ), + .AxiMaxWriteTxns ( 24 ), + .AxiUserAsId ( 1 ), + .AxiUserIdMsb ( 0 ), + .AxiUserIdLsb ( 0 ), + .RiscvWordWidth ( 64 ), + .NAxiCuts ( 0 ), + .axi_req_t ( axi_slv_req_t ), + .axi_rsp_t ( axi_slv_rsp_t ) + ) i_riscv_atomics ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .axi_slv_req_i ( axi_amo_req ), + .axi_slv_rsp_o ( axi_amo_rsp ), + .axi_mst_req_o ( axi_mem_req ), + .axi_mst_rsp_i ( axi_mem_rsp ) + ); + + // AXI simulated memory + axi_sim_mem #( + .AddrWidth ( CVA6UserCfg.AxiAddrWidth ), + .DataWidth ( CVA6UserCfg.AxiDataWidth ), + .IdWidth ( AxiSlvIdWidth ), + .UserWidth ( CVA6UserCfg.AxiUserWidth ), + .axi_req_t ( axi_slv_req_t ), + .axi_rsp_t ( axi_slv_rsp_t ), + .WarnUninitialized ( 0 ), + .ClearErrOnAccess ( 1 ), + `ifdef ZERO_SIM_MEM + .UninitializedData ( "zeros" ), + `else + .UninitializedData ( "undefined" ), + `endif + .ApplDelay ( ApplDelay ), + .AcqDelay ( AcqDelay ) + ) i_axi_sim_mem ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .axi_req_i ( axi_mem_req ), + .axi_rsp_o ( axi_mem_rsp ), + .mon_w_valid_o ( /* Not connected */ ), + .mon_w_addr_o ( /* Not connected */ ), + .mon_w_data_o ( /* Not connected */ ), + .mon_w_id_o ( /* Not connected */ ), + .mon_w_user_o ( /* Not connected */ ), + .mon_w_beat_count_o ( /* Not connected */ ), + .mon_w_last_o ( /* Not connected */ ), + .mon_r_valid_o ( /* Not connected */ ), + .mon_r_addr_o ( /* Not connected */ ), + .mon_r_data_o ( /* Not connected */ ), + .mon_r_id_o ( /* Not connected */ ), + .mon_r_user_o ( /* Not connected */ ), + .mon_r_beat_count_o ( /* Not connected */ ), + .mon_r_last_o ( /* Not connected */ ) + ); + +endmodule diff --git a/test/hw/cva6tb_test_simple.sv b/test/hw/cva6tb_test_simple.sv new file mode 100644 index 00000000000..bc708282aa8 --- /dev/null +++ b/test/hw/cva6tb_test_simple.sv @@ -0,0 +1,75 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Author: Enrico Zelioli +// +// Basic testbench pre-loading a binary and polling the EOC register for success. +// Times out after a specified number of cycles. + +module test; + + import ariane_pkg::*; + import cva6tb_pkg::*; + import cva6tb_regs_pkg::EOCRegOffset; + + localparam time ClkPeriod = 2ns; + localparam time ApplDelay = ClkPeriod * 0.1; + localparam time AcqDelay = ClkPeriod * 0.9; + localparam int unsigned RstCycles = 10; + + int unsigned RetCodeSuccess; + int unsigned MaxCycles; + + function automatic void parse_args(); + if (!$value$plusargs("RetCodeSccess=%d", RetCodeSuccess)) RetCodeSuccess = 0; + if (!$value$plusargs("MaxCycles=%d", MaxCycles)) MaxCycles = 10_000; + endfunction + + logic clk; + logic rst_n; + logic eoc; + logic [30:0] retcode; + + assign eoc = i_dut.i_regs.control_regs[EOCRegOffset][0]; + assign retcode = i_dut.i_regs.control_regs[EOCRegOffset][31:1]; + + clk_rst_gen #( + .ClkPeriod ( ClkPeriod ), + .RstClkCycles ( RstCycles ) + ) i_clk_rst_gen ( + .clk_o ( clk ), + .rst_no ( rst_n ) + ); + + cva6tb_soc #( + .ApplDelay ( ApplDelay ), + .AcqDelay ( AcqDelay ) + ) i_dut ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .clic_irqs_i ( '0 ) + ); + + initial begin + setup(); + // Parse command line arguments + parse_args(); + // Preload binary into simulation memory + i_dut.load_hex(); + // Wait for reset de-assertion + wait(rst_n); + // Poll EOC + for (int unsigned i = 0; i < MaxCycles; ++i) begin + @(posedge clk); + if(eoc == 1'b1) begin + log($sformatf("EOC register was set to one - return code: %0d", retcode)); + if (retcode == RetCodeSuccess) pass(); + else fail(); + end + end + log($sformatf("Simluation timed out after %d cycles", MaxCycles)); + fail(); + end + +endmodule diff --git a/test/sw/.gitignore b/test/sw/.gitignore new file mode 100644 index 00000000000..00db6b98ce1 --- /dev/null +++ b/test/sw/.gitignore @@ -0,0 +1,2 @@ +out/ +deps/printf/ diff --git a/test/sw/Makefile b/test/sw/Makefile new file mode 100644 index 00000000000..f57115502a1 --- /dev/null +++ b/test/sw/Makefile @@ -0,0 +1,112 @@ +# Copyright 2026 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Enrico Zelioli + +SW_DIR := $(realpath .) +LD_DIR := $(SW_DIR)/link +LIB_DIR := $(SW_DIR)/lib +SRC_DIR := $(SW_DIR)/tests +INC_DIR := $(SW_DIR)/include +OUT_DIR := $(SW_DIR)/out +DEPS_DIR := $(SW_DIR)/deps + +RV_BINROOT ?= $(dir $(shell which riscv64-unknown-elf-gcc)) +RV_AR := $(RV_BINROOT)/riscv64-unknown-elf-ar +RV_CC := $(RV_BINROOT)/riscv64-unknown-elf-gcc +RV_OBJCOPY := $(RV_BINROOT)/riscv64-unknown-elf-objcopy +RV_OBJDUMP := $(RV_BINROOT)/riscv64-unknown-elf-objdump + +SW_FLAGS := -DOT_PLATFORM_RV32 -march=rv64gc_zifencei -mabi=lp64d -mstrict-align -O2 -Wall -Wextra -static -ffunction-sections -ffreestanding -fdata-sections -frandom-seed=cheshire -fuse-linker-plugin -flto -Wl,-flto +SW_CCFLAGS := $(SW_FLAGS) -ggdb -mcmodel=medany -mexplicit-relocs -fno-builtin -fverbose-asm -pipe +SW_LDFLAGS := $(SW_FLAGS) -nostartfiles -Wl,--gc-sections -Wl,-L$(LD_DIR) + +LIB_SRCS_S = $(shell find $(LIB_DIR) -name "*.S") +LIB_SRCS_C = $(shell find $(LIB_DIR) -name "*.c") +LIB_SRCS_O = $(patsubst $(LIB_DIR)/%,$(OUT_DIR)/lib/%,$(LIB_SRCS_S:.S=.o) $(LIB_SRCS_C:.c=.o)) + +DEPS_INC := $(DEPS_DIR)/printf +DEPS_SRCS_C := $(DEPS_DIR)/printf/printf.c +DEPS_SRCS_O := $(patsubst $(DEPS_DIR)/%,$(OUT_DIR)/deps/%,$(DEPS_SRCS_C:.c=.o)) + +TEST_SRCS_C := $(shell find $(SRC_DIR) -name "*.c") +TEST_SRCS_S := $(shell find $(SRC_DIR) -name "*.S") +TEST_SRCS_O := $(patsubst $(SRC_DIR)/%,$(OUT_DIR)/tests/%,$(TEST_SRCS_C:.c=.o) $(TEST_SRCS_S:.S=.o)) +TEST_ELFS := $(patsubst $(SRC_DIR)/%,$(OUT_DIR)/%,$(TEST_SRCS_C:.c=.elf) $(TEST_SRCS_S:.S=.elf)) +TEST_DUMPS := $(TEST_ELFS:.elf=.dump) +TEST_HEXES := $(TEST_ELFS:.elf=.hex) + +.PRECIOUS: $(OUT_DIR)/%.elf $(OUT_DIR)/tests/%.o + +.PHONY: default +default: all + +$(DEPS_DIR)/printf: + git clone -b v4.0.0 https://github.com/mpaland/printf.git $(DEPS_DIR)/printf + +$(DEPS_DIR)/riscv-tests/: $(DEPS_DIR)/patches/riscv-tests.patch $(DEPS_DIR)/patches/riscv-tests-env.patch + git clone https://github.com/riscv-software-src/riscv-tests.git $(DEPS_DIR)/riscv-tests + cd $(DEPS_DIR)/riscv-tests && git submodule update --init --recursive + cd $(DEPS_DIR)/riscv-tests && git apply $(DEPS_DIR)/patches/riscv-tests.patch + cd $(DEPS_DIR)/riscv-tests && git apply $(DEPS_DIR)/patches/riscv-tests-fencet.patch + cd $(DEPS_DIR)/riscv-tests/env && git apply $(DEPS_DIR)/patches/riscv-tests-env.patch + +$(DEPS_DIR)/riscv-hyp-tests/: $(DEPS_DIR)/patches/riscv-hyp-tests.patch + git clone https://github.com/josecm/riscv-hyp-tests.git $(DEPS_DIR)/riscv-hyp-tests + cd $(DEPS_DIR)/riscv-hyp-tests && git apply $(DEPS_DIR)/patches/riscv-hyp-tests.patch + +.PHONY: riscv-tests +riscv-tests: | $(DEPS_DIR)/riscv-tests/ + @mkdir -p $(DEPS_DIR)/riscv-tests/build + cd $(DEPS_DIR)/riscv-tests/build && ../configure && make isa + +.PHONY: riscv-hyp-tests +riscv-hyp-tests: | $(DEPS_DIR)/riscv-hyp-tests/ + make -C $(DEPS_DIR)/riscv-hyp-tests PLAT=cva6 LOG_LEVEL=LOG_DETAIL + $(RV_OBJCOPY) -O verilog $(DEPS_DIR)/riscv-hyp-tests/build/cva6/rvh_test.elf $(DEPS_DIR)/riscv-hyp-tests/build/cva6/rvh_test.hex + +.PHONY: deps +deps: $(DEPS_DIR)/printf + +.PHONY: lib +lib: $(OUT_DIR)/libcva6.a + +.PHONY: all +all: $(DEPS_DIR)/printf $(TEST_DUMPS) $(TEST_HEXES) + +.PHONY: clean +clean: + rm -rf $(OUT_DIR) + +$(OUT_DIR)/deps/%.o: $(DEPS_DIR)/%.c + @mkdir -p $(dir $@) + $(RV_CC) $(SW_CCFLAGS) -I$(DEPS_INC) -c $< -o $@ + +$(OUT_DIR)/lib/%.o: $(LIB_DIR)/%.c + @mkdir -p $(dir $@) + $(RV_CC) $(SW_CCFLAGS) -I$(INC_DIR) -I$(DEPS_INC) -c $< -o $@ + +$(OUT_DIR)/lib/%.o: $(LIB_DIR)/%.S + @mkdir -p $(dir $@) + $(RV_CC) $(SW_CCFLAGS) -I$(INC_DIR) -I$(DEPS_INC) -c $< -o $@ + +$(OUT_DIR)/libcva6.a: $(LIB_SRCS_O) $(DEPS_SRCS_O) + $(RV_AR) rcs $@ $^ + +$(OUT_DIR)/tests/%.o: $(SRC_DIR)/%.c + @mkdir -p $(dir $@) + $(RV_CC) $(SW_CCFLAGS) -I$(INC_DIR) -I$(DEPS_INC) -c $< -o $@ + +$(OUT_DIR)/tests/%.o: $(SRC_DIR)/%.S + @mkdir -p $(dir $@) + $(RV_CC) $(SW_CCFLAGS) -I$(INC_DIR) -I$(DEPS_INC) -c $< -o $@ + +$(OUT_DIR)/%.elf: $(OUT_DIR)/tests/%.o $(OUT_DIR)/libcva6.a + $(RV_CC) $(SW_LDFLAGS) -T$(LD_DIR)/link.ld -o $@ $< $(OUT_DIR)/libcva6.a + +$(OUT_DIR)/%.dump: $(OUT_DIR)/%.elf + $(RV_OBJDUMP) -d $< > $@ + +$(OUT_DIR)/%.hex: $(OUT_DIR)/%.elf + $(RV_OBJCOPY) -O verilog $< $@ diff --git a/test/sw/deps/patches/riscv-hyp-tests.patch b/test/sw/deps/patches/riscv-hyp-tests.patch new file mode 100644 index 00000000000..d6bda5ddc7f --- /dev/null +++ b/test/sw/deps/patches/riscv-hyp-tests.patch @@ -0,0 +1,2143 @@ +diff --git a/inc/rvh_test.h b/inc/rvh_test.h +index 352eafe..7cca2d6 100644 +--- a/inc/rvh_test.h ++++ b/inc/rvh_test.h +@@ -89,7 +89,7 @@ static const char* priv_strs[] = { + + enum ecall {ECALL_GOTO_PRIV = 1}; + +-extern struct exception { ++extern volatile struct exception { + bool testing; + bool triggered; + enum priv priv; +@@ -124,7 +124,7 @@ extern size_t test_table_size; + printf(CBLU "\t%-85.*s" CDFLT, line_size, test);\ + for(int i = line_size; i < size; i+=line_size)\ + printf(CBLU "\n\t%-85.*s" CDFLT, line_size, &test[i]);\ +- printf("%s" CDFLT, (cond) ? CGRN "PASSED" : CRED "FAILED");\ ++ printf("%s" CDFLT, (cond) ? CGRN "PASSED" CDFLT : CRED "FAILED" CDFLT);\ + if(!(cond)) { printf("\n\t("); printf(""__VA_ARGS__); printf(")"); }\ + printf("\n");\ + }\ +@@ -166,7 +166,7 @@ extern size_t test_table_size; + #define TEST_END(test) {\ + failed:\ + if(LOG_LEVEL >= LOG_INFO && LOG_LEVEL < LOG_VERBOSE){\ +- printf("%s\n" CDFLT, (test_status) ? CGRN "PASSED" : CRED "FAILED");\ ++ printf("%s\n" CDFLT, (test_status) ? CGRN "PASSED" CDFLT : CRED "FAILED" CDFLT);\ + }\ + goto_priv(PRIV_M);\ + reset_state();\ +diff --git a/platform/cva6/encoding.h b/platform/cva6/encoding.h +new file mode 100644 +index 0000000..c109ce1 +--- /dev/null ++++ b/platform/cva6/encoding.h +@@ -0,0 +1,1471 @@ ++// See LICENSE for license details. ++ ++#ifndef RISCV_CSR_ENCODING_H ++#define RISCV_CSR_ENCODING_H ++ ++#define MSTATUS_UIE 0x00000001 ++#define MSTATUS_SIE 0x00000002 ++#define MSTATUS_HIE 0x00000004 ++#define MSTATUS_MIE 0x00000008 ++#define MSTATUS_UPIE 0x00000010 ++#define MSTATUS_SPIE 0x00000020 ++#define MSTATUS_HPIE 0x00000040 ++#define MSTATUS_MPIE 0x00000080 ++#define MSTATUS_SPP 0x00000100 ++#define MSTATUS_HPP 0x00000600 ++#define MSTATUS_MPP 0x00001800 ++#define MSTATUS_FS 0x00006000 ++#define MSTATUS_XS 0x00018000 ++#define MSTATUS_MPRV 0x00020000 ++#define MSTATUS_SUM 0x00040000 ++#define MSTATUS_MXR 0x00080000 ++#define MSTATUS_TVM 0x00100000 ++#define MSTATUS_TW 0x00200000 ++#define MSTATUS_TSR 0x00400000 ++#define MSTATUS32_SD 0x80000000 ++#define MSTATUS_UXL 0x0000000300000000 ++#define MSTATUS_SXL 0x0000000C00000000 ++#define MSTATUS64_SD 0x8000000000000000 ++ ++#define SSTATUS_UIE 0x00000001 ++#define SSTATUS_SIE 0x00000002 ++#define SSTATUS_UPIE 0x00000010 ++#define SSTATUS_SPIE 0x00000020 ++#define SSTATUS_SPP 0x00000100 ++#define SSTATUS_FS 0x00006000 ++#define SSTATUS_XS 0x00018000 ++#define SSTATUS_SUM 0x00040000 ++#define SSTATUS_MXR 0x00080000 ++#define SSTATUS32_SD 0x80000000 ++#define SSTATUS_UXL 0x0000000300000000 ++#define SSTATUS64_SD 0x8000000000000000 ++ ++#define DCSR_XDEBUGVER (3U<<30) ++#define DCSR_NDRESET (1<<29) ++#define DCSR_FULLRESET (1<<28) ++#define DCSR_EBREAKM (1<<15) ++#define DCSR_EBREAKH (1<<14) ++#define DCSR_EBREAKS (1<<13) ++#define DCSR_EBREAKU (1<<12) ++#define DCSR_STOPCYCLE (1<<10) ++#define DCSR_STOPTIME (1<<9) ++#define DCSR_CAUSE (7<<6) ++#define DCSR_DEBUGINT (1<<5) ++#define DCSR_HALT (1<<3) ++#define DCSR_STEP (1<<2) ++#define DCSR_PRV (3<<0) ++ ++#define DCSR_CAUSE_NONE 0 ++#define DCSR_CAUSE_SWBP 1 ++#define DCSR_CAUSE_HWBP 2 ++#define DCSR_CAUSE_DEBUGINT 3 ++#define DCSR_CAUSE_STEP 4 ++#define DCSR_CAUSE_HALT 5 ++ ++#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) ++#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) ++#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) ++ ++#define MCONTROL_SELECT (1<<19) ++#define MCONTROL_TIMING (1<<18) ++#define MCONTROL_ACTION (0x3f<<12) ++#define MCONTROL_CHAIN (1<<11) ++#define MCONTROL_MATCH (0xf<<7) ++#define MCONTROL_M (1<<6) ++#define MCONTROL_H (1<<5) ++#define MCONTROL_S (1<<4) ++#define MCONTROL_U (1<<3) ++#define MCONTROL_EXECUTE (1<<2) ++#define MCONTROL_STORE (1<<1) ++#define MCONTROL_LOAD (1<<0) ++ ++#define MCONTROL_TYPE_NONE 0 ++#define MCONTROL_TYPE_MATCH 2 ++ ++#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 ++#define MCONTROL_ACTION_DEBUG_MODE 1 ++#define MCONTROL_ACTION_TRACE_START 2 ++#define MCONTROL_ACTION_TRACE_STOP 3 ++#define MCONTROL_ACTION_TRACE_EMIT 4 ++ ++#define MCONTROL_MATCH_EQUAL 0 ++#define MCONTROL_MATCH_NAPOT 1 ++#define MCONTROL_MATCH_GE 2 ++#define MCONTROL_MATCH_LT 3 ++#define MCONTROL_MATCH_MASK_LOW 4 ++#define MCONTROL_MATCH_MASK_HIGH 5 ++ ++#define MIP_SSIP (1 << IRQ_S_SOFT) ++#define MIP_HSIP (1 << IRQ_H_SOFT) ++#define MIP_MSIP (1 << IRQ_M_SOFT) ++#define MIP_STIP (1 << IRQ_S_TIMER) ++#define MIP_HTIP (1 << IRQ_H_TIMER) ++#define MIP_MTIP (1 << IRQ_M_TIMER) ++#define MIP_SEIP (1 << IRQ_S_EXT) ++#define MIP_HEIP (1 << IRQ_H_EXT) ++#define MIP_MEIP (1 << IRQ_M_EXT) ++ ++#define SIP_SSIP MIP_SSIP ++#define SIP_STIP MIP_STIP ++ ++#define PRV_U 0 ++#define PRV_S 1 ++#define PRV_H 2 ++#define PRV_M 3 ++ ++#define SATP32_MODE 0x80000000 ++#define SATP32_ASID 0x7FC00000 ++#define SATP32_PPN 0x003FFFFF ++#define SATP64_MODE 0xF000000000000000 ++#define SATP64_ASID 0x0FFFF00000000000 ++#define SATP64_PPN 0x00000FFFFFFFFFFF ++ ++#define SATP_MODE_OFF 0 ++#define SATP_MODE_SV32 1 ++#define SATP_MODE_SV39 8 ++#define SATP_MODE_SV48 9 ++#define SATP_MODE_SV57 10 ++#define SATP_MODE_SV64 11 ++ ++#define PMP_R 0x01 ++#define PMP_W 0x02 ++#define PMP_X 0x04 ++#define PMP_A 0x18 ++#define PMP_L 0x80 ++#define PMP_SHIFT 2 ++ ++#define PMP_TOR 0x08 ++#define PMP_NA4 0x10 ++#define PMP_NAPOT 0x18 ++ ++#define IRQ_S_SOFT 1 ++#define IRQ_H_SOFT 2 ++#define IRQ_M_SOFT 3 ++#define IRQ_S_TIMER 5 ++#define IRQ_H_TIMER 6 ++#define IRQ_M_TIMER 7 ++#define IRQ_S_EXT 9 ++#define IRQ_H_EXT 10 ++#define IRQ_M_EXT 11 ++#define IRQ_COP 12 ++#define IRQ_HOST 13 ++ ++#define DEFAULT_RSTVEC 0x00001000 ++#define CLINT_BASE 0x02000000 ++#define CLINT_SIZE 0x000c0000 ++#define EXT_IO_BASE 0x40000000 ++#define DRAM_BASE 0x80000000 ++ ++// page table entry (PTE) fields ++#define PTE_V 0x001 // Valid ++#define PTE_R 0x002 // Read ++#define PTE_W 0x004 // Write ++#define PTE_X 0x008 // Execute ++#define PTE_U 0x010 // User ++#define PTE_G 0x020 // Global ++#define PTE_A 0x040 // Accessed ++#define PTE_D 0x080 // Dirty ++#define PTE_SOFT 0x300 // Reserved for Software ++ ++#define PTE_PPN_SHIFT 10 ++ ++#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) ++ ++#ifdef __riscv ++ ++#if __riscv_xlen == 64 ++# define MSTATUS_SD MSTATUS64_SD ++# define SSTATUS_SD SSTATUS64_SD ++# define RISCV_PGLEVEL_BITS 9 ++# define SATP_MODE SATP64_MODE ++#else ++# define MSTATUS_SD MSTATUS32_SD ++# define SSTATUS_SD SSTATUS32_SD ++# define RISCV_PGLEVEL_BITS 10 ++# define SATP_MODE SATP32_MODE ++#endif ++#define RISCV_PGSHIFT 12 ++#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) ++ ++#ifndef __ASSEMBLER__ ++ ++#ifdef __GNUC__ ++ ++#define read_csr(reg) ({ unsigned long __tmp; \ ++ asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ ++ __tmp; }) ++ ++#define write_csr(reg, val) ({ \ ++ asm volatile ("csrw " #reg ", %0" :: "rK"(val)); }) ++ ++#define swap_csr(reg, val) ({ unsigned long __tmp; \ ++ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ ++ __tmp; }) ++ ++#define set_csr(reg, bit) ({ unsigned long __tmp; \ ++ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ ++ __tmp; }) ++ ++#define clear_csr(reg, bit) ({ unsigned long __tmp; \ ++ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ ++ __tmp; }) ++ ++#define rdtime() read_csr(time) ++#define rdcycle() read_csr(cycle) ++#define rdinstret() read_csr(instret) ++ ++#endif ++ ++#endif ++ ++#endif ++ ++#endif ++/* Automatically generated by parse-opcodes. */ ++#ifndef RISCV_ENCODING_H ++#define RISCV_ENCODING_H ++#define MATCH_BEQ 0x63 ++#define MASK_BEQ 0x707f ++#define MATCH_BNE 0x1063 ++#define MASK_BNE 0x707f ++#define MATCH_BLT 0x4063 ++#define MASK_BLT 0x707f ++#define MATCH_BGE 0x5063 ++#define MASK_BGE 0x707f ++#define MATCH_BLTU 0x6063 ++#define MASK_BLTU 0x707f ++#define MATCH_BGEU 0x7063 ++#define MASK_BGEU 0x707f ++#define MATCH_JALR 0x67 ++#define MASK_JALR 0x707f ++#define MATCH_JAL 0x6f ++#define MASK_JAL 0x7f ++#define MATCH_LUI 0x37 ++#define MASK_LUI 0x7f ++#define MATCH_AUIPC 0x17 ++#define MASK_AUIPC 0x7f ++#define MATCH_ADDI 0x13 ++#define MASK_ADDI 0x707f ++#define MATCH_SLLI 0x1013 ++#define MASK_SLLI 0xfc00707f ++#define MATCH_SLTI 0x2013 ++#define MASK_SLTI 0x707f ++#define MATCH_SLTIU 0x3013 ++#define MASK_SLTIU 0x707f ++#define MATCH_XORI 0x4013 ++#define MASK_XORI 0x707f ++#define MATCH_SRLI 0x5013 ++#define MASK_SRLI 0xfc00707f ++#define MATCH_SRAI 0x40005013 ++#define MASK_SRAI 0xfc00707f ++#define MATCH_ORI 0x6013 ++#define MASK_ORI 0x707f ++#define MATCH_ANDI 0x7013 ++#define MASK_ANDI 0x707f ++#define MATCH_ADD 0x33 ++#define MASK_ADD 0xfe00707f ++#define MATCH_SUB 0x40000033 ++#define MASK_SUB 0xfe00707f ++#define MATCH_SLL 0x1033 ++#define MASK_SLL 0xfe00707f ++#define MATCH_SLT 0x2033 ++#define MASK_SLT 0xfe00707f ++#define MATCH_SLTU 0x3033 ++#define MASK_SLTU 0xfe00707f ++#define MATCH_XOR 0x4033 ++#define MASK_XOR 0xfe00707f ++#define MATCH_SRL 0x5033 ++#define MASK_SRL 0xfe00707f ++#define MATCH_SRA 0x40005033 ++#define MASK_SRA 0xfe00707f ++#define MATCH_OR 0x6033 ++#define MASK_OR 0xfe00707f ++#define MATCH_AND 0x7033 ++#define MASK_AND 0xfe00707f ++#define MATCH_ADDIW 0x1b ++#define MASK_ADDIW 0x707f ++#define MATCH_SLLIW 0x101b ++#define MASK_SLLIW 0xfe00707f ++#define MATCH_SRLIW 0x501b ++#define MASK_SRLIW 0xfe00707f ++#define MATCH_SRAIW 0x4000501b ++#define MASK_SRAIW 0xfe00707f ++#define MATCH_ADDW 0x3b ++#define MASK_ADDW 0xfe00707f ++#define MATCH_SUBW 0x4000003b ++#define MASK_SUBW 0xfe00707f ++#define MATCH_SLLW 0x103b ++#define MASK_SLLW 0xfe00707f ++#define MATCH_SRLW 0x503b ++#define MASK_SRLW 0xfe00707f ++#define MATCH_SRAW 0x4000503b ++#define MASK_SRAW 0xfe00707f ++#define MATCH_LB 0x3 ++#define MASK_LB 0x707f ++#define MATCH_LH 0x1003 ++#define MASK_LH 0x707f ++#define MATCH_LW 0x2003 ++#define MASK_LW 0x707f ++#define MATCH_LD 0x3003 ++#define MASK_LD 0x707f ++#define MATCH_LBU 0x4003 ++#define MASK_LBU 0x707f ++#define MATCH_LHU 0x5003 ++#define MASK_LHU 0x707f ++#define MATCH_LWU 0x6003 ++#define MASK_LWU 0x707f ++#define MATCH_SB 0x23 ++#define MASK_SB 0x707f ++#define MATCH_SH 0x1023 ++#define MASK_SH 0x707f ++#define MATCH_SW 0x2023 ++#define MASK_SW 0x707f ++#define MATCH_SD 0x3023 ++#define MASK_SD 0x707f ++#define MATCH_FENCE 0xf ++#define MASK_FENCE 0x707f ++#define MATCH_FENCE_I 0x100f ++#define MASK_FENCE_I 0x707f ++#define MATCH_MUL 0x2000033 ++#define MASK_MUL 0xfe00707f ++#define MATCH_MULH 0x2001033 ++#define MASK_MULH 0xfe00707f ++#define MATCH_MULHSU 0x2002033 ++#define MASK_MULHSU 0xfe00707f ++#define MATCH_MULHU 0x2003033 ++#define MASK_MULHU 0xfe00707f ++#define MATCH_DIV 0x2004033 ++#define MASK_DIV 0xfe00707f ++#define MATCH_DIVU 0x2005033 ++#define MASK_DIVU 0xfe00707f ++#define MATCH_REM 0x2006033 ++#define MASK_REM 0xfe00707f ++#define MATCH_REMU 0x2007033 ++#define MASK_REMU 0xfe00707f ++#define MATCH_MULW 0x200003b ++#define MASK_MULW 0xfe00707f ++#define MATCH_DIVW 0x200403b ++#define MASK_DIVW 0xfe00707f ++#define MATCH_DIVUW 0x200503b ++#define MASK_DIVUW 0xfe00707f ++#define MATCH_REMW 0x200603b ++#define MASK_REMW 0xfe00707f ++#define MATCH_REMUW 0x200703b ++#define MASK_REMUW 0xfe00707f ++#define MATCH_AMOADD_W 0x202f ++#define MASK_AMOADD_W 0xf800707f ++#define MATCH_AMOXOR_W 0x2000202f ++#define MASK_AMOXOR_W 0xf800707f ++#define MATCH_AMOOR_W 0x4000202f ++#define MASK_AMOOR_W 0xf800707f ++#define MATCH_AMOAND_W 0x6000202f ++#define MASK_AMOAND_W 0xf800707f ++#define MATCH_AMOMIN_W 0x8000202f ++#define MASK_AMOMIN_W 0xf800707f ++#define MATCH_AMOMAX_W 0xa000202f ++#define MASK_AMOMAX_W 0xf800707f ++#define MATCH_AMOMINU_W 0xc000202f ++#define MASK_AMOMINU_W 0xf800707f ++#define MATCH_AMOMAXU_W 0xe000202f ++#define MASK_AMOMAXU_W 0xf800707f ++#define MATCH_AMOSWAP_W 0x800202f ++#define MASK_AMOSWAP_W 0xf800707f ++#define MATCH_LR_W 0x1000202f ++#define MASK_LR_W 0xf9f0707f ++#define MATCH_SC_W 0x1800202f ++#define MASK_SC_W 0xf800707f ++#define MATCH_AMOADD_D 0x302f ++#define MASK_AMOADD_D 0xf800707f ++#define MATCH_AMOXOR_D 0x2000302f ++#define MASK_AMOXOR_D 0xf800707f ++#define MATCH_AMOOR_D 0x4000302f ++#define MASK_AMOOR_D 0xf800707f ++#define MATCH_AMOAND_D 0x6000302f ++#define MASK_AMOAND_D 0xf800707f ++#define MATCH_AMOMIN_D 0x8000302f ++#define MASK_AMOMIN_D 0xf800707f ++#define MATCH_AMOMAX_D 0xa000302f ++#define MASK_AMOMAX_D 0xf800707f ++#define MATCH_AMOMINU_D 0xc000302f ++#define MASK_AMOMINU_D 0xf800707f ++#define MATCH_AMOMAXU_D 0xe000302f ++#define MASK_AMOMAXU_D 0xf800707f ++#define MATCH_AMOSWAP_D 0x800302f ++#define MASK_AMOSWAP_D 0xf800707f ++#define MATCH_LR_D 0x1000302f ++#define MASK_LR_D 0xf9f0707f ++#define MATCH_SC_D 0x1800302f ++#define MASK_SC_D 0xf800707f ++#define MATCH_ECALL 0x73 ++#define MASK_ECALL 0xffffffff ++#define MATCH_EBREAK 0x100073 ++#define MASK_EBREAK 0xffffffff ++#define MATCH_URET 0x200073 ++#define MASK_URET 0xffffffff ++#define MATCH_SRET 0x10200073 ++#define MASK_SRET 0xffffffff ++#define MATCH_MRET 0x30200073 ++#define MASK_MRET 0xffffffff ++#define MATCH_DRET 0x7b200073 ++#define MASK_DRET 0xffffffff ++#define MATCH_SFENCE_VMA 0x12000073 ++#define MASK_SFENCE_VMA 0xfe007fff ++#define MATCH_WFI 0x10500073 ++#define MASK_WFI 0xffffffff ++#define MATCH_CSRRW 0x1073 ++#define MASK_CSRRW 0x707f ++#define MATCH_CSRRS 0x2073 ++#define MASK_CSRRS 0x707f ++#define MATCH_CSRRC 0x3073 ++#define MASK_CSRRC 0x707f ++#define MATCH_CSRRWI 0x5073 ++#define MASK_CSRRWI 0x707f ++#define MATCH_CSRRSI 0x6073 ++#define MASK_CSRRSI 0x707f ++#define MATCH_CSRRCI 0x7073 ++#define MASK_CSRRCI 0x707f ++#define MATCH_FADD_S 0x53 ++#define MASK_FADD_S 0xfe00007f ++#define MATCH_FSUB_S 0x8000053 ++#define MASK_FSUB_S 0xfe00007f ++#define MATCH_FMUL_S 0x10000053 ++#define MASK_FMUL_S 0xfe00007f ++#define MATCH_FDIV_S 0x18000053 ++#define MASK_FDIV_S 0xfe00007f ++#define MATCH_FSGNJ_S 0x20000053 ++#define MASK_FSGNJ_S 0xfe00707f ++#define MATCH_FSGNJN_S 0x20001053 ++#define MASK_FSGNJN_S 0xfe00707f ++#define MATCH_FSGNJX_S 0x20002053 ++#define MASK_FSGNJX_S 0xfe00707f ++#define MATCH_FMIN_S 0x28000053 ++#define MASK_FMIN_S 0xfe00707f ++#define MATCH_FMAX_S 0x28001053 ++#define MASK_FMAX_S 0xfe00707f ++#define MATCH_FSQRT_S 0x58000053 ++#define MASK_FSQRT_S 0xfff0007f ++#define MATCH_FADD_D 0x2000053 ++#define MASK_FADD_D 0xfe00007f ++#define MATCH_FSUB_D 0xa000053 ++#define MASK_FSUB_D 0xfe00007f ++#define MATCH_FMUL_D 0x12000053 ++#define MASK_FMUL_D 0xfe00007f ++#define MATCH_FDIV_D 0x1a000053 ++#define MASK_FDIV_D 0xfe00007f ++#define MATCH_FSGNJ_D 0x22000053 ++#define MASK_FSGNJ_D 0xfe00707f ++#define MATCH_FSGNJN_D 0x22001053 ++#define MASK_FSGNJN_D 0xfe00707f ++#define MATCH_FSGNJX_D 0x22002053 ++#define MASK_FSGNJX_D 0xfe00707f ++#define MATCH_FMIN_D 0x2a000053 ++#define MASK_FMIN_D 0xfe00707f ++#define MATCH_FMAX_D 0x2a001053 ++#define MASK_FMAX_D 0xfe00707f ++#define MATCH_FCVT_S_D 0x40100053 ++#define MASK_FCVT_S_D 0xfff0007f ++#define MATCH_FCVT_D_S 0x42000053 ++#define MASK_FCVT_D_S 0xfff0007f ++#define MATCH_FSQRT_D 0x5a000053 ++#define MASK_FSQRT_D 0xfff0007f ++#define MATCH_FADD_Q 0x6000053 ++#define MASK_FADD_Q 0xfe00007f ++#define MATCH_FSUB_Q 0xe000053 ++#define MASK_FSUB_Q 0xfe00007f ++#define MATCH_FMUL_Q 0x16000053 ++#define MASK_FMUL_Q 0xfe00007f ++#define MATCH_FDIV_Q 0x1e000053 ++#define MASK_FDIV_Q 0xfe00007f ++#define MATCH_FSGNJ_Q 0x26000053 ++#define MASK_FSGNJ_Q 0xfe00707f ++#define MATCH_FSGNJN_Q 0x26001053 ++#define MASK_FSGNJN_Q 0xfe00707f ++#define MATCH_FSGNJX_Q 0x26002053 ++#define MASK_FSGNJX_Q 0xfe00707f ++#define MATCH_FMIN_Q 0x2e000053 ++#define MASK_FMIN_Q 0xfe00707f ++#define MATCH_FMAX_Q 0x2e001053 ++#define MASK_FMAX_Q 0xfe00707f ++#define MATCH_FCVT_S_Q 0x40300053 ++#define MASK_FCVT_S_Q 0xfff0007f ++#define MATCH_FCVT_Q_S 0x46000053 ++#define MASK_FCVT_Q_S 0xfff0007f ++#define MATCH_FCVT_D_Q 0x42300053 ++#define MASK_FCVT_D_Q 0xfff0007f ++#define MATCH_FCVT_Q_D 0x46100053 ++#define MASK_FCVT_Q_D 0xfff0007f ++#define MATCH_FSQRT_Q 0x5e000053 ++#define MASK_FSQRT_Q 0xfff0007f ++#define MATCH_FLE_S 0xa0000053 ++#define MASK_FLE_S 0xfe00707f ++#define MATCH_FLT_S 0xa0001053 ++#define MASK_FLT_S 0xfe00707f ++#define MATCH_FEQ_S 0xa0002053 ++#define MASK_FEQ_S 0xfe00707f ++#define MATCH_FLE_D 0xa2000053 ++#define MASK_FLE_D 0xfe00707f ++#define MATCH_FLT_D 0xa2001053 ++#define MASK_FLT_D 0xfe00707f ++#define MATCH_FEQ_D 0xa2002053 ++#define MASK_FEQ_D 0xfe00707f ++#define MATCH_FLE_Q 0xa6000053 ++#define MASK_FLE_Q 0xfe00707f ++#define MATCH_FLT_Q 0xa6001053 ++#define MASK_FLT_Q 0xfe00707f ++#define MATCH_FEQ_Q 0xa6002053 ++#define MASK_FEQ_Q 0xfe00707f ++#define MATCH_FCVT_W_S 0xc0000053 ++#define MASK_FCVT_W_S 0xfff0007f ++#define MATCH_FCVT_WU_S 0xc0100053 ++#define MASK_FCVT_WU_S 0xfff0007f ++#define MATCH_FCVT_L_S 0xc0200053 ++#define MASK_FCVT_L_S 0xfff0007f ++#define MATCH_FCVT_LU_S 0xc0300053 ++#define MASK_FCVT_LU_S 0xfff0007f ++#define MATCH_FMV_X_W 0xe0000053 ++#define MASK_FMV_X_W 0xfff0707f ++#define MATCH_FCLASS_S 0xe0001053 ++#define MASK_FCLASS_S 0xfff0707f ++#define MATCH_FCVT_W_D 0xc2000053 ++#define MASK_FCVT_W_D 0xfff0007f ++#define MATCH_FCVT_WU_D 0xc2100053 ++#define MASK_FCVT_WU_D 0xfff0007f ++#define MATCH_FCVT_L_D 0xc2200053 ++#define MASK_FCVT_L_D 0xfff0007f ++#define MATCH_FCVT_LU_D 0xc2300053 ++#define MASK_FCVT_LU_D 0xfff0007f ++#define MATCH_FMV_X_D 0xe2000053 ++#define MASK_FMV_X_D 0xfff0707f ++#define MATCH_FCLASS_D 0xe2001053 ++#define MASK_FCLASS_D 0xfff0707f ++#define MATCH_FCVT_W_Q 0xc6000053 ++#define MASK_FCVT_W_Q 0xfff0007f ++#define MATCH_FCVT_WU_Q 0xc6100053 ++#define MASK_FCVT_WU_Q 0xfff0007f ++#define MATCH_FCVT_L_Q 0xc6200053 ++#define MASK_FCVT_L_Q 0xfff0007f ++#define MATCH_FCVT_LU_Q 0xc6300053 ++#define MASK_FCVT_LU_Q 0xfff0007f ++#define MATCH_FMV_X_Q 0xe6000053 ++#define MASK_FMV_X_Q 0xfff0707f ++#define MATCH_FCLASS_Q 0xe6001053 ++#define MASK_FCLASS_Q 0xfff0707f ++#define MATCH_FCVT_S_W 0xd0000053 ++#define MASK_FCVT_S_W 0xfff0007f ++#define MATCH_FCVT_S_WU 0xd0100053 ++#define MASK_FCVT_S_WU 0xfff0007f ++#define MATCH_FCVT_S_L 0xd0200053 ++#define MASK_FCVT_S_L 0xfff0007f ++#define MATCH_FCVT_S_LU 0xd0300053 ++#define MASK_FCVT_S_LU 0xfff0007f ++#define MATCH_FMV_W_X 0xf0000053 ++#define MASK_FMV_W_X 0xfff0707f ++#define MATCH_FCVT_D_W 0xd2000053 ++#define MASK_FCVT_D_W 0xfff0007f ++#define MATCH_FCVT_D_WU 0xd2100053 ++#define MASK_FCVT_D_WU 0xfff0007f ++#define MATCH_FCVT_D_L 0xd2200053 ++#define MASK_FCVT_D_L 0xfff0007f ++#define MATCH_FCVT_D_LU 0xd2300053 ++#define MASK_FCVT_D_LU 0xfff0007f ++#define MATCH_FMV_D_X 0xf2000053 ++#define MASK_FMV_D_X 0xfff0707f ++#define MATCH_FCVT_Q_W 0xd6000053 ++#define MASK_FCVT_Q_W 0xfff0007f ++#define MATCH_FCVT_Q_WU 0xd6100053 ++#define MASK_FCVT_Q_WU 0xfff0007f ++#define MATCH_FCVT_Q_L 0xd6200053 ++#define MASK_FCVT_Q_L 0xfff0007f ++#define MATCH_FCVT_Q_LU 0xd6300053 ++#define MASK_FCVT_Q_LU 0xfff0007f ++#define MATCH_FMV_Q_X 0xf6000053 ++#define MASK_FMV_Q_X 0xfff0707f ++#define MATCH_FLW 0x2007 ++#define MASK_FLW 0x707f ++#define MATCH_FLD 0x3007 ++#define MASK_FLD 0x707f ++#define MATCH_FLQ 0x4007 ++#define MASK_FLQ 0x707f ++#define MATCH_FSW 0x2027 ++#define MASK_FSW 0x707f ++#define MATCH_FSD 0x3027 ++#define MASK_FSD 0x707f ++#define MATCH_FSQ 0x4027 ++#define MASK_FSQ 0x707f ++#define MATCH_FMADD_S 0x43 ++#define MASK_FMADD_S 0x600007f ++#define MATCH_FMSUB_S 0x47 ++#define MASK_FMSUB_S 0x600007f ++#define MATCH_FNMSUB_S 0x4b ++#define MASK_FNMSUB_S 0x600007f ++#define MATCH_FNMADD_S 0x4f ++#define MASK_FNMADD_S 0x600007f ++#define MATCH_FMADD_D 0x2000043 ++#define MASK_FMADD_D 0x600007f ++#define MATCH_FMSUB_D 0x2000047 ++#define MASK_FMSUB_D 0x600007f ++#define MATCH_FNMSUB_D 0x200004b ++#define MASK_FNMSUB_D 0x600007f ++#define MATCH_FNMADD_D 0x200004f ++#define MASK_FNMADD_D 0x600007f ++#define MATCH_FMADD_Q 0x6000043 ++#define MASK_FMADD_Q 0x600007f ++#define MATCH_FMSUB_Q 0x6000047 ++#define MASK_FMSUB_Q 0x600007f ++#define MATCH_FNMSUB_Q 0x600004b ++#define MASK_FNMSUB_Q 0x600007f ++#define MATCH_FNMADD_Q 0x600004f ++#define MASK_FNMADD_Q 0x600007f ++#define MATCH_C_NOP 0x1 ++#define MASK_C_NOP 0xffff ++#define MATCH_C_ADDI16SP 0x6101 ++#define MASK_C_ADDI16SP 0xef83 ++#define MATCH_C_JR 0x8002 ++#define MASK_C_JR 0xf07f ++#define MATCH_C_JALR 0x9002 ++#define MASK_C_JALR 0xf07f ++#define MATCH_C_EBREAK 0x9002 ++#define MASK_C_EBREAK 0xffff ++#define MATCH_C_LD 0x6000 ++#define MASK_C_LD 0xe003 ++#define MATCH_C_SD 0xe000 ++#define MASK_C_SD 0xe003 ++#define MATCH_C_ADDIW 0x2001 ++#define MASK_C_ADDIW 0xe003 ++#define MATCH_C_LDSP 0x6002 ++#define MASK_C_LDSP 0xe003 ++#define MATCH_C_SDSP 0xe002 ++#define MASK_C_SDSP 0xe003 ++#define MATCH_C_ADDI4SPN 0x0 ++#define MASK_C_ADDI4SPN 0xe003 ++#define MATCH_C_FLD 0x2000 ++#define MASK_C_FLD 0xe003 ++#define MATCH_C_LW 0x4000 ++#define MASK_C_LW 0xe003 ++#define MATCH_C_FLW 0x6000 ++#define MASK_C_FLW 0xe003 ++#define MATCH_C_FSD 0xa000 ++#define MASK_C_FSD 0xe003 ++#define MATCH_C_SW 0xc000 ++#define MASK_C_SW 0xe003 ++#define MATCH_C_FSW 0xe000 ++#define MASK_C_FSW 0xe003 ++#define MATCH_C_ADDI 0x1 ++#define MASK_C_ADDI 0xe003 ++#define MATCH_C_JAL 0x2001 ++#define MASK_C_JAL 0xe003 ++#define MATCH_C_LI 0x4001 ++#define MASK_C_LI 0xe003 ++#define MATCH_C_LUI 0x6001 ++#define MASK_C_LUI 0xe003 ++#define MATCH_C_SRLI 0x8001 ++#define MASK_C_SRLI 0xec03 ++#define MATCH_C_SRAI 0x8401 ++#define MASK_C_SRAI 0xec03 ++#define MATCH_C_ANDI 0x8801 ++#define MASK_C_ANDI 0xec03 ++#define MATCH_C_SUB 0x8c01 ++#define MASK_C_SUB 0xfc63 ++#define MATCH_C_XOR 0x8c21 ++#define MASK_C_XOR 0xfc63 ++#define MATCH_C_OR 0x8c41 ++#define MASK_C_OR 0xfc63 ++#define MATCH_C_AND 0x8c61 ++#define MASK_C_AND 0xfc63 ++#define MATCH_C_SUBW 0x9c01 ++#define MASK_C_SUBW 0xfc63 ++#define MATCH_C_ADDW 0x9c21 ++#define MASK_C_ADDW 0xfc63 ++#define MATCH_C_J 0xa001 ++#define MASK_C_J 0xe003 ++#define MATCH_C_BEQZ 0xc001 ++#define MASK_C_BEQZ 0xe003 ++#define MATCH_C_BNEZ 0xe001 ++#define MASK_C_BNEZ 0xe003 ++#define MATCH_C_SLLI 0x2 ++#define MASK_C_SLLI 0xe003 ++#define MATCH_C_FLDSP 0x2002 ++#define MASK_C_FLDSP 0xe003 ++#define MATCH_C_LWSP 0x4002 ++#define MASK_C_LWSP 0xe003 ++#define MATCH_C_FLWSP 0x6002 ++#define MASK_C_FLWSP 0xe003 ++#define MATCH_C_MV 0x8002 ++#define MASK_C_MV 0xf003 ++#define MATCH_C_ADD 0x9002 ++#define MASK_C_ADD 0xf003 ++#define MATCH_C_FSDSP 0xa002 ++#define MASK_C_FSDSP 0xe003 ++#define MATCH_C_SWSP 0xc002 ++#define MASK_C_SWSP 0xe003 ++#define MATCH_C_FSWSP 0xe002 ++#define MASK_C_FSWSP 0xe003 ++#define MATCH_CUSTOM0 0xb ++#define MASK_CUSTOM0 0x707f ++#define MATCH_CUSTOM0_RS1 0x200b ++#define MASK_CUSTOM0_RS1 0x707f ++#define MATCH_CUSTOM0_RS1_RS2 0x300b ++#define MASK_CUSTOM0_RS1_RS2 0x707f ++#define MATCH_CUSTOM0_RD 0x400b ++#define MASK_CUSTOM0_RD 0x707f ++#define MATCH_CUSTOM0_RD_RS1 0x600b ++#define MASK_CUSTOM0_RD_RS1 0x707f ++#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b ++#define MASK_CUSTOM0_RD_RS1_RS2 0x707f ++#define MATCH_CUSTOM1 0x2b ++#define MASK_CUSTOM1 0x707f ++#define MATCH_CUSTOM1_RS1 0x202b ++#define MASK_CUSTOM1_RS1 0x707f ++#define MATCH_CUSTOM1_RS1_RS2 0x302b ++#define MASK_CUSTOM1_RS1_RS2 0x707f ++#define MATCH_CUSTOM1_RD 0x402b ++#define MASK_CUSTOM1_RD 0x707f ++#define MATCH_CUSTOM1_RD_RS1 0x602b ++#define MASK_CUSTOM1_RD_RS1 0x707f ++#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b ++#define MASK_CUSTOM1_RD_RS1_RS2 0x707f ++#define MATCH_CUSTOM2 0x5b ++#define MASK_CUSTOM2 0x707f ++#define MATCH_CUSTOM2_RS1 0x205b ++#define MASK_CUSTOM2_RS1 0x707f ++#define MATCH_CUSTOM2_RS1_RS2 0x305b ++#define MASK_CUSTOM2_RS1_RS2 0x707f ++#define MATCH_CUSTOM2_RD 0x405b ++#define MASK_CUSTOM2_RD 0x707f ++#define MATCH_CUSTOM2_RD_RS1 0x605b ++#define MASK_CUSTOM2_RD_RS1 0x707f ++#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b ++#define MASK_CUSTOM2_RD_RS1_RS2 0x707f ++#define MATCH_CUSTOM3 0x7b ++#define MASK_CUSTOM3 0x707f ++#define MATCH_CUSTOM3_RS1 0x207b ++#define MASK_CUSTOM3_RS1 0x707f ++#define MATCH_CUSTOM3_RS1_RS2 0x307b ++#define MASK_CUSTOM3_RS1_RS2 0x707f ++#define MATCH_CUSTOM3_RD 0x407b ++#define MASK_CUSTOM3_RD 0x707f ++#define MATCH_CUSTOM3_RD_RS1 0x607b ++#define MASK_CUSTOM3_RD_RS1 0x707f ++#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b ++#define MASK_CUSTOM3_RD_RS1_RS2 0x707f ++#define CSR_FFLAGS 0x1 ++#define CSR_FRM 0x2 ++#define CSR_FCSR 0x3 ++#define CSR_CYCLE 0xc00 ++#define CSR_TIME 0xc01 ++#define CSR_INSTRET 0xc02 ++#define CSR_HPMCOUNTER3 0xc03 ++#define CSR_HPMCOUNTER4 0xc04 ++#define CSR_HPMCOUNTER5 0xc05 ++#define CSR_HPMCOUNTER6 0xc06 ++#define CSR_HPMCOUNTER7 0xc07 ++#define CSR_HPMCOUNTER8 0xc08 ++#define CSR_HPMCOUNTER9 0xc09 ++#define CSR_HPMCOUNTER10 0xc0a ++#define CSR_HPMCOUNTER11 0xc0b ++#define CSR_HPMCOUNTER12 0xc0c ++#define CSR_HPMCOUNTER13 0xc0d ++#define CSR_HPMCOUNTER14 0xc0e ++#define CSR_HPMCOUNTER15 0xc0f ++#define CSR_HPMCOUNTER16 0xc10 ++#define CSR_HPMCOUNTER17 0xc11 ++#define CSR_HPMCOUNTER18 0xc12 ++#define CSR_HPMCOUNTER19 0xc13 ++#define CSR_HPMCOUNTER20 0xc14 ++#define CSR_HPMCOUNTER21 0xc15 ++#define CSR_HPMCOUNTER22 0xc16 ++#define CSR_HPMCOUNTER23 0xc17 ++#define CSR_HPMCOUNTER24 0xc18 ++#define CSR_HPMCOUNTER25 0xc19 ++#define CSR_HPMCOUNTER26 0xc1a ++#define CSR_HPMCOUNTER27 0xc1b ++#define CSR_HPMCOUNTER28 0xc1c ++#define CSR_HPMCOUNTER29 0xc1d ++#define CSR_HPMCOUNTER30 0xc1e ++#define CSR_HPMCOUNTER31 0xc1f ++#define CSR_SSTATUS 0x100 ++#define CSR_SIE 0x104 ++#define CSR_STVEC 0x105 ++#define CSR_SCOUNTEREN 0x106 ++#define CSR_SSCRATCH 0x140 ++#define CSR_SEPC 0x141 ++#define CSR_SCAUSE 0x142 ++#define CSR_STVAL 0x143 ++#define CSR_SIP 0x144 ++#define CSR_SATP 0x180 ++#define CSR_MSTATUS 0x300 ++#define CSR_MISA 0x301 ++#define CSR_MEDELEG 0x302 ++#define CSR_MIDELEG 0x303 ++#define CSR_MIE 0x304 ++#define CSR_MTVEC 0x305 ++#define CSR_MCOUNTEREN 0x306 ++#define CSR_MSCRATCH 0x340 ++#define CSR_MEPC 0x341 ++#define CSR_MCAUSE 0x342 ++#define CSR_MTVAL 0x343 ++#define CSR_MIP 0x344 ++#define CSR_PMPCFG0 0x3a0 ++#define CSR_PMPCFG1 0x3a1 ++#define CSR_PMPCFG2 0x3a2 ++#define CSR_PMPCFG3 0x3a3 ++#define CSR_PMPADDR0 0x3b0 ++#define CSR_PMPADDR1 0x3b1 ++#define CSR_PMPADDR2 0x3b2 ++#define CSR_PMPADDR3 0x3b3 ++#define CSR_PMPADDR4 0x3b4 ++#define CSR_PMPADDR5 0x3b5 ++#define CSR_PMPADDR6 0x3b6 ++#define CSR_PMPADDR7 0x3b7 ++#define CSR_PMPADDR8 0x3b8 ++#define CSR_PMPADDR9 0x3b9 ++#define CSR_PMPADDR10 0x3ba ++#define CSR_PMPADDR11 0x3bb ++#define CSR_PMPADDR12 0x3bc ++#define CSR_PMPADDR13 0x3bd ++#define CSR_PMPADDR14 0x3be ++#define CSR_PMPADDR15 0x3bf ++#define CSR_TSELECT 0x7a0 ++#define CSR_TDATA1 0x7a1 ++#define CSR_TDATA2 0x7a2 ++#define CSR_TDATA3 0x7a3 ++#define CSR_DCSR 0x7b0 ++#define CSR_DPC 0x7b1 ++#define CSR_DSCRATCH 0x7b2 ++#define CSR_MCYCLE 0xb00 ++#define CSR_MINSTRET 0xb02 ++#define CSR_MHPMCOUNTER3 0xb03 ++#define CSR_MHPMCOUNTER4 0xb04 ++#define CSR_MHPMCOUNTER5 0xb05 ++#define CSR_MHPMCOUNTER6 0xb06 ++#define CSR_MHPMCOUNTER7 0xb07 ++#define CSR_MHPMCOUNTER8 0xb08 ++#define CSR_MHPMCOUNTER9 0xb09 ++#define CSR_MHPMCOUNTER10 0xb0a ++#define CSR_MHPMCOUNTER11 0xb0b ++#define CSR_MHPMCOUNTER12 0xb0c ++#define CSR_MHPMCOUNTER13 0xb0d ++#define CSR_MHPMCOUNTER14 0xb0e ++#define CSR_MHPMCOUNTER15 0xb0f ++#define CSR_MHPMCOUNTER16 0xb10 ++#define CSR_MHPMCOUNTER17 0xb11 ++#define CSR_MHPMCOUNTER18 0xb12 ++#define CSR_MHPMCOUNTER19 0xb13 ++#define CSR_MHPMCOUNTER20 0xb14 ++#define CSR_MHPMCOUNTER21 0xb15 ++#define CSR_MHPMCOUNTER22 0xb16 ++#define CSR_MHPMCOUNTER23 0xb17 ++#define CSR_MHPMCOUNTER24 0xb18 ++#define CSR_MHPMCOUNTER25 0xb19 ++#define CSR_MHPMCOUNTER26 0xb1a ++#define CSR_MHPMCOUNTER27 0xb1b ++#define CSR_MHPMCOUNTER28 0xb1c ++#define CSR_MHPMCOUNTER29 0xb1d ++#define CSR_MHPMCOUNTER30 0xb1e ++#define CSR_MHPMCOUNTER31 0xb1f ++#define CSR_MHPMEVENT3 0x323 ++#define CSR_MHPMEVENT4 0x324 ++#define CSR_MHPMEVENT5 0x325 ++#define CSR_MHPMEVENT6 0x326 ++#define CSR_MHPMEVENT7 0x327 ++#define CSR_MHPMEVENT8 0x328 ++#define CSR_MHPMEVENT9 0x329 ++#define CSR_MHPMEVENT10 0x32a ++#define CSR_MHPMEVENT11 0x32b ++#define CSR_MHPMEVENT12 0x32c ++#define CSR_MHPMEVENT13 0x32d ++#define CSR_MHPMEVENT14 0x32e ++#define CSR_MHPMEVENT15 0x32f ++#define CSR_MHPMEVENT16 0x330 ++#define CSR_MHPMEVENT17 0x331 ++#define CSR_MHPMEVENT18 0x332 ++#define CSR_MHPMEVENT19 0x333 ++#define CSR_MHPMEVENT20 0x334 ++#define CSR_MHPMEVENT21 0x335 ++#define CSR_MHPMEVENT22 0x336 ++#define CSR_MHPMEVENT23 0x337 ++#define CSR_MHPMEVENT24 0x338 ++#define CSR_MHPMEVENT25 0x339 ++#define CSR_MHPMEVENT26 0x33a ++#define CSR_MHPMEVENT27 0x33b ++#define CSR_MHPMEVENT28 0x33c ++#define CSR_MHPMEVENT29 0x33d ++#define CSR_MHPMEVENT30 0x33e ++#define CSR_MHPMEVENT31 0x33f ++#define CSR_MVENDORID 0xf11 ++#define CSR_MARCHID 0xf12 ++#define CSR_MIMPID 0xf13 ++#define CSR_MHARTID 0xf14 ++#define CSR_CYCLEH 0xc80 ++#define CSR_TIMEH 0xc81 ++#define CSR_INSTRETH 0xc82 ++#define CSR_HPMCOUNTER3H 0xc83 ++#define CSR_HPMCOUNTER4H 0xc84 ++#define CSR_HPMCOUNTER5H 0xc85 ++#define CSR_HPMCOUNTER6H 0xc86 ++#define CSR_HPMCOUNTER7H 0xc87 ++#define CSR_HPMCOUNTER8H 0xc88 ++#define CSR_HPMCOUNTER9H 0xc89 ++#define CSR_HPMCOUNTER10H 0xc8a ++#define CSR_HPMCOUNTER11H 0xc8b ++#define CSR_HPMCOUNTER12H 0xc8c ++#define CSR_HPMCOUNTER13H 0xc8d ++#define CSR_HPMCOUNTER14H 0xc8e ++#define CSR_HPMCOUNTER15H 0xc8f ++#define CSR_HPMCOUNTER16H 0xc90 ++#define CSR_HPMCOUNTER17H 0xc91 ++#define CSR_HPMCOUNTER18H 0xc92 ++#define CSR_HPMCOUNTER19H 0xc93 ++#define CSR_HPMCOUNTER20H 0xc94 ++#define CSR_HPMCOUNTER21H 0xc95 ++#define CSR_HPMCOUNTER22H 0xc96 ++#define CSR_HPMCOUNTER23H 0xc97 ++#define CSR_HPMCOUNTER24H 0xc98 ++#define CSR_HPMCOUNTER25H 0xc99 ++#define CSR_HPMCOUNTER26H 0xc9a ++#define CSR_HPMCOUNTER27H 0xc9b ++#define CSR_HPMCOUNTER28H 0xc9c ++#define CSR_HPMCOUNTER29H 0xc9d ++#define CSR_HPMCOUNTER30H 0xc9e ++#define CSR_HPMCOUNTER31H 0xc9f ++#define CSR_MCYCLEH 0xb80 ++#define CSR_MINSTRETH 0xb82 ++#define CSR_MHPMCOUNTER3H 0xb83 ++#define CSR_MHPMCOUNTER4H 0xb84 ++#define CSR_MHPMCOUNTER5H 0xb85 ++#define CSR_MHPMCOUNTER6H 0xb86 ++#define CSR_MHPMCOUNTER7H 0xb87 ++#define CSR_MHPMCOUNTER8H 0xb88 ++#define CSR_MHPMCOUNTER9H 0xb89 ++#define CSR_MHPMCOUNTER10H 0xb8a ++#define CSR_MHPMCOUNTER11H 0xb8b ++#define CSR_MHPMCOUNTER12H 0xb8c ++#define CSR_MHPMCOUNTER13H 0xb8d ++#define CSR_MHPMCOUNTER14H 0xb8e ++#define CSR_MHPMCOUNTER15H 0xb8f ++#define CSR_MHPMCOUNTER16H 0xb90 ++#define CSR_MHPMCOUNTER17H 0xb91 ++#define CSR_MHPMCOUNTER18H 0xb92 ++#define CSR_MHPMCOUNTER19H 0xb93 ++#define CSR_MHPMCOUNTER20H 0xb94 ++#define CSR_MHPMCOUNTER21H 0xb95 ++#define CSR_MHPMCOUNTER22H 0xb96 ++#define CSR_MHPMCOUNTER23H 0xb97 ++#define CSR_MHPMCOUNTER24H 0xb98 ++#define CSR_MHPMCOUNTER25H 0xb99 ++#define CSR_MHPMCOUNTER26H 0xb9a ++#define CSR_MHPMCOUNTER27H 0xb9b ++#define CSR_MHPMCOUNTER28H 0xb9c ++#define CSR_MHPMCOUNTER29H 0xb9d ++#define CSR_MHPMCOUNTER30H 0xb9e ++#define CSR_MHPMCOUNTER31H 0xb9f ++#define CAUSE_MISALIGNED_FETCH 0x0 ++#define CAUSE_FETCH_ACCESS 0x1 ++#define CAUSE_ILLEGAL_INSTRUCTION 0x2 ++#define CAUSE_BREAKPOINT 0x3 ++#define CAUSE_MISALIGNED_LOAD 0x4 ++#define CAUSE_LOAD_ACCESS 0x5 ++#define CAUSE_MISALIGNED_STORE 0x6 ++#define CAUSE_STORE_ACCESS 0x7 ++#define CAUSE_USER_ECALL 0x8 ++#define CAUSE_SUPERVISOR_ECALL 0x9 ++#define CAUSE_HYPERVISOR_ECALL 0xa ++#define CAUSE_MACHINE_ECALL 0xb ++#define CAUSE_FETCH_PAGE_FAULT 0xc ++#define CAUSE_LOAD_PAGE_FAULT 0xd ++#define CAUSE_STORE_PAGE_FAULT 0xf ++#endif ++#ifdef DECLARE_INSN ++DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) ++DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) ++DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) ++DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) ++DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) ++DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) ++DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) ++DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) ++DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) ++DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) ++DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) ++DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) ++DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) ++DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) ++DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) ++DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) ++DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) ++DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) ++DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) ++DECLARE_INSN(add, MATCH_ADD, MASK_ADD) ++DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) ++DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) ++DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) ++DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) ++DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) ++DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) ++DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) ++DECLARE_INSN(or, MATCH_OR, MASK_OR) ++DECLARE_INSN(and, MATCH_AND, MASK_AND) ++DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) ++DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) ++DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) ++DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) ++DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) ++DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) ++DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) ++DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) ++DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) ++DECLARE_INSN(lb, MATCH_LB, MASK_LB) ++DECLARE_INSN(lh, MATCH_LH, MASK_LH) ++DECLARE_INSN(lw, MATCH_LW, MASK_LW) ++DECLARE_INSN(ld, MATCH_LD, MASK_LD) ++DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) ++DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) ++DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) ++DECLARE_INSN(sb, MATCH_SB, MASK_SB) ++DECLARE_INSN(sh, MATCH_SH, MASK_SH) ++DECLARE_INSN(sw, MATCH_SW, MASK_SW) ++DECLARE_INSN(sd, MATCH_SD, MASK_SD) ++DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) ++DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) ++DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) ++DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) ++DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) ++DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) ++DECLARE_INSN(div, MATCH_DIV, MASK_DIV) ++DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) ++DECLARE_INSN(rem, MATCH_REM, MASK_REM) ++DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) ++DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) ++DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) ++DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) ++DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) ++DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) ++DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) ++DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) ++DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) ++DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) ++DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) ++DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) ++DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) ++DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) ++DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) ++DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) ++DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) ++DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) ++DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) ++DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) ++DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) ++DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) ++DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) ++DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) ++DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) ++DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) ++DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) ++DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) ++DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) ++DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) ++DECLARE_INSN(uret, MATCH_URET, MASK_URET) ++DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) ++DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) ++DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) ++DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) ++DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) ++DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) ++DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) ++DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) ++DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) ++DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) ++DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) ++DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) ++DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) ++DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) ++DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) ++DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) ++DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) ++DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) ++DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) ++DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) ++DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) ++DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) ++DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) ++DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) ++DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) ++DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) ++DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) ++DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) ++DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) ++DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) ++DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) ++DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) ++DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) ++DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) ++DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) ++DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) ++DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) ++DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) ++DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) ++DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) ++DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) ++DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) ++DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) ++DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) ++DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) ++DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) ++DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) ++DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) ++DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) ++DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) ++DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) ++DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) ++DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) ++DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) ++DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) ++DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) ++DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) ++DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) ++DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) ++DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) ++DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) ++DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) ++DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) ++DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) ++DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) ++DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) ++DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) ++DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) ++DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) ++DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) ++DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) ++DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) ++DECLARE_INSN(fmv_x_q, MATCH_FMV_X_Q, MASK_FMV_X_Q) ++DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) ++DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) ++DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) ++DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) ++DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) ++DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) ++DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) ++DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) ++DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) ++DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) ++DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) ++DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) ++DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) ++DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) ++DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) ++DECLARE_INSN(fmv_q_x, MATCH_FMV_Q_X, MASK_FMV_Q_X) ++DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) ++DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) ++DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) ++DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) ++DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) ++DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) ++DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) ++DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) ++DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) ++DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) ++DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) ++DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) ++DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) ++DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) ++DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) ++DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) ++DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) ++DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) ++DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) ++DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) ++DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) ++DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) ++DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) ++DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) ++DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) ++DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) ++DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) ++DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) ++DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) ++DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) ++DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) ++DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) ++DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) ++DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) ++DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) ++DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) ++DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) ++DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) ++DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) ++DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) ++DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) ++DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) ++DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) ++DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) ++DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) ++DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) ++DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) ++DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) ++DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) ++DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) ++DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) ++DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) ++DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) ++DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) ++DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) ++DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) ++DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) ++DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) ++DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) ++DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) ++DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) ++DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) ++DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) ++DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) ++DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) ++DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) ++DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) ++DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) ++DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) ++DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) ++DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) ++DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) ++DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) ++DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) ++DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) ++DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) ++DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) ++DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) ++DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) ++DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) ++DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) ++DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) ++DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) ++DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) ++#endif ++#ifdef DECLARE_CSR ++DECLARE_CSR(fflags, CSR_FFLAGS) ++DECLARE_CSR(frm, CSR_FRM) ++DECLARE_CSR(fcsr, CSR_FCSR) ++DECLARE_CSR(cycle, CSR_CYCLE) ++DECLARE_CSR(time, CSR_TIME) ++DECLARE_CSR(instret, CSR_INSTRET) ++DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) ++DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) ++DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) ++DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) ++DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) ++DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) ++DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) ++DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) ++DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) ++DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) ++DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) ++DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) ++DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) ++DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) ++DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) ++DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) ++DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) ++DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) ++DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) ++DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) ++DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) ++DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) ++DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) ++DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) ++DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) ++DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) ++DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) ++DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) ++DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) ++DECLARE_CSR(sstatus, CSR_SSTATUS) ++DECLARE_CSR(sie, CSR_SIE) ++DECLARE_CSR(stvec, CSR_STVEC) ++DECLARE_CSR(scounteren, CSR_SCOUNTEREN) ++DECLARE_CSR(sscratch, CSR_SSCRATCH) ++DECLARE_CSR(sepc, CSR_SEPC) ++DECLARE_CSR(scause, CSR_SCAUSE) ++DECLARE_CSR(stval, CSR_STVAL) ++DECLARE_CSR(sip, CSR_SIP) ++DECLARE_CSR(satp, CSR_SATP) ++DECLARE_CSR(mstatus, CSR_MSTATUS) ++DECLARE_CSR(misa, CSR_MISA) ++DECLARE_CSR(medeleg, CSR_MEDELEG) ++DECLARE_CSR(mideleg, CSR_MIDELEG) ++DECLARE_CSR(mie, CSR_MIE) ++DECLARE_CSR(mtvec, CSR_MTVEC) ++DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) ++DECLARE_CSR(mscratch, CSR_MSCRATCH) ++DECLARE_CSR(mepc, CSR_MEPC) ++DECLARE_CSR(mcause, CSR_MCAUSE) ++DECLARE_CSR(mtval, CSR_MTVAL) ++DECLARE_CSR(mip, CSR_MIP) ++DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) ++DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) ++DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) ++DECLARE_CSR(pmpcfg3, CSR_PMPCFG3) ++DECLARE_CSR(pmpaddr0, CSR_PMPADDR0) ++DECLARE_CSR(pmpaddr1, CSR_PMPADDR1) ++DECLARE_CSR(pmpaddr2, CSR_PMPADDR2) ++DECLARE_CSR(pmpaddr3, CSR_PMPADDR3) ++DECLARE_CSR(pmpaddr4, CSR_PMPADDR4) ++DECLARE_CSR(pmpaddr5, CSR_PMPADDR5) ++DECLARE_CSR(pmpaddr6, CSR_PMPADDR6) ++DECLARE_CSR(pmpaddr7, CSR_PMPADDR7) ++DECLARE_CSR(pmpaddr8, CSR_PMPADDR8) ++DECLARE_CSR(pmpaddr9, CSR_PMPADDR9) ++DECLARE_CSR(pmpaddr10, CSR_PMPADDR10) ++DECLARE_CSR(pmpaddr11, CSR_PMPADDR11) ++DECLARE_CSR(pmpaddr12, CSR_PMPADDR12) ++DECLARE_CSR(pmpaddr13, CSR_PMPADDR13) ++DECLARE_CSR(pmpaddr14, CSR_PMPADDR14) ++DECLARE_CSR(pmpaddr15, CSR_PMPADDR15) ++DECLARE_CSR(tselect, CSR_TSELECT) ++DECLARE_CSR(tdata1, CSR_TDATA1) ++DECLARE_CSR(tdata2, CSR_TDATA2) ++DECLARE_CSR(tdata3, CSR_TDATA3) ++DECLARE_CSR(dcsr, CSR_DCSR) ++DECLARE_CSR(dpc, CSR_DPC) ++DECLARE_CSR(dscratch, CSR_DSCRATCH) ++DECLARE_CSR(mcycle, CSR_MCYCLE) ++DECLARE_CSR(minstret, CSR_MINSTRET) ++DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) ++DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) ++DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) ++DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) ++DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) ++DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) ++DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) ++DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) ++DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) ++DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) ++DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) ++DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) ++DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) ++DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) ++DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) ++DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) ++DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) ++DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) ++DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) ++DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) ++DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) ++DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) ++DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) ++DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) ++DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) ++DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) ++DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) ++DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) ++DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) ++DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) ++DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) ++DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) ++DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) ++DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) ++DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) ++DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) ++DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) ++DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) ++DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) ++DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) ++DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) ++DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) ++DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) ++DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) ++DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) ++DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) ++DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) ++DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) ++DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) ++DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) ++DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) ++DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) ++DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) ++DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) ++DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) ++DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) ++DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) ++DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) ++DECLARE_CSR(mvendorid, CSR_MVENDORID) ++DECLARE_CSR(marchid, CSR_MARCHID) ++DECLARE_CSR(mimpid, CSR_MIMPID) ++DECLARE_CSR(mhartid, CSR_MHARTID) ++DECLARE_CSR(cycleh, CSR_CYCLEH) ++DECLARE_CSR(timeh, CSR_TIMEH) ++DECLARE_CSR(instreth, CSR_INSTRETH) ++DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) ++DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) ++DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) ++DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) ++DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) ++DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) ++DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) ++DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) ++DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) ++DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) ++DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) ++DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) ++DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) ++DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) ++DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) ++DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) ++DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) ++DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) ++DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) ++DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) ++DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) ++DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) ++DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) ++DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) ++DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) ++DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) ++DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) ++DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) ++DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) ++DECLARE_CSR(mcycleh, CSR_MCYCLEH) ++DECLARE_CSR(minstreth, CSR_MINSTRETH) ++DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) ++DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) ++DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) ++DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) ++DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) ++DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) ++DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) ++DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) ++DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) ++DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) ++DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) ++DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) ++DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) ++DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) ++DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) ++DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) ++DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) ++DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) ++DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) ++DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) ++DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) ++DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) ++DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) ++DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) ++DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) ++DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) ++DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) ++DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) ++DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) ++#endif ++#ifdef DECLARE_CAUSE ++DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) ++DECLARE_CAUSE("fetch access", CAUSE_FETCH_ACCESS) ++DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) ++DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) ++DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) ++DECLARE_CAUSE("load access", CAUSE_LOAD_ACCESS) ++DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) ++DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS) ++DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) ++DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) ++DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) ++DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) ++DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT) ++DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT) ++DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT) ++#endif +diff --git a/platform/cva6/inc/platform.h b/platform/cva6/inc/platform.h +new file mode 100644 +index 0000000..2b944fd +--- /dev/null ++++ b/platform/cva6/inc/platform.h +@@ -0,0 +1,9 @@ ++#ifndef PLATFORM_H ++#define PLATFORM_H ++ ++#define MEM_BASE (0x80000000) ++#define MEM_SIZE (0x10000000) ++#define CON_BASE (0x10001000) ++#define EOC_BASE (0x10000004) ++ ++#endif +diff --git a/platform/cva6/syscalls.c b/platform/cva6/syscalls.c +new file mode 100644 +index 0000000..6542ab5 +--- /dev/null ++++ b/platform/cva6/syscalls.c +@@ -0,0 +1,441 @@ ++// See LICENSE for license details. ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "util.h" ++#include "platform.h" ++ ++#define SYS_write 64 ++ ++#undef strcmp ++ ++// volatile uint64_t tohost __attribute__((section(".tohost"), aligned(64))); ++// volatile uint64_t fromhost __attribute__((section(".tohost"), aligned(64))); ++extern volatile uint64_t tohost; ++extern volatile uint64_t fromhost; ++ ++size_t strlen(const char *s) ++{ ++ const char *p = s; ++ while (*p) ++ p++; ++ return p - s; ++} ++ ++size_t strnlen(const char *s, size_t n) ++{ ++ const char *p = s; ++ while (n-- && *p) ++ p++; ++ return p - s; ++} ++ ++#define NUM_COUNTERS 2 ++static uintptr_t counters[NUM_COUNTERS]; ++static char* counter_names[NUM_COUNTERS]; ++ ++void setStats(int enable) ++{ ++ int i = 0; ++#define READ_CTR(name) do { \ ++ while (i >= NUM_COUNTERS) ; \ ++ uintptr_t csr = read_csr(name); \ ++ if (!enable) { csr -= counters[i]; counter_names[i] = #name; } \ ++ counters[i++] = csr; \ ++ } while (0) ++ ++ READ_CTR(mcycle); ++ READ_CTR(minstret); ++ ++#undef READ_CTR ++} ++ ++void __attribute__((noreturn)) cva6_exit(int code) { ++ uintptr_t eoc_base = (uintptr_t)EOC_BASE; ++ ++ // Write to EOC register ++ __asm__ volatile ( ++ "mv t0, %0;" ++ "mv t1, %1;" ++ "slli t1, t1, 1;" ++ "ori t1, t1, 1;" ++ "sw t1, 0(t0);" ++ : ++ : "r"(eoc_base), "r"(code) ++ : "t0", "t1", "memory" ++ ); ++ while (1); ++} ++ ++uintptr_t __attribute__((weak)) handle_trap(uintptr_t cause, uintptr_t epc, uintptr_t regs[32]) ++{ ++ cva6_exit(1337); ++} ++ ++void exit(int code) ++{ ++ cva6_exit(code); ++} ++ ++void abort() ++{ ++ exit(128 + SIGABRT); ++} ++ ++void printstr(const char* s) ++{ ++ for (unsigned int i = 0; i < strlen(s); ++i) ++ putchar(s[i]); ++} ++ ++int puts(const char* s) ++{ ++ printstr(s); ++ printstr("\n"); ++ return strlen(s); ++} ++ ++void __attribute__((weak)) thread_entry(int cid, int nc) ++{ ++ // multi-threaded programs override this function. ++ // for the case of single-threaded programs, only let core 0 proceed. ++ while (cid != 0); ++} ++ ++int __attribute__((weak)) main(int argc, char** argv) ++{ ++ // single-threaded programs override this function. ++ printstr("Implement main(), foo!\n"); ++ return -1; ++} ++ ++ ++#undef putchar ++int putchar(int ch) ++{ ++ uintptr_t addr = (uintptr_t)CON_BASE; ++ *(volatile char *)addr = ch; ++ ++ return 0; ++} ++ ++void printhex(uint64_t x) ++{ ++ char str[17]; ++ int i; ++ for (i = 0; i < 16; i++) ++ { ++ str[15-i] = (x & 0xF) + ((x & 0xF) < 10 ? '0' : 'a'-10); ++ x >>= 4; ++ } ++ str[16] = 0; ++ ++ printstr(str); ++} ++ ++static inline void printnum(void (*putch)(int, void**), void **putdat, ++ unsigned long long num, unsigned base, int width, int padc) ++{ ++ unsigned digs[sizeof(num)*CHAR_BIT]; ++ int pos = 0; ++ ++ while (1) ++ { ++ digs[pos++] = num % base; ++ if (num < base) ++ break; ++ num /= base; ++ } ++ ++ while (width-- > pos) ++ putch(padc, putdat); ++ ++ while (pos-- > 0) ++ putch(digs[pos] + (digs[pos] >= 10 ? 'a' - 10 : '0'), putdat); ++} ++ ++static unsigned long long getuint(va_list *ap, int lflag) ++{ ++ if (lflag >= 2) ++ return va_arg(*ap, unsigned long long); ++ else if (lflag) ++ return va_arg(*ap, unsigned long); ++ else ++ return va_arg(*ap, unsigned int); ++} ++ ++static long long getint(va_list *ap, int lflag) ++{ ++ if (lflag >= 2) ++ return va_arg(*ap, long long); ++ else if (lflag) ++ return va_arg(*ap, long); ++ else ++ return va_arg(*ap, int); ++} ++ ++static void vprintfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list ap) ++{ ++ register const char* p; ++ const char* last_fmt; ++ register int ch, err; ++ unsigned long long num; ++ int base, lflag, width, precision, altflag; ++ char padc; ++ ++ while (1) { ++ while ((ch = *(unsigned char *) fmt) != '%') { ++ if (ch == '\0') ++ return; ++ fmt++; ++ putch(ch, putdat); ++ } ++ fmt++; ++ ++ // Process a %-escape sequence ++ last_fmt = fmt; ++ padc = ' '; ++ width = -1; ++ precision = -1; ++ lflag = 0; ++ altflag = 0; ++ reswitch: ++ switch (ch = *(unsigned char *) fmt++) { ++ ++ // flag to pad on the right ++ case '-': ++ padc = '-'; ++ goto reswitch; ++ ++ // flag to pad with 0's instead of spaces ++ case '0': ++ padc = '0'; ++ goto reswitch; ++ ++ // width field ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ case '8': ++ case '9': ++ for (precision = 0; ; ++fmt) { ++ precision = precision * 10 + ch - '0'; ++ ch = *fmt; ++ if (ch < '0' || ch > '9') ++ break; ++ } ++ goto process_precision; ++ ++ case '*': ++ precision = va_arg(ap, int); ++ goto process_precision; ++ ++ case '.': ++ if (width < 0) ++ width = 0; ++ goto reswitch; ++ ++ case '#': ++ altflag = 1; ++ goto reswitch; ++ ++ process_precision: ++ if (width < 0) ++ width = precision, precision = -1; ++ goto reswitch; ++ ++ // long flag (doubled for long long) ++ case 'l': ++ lflag++; ++ goto reswitch; ++ ++ // character ++ case 'c': ++ putch(va_arg(ap, int), putdat); ++ break; ++ ++ // string ++ case 's': ++ if ((p = va_arg(ap, char *)) == NULL) ++ p = "(null)"; ++ if (width > 0 && padc != '-') ++ for (width -= strnlen(p, precision); width > 0; width--) ++ putch(padc, putdat); ++ for (; (ch = *p) != '\0' && (precision < 0 || --precision >= 0); width--) { ++ putch(ch, putdat); ++ p++; ++ } ++ for (; width > 0; width--) ++ putch(' ', putdat); ++ break; ++ ++ // (signed) decimal ++ case 'd': ++ num = getint(&ap, lflag); ++ if ((long long) num < 0) { ++ putch('-', putdat); ++ num = -(long long) num; ++ } ++ base = 10; ++ goto signed_number; ++ ++ // unsigned decimal ++ case 'u': ++ base = 10; ++ goto unsigned_number; ++ ++ // (unsigned) octal ++ case 'o': ++ // should do something with padding so it's always 3 octits ++ base = 8; ++ goto unsigned_number; ++ ++ // pointer ++ case 'p': ++ static_assert(sizeof(long) == sizeof(void*)); ++ lflag = 1; ++ putch('0', putdat); ++ putch('x', putdat); ++ /* fall through to 'x' */ ++ ++ // (unsigned) hexadecimal ++ case 'x': ++ base = 16; ++ unsigned_number: ++ num = getuint(&ap, lflag); ++ signed_number: ++ printnum(putch, putdat, num, base, width, padc); ++ break; ++ ++ // escaped '%' character ++ case '%': ++ putch(ch, putdat); ++ break; ++ ++ // unrecognized escape sequence - just print it literally ++ default: ++ putch('%', putdat); ++ fmt = last_fmt; ++ break; ++ } ++ } ++} ++ ++int printf(const char* fmt, ...) ++{ ++ va_list ap; ++ va_start(ap, fmt); ++ ++ vprintfmt((void*)putchar, 0, fmt, ap); ++ ++ va_end(ap); ++ return 0; // incorrect return value, but who cares, anyway? ++} ++ ++int sprintf(char* str, const char* fmt, ...) ++{ ++ va_list ap; ++ char* str0 = str; ++ va_start(ap, fmt); ++ ++ void sprintf_putch(int ch, void** data) ++ { ++ char** pstr = (char**)data; ++ **pstr = ch; ++ (*pstr)++; ++ } ++ ++ vprintfmt(sprintf_putch, (void**)&str, fmt, ap); ++ *str = 0; ++ ++ va_end(ap); ++ return str - str0; ++} ++ ++void* memcpy(void* dest, const void* src, size_t len) ++{ ++ if ((((uintptr_t)dest | (uintptr_t)src | len) & (sizeof(uintptr_t)-1)) == 0) { ++ const uintptr_t* s = src; ++ uintptr_t *d = dest; ++ while (d < (uintptr_t*)(dest + len)) ++ *d++ = *s++; ++ } else { ++ const char* s = src; ++ char *d = dest; ++ while (d < (char*)(dest + len)) ++ *d++ = *s++; ++ } ++ return dest; ++} ++ ++void* memset(void* dest, int byte, size_t len) ++{ ++ if ((((uintptr_t)dest | len) & (sizeof(uintptr_t)-1)) == 0) { ++ uintptr_t word = byte & 0xFF; ++ word |= word << 8; ++ word |= word << 16; ++ word |= word << 16 << 16; ++ ++ uintptr_t *d = dest; ++ while (d < (uintptr_t*)(dest + len)) ++ *d++ = word; ++ } else { ++ char *d = dest; ++ while (d < (char*)(dest + len)) ++ *d++ = byte; ++ } ++ return dest; ++} ++ ++int strcmp(const char* s1, const char* s2) ++{ ++ unsigned char c1, c2; ++ ++ do { ++ c1 = *s1++; ++ c2 = *s2++; ++ } while (c1 != 0 && c1 == c2); ++ ++ return c1 - c2; ++} ++ ++char* strcpy(char* dest, const char* src) ++{ ++ char* d = dest; ++ while ((*d++ = *src++)) ++ ; ++ return dest; ++} ++ ++long atol(const char* str) ++{ ++ long res = 0; ++ int sign = 0; ++ ++ while (*str == ' ') ++ str++; ++ ++ if (*str == '-' || *str == '+') { ++ sign = *str == '-'; ++ str++; ++ } ++ ++ while (*str) { ++ res *= 10; ++ res += *str++ - '0'; ++ } ++ ++ return sign ? -res : res; ++} ++ ++void _init(){ ++ ++} +diff --git a/platform/cva6/util.h b/platform/cva6/util.h +new file mode 100644 +index 0000000..081cfd6 +--- /dev/null ++++ b/platform/cva6/util.h +@@ -0,0 +1,90 @@ ++// See LICENSE for license details. ++ ++#ifndef __UTIL_H ++#define __UTIL_H ++ ++extern void setStats(int enable); ++ ++#include ++ ++#define static_assert(cond) switch(0) { case 0: case !!(long)(cond): ; } ++ ++static int verify(int n, const volatile int* test, const int* verify) ++{ ++ int i; ++ // Unrolled for faster verification ++ for (i = 0; i < n/2*2; i+=2) ++ { ++ int t0 = test[i], t1 = test[i+1]; ++ int v0 = verify[i], v1 = verify[i+1]; ++ if (t0 != v0) return i+1; ++ if (t1 != v1) return i+2; ++ } ++ if (n % 2 != 0 && test[n-1] != verify[n-1]) ++ return n; ++ return 0; ++} ++ ++static int verifyDouble(int n, const volatile double* test, const double* verify) ++{ ++ int i; ++ // Unrolled for faster verification ++ for (i = 0; i < n/2*2; i+=2) ++ { ++ double t0 = test[i], t1 = test[i+1]; ++ double v0 = verify[i], v1 = verify[i+1]; ++ int eq1 = t0 == v0, eq2 = t1 == v1; ++ if (!(eq1 & eq2)) return i+1+eq1; ++ } ++ if (n % 2 != 0 && test[n-1] != verify[n-1]) ++ return n; ++ return 0; ++} ++ ++static void __attribute__((noinline)) barrier(int ncores) ++{ ++ static volatile int sense; ++ static volatile int count; ++ static __thread int threadsense; ++ ++ __sync_synchronize(); ++ ++ threadsense = !threadsense; ++ if (__sync_fetch_and_add(&count, 1) == ncores-1) ++ { ++ count = 0; ++ sense = threadsense; ++ } ++ else while(sense != threadsense) ++ ; ++ ++ __sync_synchronize(); ++} ++ ++static uint64_t lfsr(uint64_t x) ++{ ++ uint64_t bit = (x ^ (x >> 1)) & 1; ++ return (x >> 1) | (bit << 62); ++} ++ ++static uintptr_t insn_len(uintptr_t pc) ++{ ++ return (*(unsigned short*)pc & 3) ? 4 : 2; ++} ++ ++#ifdef __riscv ++#include "encoding.h" ++#endif ++ ++#define stringify_1(s) #s ++#define stringify(s) stringify_1(s) ++#define stats(code, iter) do { \ ++ unsigned long _c = -read_csr(mcycle), _i = -read_csr(minstret); \ ++ code; \ ++ _c += read_csr(mcycle), _i += read_csr(minstret); \ ++ if (cid == 0) \ ++ printf("\n%s: %ld cycles, %ld.%ld cycles/iter, %ld.%ld CPI\n", \ ++ stringify(code), _c, _c/iter, 10*_c/iter%10, _c/_i, 10*_c/_i%10); \ ++ } while(0) ++ ++#endif //__UTIL_H +diff --git a/rvh_test.c b/rvh_test.c +index 22325ae..4982bd2 100644 +--- a/rvh_test.c ++++ b/rvh_test.c +@@ -10,7 +10,7 @@ unsigned test_num = 0; + unsigned curr_priv = PRIV_M; + unsigned real_priv = PRIV_M; + +-struct exception excpt; ++volatile struct exception excpt; + + uint64_t ecall_args[2]; + +diff --git a/tinst_tests.c b/tinst_tests.c +index 59da4e4..d5416c8 100644 +--- a/tinst_tests.c ++++ b/tinst_tests.c +@@ -139,7 +139,7 @@ bool tinst_tests(){ + + TEST_SETUP_EXCEPT(); + c_sw(vaddr_f, value); +- TEST_ASSERT("correct tinst when executing a c.lw which results in a lpf", ++ TEST_ASSERT("correct tinst when executing a c.sw which results in a lpf", + excpt.triggered == true && + excpt.cause == CAUSE_SPF && + TINST_CHECK_COMPRESSED(TINST_STORE) +@@ -157,7 +157,7 @@ bool tinst_tests(){ + value = lr_w(vaddr_f); + TEST_ASSERT("correct tinst when executing a lr.w which results in a lpf", + excpt.triggered == true && +- excpt.cause == CAUSE_LPF && ++ excpt.cause == CAUSE_SPF && + TINST_CHECK(TINST_AMO) + ); + +diff --git a/translation_tests.c b/translation_tests.c +index d2c08d9..51deb31 100644 +--- a/translation_tests.c ++++ b/translation_tests.c +@@ -133,8 +133,10 @@ bool second_stage_only_translation(){ + bool check2 = read64(vaddr2) == 0x22; + TEST_ASSERT("vs gets right values", excpt.triggered == false && check1 && check2); + ++ goto_priv(PRIV_HS); + hpt_switch(); +- sfence(); ++ hfence_gvma(); ++ goto_priv(PRIV_VS); + TEST_SETUP_EXCEPT(); + check1 = read64(vaddr1) == 0x22; + check2 = read64(vaddr2) == 0x11; +@@ -292,7 +294,7 @@ bool m_and_hs_using_vs_access(){ + TEST_ASSERT("hs hlvxwu on vs-level non-exec page leads to lpf", + excpt.triggered == true && + excpt.cause == CAUSE_LPF && +- excpt.gva == false && ++ excpt.gva == true && + excpt.xpv == false + ); + +@@ -353,10 +355,16 @@ bool m_and_hs_using_vs_access(){ + ); + CSRC(CSR_VSSTATUS, SSTATUS_SUM); + ++ // NOTE: on CVA6 proper privilege checks for R,W,X bits seems to be checked only on a TLB miss. ++ // On a hit, only a subset of the permissions checks are done, and no exception is triggered if a cached X-only page is read. ++ // For now, make sure the TLB is flushed before the test so that we at least check the correct permissions check inside the PTW. ++ hfence(); + vaddr = vs_page_base(VSX_GUX); + addr = phys_page_base(VSX_GUX); + goto_priv(PRIV_HS); + set_prev_priv(PRIV_VS); ++ // Make sure sstatus.MXR is clear ++ CSRC(sstatus, SSTATUS_MXR); + TEST_SETUP_EXCEPT(); + val = hlvd(vaddr); + TEST_ASSERT("hs hlvd of xo vs page leads to exception", diff --git a/test/sw/deps/patches/riscv-tests-env.patch b/test/sw/deps/patches/riscv-tests-env.patch new file mode 100644 index 00000000000..5c78c1d1a00 --- /dev/null +++ b/test/sw/deps/patches/riscv-tests-env.patch @@ -0,0 +1,67 @@ +diff --git a/p/link.ld b/p/link.ld +index b3e315e..493b90d 100644 +--- a/p/link.ld ++++ b/p/link.ld +@@ -13,5 +13,6 @@ SECTIONS + .data : { *(.data) } + .bss : { *(.bss) } + _end = .; ++ __base_regs = 0x10000000; + } + +diff --git a/p/riscv_test.h b/p/riscv_test.h +index 3d4637a..1226862 100644 +--- a/p/riscv_test.h ++++ b/p/riscv_test.h +@@ -215,7 +215,13 @@ handle_exception: \ + write_tohost: \ + sw TESTNUM, tohost, t5; \ + sw zero, tohost + 4, t5; \ +- j write_tohost; \ ++ slli TESTNUM, TESTNUM, 1; \ ++ ori TESTNUM, TESTNUM, 1; \ ++ la t0, __base_regs; \ ++ sw TESTNUM, 4(t0); \ ++_end_loop: \ ++ wfi; \ ++ j _end_loop; \ + reset_vector: \ + INIT_XREG; \ + RISCV_MULTICORE_DISABLE; \ +diff --git a/v/vm.c b/v/vm.c +index cc58417..8fd0302 100644 +--- a/v/vm.c ++++ b/v/vm.c +@@ -66,7 +66,12 @@ static void cputstring(const char* s) + + static void terminate(int code) + { +- do_tohost(code); ++ // Write to EOC register at __base_regs ++ __asm__ ( ++ "li t0, 0x10000000;" ++ "li t1, 3;" ++ "sw t1, 4(t0);" ++ ); + while (1); + } + +@@ -253,6 +258,8 @@ static void coherence_torture() + } + } + ++extern char __base_regs; ++ + void vm_boot(uintptr_t test_addr) + { + uint64_t random = ENTROPY; +@@ -276,7 +283,9 @@ void vm_boot(uintptr_t test_addr) + #elif SATP_MODE_CHOICE == SATP_MODE_SV39 + l1pt[PTES_PER_PT-1] = ((pte_t)kernel_l2pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V; + kernel_l2pt[PTES_PER_PT-1] = (DRAM_BASE/RISCV_PGSIZE << PTE_PPN_SHIFT) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D; ++ kernel_l2pt[63] = ((pte_t)&__base_regs >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D; + user_l2pt[0] = ((pte_t)user_llpt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V; ++ user_l2pt[128] = ((pte_t)&__base_regs >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D; + #elif SATP_MODE_CHOICE == SATP_MODE_SV32 + l1pt[PTES_PER_PT-1] = (DRAM_BASE/RISCV_PGSIZE << PTE_PPN_SHIFT) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D; + #else diff --git a/test/sw/deps/patches/riscv-tests-fencet.patch b/test/sw/deps/patches/riscv-tests-fencet.patch new file mode 100644 index 00000000000..963bcc06817 --- /dev/null +++ b/test/sw/deps/patches/riscv-tests-fencet.patch @@ -0,0 +1,74 @@ +diff --git a/isa/rv64ui/Makefrag b/isa/rv64ui/Makefrag +index 59e40cf..50ffaa6 100644 +--- a/isa/rv64ui/Makefrag ++++ b/isa/rv64ui/Makefrag +@@ -8,7 +8,7 @@ rv64ui_sc_tests = \ + auipc \ + beq bge bgeu blt bltu bne \ + simple \ +- fence_i \ ++ fence_i fence_t \ + jal jalr \ + lb lbu lh lhu lw lwu ld ld_st \ + lui \ +diff --git a/isa/rv64ui/fence_t.S b/isa/rv64ui/fence_t.S +new file mode 100644 +index 0000000..cde4e38 +--- /dev/null ++++ b/isa/rv64ui/fence_t.S +@@ -0,0 +1,55 @@ ++# See LICENSE for license details. ++ ++#***************************************************************************** ++# fence_i.S ++#----------------------------------------------------------------------------- ++# ++# Test self-modifying code and the fence.i instruction. ++# ++ ++#include "riscv_test.h" ++#include "test_macros.h" ++ ++RVTEST_RV64U ++RVTEST_CODE_BEGIN ++ ++li TESTNUM, 2 ++ ++.align 12 ++l1: ++ j l2 ++.align 12 ++l2: ++ j l3 ++.align 12 ++l3: ++ j l4 ++.align 12 ++l4: ++ j l5 ++.align 12 ++l5: ++ j l6 ++.align 12 ++l6: ++ j l7 ++.align 12 ++l7: ++ .word 0x00fff00b ++ addi TESTNUM, TESTNUM, -1 ++ bnez TESTNUM, l1 ++ li TESTNUM, 1 ++ ++TEST_PASSFAIL ++ ++RVTEST_CODE_END ++ ++ .data ++RVTEST_DATA_BEGIN ++ ++ TEST_DATA ++ ++insn: ++ addi a3, a3, 333 ++ ++RVTEST_DATA_END diff --git a/test/sw/deps/patches/riscv-tests.patch b/test/sw/deps/patches/riscv-tests.patch new file mode 100644 index 00000000000..05916c70ec1 --- /dev/null +++ b/test/sw/deps/patches/riscv-tests.patch @@ -0,0 +1,31 @@ +diff --git a/isa/Makefile b/isa/Makefile +index 0f0106f..77e93e3 100644 +--- a/isa/Makefile ++++ b/isa/Makefile +@@ -63,6 +63,7 @@ RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf- + RISCV_GCC ?= $(RISCV_PREFIX)gcc + RISCV_GCC_OPTS ?= -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles + RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump --disassemble-all --disassemble-zeroes --section=.text --section=.text.startup --section=.text.init --section=.data ++RISCV_OBJCOPY ?= $(RISCV_PREFIX)objcopy + RISCV_SIM ?= spike + + vpath %.S $(src_dir) +@@ -70,6 +71,9 @@ vpath %.S $(src_dir) + #------------------------------------------------------------ + # Build assembly tests + ++%.hex: % ++ $(RISCV_OBJCOPY) -O verilog $< $@ ++ + %.dump: % + $(RISCV_OBJDUMP) $< > $@ + +@@ -153,7 +157,7 @@ junk += $(tests) $(tests_dump) $(tests_hex) $(tests_out) $(tests32_out) + #------------------------------------------------------------ + # Default + +-all: $(tests_dump) ++all: $(tests_dump) $(tests_hex) + + #------------------------------------------------------------ + # Clean up diff --git a/test/sw/include/clic.h b/test/sw/include/clic.h new file mode 100644 index 00000000000..5d430805bda --- /dev/null +++ b/test/sw/include/clic.h @@ -0,0 +1,35 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Author: Enrico Zelioli + +#pragma once + +#define CLICINT_OFFSET 0x1000 + +#define CLICINT_IP_BIT 0 +#define CLICINT_IE_BIT 8 +#define CLICINT_ATTR_SHV_BIT 16 +#define CLICINT_ATTR_TRIG_BIT 17 +#define CLICINT_CTL_BIT 24 + +#include +#include + +// CLIC base address from linker script +extern char __base_clic[]; + +static inline uint32_t clic_read_clicint(uint32_t irq_num) { + uintptr_t CLIC_BASE = (uintptr_t)__base_clic; + return read32(CLIC_BASE + CLICINT_OFFSET + irq_num * 4); +} + +static inline void clic_write_clicint(uint32_t irq_num, uint32_t value) { + uintptr_t CLIC_BASE = (uintptr_t)__base_clic; + write32(CLIC_BASE + CLICINT_OFFSET + irq_num * 4, value); +} + +void clic_setup(uint32_t irq_num, int vectored); +void clic_set_pending(uint32_t irq_num); +void clic_clear_pending(uint32_t irq_num); diff --git a/test/sw/include/console.h b/test/sw/include/console.h new file mode 100644 index 00000000000..bf055add0cb --- /dev/null +++ b/test/sw/include/console.h @@ -0,0 +1,13 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Author: Enrico Zelioli + +#pragma once + +// Sim console base address from linker script +extern char __base_console[]; + +void console_putchar(char character); +void console_puts(char *s, unsigned int n); diff --git a/test/sw/include/util.h b/test/sw/include/util.h new file mode 100644 index 00000000000..baa3935164d --- /dev/null +++ b/test/sw/include/util.h @@ -0,0 +1,42 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Author: Enrico Zelioli + +#pragma once + +#include + +static inline uint32_t read32(uintptr_t address) { + return *(uint32_t *)address; +} + +static inline void write32(uintptr_t address, uint32_t value) { + *(uint32_t *)address = value; +} + +static inline void set_mtvec(uintptr_t address, int enable_clic) { + uint64_t value = address & ~0x3; // Ensure address is aligned to 4 bytes + if (enable_clic) { + value |= 0x3; + } + asm volatile ("csrw mtvec, %0" :: "r"(value)); +} + +static inline void set_mtvt(uintptr_t address) { + uint64_t value = address & ~0xFF; // Ensure address is aligned to 256 bytes + asm volatile ("csrw 0x307, %0" :: "r"(value)); +} + +// Enables or disables M-mode global interrupts +static inline void set_global_mie(int enable) { + if (enable) + asm volatile("csrsi mstatus, 8" ::: "memory"); + else + asm volatile("csrci mstatus, 8" ::: "memory"); +} + +static inline void set_mintthresh(uint64_t value) { + asm volatile ("csrw 0x347, %0" :: "r"(value)); +} diff --git a/test/sw/lib/clic.c b/test/sw/lib/clic.c new file mode 100644 index 00000000000..4d8a98f042d --- /dev/null +++ b/test/sw/lib/clic.c @@ -0,0 +1,30 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Author: Enrico Zelioli + +#include +#include "clic.h" + +void clic_setup(uint32_t irq_num, int vectored) { + uint32_t clicint_value = clic_read_clicint(irq_num); + // Set interrupt as edge-triggered, enable it, and set it as non-privileged + clicint_value |= (1 << CLICINT_ATTR_TRIG_BIT); // Edge-triggered + clicint_value |= (1 << CLICINT_IE_BIT); // Enable interrupt + clicint_value |= (0xaa << CLICINT_CTL_BIT); // Set interrupt level and priority + if (vectored) clicint_value |= (1 << CLICINT_ATTR_SHV_BIT); // Vectored interrupt + else clicint_value &= ~(1 << CLICINT_ATTR_SHV_BIT); // Non-vectored interrupt + clic_write_clicint(irq_num, clicint_value); +} + +void clic_set_pending(uint32_t irq_num) { + uint32_t clicint_value = clic_read_clicint(irq_num); + clicint_value |= (1 << CLICINT_IP_BIT); // Set pending bit + clic_write_clicint(irq_num, clicint_value); +} +void clic_clear_pending(uint32_t irq_num) { + uint32_t clicint_value = clic_read_clicint(irq_num); + clicint_value &= ~(1 << CLICINT_IP_BIT); // Clear pending bit + clic_write_clicint(irq_num, clicint_value); +} diff --git a/test/sw/lib/console.c b/test/sw/lib/console.c new file mode 100644 index 00000000000..28db9464693 --- /dev/null +++ b/test/sw/lib/console.c @@ -0,0 +1,23 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Author: Enrico Zelioli + +#include +#include "console.h" + +void console_putchar(char character) { + uintptr_t addr = (uintptr_t)__base_console; + *(volatile char *)addr = character; +} + +void console_puts(char *s, unsigned int n) { + for (unsigned int i = 0; i < n; ++i) + console_putchar(s[i]); +} + +// Redefine _putchar for printf support +void _putchar(char character) { + console_putchar(character); +} diff --git a/test/sw/lib/crt0.S b/test/sw/lib/crt0.S new file mode 100644 index 00000000000..1a329439839 --- /dev/null +++ b/test/sw/lib/crt0.S @@ -0,0 +1,82 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Author: Enrico Zelioli + +.section .text._start + +.global _start +.align 4 +_start: + + // Clear all registers + li x1, 0 + li x2, 0 + li x3, 0 + li x4, 0 + li x5, 0 + li x6, 0 + li x7, 0 + li x8, 0 + li x9, 0 + li x10, 0 + li x11, 0 + li x12, 0 + li x13, 0 + li x14, 0 + li x15, 0 + li x16, 0 + li x17, 0 + li x18, 0 + li x19, 0 + li x20, 0 + li x21, 0 + li x22, 0 + li x23, 0 + li x24, 0 + li x25, 0 + li x26, 0 + li x27, 0 + li x28, 0 + li x29, 0 + li x30, 0 + li x31, 0 + + // Init stack and global pointer with safe, linked values + la sp, __stack_pointer$ + .option push + .option norelax + la gp, __global_pointer$ + .option pop + + // Set up trap handler + la t0, trap_handler + csrw mtvec, t0 + + // Call main + jal main + + j _exit + +// If main returns, we end up here +.global _exit +.align 4 +_exit: + // Save the return value to EOC register, then wait forever + slli a0, a0, 1 + ori a0, a0, 1 + la t0, __base_regs + sw a0, 4(t0) +1: wfi + j 1b + +.weak main +main: + li a0, 0 + ret + +.align 8 +.globl trap_handler +trap_handler: + mret diff --git a/test/sw/link/link.ld b/test/sw/link/link.ld new file mode 100644 index 00000000000..f6e2d5aa187 --- /dev/null +++ b/test/sw/link/link.ld @@ -0,0 +1,58 @@ +/* Copyright 2026 ETH Zurich and University of Bologna. */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +ENTRY(_start) + +MEMORY { + dram (rwx) : ORIGIN = 0x80000000, LENGTH = 8M +} + +SECTIONS { + + /* Keep binaries lean */ + /DISCARD/ : { *(.riscv.attributes) *(.comment) } + + /* Global and stack pointer */ + __global_pointer$ = ADDR(.misc) + SIZEOF(.misc) / 2; + __stack_pointer$ = ORIGIN(dram) + LENGTH(dram) - 8; + + .text : { + *(.text._start) + *(.text) + *(.text.*) + } > dram + + .misc : ALIGN(16) { + *(.rodata) + *(.rodata.*) + *(.data) + *(.data.*) + *(.srodata) + *(.srodata.*) + *(.sdata) + *(.sdata.*) + } > dram + + .bss : ALIGN(16) { + __bss_start = .; + *(.bss) + *(.bss.*) + *(.sbss) + *(.sbss.*) + __bss_end = .; + } > dram + + .bulk : ALIGN(16) { + *(.bulk) + *(.bulk.*) + } > dram + + /* Relevant addresses */ + __base_regs = 0x10000000; + __base_console = 0x10001000; + __base_clic = 0x10040000; + __base_dram = ORIGIN(dram); + __base_heap = ADDR(.bulk) + SIZEOF(.bulk); + +} diff --git a/test/sw/tests/clic_multiple.S b/test/sw/tests/clic_multiple.S new file mode 100644 index 00000000000..1f9cba8e6d6 --- /dev/null +++ b/test/sw/tests/clic_multiple.S @@ -0,0 +1,214 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Nils Wistoff +// +// Test clic. +// +// Queues two software interrupts with different interrupt levels. The lower +// level interrupt is queued first. Then raises the threshold to a level which is +// between those two interrupts. Only the latter interrupt should fire and be +// handled. + +#define xstr(s) str(s) +#define str(s) s +#define CLIC_BASE 0x10040000 +#define CLIC_CLICCFG_REG (CLIC_BASE + 0x0) +#define CLIC_CLICINT_REG(id) (CLIC_BASE + 0x1000 + 0x4 * id) +#define CLIC_CLICINT_IP_OFFSET (0) +#define CLIC_CLICINT_IP_MASK (1) +#define CLIC_CLICINT_IE_OFFSET (8) +#define CLIC_CLICINT_IE_MASK (1) +#define CLIC_CLICINT_ATTR_SHV_OFFSET (16) +#define CLIC_CLICINT_ATTR_SHV_MASK (1) +#define CLIC_CLICINT_ATTR_TRIG_OFFSET (17) +#define CLIC_CLICINT_ATTR_TRIG_MASK (0x3) +#define CLIC_CLICINT_ATTR_MODE_OFFSET (22) +#define CLIC_CLICINT_ATTR_MODE_MASK (0x3) +#define CLIC_CLICINT_CTL_OFFSET (24) +#define CLIC_CLICINT_CTL_MASK (0xff) + +#define MINTTHRESH (0x347) +#define MTVT (0x307) + +.align +.option norvc +.global main +main: + .macro clic_enable_irq id ctl + + // Set shv of irq + li t0, CLIC_CLICINT_REG(\id) + li t1, 1 << CLIC_CLICINT_ATTR_SHV_OFFSET + sw t1, 0(t0) + + // set trigger type to edge-triggered of irq + li t0, CLIC_CLICINT_REG(\id) + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_ATTR_TRIG_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // enable irq via SW by writing to clicintip + li t0, CLIC_CLICINT_REG(\id) + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_IP_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // set interrupt level and priority for interrupt + li t0, CLIC_CLICINT_REG(\id) + lw t1, 0(t0) + li t2, \ctl << CLIC_CLICINT_CTL_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // enable interrupt + li t0, CLIC_CLICINT_REG(\id) + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_IE_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + .endm + + +.align 2 +.option norvc +1: + // Enable interrupts (set mstatus.mie) + csrsi mstatus, 0x8 + + // Activate CLIC mode + la t0, mtvec_handler_fail + ori t0, t0, 0x3 + csrrw s0, mtvec, t0 + + // Write mtvt base + la t0, mtvt_handler + csrw MTVT, t0 + + // set number of bits for level encoding + li t0, CLIC_CLICCFG_REG + li t1, 0x4 << 1 + sw t1, 0(t0) + + // raise interrupt threshold to max and check that the interrupt doesn't fire yet + li a0, 0x1 + li t0, 0xff + csrw MINTTHRESH, t0 + + clic_enable_irq 31 0xaa + + clic_enable_irq 30 0xcc + + // wait + li t0, 500 +1: + addi t0, t0, -1 + bnez t0, 1b + + // lower interrupt threshold (interrupt 30 should happen) + li a0, 30 + li t0, 0xbb + csrw MINTTHRESH, t0 + + // wait + li t0, 500 +2: + addi t0, t0, -1 + bnez t0, 2b + + // lower interrupt threshold (interrupt 31 should happen) + li a0, 31 + li t0, 0x0 + csrw MINTTHRESH, t0 + + // wait + li t0, 500 +3: + addi t0, t0, -1 + bnez t0, 3b + + j fail_restore + +pass_restore: + csrw mtvec, s0 + li a0, 0 + ret + +fail_restore: + csrw mtvec, s0 + li a0, 1 + ret + +thirty: + // a0!=30: we should not get here, fail. else: we expect to get here, pass. + addi a0, a0, -30 + bnez a0, fail_restore + li a0, 0 + mret + +thirtyone: + // a0!=31: we should not get here, fail. else: we expect to get here, pass. + addi a0, a0, -31 + bnez a0, fail_restore + li a0, 0 + j pass_restore + + .align 8 + .global mtvt_handler +mtvt_handler: + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j thirty + j thirtyone + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + + +.align 8 +.global mtvec_handler_fail +mtvec_handler_fail: + // Restore mtvec and fail + csrw mtvec, s0 + li a0, 1 + ret + + .data diff --git a/test/sw/tests/clic_simple.S b/test/sw/tests/clic_simple.S new file mode 100644 index 00000000000..5e3dd2dd0d1 --- /dev/null +++ b/test/sw/tests/clic_simple.S @@ -0,0 +1,172 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Nils Wistoff +// +// Basic CLIC test. Based on https://github.com/pulp-platform/safety_island/blob/main/sw/tests/runtime_clic_basic/clic-basic.c + +#define xstr(s) str(s) +#define str(s) s +#define CLIC_BASE 0x10040000 +#define CLIC_CLICCFG_REG (CLIC_BASE + 0x0) +#define CLIC_CLICINT_REG(id) (CLIC_BASE + 0x1000 + 0x4 * id) +#define CLIC_CLICINT_IP_OFFSET (0) +#define CLIC_CLICINT_IP_MASK (1) +#define CLIC_CLICINT_IE_OFFSET (8) +#define CLIC_CLICINT_IE_MASK (1) +#define CLIC_CLICINT_ATTR_SHV_OFFSET (16) +#define CLIC_CLICINT_ATTR_SHV_MASK (1) +#define CLIC_CLICINT_ATTR_TRIG_OFFSET (17) +#define CLIC_CLICINT_ATTR_TRIG_MASK (0x3) +#define CLIC_CLICINT_ATTR_MODE_OFFSET (22) +#define CLIC_CLICINT_ATTR_MODE_MASK (0x3) +#define CLIC_CLICINT_CTL_OFFSET (24) +#define CLIC_CLICINT_CTL_MASK (0xff) + +.align +.option norvc +.global main +main: + // Enable interrupts (set mstatus.mie) + csrsi mstatus, 0x8 + + // Activate CLIC mode + la t0, mtvec_handler_fail + ori t0, t0, 0x3 + csrrw s0, mtvec, t0 + + // Write mtvt base + la t0, mtvt_handler + csrw 0x307, t0 // mtvt + + // Set shv of irq 31 + li t0, CLIC_CLICINT_REG(31) + li t1, 1 << CLIC_CLICINT_ATTR_SHV_OFFSET + sw t1, 0(t0) + + // set trigger type to edge-triggered + li t0, CLIC_CLICINT_REG(31) + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_ATTR_TRIG_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // enable irq31 via SW by writing to clicintip31 + li t0, CLIC_CLICINT_REG(31) + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_IP_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // set number of bits for level encoding + li t0, CLIC_CLICCFG_REG + li t1, 0x4 << 1 + sw t1, 0(t0) + + // set interrupt level and priority for interrupt 31 + li t0, CLIC_CLICINT_REG(31) + lw t1, 0(t0) + li t2, 0xaa << CLIC_CLICINT_CTL_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // raise interrupt threshold to max and check that the interrupt doesn't fire yet + li a0, 0x1 + li t0, 0xff + csrw 0x347, t0 // mintthresh + li t0, CLIC_CLICINT_REG(31) + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_IE_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // wait + li t0, 500 +1: + addi t0, t0, -1 + bnez t0, 1b + + // lower interrupt threshold (interrupt should happen) + li a0, 0x0 + li t0, 0x0 + csrw 0x347, t0 // mintthresh + + // wait + li t0, 500 +2: + addi t0, t0, -1 + bnez t0, 2b + + j fail_restore + +pass_restore: + csrw mtvec, s0 + li a0, 0 + ret + +fail_restore: + csrw mtvec, s0 + li a0, 1 + ret + +thirtyone: + // a0=0: we should not get here, fail. else: we expect to get here, pass. + beqz a0, pass_restore + j fail_restore + + .align 8 + .global mtvt_handler +mtvt_handler: + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j thirtyone + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + j fail_restore + + + .align 8 + .global mtvec_handler_fail +mtvec_handler_fail: + // Restore mtvec and fail + csrw mtvec, s0 + li a0, 1 + ret + +.data diff --git a/test/sw/tests/clic_smode.S b/test/sw/tests/clic_smode.S new file mode 100644 index 00000000000..ff265b49e6c --- /dev/null +++ b/test/sw/tests/clic_smode.S @@ -0,0 +1,266 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Enrico Zelioli +// +// Test CLIC interrupt controller. +// +// Test the correct handling of interrupts when executing in different +// privilege modes. Check the following cases: +// - Interrupts delegated to S-mode are not taken when executing in M-mode. +// - Interrupts delegated to S-mode are taken when executing in S-mode. + +#define xstr(s) str(s) +#define str(s) s +#define CLIC_BASE 0x10040000 +#define CLIC_CLICCFG_REG (CLIC_BASE + 0x0) +#define CLIC_CLICCFG_NLBITS_OFFSET (0) +#define CLIC_CLICCFG_NMBITS_OFFSET (4) +#define CLIC_CLICINT_REG(id) (CLIC_BASE + 0x1000 + 0x4 * id) +#define CLIC_CLICINT_IP_OFFSET (0) +#define CLIC_CLICINT_IP_MASK (1) +#define CLIC_CLICINT_IE_OFFSET (8) +#define CLIC_CLICINT_IE_MASK (1) +#define CLIC_CLICINT_ATTR_SHV_OFFSET (16) +#define CLIC_CLICINT_ATTR_SHV_MASK (1) +#define CLIC_CLICINT_ATTR_TRIG_OFFSET (17) +#define CLIC_CLICINT_ATTR_TRIG_MASK (0x3) +#define CLIC_CLICINT_ATTR_MODE_OFFSET (22) +#define CLIC_CLICINT_ATTR_MODE_MASK (0x3) +#define CLIC_CLICINT_CTL_OFFSET (24) +#define CLIC_CLICINT_CTL_MASK (0xff) + +#define MINTTHRESH (0x347) +#define MTVT (0x307) + +#define TEST_IRQ_LINE (31) + +#define SMODE (1) +#define MMODE (3) + +#define WAIT(N) \ + li a0, (N); \ + jal wait + +// Wait task: perform busy loop. +// Number of iterations is passed in a0. +wait: + mv t0, a0 +1: + addi t0, t0, -1 + bnez t0, 1b + + ret + +// Enable an interrupt line on the CLIC. +// Interrupt line number is passed in a0. +// Interrupt privilege mode is passed in a1. +enable_interrupt: + + // Compute interrupt's clicint base address + mv s2, a0 + slli s2, s2, 2 + li s1, CLIC_CLICINT_REG(0) + add s2, s2, s1 + + // Set trigger type to edge-triggered + mv t0, s2 + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_ATTR_TRIG_OFFSET + or t1, t1, t2 + // Set privilege mode + li t2, CLIC_CLICINT_ATTR_MODE_MASK + slli t2, t2, CLIC_CLICINT_ATTR_MODE_OFFSET + not t2, t2 + and t1, t1, t2 + slli t2, a1, CLIC_CLICINT_ATTR_MODE_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // Set interrupt level and priority + mv t0, s2 + lw t1, 0(t0) + li t2, 0xaa << CLIC_CLICINT_CTL_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // Enable interrupt + mv t0, s2 + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_IE_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + ret + +// Trigger an interrupt line on the CLIC. +// Interrupt line number is passed in a0. +trigger_interrupt: + + // Compute interrupt's clicint base address + mv s2, a0 + slli s2, s2, 2 + li s1, CLIC_CLICINT_REG(0) + add s2, s2, s1 + + // Trigger interrupt via SW + mv t0, s2 + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_IP_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + ret + +// Restore mtvec and return 0 (PASS) +pass_restore: + csrw mtvec, s0 + li a0, 0 + j exit + +// Restore mtvec and return 1 (FAIL) +fail_restore: + csrw mtvec, s0 + li a0, 1 + j exit + +// Enviroment call to M-mode. By default, +// return value is passed in a0. Return PASS. +smode_pass: + li a0, 0 + ecall + +// Enviroment call to M-mode. By default, +// return value is passed in a0. Return FAIL. +smode_fail: + li a0, 1 + ecall + +// Return to runtime environment. +// Return address was saved in mscratch +exit: + csrr ra, mscratch + ret + +.align +.option norvc +.global main +main: + + // Save return address + csrw mscratch, ra + + // Enable interrupts (set mstatus.mie) + csrsi mstatus, 0x8 + + // Activate CLIC mode + la t0, mtvec_handler_fail + ori t0, t0, 0x3 + csrrw s0, mtvec, t0 + + // CLIC configuration + // Set number of bits for level and privilege mode encoding + li t0, CLIC_CLICCFG_REG + li t1, 0x4 << CLIC_CLICCFG_NLBITS_OFFSET + li t2, 0x3 << CLIC_CLICCFG_NMBITS_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // Set interrupt threshold to zero + li a0, 0x1 + csrw MINTTHRESH, zero + + ///////////////////////////////////// + // Test 1 // + ///////////////////////////////////// + // Delegate interrupt line to S-mode and + // check that it does not trigger while + // executing in M-mode + li a0, TEST_IRQ_LINE + li a1, SMODE + jal enable_interrupt + WAIT(500) + li a0, TEST_IRQ_LINE + jal trigger_interrupt + WAIT(500) + + ///////////////////////////////////// + // Test 2 // + ///////////////////////////////////// + // Jump to S-mode and check that the same + // interrupt when triggered is taken + + // mret will jump to the address in mepc + la t0, smode_entry + csrw mepc, t0 + // Set up PMPs + li t0, -1 + srli t0, t0, 2 + csrw pmpaddr0, t0 // top of TOR range + li t0, 0x0f // R=1 W=1 X=1 A=TOR(01) + csrw pmpcfg0, t0 + // Set mstatus.MPP to 01 (S-mode) + li t0, 0x800 + csrs mstatus, t0 + mret + + j fail_restore + + +// S-mode entry point. +// Set up interrupt handler and enable interrupts. +// Interrupt was set pending already and should +// trigger immediately after interrupts are enabled. +smode_entry: + + // Write interrupt handler + la t0, stvec_handler_succeed + ori t0, t0, 0x3 + csrrw s0, stvec, t0 + + // Enable interrupts (set sstatus.sie) + csrsi sstatus, 0x2 + + WAIT(100) + + // Should not reach here + j smode_fail + + +// Check return value from S-mode +// (by convention stored in a0) +// and succeed or fail accordingly. +check_smode_return: + beqz a0, pass_restore + j fail_restore + +.align 8 +.global mtvec_handler_fail +mtvec_handler_fail: + csrr t0, mcause + li t1, 1 << 63 + and t0, t0, t1 + beqz t0, check_smode_return + j fail_restore + +.align 8 +.global mtvec_handler_succeed +mtvec_handler_succeed: + csrr t0, mcause + li t1, 1 << 63 + and t0, t0, t1 + beqz t0, check_smode_return + j pass_restore + +.align 8 +.global stvec_handler_fail +stvec_handler_fail: + j smode_fail + +.align 8 +.global stvec_handler_succeed +stvec_handler_succeed: + j smode_pass + +.data diff --git a/test/sw/tests/clic_vsmode.S b/test/sw/tests/clic_vsmode.S new file mode 100644 index 00000000000..399260163cb --- /dev/null +++ b/test/sw/tests/clic_vsmode.S @@ -0,0 +1,334 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Enrico Zelioli +// +// Test CLIC interrupt controller. +// +// Test the correct handling of interrupts when executing in different +// privilege modes. Check the following cases: +// - Interrupts delegated to VS-mode are not taken when executing in M-mode. +// - Interrupts delegated to VS-mode are not taken when executing in HS-mode. +// - Interrupts delegated to VS-mode are taken when executing in VS-mode. + +#define xstr(s) str(s) +#define str(s) s +#define CLIC_BASE 0x10040000 +#define CLIC_CLICCFG_REG (CLIC_BASE + 0x0) +#define CLIC_CLICCFG_NLBITS_OFFSET (0) +#define CLIC_CLICCFG_NMBITS_OFFSET (4) +#define CLIC_CLICINT_REG(id) (CLIC_BASE + 0x1000 + 0x4 * id) +#define CLIC_CLICINT_IP_OFFSET (0) +#define CLIC_CLICINT_IP_MASK (1) +#define CLIC_CLICINT_IE_OFFSET (8) +#define CLIC_CLICINT_IE_MASK (1) +#define CLIC_CLICINT_ATTR_SHV_OFFSET (16) +#define CLIC_CLICINT_ATTR_SHV_MASK (1) +#define CLIC_CLICINT_ATTR_TRIG_OFFSET (17) +#define CLIC_CLICINT_ATTR_TRIG_MASK (0x3) +#define CLIC_CLICINT_ATTR_MODE_OFFSET (22) +#define CLIC_CLICINT_ATTR_MODE_MASK (0x3) +#define CLIC_CLICINT_CTL_OFFSET (24) +#define CLIC_CLICINT_CTL_MASK (0xff) +#define CLIC_CLICINTV_REG(id) (CLIC_BASE + 0xd000 + id) + +#define MINTTHRESH (0x347) +#define MTVT (0x307) + +#define TEST_IRQ_LINE (31) +#define TEST_VSID (1) + +#define SMODE (1) +#define MMODE (3) + +#define WAIT(N) \ + li a0, (N); \ + jal wait + +// Wait task: perform busy loop. +// Number of iterations is passed in a0. +wait: + mv t0, a0 +1: + addi t0, t0, -1 + bnez t0, 1b + + ret + +// Enable an interrupt line on the CLIC. +// Interrupt line number is passed in a0. +// Interrupt privilege mode is passed in a1. +enable_interrupt: + + // Compute interrupt's clicint base address + mv s2, a0 + slli s2, s2, 2 + li s1, CLIC_CLICINT_REG(0) + add s2, s2, s1 + + // Set trigger type to edge-triggered + mv t0, s2 + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_ATTR_TRIG_OFFSET + or t1, t1, t2 + // Set privilege mode + li t2, CLIC_CLICINT_ATTR_MODE_MASK + slli t2, t2, CLIC_CLICINT_ATTR_MODE_OFFSET + not t2, t2 + and t1, t1, t2 + slli t2, a1, CLIC_CLICINT_ATTR_MODE_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // Set interrupt level and priority + mv t0, s2 + lw t1, 0(t0) + li t2, 0xaa << CLIC_CLICINT_CTL_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // Enable interrupt + mv t0, s2 + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_IE_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + ret + +// Delegate an interrupt line on the CLIC to VS-mode. +// Interrupt line number is passed in a0. +// Interrupt line VSID is passed in a1. +delegate_vs_interrupt: + + // Compute interrupt's clicintv base address + li t0, 0x3 + and t1, a0, t0 # Offset + not t0, t0 + and s2, a0, t0 # Base address + li s1, CLIC_CLICINTV_REG(0) + add s2, s2, s1 + + // Write to clicintv register + slli t0, a1, 0x2 + ori t0, t0, 0x1 + slli t1, t1, 3 + sll t0, t0, t1 + sw t0, (s2) + + ret + +// Trigger an interrupt line on the CLIC. +// Interrupt line number is passed in a0. +trigger_interrupt: + + // Compute interrupt's clicint base address + mv s2, a0 + slli s2, s2, 2 + li s1, CLIC_CLICINT_REG(0) + add s2, s2, s1 + + // Trigger interrupt via SW + mv t0, s2 + lw t1, 0(t0) + li t2, 1 << CLIC_CLICINT_IP_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + ret + +// Restore mtvec and return 0 (PASS) +pass_restore: + csrw mtvec, s0 + li a0, 0 + j exit + +// Restore mtvec and return 1 (FAIL) +fail_restore: + csrw mtvec, s0 + li a0, 1 + j exit + +// Enviroment call to M-mode. By default, +// return value is passed in a0. Return PASS. +smode_pass: + li a0, 0 + ecall + +// Enviroment call to M-mode. By default, +// return value is passed in a0. Return FAIL. +smode_fail: + li a0, 1 + ecall + +// Return to runtime environment. +// Return address was saved in mscratch +exit: + csrr ra, mscratch + ret + +.align +.option norvc +.global main +main: + + // Save return address + csrw mscratch, ra + + // Enable interrupts (set mstatus.mie) + csrsi mstatus, 0x8 + + // Activate CLIC mode + la t0, mtvec_handler_fail + ori t0, t0, 0x3 + csrrw s0, mtvec, t0 + + // CLIC configuration + // Set number of bits for level and privilege mode encoding + li t0, CLIC_CLICCFG_REG + li t1, 0x4 << CLIC_CLICCFG_NLBITS_OFFSET + li t2, 0x3 << CLIC_CLICCFG_NMBITS_OFFSET + or t1, t1, t2 + sw t1, 0(t0) + + // Set interrupt threshold to zero + li a0, 0x1 + csrw MINTTHRESH, zero + + ///////////////////////////////////// + // Test 1 // + ///////////////////////////////////// + // Delegate interrupt line to VS-mode and + // check that it does not trigger while + // executing in M-mode + li a0, TEST_IRQ_LINE + li a1, SMODE + jal enable_interrupt + li a1, 1 + jal delegate_vs_interrupt + WAIT(500) + li a0, TEST_IRQ_LINE + jal trigger_interrupt + WAIT(500) + + ///////////////////////////////////// + // Test 2 // + ///////////////////////////////////// + // Jump to HS-mode and check that the same + // interrupt does not trigger + + // mret will jump to the address in mepc + la t0, hsmode_entry + csrw mepc, t0 + // Set up PMPs + li t0, -1 + srli t0, t0, 2 + csrw pmpaddr0, t0 // top of TOR range + li t0, 0x0f // R=1 W=1 X=1 A=TOR(01) + csrw pmpcfg0, t0 + // Set mstatus.MPP to 01 (HS-mode) + li t0, 0x1000 + csrs mstatus, t0 + mret + + j fail_restore + + +// HS-mode entry point. +// Set up interrupt handler and enable interrupts. +// Interrupt was set pending already and should not +// trigger even after interrupts are enabled. +hsmode_entry: + + // Write interrupt handler + la t0, stvec_handler_fail + ori t0, t0, 0x3 + csrrw s0, stvec, t0 + + // Enable interrupts (set sstatus.sie) + csrsi sstatus, 0x2 + + // Wait some time to make sure no interrupt + // is bein triggered. + WAIT(10) + + ///////////////////////////////////// + // Test 3 // + ///////////////////////////////////// + // Jump to VS-mode and check that the same + // interrupt when triggered is taken + + // sret will jump to the address in mepc + la t0, vsmode_entry + csrw sepc, t0 + // Set sstatus.SPP to 1 (HS/VS-mode) + li t0, 0x100 + csrs sstatus, t0 + // Set hstatus.SPV to 1 (VS-mode) and + // set hstatus.VGEIN to TEST_VSID + li t0, 0x80 + li t1, TEST_VSID << 12 + or t0, t0, t1 + csrs hstatus, t0 + sret + + // Should not reach here + j smode_fail + +// VS-mode entry point. +// Set up interrupt handler and enable interrupts. +// Interrupt was set pending already and should +// trigger immediately after interrupts are enabled. +vsmode_entry: + + // Write interrupt handler + la t0, stvec_handler_succeed + ori t0, t0, 0x3 + csrrw s0, stvec, t0 + + // Enable interrupts (set sstatus.sie) + csrsi sstatus, 0x2 + + WAIT(100) + + // Should not reach here + j smode_fail + + +// Check return value from S-mode +// (by convention stored in a0) +// and succeed or fail accordingly. +check_smode_return: + beqz a0, pass_restore + j fail_restore + +.align 8 +.global mtvec_handler_fail +mtvec_handler_fail: + csrr t0, mcause + li t1, 1 << 63 + and t0, t0, t1 + beqz t0, check_smode_return + j fail_restore + +.align 8 +.global mtvec_handler_succeed +mtvec_handler_succeed: + csrr t0, mcause + li t1, 1 << 63 + and t0, t0, t1 + beqz t0, check_smode_return + j pass_restore + +.align 8 +.global stvec_handler_fail +stvec_handler_fail: + j smode_fail + +.align 8 +.global stvec_handler_succeed +stvec_handler_succeed: + j smode_pass + +.data diff --git a/test/sw/tests/hello.c b/test/sw/tests/hello.c new file mode 100644 index 00000000000..e7b6a9925be --- /dev/null +++ b/test/sw/tests/hello.c @@ -0,0 +1,12 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Author: Enrico Zelioli + +#include "console.h" + +int main() { + console_puts("Hello\n", 6); + return 0; +} diff --git a/test/util/run-riscv-tests.sh b/test/util/run-riscv-tests.sh new file mode 100755 index 00000000000..cf908c9ae42 --- /dev/null +++ b/test/util/run-riscv-tests.sh @@ -0,0 +1,380 @@ +#!/bin/bash + +# Exit on error +set -e + +red='\033[0;31m' +green='\033[0;32m' +nc='\033[0m' + +if [ "$TERM" = "xterm-256color" ]; then + passmsg="${green}PASSED${nc}" + failmsg="${red}FAILED${nc}" +else + passmsg="PASSED" + failmsg="FAILED" +fi + +rv64ui_p_tests=( + "rv64ui-p-add" + "rv64ui-p-addi" + "rv64ui-p-addiw" + "rv64ui-p-addw" + "rv64ui-p-and" + "rv64ui-p-andi" + "rv64ui-p-auipc" + "rv64ui-p-beq" + "rv64ui-p-bge" + "rv64ui-p-bgeu" + "rv64ui-p-blt" + "rv64ui-p-bltu" + "rv64ui-p-bne" + "rv64ui-p-fence_i" + "rv64ui-p-fence_t" + "rv64ui-p-jal" + "rv64ui-p-jalr" + "rv64ui-p-lb" + "rv64ui-p-lbu" + "rv64ui-p-ld" + "rv64ui-p-ld_st" + "rv64ui-p-lh" + "rv64ui-p-lhu" + "rv64ui-p-lui" + "rv64ui-p-lw" + "rv64ui-p-lwu" + # "rv64ui-p-ma_data" + "rv64ui-p-or" + "rv64ui-p-ori" + "rv64ui-p-sb" + "rv64ui-p-sd" + "rv64ui-p-sh" + "rv64ui-p-simple" + "rv64ui-p-sll" + "rv64ui-p-slli" + "rv64ui-p-slliw" + "rv64ui-p-sllw" + "rv64ui-p-slt" + "rv64ui-p-slti" + "rv64ui-p-sltiu" + "rv64ui-p-sltu" + "rv64ui-p-sra" + "rv64ui-p-srai" + "rv64ui-p-sraiw" + "rv64ui-p-sraw" + "rv64ui-p-srl" + "rv64ui-p-srli" + "rv64ui-p-srliw" + "rv64ui-p-srlw" + "rv64ui-p-st_ld" + "rv64ui-p-sub" + "rv64ui-p-subw" + "rv64ui-p-sw" + "rv64ui-p-xor" + "rv64ui-p-xori" +) + +rv64ui_v_tests=( + "rv64ui-v-add" + "rv64ui-v-addi" + "rv64ui-v-addiw" + "rv64ui-v-addw" + "rv64ui-v-and" + "rv64ui-v-andi" + "rv64ui-v-auipc" + "rv64ui-v-beq" + "rv64ui-v-bge" + "rv64ui-v-bgeu" + "rv64ui-v-blt" + "rv64ui-v-bltu" + "rv64ui-v-bne" + "rv64ui-v-fence_i" + # "rv64ui-v-fence_t" + "rv64ui-v-jal" + "rv64ui-v-jalr" + "rv64ui-v-lb" + "rv64ui-v-lbu" + "rv64ui-v-ld" + "rv64ui-v-ld_st" + "rv64ui-v-lh" + "rv64ui-v-lhu" + "rv64ui-v-lui" + "rv64ui-v-lw" + "rv64ui-v-lwu" + # "rv64ui-v-ma_data" + "rv64ui-v-or" + "rv64ui-v-ori" + "rv64ui-v-sb" + "rv64ui-v-sd" + "rv64ui-v-sh" + "rv64ui-v-simple" + "rv64ui-v-sll" + "rv64ui-v-slli" + "rv64ui-v-slliw" + "rv64ui-v-sllw" + "rv64ui-v-slt" + "rv64ui-v-slti" + "rv64ui-v-sltiu" + "rv64ui-v-sltu" + "rv64ui-v-sra" + "rv64ui-v-srai" + "rv64ui-v-sraiw" + "rv64ui-v-sraw" + "rv64ui-v-srl" + "rv64ui-v-srli" + "rv64ui-v-srliw" + "rv64ui-v-srlw" + "rv64ui-v-st_ld" + "rv64ui-v-sub" + "rv64ui-v-subw" + "rv64ui-v-sw" + "rv64ui-v-xor" + "rv64ui-v-xori" +) + +rv64um_tests=( + "rv64um-p-div" + "rv64um-p-divu" + "rv64um-p-divuw" + "rv64um-p-divw" + "rv64um-p-mulh" + "rv64um-p-mulhsu" + "rv64um-p-mulhu" + "rv64um-p-mul" + "rv64um-p-mulw" + "rv64um-p-rem" + "rv64um-p-remu" + "rv64um-p-remuw" + "rv64um-p-remw" + "rv64um-v-div" + "rv64um-v-divu" + "rv64um-v-divuw" + "rv64um-v-divw" + "rv64um-v-mulh" + "rv64um-v-mulhsu" + "rv64um-v-mulhu" + "rv64um-v-mul" + "rv64um-v-mulw" + "rv64um-v-rem" + "rv64um-v-remu" + "rv64um-v-remuw" + "rv64um-v-remw" +) + +rv64ua_tests=( + "rv64ua-p-amoadd_d" + "rv64ua-p-amoadd_w" + "rv64ua-p-amoand_d" + "rv64ua-p-amoand_w" + "rv64ua-p-amomax_d" + "rv64ua-p-amomaxu_d" + "rv64ua-p-amomaxu_w" + "rv64ua-p-amomax_w" + "rv64ua-p-amomin_d" + "rv64ua-p-amominu_d" + "rv64ua-p-amominu_w" + "rv64ua-p-amomin_w" + "rv64ua-p-amoor_d" + "rv64ua-p-amoor_w" + "rv64ua-p-amoswap_d" + "rv64ua-p-amoswap_w" + "rv64ua-p-amoxor_d" + "rv64ua-p-amoxor_w" + # "rv64ua-p-lrsc" + "rv64ua-v-amoadd_d" + "rv64ua-v-amoadd_w" + "rv64ua-v-amoand_d" + "rv64ua-v-amoand_w" + "rv64ua-v-amomax_d" + "rv64ua-v-amomaxu_d" + "rv64ua-v-amomaxu_w" + "rv64ua-v-amomax_w" + "rv64ua-v-amomin_d" + "rv64ua-v-amominu_d" + "rv64ua-v-amominu_w" + "rv64ua-v-amomin_w" + "rv64ua-v-amoor_d" + "rv64ua-v-amoor_w" + "rv64ua-v-amoswap_d" + "rv64ua-v-amoswap_w" + "rv64ua-v-amoxor_d" + "rv64ua-v-amoxor_w" + # "rv64ua-v-lrsc" +) + +rv64uc_tests=( + "rv64uc-p-rvc" + "rv64uc-v-rvc" +) + +rv64ud_tests=( + "rv64ud-p-fadd" + "rv64ud-p-fclass" + "rv64ud-p-fcmp" + "rv64ud-p-fcvt" + "rv64ud-p-fcvt_w" + "rv64ud-p-fdiv" + "rv64ud-p-fmadd" + "rv64ud-p-fmin" + "rv64ud-p-ldst" + "rv64ud-p-move" + "rv64ud-p-recoding" + "rv64ud-p-structural" + "rv64ud-v-fadd" + "rv64ud-v-fclass" + "rv64ud-v-fcmp" + "rv64ud-v-fcvt" + "rv64ud-v-fcvt_w" + "rv64ud-v-fdiv" + "rv64ud-v-fmadd" + "rv64ud-v-fmin" + "rv64ud-v-ldst" + "rv64ud-v-move" + "rv64ud-v-recoding" + "rv64ud-v-structural" +) + +rv64uf_tests=( + "rv64uf-p-fadd" + "rv64uf-p-fclass" + "rv64uf-p-fcmp" + "rv64uf-p-fcvt" + "rv64uf-p-fcvt_w" + "rv64uf-p-fdiv" + "rv64uf-p-fmadd" + "rv64uf-p-fmin" + "rv64uf-p-ldst" + "rv64uf-p-move" + "rv64uf-p-recoding" + "rv64uf-v-fadd" + "rv64uf-v-fclass" + "rv64uf-v-fcmp" + "rv64uf-v-fcvt" + "rv64uf-v-fcvt_w" + "rv64uf-v-fdiv" + "rv64uf-v-fmadd" + "rv64uf-v-fmin" + "rv64uf-v-ldst" + "rv64uf-v-move" + "rv64uf-v-recoding" +) + +rv64mi_tests=( + # "rv64mi-p-breakpoint" + "rv64mi-p-csr" + "rv64mi-p-illegal" + "rv64mi-p-instret_overflow" + "rv64mi-p-ld-misaligned" + "rv64mi-p-lh-misaligned" + "rv64mi-p-lw-misaligned" + "rv64mi-p-ma_addr" + "rv64mi-p-ma_fetch" + "rv64mi-p-mcsr" + # "rv64mi-p-pmpaddr" + "rv64mi-p-sbreak" + "rv64mi-p-scall" + "rv64mi-p-sd-misaligned" + "rv64mi-p-sh-misaligned" + "rv64mi-p-sw-misaligned" + "rv64mi-p-zicntr" +) + +rv64mzicbo_tests=( + "rv64mzicbo-p-zero" +) + +rv64s_tests=( + "rv64si-p-csr" + "rv64si-p-dirty" + "rv64si-p-icache-alias" + "rv64si-p-ma_fetch" + "rv64si-p-sbreak" + "rv64si-p-scall" + "rv64si-p-wfi" + "rv64ssvnapot-p-napot" +) + +short_tests=( + "${rv64ui_p_tests[@]}" + "${rv64ui_v_tests[@]}" + "${rv64ua_tests[@]}" + "${rv64uc_tests[@]}" + "${rv64uf_tests[@]}" + "${rv64ud_tests[@]}" + "${rv64mi_tests[@]}" + # "${rv64mzicbo_tests[@]}" + "${rv64s_tests[@]}" +) + +long_tests=( + "rv64ua-p-lrsc" + "rv64ua-v-lrsc" +) + +all_tests=( + "${short_tests[@]}" + "${long_tests[@]}" +) + +scriptdir="$(dirname -- "${BASH_SOURCE[0]}")" + +export bindir="$(realpath -m "${scriptdir}/../sw/deps/riscv-tests/build/isa")" +export logdir="$(realpath -m "${scriptdir}/../verilator/logs")" +export simbin="$(realpath -m "${scriptdir}/../verilator/build/Vtest")" + +run_short_test () { + t="$1" + hexfile="${bindir}/${t}.hex" + logfile="${logdir}/${t}.log" + echo "Running test \"${t}\"" + ${simbin} +binary="${hexfile}" +RetCodeSccess=1 +MaxCycles=100000 > ${logfile} +} + +run_long_test () { + t="$1" + hexfile="${bindir}/${t}.hex" + logfile="${logdir}/${t}.log" + echo "Running test \"${t}\"" + ${simbin} +binary="${hexfile}" +RetCodeSccess=1 +MaxCycles=2000000 > ${logfile} +} + +run_short_tests () { + mkdir -p ${logdir} + export -f run_short_test + printf '%s\n' "$@" | xargs -n1 -P 8 bash -c 'run_short_test $1' _ +} + +run_long_tests () { + mkdir -p ${logdir} + export -f run_long_test + printf '%s\n' "$@" | xargs -n1 -P 8 bash -c 'run_long_test $1' _ +} + +check_results() { + testcount=$# + failcount=0 + passcount=0 + + for t in "$@"; do + logfile="${logdir}/${t}.log" + if $(grep -q "SIMULATION PASSED" < ${logfile}); then + echo -e "Test \"${t}\"\t: ${passmsg}" + passcount=$((passcount+1)) + else + echo -e "Test \"${t}\"\t: ${failmsg}" + failcount=$((failcount+1)) + fi + done + + if [ ${failcount} -gt 0 ]; then + echo "FAIL: ${failcount}/${testcount} tests failed" + else + if [ ${passcount} -ne ${testcount} ]; then + echo "WARNING: less tests than expected (${passcount} vs ${testcount})" + fi + echo "SUCCESS: all ${passcount} tests passed" + fi +} + +run_long_tests "${long_tests[@]}" +run_short_tests "${short_tests[@]}" +check_results "${all_tests[@]}" diff --git a/test/verilator/.gitignore b/test/verilator/.gitignore new file mode 100644 index 00000000000..d12b6c63cf6 --- /dev/null +++ b/test/verilator/.gitignore @@ -0,0 +1,5 @@ +*.flist +*.fst +*.vcd +*.dasm +build/ diff --git a/test/vsim/.gitignore b/test/vsim/.gitignore new file mode 100644 index 00000000000..567609b1234 --- /dev/null +++ b/test/vsim/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/test/vsim/waves/clic.tcl b/test/vsim/waves/clic.tcl new file mode 100644 index 00000000000..79ec152a2e2 --- /dev/null +++ b/test/vsim/waves/clic.tcl @@ -0,0 +1,26 @@ +# CLIC +if {![info exists clic]} { + set clic "/test/i_dut/i_clic" +} + +add wave -group CLIC ${clic}/clk_i +add wave -group CLIC ${clic}/rst_ni +add wave -group CLIC ${clic}/reg_req_i +add wave -group CLIC ${clic}/reg_rsp_o +add wave -group CLIC ${clic}/intr_src_i +add wave -group CLIC ${clic}/irq_valid_o +add wave -group CLIC ${clic}/irq_ready_i +add wave -group CLIC ${clic}/irq_id_o +add wave -group CLIC ${clic}/irq_level_o +add wave -group CLIC ${clic}/irq_shv_o +add wave -group CLIC ${clic}/irq_priv_o +add wave -group CLIC ${clic}/irq_v_o +add wave -group CLIC ${clic}/irq_vsid_o +add wave -group CLIC ${clic}/irq_kill_req_o +add wave -group CLIC ${clic}/irq_kill_ack_i +add wave -group CLIC ${clic}/irq_max +add wave -group CLIC ${clic}/irq_mode +add wave -group CLIC ${clic}/ie +add wave -group CLIC ${clic}/ip +add wave -group CLIC ${clic}/ip_sw +add wave -group CLIC ${clic}/shv diff --git a/test/vsim/waves/cva6.tcl b/test/vsim/waves/cva6.tcl new file mode 100644 index 00000000000..2d017d10cb1 --- /dev/null +++ b/test/vsim/waves/cva6.tcl @@ -0,0 +1,114 @@ +# CVA6 top level +if {![info exists CVA6]} { + set CVA6 "/test/i_dut/i_cva6" +} + +add wave -group CVA6 ${CVA6}/clk_i +add wave -group CVA6 ${CVA6}/rst_ni +add wave -group CVA6 ${CVA6}/boot_addr_i +add wave -group CVA6 ${CVA6}/hart_id_i +add wave -group CVA6 ${CVA6}/irq_i +add wave -group CVA6 ${CVA6}/ipi_i +add wave -group CVA6 ${CVA6}/time_irq_i +add wave -group CVA6 ${CVA6}/debug_req_i +add wave -group CVA6 ${CVA6}/clic_irq_valid_i +add wave -group CVA6 ${CVA6}/clic_irq_id_i +add wave -group CVA6 ${CVA6}/clic_irq_level_i +add wave -group CVA6 ${CVA6}/clic_irq_priv_i +add wave -group CVA6 ${CVA6}/clic_irq_v_i +add wave -group CVA6 ${CVA6}/clic_irq_vsid_i +add wave -group CVA6 ${CVA6}/clic_irq_shv_i +add wave -group CVA6 ${CVA6}/clic_irq_ready_o +add wave -group CVA6 ${CVA6}/clic_kill_req_i +add wave -group CVA6 ${CVA6}/clic_kill_ack_o +add wave -group CVA6 ${CVA6}/noc_req_o +add wave -group CVA6 ${CVA6}/noc_resp_i + +# add wave -divider "Internal signals" + +add wave -group CVA6 ${CVA6}/priv_lvl +add wave -group CVA6 ${CVA6}/v +add wave -group CVA6 ${CVA6}/rst_uarch_n +add wave -group CVA6 ${CVA6}/eret +add wave -group CVA6 ${CVA6}/resolved_branch +add wave -group CVA6 ${CVA6}/ex_commit +add wave -group CVA6 ${CVA6}/pc_commit +add wave -group CVA6 ${CVA6}/commit_ack + +add wave -group CVA6 ${CVA6}/fetch_valid_if_id +add wave -group CVA6 ${CVA6}/fetch_ready_id_if +add wave -group CVA6 ${CVA6}/fetch_entry_if_id + +add wave -group CVA6 ${CVA6}/issue_entry_valid_id_issue +add wave -group CVA6 ${CVA6}/issue_instr_issue_id +add wave -group CVA6 ${CVA6}/issue_entry_id_issue + +add wave -group CVA6 ${CVA6}/commit_ack_commit_id +add wave -group CVA6 ${CVA6}/commit_instr_id_commit + +# Frontend +set Frontend "${CVA6}/i_frontend" + +add wave -group CVA6 -group Frontend ${Frontend}/clk_i +add wave -group CVA6 -group Frontend ${Frontend}/rst_ni +# add wave -group CVA6 -group Frontend ${Frontend}/boot_addr_i +add wave -group CVA6 -group Frontend ${Frontend}/flush_bp_i +add wave -group CVA6 -group Frontend ${Frontend}/flush_i +add wave -group CVA6 -group Frontend ${Frontend}/halt_i +add wave -group CVA6 -group Frontend ${Frontend}/halt_frontend_i +add wave -group CVA6 -group Frontend ${Frontend}/set_pc_commit_i +add wave -group CVA6 -group Frontend ${Frontend}/pc_commit_i +add wave -group CVA6 -group Frontend ${Frontend}/ex_valid_i +add wave -group CVA6 -group Frontend ${Frontend}/resolved_branch_i +add wave -group CVA6 -group Frontend ${Frontend}/eret_i +# add wave -group CVA6 -group Frontend ${Frontend}/epc_i +# add wave -group CVA6 -group Frontend ${Frontend}/trap_vector_base_i +add wave -group CVA6 -group Frontend ${Frontend}/set_debug_pc_i +add wave -group CVA6 -group Frontend ${Frontend}/debug_mode_i +add wave -group CVA6 -group Frontend ${Frontend}/icache_dreq_o +add wave -group CVA6 -group Frontend ${Frontend}/icache_dreq_i +add wave -group CVA6 -group Frontend ${Frontend}/fetch_entry_o +add wave -group CVA6 -group Frontend ${Frontend}/fetch_entry_valid_o +add wave -group CVA6 -group Frontend ${Frontend}/fetch_entry_ready_i + +# Instruction cache +set icache "${CVA6}/gen_cache_wb/i_cache_subsystem/i_cva6_icache_axi_wrapper" + +add wave -group CVA6 -group ICache ${icache}/clk_i +add wave -group CVA6 -group ICache ${icache}/rst_ni +# add wave -group CVA6 -group ICache ${icache}/priv_lvl_i +add wave -group CVA6 -group ICache ${icache}/flush_i +add wave -group CVA6 -group ICache ${icache}/en_i +add wave -group CVA6 -group ICache ${icache}/miss_o +add wave -group CVA6 -group ICache ${icache}/busy_o +add wave -group CVA6 -group ICache ${icache}/stall_i +add wave -group CVA6 -group ICache ${icache}/init_ni +add wave -group CVA6 -group ICache ${icache}/areq_i +add wave -group CVA6 -group ICache ${icache}/areq_o +add wave -group CVA6 -group ICache ${icache}/dreq_i +add wave -group CVA6 -group ICache ${icache}/dreq_o +add wave -group CVA6 -group ICache ${icache}/axi_req_o +add wave -group CVA6 -group ICache ${icache}/axi_resp_i +add wave -group CVA6 -group ICache ${icache}/i_cva6_icache/state_q +add wave -group CVA6 -group ICache ${icache}/i_cva6_icache/flush_cnt_q + +# Data cache +set dcache "${CVA6}/gen_cache_wb/i_cache_subsystem/i_nbdcache" + +add wave -group CVA6 -group DCache ${dcache}/clk_i +add wave -group CVA6 -group DCache ${dcache}/rst_ni +add wave -group CVA6 -group DCache ${dcache}/enable_i +add wave -group CVA6 -group DCache ${dcache}/flush_i +add wave -group CVA6 -group DCache ${dcache}/flush_ack_o +add wave -group CVA6 -group DCache ${dcache}/miss_o +add wave -group CVA6 -group DCache ${dcache}/busy_o +add wave -group CVA6 -group DCache ${dcache}/stall_i +add wave -group CVA6 -group DCache ${dcache}/init_ni +add wave -group CVA6 -group DCache ${dcache}/axi_bypass_o +add wave -group CVA6 -group DCache ${dcache}/axi_bypass_i +add wave -group CVA6 -group DCache ${dcache}/axi_data_o +add wave -group CVA6 -group DCache ${dcache}/axi_data_i +add wave -group CVA6 -group DCache ${dcache}/req_ports_i +add wave -group CVA6 -group DCache ${dcache}/req_ports_o +add wave -group CVA6 -group DCache ${dcache}/amo_req_i +add wave -group CVA6 -group DCache ${dcache}/amo_resp_o diff --git a/vendor/pulp-platform/fpga-support/fpga-support-stubs.sv b/vendor/pulp-platform/fpga-support/fpga-support-stubs.sv new file mode 100644 index 00000000000..28571b83473 --- /dev/null +++ b/vendor/pulp-platform/fpga-support/fpga-support-stubs.sv @@ -0,0 +1,81 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +module SyncDpRam +#( + parameter ADDR_WIDTH = 10, + parameter DATA_DEPTH = 1024, + parameter DATA_WIDTH = 32, + parameter OUT_REGS = 0, + parameter SIM_INIT = 0 +)( + input logic Clk_CI, + input logic Rst_RBI, + input logic CSelA_SI, + input logic WrEnA_SI, + input logic [DATA_WIDTH-1:0] WrDataA_DI, + input logic [ADDR_WIDTH-1:0] AddrA_DI, + output logic [DATA_WIDTH-1:0] RdDataA_DO, + input logic CSelB_SI, + input logic WrEnB_SI, + input logic [DATA_WIDTH-1:0] WrDataB_DI, + input logic [ADDR_WIDTH-1:0] AddrB_DI, + output logic [DATA_WIDTH-1:0] RdDataB_DO +); + + if (1) begin : assert_instantiation + $fatal( 1, "Instantiated FPGA-specific cell; this is illegal in PULP CVA6 (%m)"); + end + +endmodule + + +module AsyncDpRam +#( + parameter ADDR_WIDTH = 10, + parameter DATA_DEPTH = 1024, // usually 2**ADDR_WIDTH, but can be lower + parameter DATA_WIDTH = 32 +)( + input logic Clk_CI, + input logic WrEn_SI, + input logic [ADDR_WIDTH-1:0] WrAddr_DI, + input logic [DATA_WIDTH-1:0] WrData_DI, + input logic [ADDR_WIDTH-1:0] RdAddr_DI, + output logic [DATA_WIDTH-1:0] RdData_DO +); + + if (1) begin : assert_instantiation + $fatal( 1, "Instantiated FPGA-specific cell; this is illegal in PULP CVA6 (%m)"); + end + +endmodule + + +module AsyncThreePortRam +#( + parameter ADDR_WIDTH = 10, + parameter DATA_DEPTH = 1024, + parameter DATA_WIDTH = 32 +)( + input logic Clk_CI, + input logic WrEn_SI, + input logic [ADDR_WIDTH-1:0] WrAddr_DI, + input logic [DATA_WIDTH-1:0] WrData_DI, + input logic [ADDR_WIDTH-1:0] RdAddr_DI_0, + input logic [ADDR_WIDTH-1:0] RdAddr_DI_1, + output logic [DATA_WIDTH-1:0] RdData_DO_0, + output logic [DATA_WIDTH-1:0] RdData_DO_1 +); + + if (1) begin : assert_instantiation + $fatal( 1, "Instantiated FPGA-specific cell; this is illegal in PULP CVA6 (%m)"); + end + +endmodule