mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-23 13:27:10 -04:00
Compare commits
13 commits
master
...
pulpissimo
Author | SHA1 | Date | |
---|---|---|---|
|
95b85ddd1c | ||
|
54533b0744 | ||
|
0d07047383 | ||
|
95851f5cce | ||
|
24e3d1d090 | ||
|
28be76be62 | ||
|
3d88aa42aa | ||
|
2356c029c8 | ||
|
a93f5c8ddf | ||
|
54becdb274 | ||
|
ebc92e8c82 | ||
|
0d6e220d79 | ||
|
57108c3184 |
3222 changed files with 26274 additions and 886952 deletions
102
.github/actions/ibex-rtl-ci-steps/action.yml
vendored
102
.github/actions/ibex-rtl-ci-steps/action.yml
vendored
|
@ -1,102 +0,0 @@
|
|||
name: Ibex RTL CI Steps
|
||||
description: Ibex RTL CI Steps
|
||||
|
||||
inputs:
|
||||
ibex_config:
|
||||
required: true
|
||||
description: Ibex configuration to run CI for
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# ibex_config.py will exit with error code 1 on any error which will cause
|
||||
# the CI to fail if there's an issue with the configuration file or an
|
||||
# incorrect configuration name being used
|
||||
- name: Test and display fusesoc config for ${{ inputs.ibex_config }}
|
||||
shell: bash
|
||||
run: |
|
||||
IBEX_CONFIG_OPTS=`./util/ibex_config.py ${{ inputs.ibex_config }} fusesoc_opts`
|
||||
echo $IBEX_CONFIG_OPTS
|
||||
echo "IBEX_CONFIG_OPTS=$IBEX_CONFIG_OPTS" >> $GITHUB_ENV
|
||||
|
||||
- name: Lint Verilog source files with Verilator for ${{ inputs.ibex_config }}
|
||||
shell: bash
|
||||
run: |
|
||||
set +e
|
||||
fusesoc --cores-root . run --target=lint --tool=verilator lowrisc:ibex:ibex_top_tracing $IBEX_CONFIG_OPTS
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "::error::"
|
||||
echo "Verilog lint failed. Run 'fusesoc --cores-root . run --target=lint --tool=verilator lowrisc:ibex:ibex_top_tracing $IBEX_CONFIG_OPTS' to check and fix all errors."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Lint Verilog source files with Verible Verilog Lint for ${{ inputs.ibex_config }}
|
||||
shell: bash
|
||||
run: |
|
||||
set +e
|
||||
fusesoc --cores-root . run --target=lint --tool=veriblelint lowrisc:ibex:ibex_top_tracing $IBEX_CONFIG_OPTS
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "::error::"
|
||||
echo "Verilog lint failed. Run 'fusesoc --cores-root . run --target=lint --tool=veriblelint lowrisc:ibex:ibex_top_tracing $IBEX_CONFIG_OPTS' to check and fix all errors."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Run RISC-V Compliance test for Ibex RV32IMC for ${{ inputs.ibex_config }}
|
||||
shell: bash
|
||||
run: |
|
||||
set +e
|
||||
# Build simulation model of Ibex
|
||||
fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_riscv_compliance $IBEX_CONFIG_OPTS
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "::error::"
|
||||
echo "Unable to build Verilator model of Ibex for compliance testing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run compliance test suite
|
||||
export TARGET_SIM=$PWD/build/lowrisc_ibex_ibex_riscv_compliance_0.1/sim-verilator/Vibex_riscv_compliance
|
||||
export RISCV_PREFIX=riscv32-unknown-elf-
|
||||
export RISCV_TARGET=ibex
|
||||
export RISCV_DEVICE=rv32imc
|
||||
fail=0
|
||||
for isa in rv32i rv32im rv32imc rv32Zicsr rv32Zifencei; do
|
||||
make -C build/riscv-compliance RISCV_ISA=$isa 2>&1 | tee run.log
|
||||
if [ ${PIPESTATUS[0]} != 0 ]; then
|
||||
echo -n "::error::"
|
||||
echo "The RISC-V compliance test suite failed for $isa"
|
||||
|
||||
# There's no easy way to get the test results in machine-readable
|
||||
# form to properly exclude known-failing tests. Going with an
|
||||
# approximate solution for now.
|
||||
if [ $isa == rv32i ] && grep -q 'FAIL: 4/48' run.log; then
|
||||
echo -n "::error::"
|
||||
echo "Expected failure for rv32i, see lowrisc/ibex#100 more more information."
|
||||
else
|
||||
fail=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
exit $fail
|
||||
|
||||
- name: Run Verilator co-sim tests for for ${{ inputs.ibex_config }}
|
||||
shell: bash
|
||||
run: |
|
||||
source ci/setup-cosim.sh
|
||||
# Build simple system with co-simulation
|
||||
fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_simple_system_cosim $IBEX_CONFIG_OPTS
|
||||
|
||||
# Run directed tests against simple system co-simulation
|
||||
./ci/run-cosim-test.sh --skip-pass-check CoreMark examples/sw/benchmarks/coremark/coremark.elf
|
||||
|
||||
if ./util/ibex_config.py ${{ inputs.ibex_config }} query_fields PMPEnable | grep -q 'PMPEnable=1'; then
|
||||
./ci/run-cosim-test.sh --skip-pass-check pmp_smoke examples/sw/simple_system/pmp_smoke_test/pmp_smoke_test.elf
|
||||
else
|
||||
echo "PMP not supported on ${{ inputs.ibex_config }}, skipping pmp_smoke_test"
|
||||
fi
|
||||
|
||||
if ./util/ibex_config.py ${{ inputs.ibex_config }} query_fields SecureIbex | grep -q 'SecureIbex=1'; then
|
||||
./ci/run-cosim-test.sh dit_test examples/sw/simple_system/dit_test/dit_test.elf
|
||||
./ci/run-cosim-test.sh dummy_instr_test examples/sw/simple_system/dummy_instr_test/dummy_instr_test.elf
|
||||
else
|
||||
echo "Security features not supported on ${{ inputs.ibex_config }}, skipping security feature tests"
|
||||
fi
|
151
.github/workflows/ci.yml
vendored
151
.github/workflows/ci.yml
vendored
|
@ -1,151 +0,0 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# GitHub Actions CI build configuration
|
||||
|
||||
name: Ibex CI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
merge_group:
|
||||
types:
|
||||
- checks_requested
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
# Note: All tests run as part of one job to avoid copying intermediate build
|
||||
# artifacts around (e.g. Verilator and toolchain builds). Once more builds/tests
|
||||
# are added, we need to re-evaluate this decision to parallelize jobs and
|
||||
# improve end-to-end CI times.
|
||||
|
||||
jobs:
|
||||
lint_dv:
|
||||
name: Run quality checks (Lint and DV)
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Fetch all history so that we can run git diff on the base branch
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup environment variables
|
||||
run: |
|
||||
# Filter out empty lines or comments
|
||||
grep -v '^\(#\|$\)' ci/vars.env >> $GITHUB_ENV
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
ci/install-build-deps.sh
|
||||
|
||||
- name: Display environment
|
||||
run: |
|
||||
echo $PATH
|
||||
python3 --version
|
||||
echo -n "fusesoc "
|
||||
fusesoc --version
|
||||
verilator --version
|
||||
riscv32-unknown-elf-gcc --version
|
||||
verible-verilog-lint --version
|
||||
|
||||
# Verible format is experimental so only run on default config for now,
|
||||
# will eventually become part of the per-config CI
|
||||
- name: Format all source code with Verible format (experimental)
|
||||
run: |
|
||||
set +e
|
||||
fusesoc --cores-root . run --no-export --target=format --tool=veribleformat lowrisc:ibex:ibex_top_tracing
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "::error::"
|
||||
echo "Verilog format with Verible failed. Run 'fusesoc --cores-root . run --no-export --target=format --tool=veribleformat lowrisc:ibex:ibex_top_tracing' to check and fix all errors."
|
||||
echo "This flow is currently experimental and failures can be ignored."
|
||||
fi
|
||||
# Show diff of what verilog_format would have changed, and then revert.
|
||||
git diff --no-pager
|
||||
git reset --hard HEAD
|
||||
continue-on-error: true
|
||||
|
||||
- name: Use clang-format to check C/C++ coding style
|
||||
# This check is not idempotent, but checks changes to a base branch.
|
||||
# Run it only on pull requests.
|
||||
if: github.event_name == 'pull_request'
|
||||
run: |
|
||||
set +e
|
||||
fork_origin=${{ github.event.pull_request.base.sha }}
|
||||
changed_files=$(git diff --name-only $fork_origin | grep -v '^vendor' | grep -E '\.(cpp|cc|c|h)$')
|
||||
test -z "$changed_files" || git diff -U0 $fork_origin $changed_files | clang-format-diff -p1 | tee clang-format-output
|
||||
if [ -s clang-format-output ]; then
|
||||
echo -n "::error::"
|
||||
echo "C/C++ lint failed. Use 'git clang-format' with appropriate options to reformat the changed code."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Build and run CSR testbench with Verilator
|
||||
run: |
|
||||
# Build and run CSR testbench, chosen Ibex configuration does not effect
|
||||
# this so doesn't need to be part of per-config CI
|
||||
fusesoc --cores-root=. run --target=sim --tool=verilator lowrisc:ibex:tb_cs_registers
|
||||
|
||||
- name: Get RISC-V Compliance test suite
|
||||
run: |
|
||||
cd build
|
||||
git clone https://github.com/riscv/riscv-compliance.git
|
||||
cd riscv-compliance
|
||||
git checkout "$RISCV_COMPLIANCE_GIT_VERSION"
|
||||
|
||||
- name: Build tests for verilator co-simulation
|
||||
run: |
|
||||
# Build CoreMark without performance counter dump for co-simulation testing
|
||||
make -C ./examples/sw/benchmarks/coremark SUPPRESS_PCOUNT_DUMP=1
|
||||
make -C ./examples/sw/simple_system/pmp_smoke_test
|
||||
make -C ./examples/sw/simple_system/dit_test
|
||||
make -C ./examples/sw/simple_system/dummy_instr_test
|
||||
|
||||
# Run Ibex RTL CI per supported configuration
|
||||
- name: Run Ibex RTL CI for small configuration
|
||||
uses: ./.github/actions/ibex-rtl-ci-steps
|
||||
with:
|
||||
ibex_config: small
|
||||
- name: Run Ibex RTL CI for opentitan configuration
|
||||
uses: ./.github/actions/ibex-rtl-ci-steps
|
||||
with:
|
||||
ibex_config: opentitan
|
||||
- name: Run Ibex RTL CI for maxperf configuration
|
||||
uses: ./.github/actions/ibex-rtl-ci-steps
|
||||
with:
|
||||
ibex_config: maxperf
|
||||
- name: Run Ibex RTL CI for maxperf-pmp-bmbalanced configuration
|
||||
uses: ./.github/actions/ibex-rtl-ci-steps
|
||||
with:
|
||||
ibex_config: maxperf-pmp-bmbalanced
|
||||
- name: Run Ibex RTL CI for maxperf-pmp-bmfull configuration
|
||||
uses: ./.github/actions/ibex-rtl-ci-steps
|
||||
with:
|
||||
ibex_config: maxperf-pmp-bmfull
|
||||
- name: Run Ibex RTL CI for experimental-branch-predictor configuration
|
||||
uses: ./.github/actions/ibex-rtl-ci-steps
|
||||
with:
|
||||
ibex_config: experimental-branch-predictor
|
||||
|
||||
# Run lint on simple system
|
||||
- name: Run Verilator lint on simple system
|
||||
run: |
|
||||
set +e
|
||||
fusesoc --cores-root . run --target=lint --tool=verilator lowrisc:ibex:ibex_simple_system
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "::error::"
|
||||
echo "Verilog lint with Verilator failed. Run 'fusesoc --cores-root . run --target=lint --tool=verilator lowrisc:ibex:ibex_simple_system' to check and fix all errors."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Run Verible lint on simple system
|
||||
run: |
|
||||
set +e
|
||||
fusesoc --cores-root . run --target=lint --tool=veriblelint lowrisc:ibex:ibex_simple_system
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "::error::"
|
||||
echo "Verilog lint with Verible failed. Run 'fusesoc --cores-root . run --target=lint --tool=veriblelint lowrisc:ibex:ibex_simple_system' to check and fix all errors."
|
||||
exit 1
|
||||
fi
|
38
.github/workflows/pr_lint.yml
vendored
38
.github/workflows/pr_lint.yml
vendored
|
@ -1,38 +0,0 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# GitHub Action to run Verible linting on pull requests and add review comments.
|
||||
#
|
||||
# See https://github.com/chipsalliance/verible-linter-action.
|
||||
|
||||
name: pr-lint
|
||||
|
||||
# Triggers when there is any activity on a pull request, e.g. opened, updated.
|
||||
on:
|
||||
merge_group:
|
||||
types:
|
||||
- checks_requested
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
verible-lint:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
verible_config: "vendor/lowrisc_ip/lint/tools/veriblelint/lowrisc-styleguide.rules.verible_lint"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Display Verible config
|
||||
run: |
|
||||
echo "::group::Verible config"
|
||||
cat "$verible_config"
|
||||
echo "::endgroup::"
|
||||
- name: Run Verible linter action
|
||||
uses: chipsalliance/verible-linter-action@main
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
reviewdog_reporter: github-pr-check
|
||||
suggest_fixes: "false"
|
||||
config_file: ${{ env.verible_config }}
|
38
.github/workflows/private-ci.yml
vendored
38
.github/workflows/private-ci.yml
vendored
|
@ -1,38 +0,0 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: Ibex Private CI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
merge_group:
|
||||
types:
|
||||
- checks_requested
|
||||
pull_request_target:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
permissions:
|
||||
contents: write # For repository dispatch
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
name: Trigger Private CI
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Trigger Private CI
|
||||
run: |
|
||||
PAYLOAD='"target":"${{ github.repository_owner }}/lowrisc-private-ci/master/ibex-private-ci.yml","sha":"${{ github.event.pull_request.head.sha || github.sha }}"'
|
||||
if ${{ github.event_name == 'pull_request_target' }}; then
|
||||
PAYLOAD+=',"pull_request":${{ github.event.pull_request.number }}'
|
||||
fi
|
||||
curl -fL \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ github.token }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/${{ github.repository }}/dispatches \
|
||||
-d '{"event_type":"cross-repo-ci","client_payload":{'"$PAYLOAD"'}}'
|
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -18,6 +18,19 @@ ibex_simple_system_pcount.csv
|
|||
# Python cache files
|
||||
__pycache__
|
||||
|
||||
# This is generated by VCS when running DV simulations with WAVE=1.
|
||||
/dv/uvm/core_ibex/ucli.key
|
||||
|
||||
# This is generated by UVM when running simulations and doesn't seem
|
||||
# to be something you can disable.
|
||||
/dv/uvm/core_ibex/tr_db.log
|
||||
|
||||
# This is the default output directory in dv/uvm/core_ibex and
|
||||
# contains auto-generated files from building and running tests.
|
||||
/dv/uvm/core_ibex/out
|
||||
|
||||
# This is generated by Questa tool when running DV simulations
|
||||
modelsim.ini
|
||||
|
||||
# This is generated by Xcelium when running DV simulations, even with WAVE=0
|
||||
/dv/uvm/core_ibex/waves.shm
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
# .readthedocs.yaml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Set the version of Python and other tools you might need
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.11"
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: doc/conf.py
|
||||
|
||||
python:
|
||||
install:
|
||||
- requirements: doc/requirements.txt
|
|
@ -5,7 +5,7 @@
|
|||
# Rules for svlint, a SystemVerilog linter commonly used in editors.
|
||||
# The configuration matches the lowRISC SystemVerilog style guide at
|
||||
# https://github.com/lowRISC/style-guides/blob/master/VerilogCodingStyle.md.
|
||||
# See https://github.com/dalance/svlint/blob/master/MANUAL.md for a list of rules.
|
||||
# See https://github.com/dalance/svlint/blob/master/RULES.md for a list of rules.
|
||||
|
||||
[option]
|
||||
exclude_paths = ["build.*", "sw/.*", ".sv.tpl$", "vendor/.*"]
|
||||
|
|
84
Bender.yml
Normal file
84
Bender.yml
Normal file
|
@ -0,0 +1,84 @@
|
|||
package:
|
||||
name: ibex
|
||||
|
||||
dependencies:
|
||||
tech_cells_generic: { git: "git@github.com:pulp-platform/tech_cells_generic.git", version: 0.2.2 }
|
||||
|
||||
sources:
|
||||
- target: synthesis
|
||||
files:
|
||||
- rtl/ibex_register_file_latch.sv
|
||||
- target: xilinx
|
||||
files:
|
||||
- rtl/ibex_register_file_fpga.sv
|
||||
- target: not(rtl)
|
||||
include_dirs:
|
||||
- rtl
|
||||
- vendor/lowrisc_ip/ip/prim/rtl
|
||||
|
||||
files:
|
||||
# Source files grouped in levels. Files in level 0 have no dependencies on files in this
|
||||
# package. Files in level 1 only depend on files in level 0, files in level 2 on files in
|
||||
# levels 1 and 0, etc. Files within a level are ordered alphabetically.
|
||||
# Level 0
|
||||
- rtl/ibex_pkg.sv
|
||||
- vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv
|
||||
# Level 1
|
||||
- rtl/ibex_alu.sv
|
||||
- rtl/ibex_compressed_decoder.sv
|
||||
- rtl/ibex_controller.sv
|
||||
- rtl/ibex_counter.sv
|
||||
- rtl/ibex_csr.sv
|
||||
- rtl/ibex_decoder.sv
|
||||
- rtl/ibex_fetch_fifo.sv
|
||||
- rtl/ibex_load_store_unit.sv
|
||||
- rtl/ibex_multdiv_fast.sv
|
||||
- rtl/ibex_multdiv_slow.sv
|
||||
- rtl/ibex_pmp.sv
|
||||
- rtl/ibex_wb_stage.sv
|
||||
# Level 2
|
||||
- rtl/ibex_cs_registers.sv
|
||||
- rtl/ibex_ex_block.sv
|
||||
- rtl/ibex_id_stage.sv
|
||||
- rtl/ibex_prefetch_buffer.sv
|
||||
# Level 3
|
||||
- rtl/ibex_if_stage.sv
|
||||
# Level 4
|
||||
- rtl/ibex_core.sv
|
||||
- target: rtl
|
||||
include_dirs:
|
||||
- rtl
|
||||
- vendor/lowrisc_ip/ip/prim/rtl
|
||||
defines:
|
||||
RVFI: true
|
||||
files:
|
||||
# Level 0
|
||||
- rtl/ibex_pkg.sv
|
||||
- rtl/ibex_register_file_ff.sv
|
||||
- vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv
|
||||
# Level 1
|
||||
- rtl/ibex_alu.sv
|
||||
- rtl/ibex_compressed_decoder.sv
|
||||
- rtl/ibex_controller.sv
|
||||
- rtl/ibex_counter.sv
|
||||
- rtl/ibex_csr.sv
|
||||
- rtl/ibex_decoder.sv
|
||||
- rtl/ibex_fetch_fifo.sv
|
||||
- rtl/ibex_load_store_unit.sv
|
||||
- rtl/ibex_multdiv_fast.sv
|
||||
- rtl/ibex_multdiv_slow.sv
|
||||
- rtl/ibex_pmp.sv
|
||||
- rtl/ibex_tracer_pkg.sv
|
||||
- rtl/ibex_wb_stage.sv
|
||||
# Level 2
|
||||
- rtl/ibex_cs_registers.sv
|
||||
- rtl/ibex_ex_block.sv
|
||||
- rtl/ibex_id_stage.sv
|
||||
- rtl/ibex_prefetch_buffer.sv
|
||||
- rtl/ibex_tracer.sv
|
||||
# Level 3
|
||||
- rtl/ibex_if_stage.sv
|
||||
# Level 4
|
||||
- rtl/ibex_core.sv
|
||||
# Level 5
|
||||
- rtl/ibex_core_tracing.sv
|
36
CREDITS.md
36
CREDITS.md
|
@ -13,68 +13,34 @@ in the form of source code, bug reports, testing, marketing, or any other form,
|
|||
please feel free to open a pull request to get your name added to this file.
|
||||
|
||||
- Alex Bradbury
|
||||
- Andreas Kurth
|
||||
- Andreas Traber
|
||||
- Antonio Pullini
|
||||
- Bryan Cantrill
|
||||
- Canberk Topal
|
||||
- Cathal Minnock
|
||||
- Daniel Mlynek
|
||||
- Dawid Zimonczyk
|
||||
- Eunchan Kim
|
||||
- Felix Yan
|
||||
- Flavian Solt
|
||||
- Florian Zaruba
|
||||
- Francesco Conti
|
||||
- Gary Guo
|
||||
- Germain Haugou
|
||||
- Greg Chadwick
|
||||
- Harry Callahan
|
||||
- Hai Hoang Dang
|
||||
- Henner Zeller
|
||||
- Hodjat Asghari Esfeden
|
||||
- Igor Loi
|
||||
- Ioannis Karageorgos
|
||||
- Ivan Ribeiro
|
||||
- Karol Gugala
|
||||
- Leon Woestenberg
|
||||
- Luís Marques
|
||||
- Marek Pikuła
|
||||
- Markus Wegmann
|
||||
- Marno van der Maas
|
||||
- Ivan Ribeiro
|
||||
- Matthias Baer
|
||||
- Mehmet Burak Aykenar
|
||||
- Michael Gautschi
|
||||
- Michael Gielda
|
||||
- Michael Munday
|
||||
- Michael Platzer
|
||||
- Michael Schaffner
|
||||
- Nils Graf
|
||||
- Noah Huesser
|
||||
- Noam Gallmann
|
||||
- Pasquale Davide Schiavone
|
||||
- Paul O'Keeffe
|
||||
- Philipp Wagner
|
||||
- Pirmin Vogel
|
||||
- Prajwala Puttappa
|
||||
- Rahul Behl
|
||||
- Rhys Thomas
|
||||
- Renzo Andri
|
||||
- Robert Schilling
|
||||
- Rupert Swarbick
|
||||
- Sam Elliott
|
||||
- Scott Johnson
|
||||
- Stefan Mach
|
||||
- Stefan Tauner
|
||||
- Stefan Wallentowitz
|
||||
- Sven Stucki
|
||||
- Tao Liu
|
||||
- Tobias Wölfel
|
||||
- Tom Roberts
|
||||
- Tudor Timi
|
||||
- Udi Jonnalagadda
|
||||
- Vladimir Rozic
|
||||
- Yuichi Sugiyama
|
||||
- Yusef Karim
|
||||
- Zachary Snow
|
||||
- Zeeshan Rafique
|
||||
|
|
10
NOTICE
10
NOTICE
|
@ -1,10 +0,0 @@
|
|||
The Ibex Project
|
||||
Copyright 2024 lowRISC contributors.
|
||||
|
||||
This product includes hardware and/or software developed as part of the
|
||||
Ibex(R) (https://github.com/lowRISC/ibex) and OpenTitan(R) projects.
|
||||
|
||||
Ibex was originally developed by the PULP team at ETH Zurich and University of
|
||||
Bologna under the name zero-riscy. Ibex verification, performance enhancement
|
||||
and security hardening have been supported by the OpenTitan project
|
||||
(https://www.opentitan.org).
|
52
README.md
52
README.md
|
@ -1,23 +1,17 @@
|
|||
[Ibex OpenTitan configuration Nightly Regression](https://ibex.reports.lowrisc.org/opentitan/latest/report.html)
|
||||
<a href="https://ibex.reports.lowrisc.org/opentitan/latest/report.html">
|
||||
<img src="https://ibex.reports.lowrisc.org/opentitan/latest/summary.svg">
|
||||
</a>
|
||||
[](https://dev.azure.com/lowrisc/ibex/_build/latest?definitionId=3&branchName=master)
|
||||
|
||||
# Ibex RISC-V Core
|
||||
|
||||
Ibex is a production-quality open source 32-bit RISC-V CPU core written in
|
||||
SystemVerilog. The CPU core is heavily parametrizable and well suited for
|
||||
embedded control applications. Ibex is being extensively verified and has
|
||||
seen multiple tape-outs. Ibex supports the Integer (I) or Embedded (E),
|
||||
Integer Multiplication and Division (M), Compressed (C), and B (Bit
|
||||
Manipulation) extensions.
|
||||
Ibex is a small and efficient, 32-bit, in-order RISC-V core with a 2-stage pipeline that implements
|
||||
the RV32IMC instruction set architecture.
|
||||
|
||||
<p align="center"><img src="doc/03_reference/images/blockdiagram.svg" width="650"></p>
|
||||
|
||||
Ibex was initially developed as part of the [PULP platform](https://www.pulp-platform.org)
|
||||
under the name ["Zero-riscy"](https://doi.org/10.1109/PATMOS.2017.8106976), and has been
|
||||
This core was initially developed as part of the [PULP platform](https://www.pulp-platform.org)
|
||||
under the name "Zero-riscy" \[[1](https://doi.org/10.1109/PATMOS.2017.8106976)\], and has been
|
||||
contributed to [lowRISC](https://www.lowrisc.org) who maintains it and develops it further. It is
|
||||
under active development.
|
||||
under active development, with further code cleanups, feature additions, and test and verification
|
||||
planned for the future.
|
||||
|
||||
## Configuration
|
||||
|
||||
|
@ -29,16 +23,17 @@ These are configurations on which lowRISC is focusing for performance evaluation
|
|||
| Config | "micro" | "small" | "maxperf" | "maxperf-pmp-bmfull" |
|
||||
| ------ | ------- | --------| ----------| -------------------- |
|
||||
| Features | RV32EC | RV32IMC, 3 cycle mult | RV32IMC, 1 cycle mult, Branch target ALU, Writeback stage | RV32IMCB, 1 cycle mult, Branch target ALU, Writeback stage, 16 PMP regions |
|
||||
| Performance (CoreMark/MHz) | 0.904 | 2.47 | 3.13 | 3.13 |
|
||||
| Area - Yosys (kGE) | 16.85 | 26.60 | 32.48 | 66.02 |
|
||||
| Area - Commercial (estimated kGE) | ~15 | ~24 | ~30 | ~61 |
|
||||
| Verification status | Red | Green | Green | Green |
|
||||
| Performance (CoreMark/MHz) | 0.904 | 2.47 | 3.13 | 3.05 |
|
||||
| Area - Yosys (kGE) | 17.44 | 26.06 | 35.64 | 58.74 |
|
||||
| Area - Commercial (estimated kGE) | ~16 | ~24 | ~33 | ~54 |
|
||||
| Verification status | Red | Green | Amber | Amber |
|
||||
|
||||
Notes:
|
||||
|
||||
* Performance numbers are based on CoreMark running on the Ibex Simple System [platform](examples/simple_system/README.md).
|
||||
Note that different ISAs (use of B and C extensions) give the best results for different configurations.
|
||||
See the [Benchmarks README](examples/sw/benchmarks/README.md) for more information.
|
||||
The "maxperf-pmp-bmfull" configuration sets a `SpecBranch` parameter in `ibex_core.sv`; this helps timing but has a small negative performance impact.
|
||||
* Yosys synthesis area numbers are based on the Ibex basic synthesis [flow](syn/README.md) using the latch-based register file.
|
||||
* Commercial synthesis area numbers are a rough estimate of what might be achievable with a commercial synthesis flow and technology library.
|
||||
* For comparison, the original "Zero-riscy" core yields an area of 23.14kGE using our Yosys synthesis flow.
|
||||
|
@ -47,8 +42,8 @@ Notes:
|
|||
Amber indicates that some verification has been performed, but the configuration is still experimental.
|
||||
Red indicates a configuration with minimal/no verification.
|
||||
Users must make their own assessment of verification readiness for any tapeout.
|
||||
* v.1.0.0 of the RISC-V Bit-Manipulation Extension is supported as well as the remaining sub-extensions of draft v.0.93 of the bitmanip spec.
|
||||
The latter are *not ratified* and there may be changes before ratification.
|
||||
* v0.92 of the RISC-V Bit Manipulation Extension is supported.
|
||||
This is *not ratified* and there may be changes for the v1.0 ratified version.
|
||||
See [Standards Compliance](https://ibex-core.readthedocs.io/en/latest/01_overview/compliance.html) in the Ibex documentation for more information.
|
||||
|
||||
## Documentation
|
||||
|
@ -57,17 +52,6 @@ The Ibex user manual can be
|
|||
[read online at ReadTheDocs](https://ibex-core.readthedocs.io/en/latest/). It is also contained in
|
||||
the `doc` folder of this repository.
|
||||
|
||||
## Examples
|
||||
|
||||
The Ibex repository includes [Simple System](examples/simple_system/README.md).
|
||||
This is an intentionally simple integration of Ibex with a basic system that targets simulation.
|
||||
It is intended to provide an easy way to get bare metal binaries running on Ibex in simulation.
|
||||
|
||||
A more complete example can be found in the [Ibex Demo System repository](https://github.com/lowrisc/ibex-demo-system).
|
||||
In particular it includes a integration of the [PULP RISC-V debug module](https://github.com/pulp-platform/riscv-dbg).
|
||||
It targets the [Arty A7 FPGA board from Digilent](https://digilent.com/shop/arty-a7-artix-7-fpga-development-board/) and supports debugging via OpenOCD and GDB over USB (no external JTAG probe required).
|
||||
The Ibex Demo System is maintained by lowRISC but is not an official part of Ibex.
|
||||
|
||||
## Contributing
|
||||
|
||||
We highly appreciate community contributions. To ease our work of reviewing your contributions,
|
||||
|
@ -85,7 +69,7 @@ When contributing SystemVerilog source code, please try to be consistent and adh
|
|||
coding style guide](https://github.com/lowRISC/style-guides/blob/master/VerilogCodingStyle.md).
|
||||
|
||||
When contributing C or C++ source code, please try to adhere to [the OpenTitan C++ coding style
|
||||
guide](https://opentitan.org/book/doc/contributing/style_guides/c_cpp_coding_style.html).
|
||||
guide](https://docs.opentitan.org/doc/rm/c_cpp_coding_style/).
|
||||
All C and C++ code should be formatted with clang-format before committing.
|
||||
Either run `clang-format -i filename.cc` or `git clang-format` on added files.
|
||||
|
||||
|
@ -112,3 +96,9 @@ License, Version 2.0 (see LICENSE for full text).
|
|||
|
||||
Many people have contributed to Ibex through the years. Please have a look at
|
||||
the [credits file](CREDITS.md) and the commit history for more information.
|
||||
|
||||
## References
|
||||
1. [Schiavone, Pasquale Davide, et al. "Slow and steady wins the race? A comparison of
|
||||
ultra-low-power RISC-V cores for Internet-of-Things applications."
|
||||
_27th International Symposium on Power and Timing Modeling, Optimization and Simulation
|
||||
(PATMOS 2017)_](https://doi.org/10.1109/PATMOS.2017.8106976)
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# Reporting Security Issues
|
||||
|
||||
The lowRISC team and Ibex community (including the OpenTitan partnership) take security issues seriously.
|
||||
|
||||
We appreciate all efforts to find security vulnerabilities in Ibex and ask that responsible disclosure is practiced should you discover a potential vulnerability.
|
||||
|
||||
As Ibex and in particular its secure configuration was developed as part of [OpenTitan](https://www.github.com/lowrisc/opentitan) contact [security@opentitan.org](mailto:security@opentitan.org) to report any security issues and do not open a public issue.
|
||||
[security@opentitan.org](mailto:security@opentitan.org) will advise on the coordinated vulnerability disclosure (CVD) procedure.
|
120
azure-pipelines.yml
Normal file
120
azure-pipelines.yml
Normal file
|
@ -0,0 +1,120 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Azure Pipelines CI build configuration
|
||||
# Documentation at https://aka.ms/yaml
|
||||
|
||||
variables:
|
||||
- template: ci/vars.yml
|
||||
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- '*'
|
||||
tags:
|
||||
include:
|
||||
- '*'
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- '*'
|
||||
|
||||
# Note: All tests run as part of one job to avoid copying intermediate build
|
||||
# artifacts around (e.g. Verilator and toolchain builds). Once more builds/tests
|
||||
# are added, we need to re-evaluate this decision to parallelize jobs and
|
||||
# improve end-to-end CI times.
|
||||
|
||||
jobs:
|
||||
- job: lint_dv
|
||||
displayName: Run quality checks (Lint and DV)
|
||||
pool:
|
||||
vmImage: "ubuntu-18.04"
|
||||
steps:
|
||||
- bash: |
|
||||
ci/install-build-deps.sh
|
||||
displayName: Install build dependencies
|
||||
|
||||
- bash: |
|
||||
echo $PATH
|
||||
python3 --version
|
||||
echo -n "fusesoc "
|
||||
fusesoc --version
|
||||
verilator --version
|
||||
riscv32-unknown-elf-gcc --version
|
||||
verible-verilog-lint --version
|
||||
displayName: Display environment
|
||||
|
||||
# Verible format is experimental so only run on default config for now,
|
||||
# will eventually become part of the per-config CI
|
||||
- bash: |
|
||||
fusesoc --cores-root . run --no-export --target=format --tool=veribleformat lowrisc:ibex:ibex_core_tracing
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "##vso[task.logissue type=error]"
|
||||
echo "Verilog format with Verible failed. Run 'fusesoc --cores-root . run --no-export --target=format --tool=veribleformat lowrisc:ibex:ibex_core_tracing' to check and fix all errors."
|
||||
echo "This flow is currently experimental and failures can be ignored."
|
||||
fi
|
||||
# Show diff of what verilog_format would have changed, and then revert.
|
||||
git diff
|
||||
git reset --hard HEAD
|
||||
continueOnError: true
|
||||
displayName: Format all source code with Verible format (experimental)
|
||||
|
||||
- bash: |
|
||||
fork_origin=$(git merge-base --fork-point origin/master)
|
||||
changed_files=$(git diff --name-only $fork_origin | grep -v '^vendor' | grep -E '\.(cpp|cc|c|h)$')
|
||||
test -z "$changed_files" || git diff -U0 $fork_origin $changed_files | clang-format-diff -p1 | tee clang-format-output
|
||||
if [ -s clang-format-output ]; then
|
||||
echo -n "##vso[task.logissue type=error]"
|
||||
echo "C/C++ lint failed. Use 'git clang-format' with appropriate options to reformat the changed code."
|
||||
exit 1
|
||||
fi
|
||||
# This check is not idempotent, but checks changes to a base branch.
|
||||
# Run it only on pull requests.
|
||||
condition: eq(variables['Build.Reason'], 'PullRequest')
|
||||
displayName: 'Use clang-format to check C/C++ coding style'
|
||||
|
||||
- bash: |
|
||||
# Build and run CSR testbench, chosen Ibex configuration does not effect
|
||||
# this so doesn't need to be part of per-config CI
|
||||
fusesoc --cores-root=. run --target=sim --tool=verilator lowrisc:ibex:tb_cs_registers
|
||||
displayName: Build and run CSR testbench with Verilator
|
||||
|
||||
- bash: |
|
||||
cd build
|
||||
git clone https://github.com/riscv/riscv-compliance.git
|
||||
cd riscv-compliance
|
||||
git checkout "$RISCV_COMPLIANCE_GIT_VERSION"
|
||||
displayName: Get RISC-V Compliance test suite
|
||||
|
||||
# Run Ibex RTL CI per supported configuration
|
||||
- template : ci/ibex-rtl-ci-steps.yml
|
||||
parameters:
|
||||
ibex_configs:
|
||||
# Note: Try to keep the list of configurations in sync with the one used
|
||||
# in Private CI.
|
||||
- small
|
||||
- experimental-maxperf-pmp
|
||||
- experimental-maxperf-pmp-bmfull
|
||||
- experimental-maxperf-pmp-bmfull-icache
|
||||
- experimental-branch-predictor
|
||||
|
||||
# Run lint on simple system
|
||||
- bash: |
|
||||
fusesoc --cores-root . run --target=lint --tool=verilator lowrisc:ibex:ibex_simple_system
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "##vso[task.logissue type=error]"
|
||||
echo "Verilog lint with Verilator failed. Run 'fusesoc --cores-root . run --target=lint --tool=verilator lowrisc:ibex:ibex_simple_system' to check and fix all errors."
|
||||
exit 1
|
||||
fi
|
||||
displayName: Run Verilator lint on simple system
|
||||
|
||||
- bash: |
|
||||
fusesoc --cores-root . run --target=lint --tool=veriblelint lowrisc:ibex:ibex_simple_system
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "##vso[task.logissue type=error]"
|
||||
echo "Verilog lint with Verible failed. Run 'fusesoc --cores-root . run --target=lint --tool=veriblelint lowrisc:ibex:ibex_simple_system' to check and fix all errors."
|
||||
exit 1
|
||||
fi
|
||||
displayName: Run Verible lint on simple system
|
31
ci/azp-private.yml
Normal file
31
ci/azp-private.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Private CI trigger. Used to run tooling that can't currently be shared
|
||||
# publicly.
|
||||
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- '*'
|
||||
tags:
|
||||
include:
|
||||
- "*"
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- '*'
|
||||
|
||||
# The runner used for private CI enforces the use of the template below. All
|
||||
# build steps need to be placed into the template.
|
||||
resources:
|
||||
repositories:
|
||||
- repository: lowrisc-private-ci
|
||||
type: github
|
||||
endpoint: lowRISC
|
||||
name: lowrisc/lowrisc-private-ci
|
||||
|
||||
extends:
|
||||
template: jobs-ibex.yml@lowrisc-private-ci
|
67
ci/ibex-rtl-ci-steps.yml
Normal file
67
ci/ibex-rtl-ci-steps.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
parameters:
|
||||
ibex_configs: []
|
||||
|
||||
steps:
|
||||
- ${{ each config in parameters.ibex_configs }}:
|
||||
# ibex_config.py will exit with error code 1 on any error which will cause
|
||||
# the CI to fail if there's an issue with the configuration file or an
|
||||
# incorrect configuration name being used
|
||||
- bash: |
|
||||
set -e
|
||||
IBEX_CONFIG_OPTS=`./util/ibex_config.py ${{ config }} fusesoc_opts`
|
||||
echo $IBEX_CONFIG_OPTS
|
||||
echo "##vso[task.setvariable variable=ibex_config_opts]" $IBEX_CONFIG_OPTS
|
||||
displayName: Test and display fusesoc config for ${{ config }}
|
||||
|
||||
- bash: |
|
||||
fusesoc --cores-root . run --target=lint --tool=verilator lowrisc:ibex:ibex_core_tracing $IBEX_CONFIG_OPTS
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "##vso[task.logissue type=error]"
|
||||
echo "Verilog lint failed. Run 'fusesoc --cores-root . run --target=lint --tool=verilator lowrisc:ibex:ibex_core_tracing $IBEX_CONFIG_OPTS' to check and fix all errors."
|
||||
exit 1
|
||||
fi
|
||||
displayName: Lint Verilog source files with Verilator for ${{ config }}
|
||||
|
||||
- bash: |
|
||||
fusesoc --cores-root . run --target=lint --tool=veriblelint lowrisc:ibex:ibex_core_tracing $IBEX_CONFIG_OPTS
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "##vso[task.logissue type=error]"
|
||||
echo "Verilog lint failed. Run 'fusesoc --cores-root . run --target=lint --tool=veriblelint lowrisc:ibex:ibex_core_tracing $IBEX_CONFIG_OPTS' to check and fix all errors."
|
||||
exit 1
|
||||
fi
|
||||
displayName: Lint Verilog source files with Verible Verilog Lint for ${{ config }}
|
||||
|
||||
- bash: |
|
||||
# Build simulation model of Ibex
|
||||
fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_riscv_compliance $IBEX_CONFIG_OPTS
|
||||
if [ $? != 0 ]; then
|
||||
echo -n "##vso[task.logissue type=error]"
|
||||
echo "Unable to build Verilator model of Ibex for compliance testing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run compliance test suite
|
||||
export TARGET_SIM=$PWD/build/lowrisc_ibex_ibex_riscv_compliance_0.1/sim-verilator/Vibex_riscv_compliance
|
||||
export RISCV_PREFIX=riscv32-unknown-elf-
|
||||
export RISCV_TARGET=ibex
|
||||
export RISCV_DEVICE=rv32imc
|
||||
fail=0
|
||||
for isa in rv32i rv32im rv32imc rv32Zicsr rv32Zifencei; do
|
||||
make -C build/riscv-compliance RISCV_ISA=$isa 2>&1 | tee run.log
|
||||
if [ ${PIPESTATUS[0]} != 0 ]; then
|
||||
echo -n "##vso[task.logissue type=error]"
|
||||
echo "The RISC-V compliance test suite failed for $isa"
|
||||
|
||||
# There's no easy way to get the test results in machine-readable
|
||||
# form to properly exclude known-failing tests. Going with an
|
||||
# approximate solution for now.
|
||||
if [ $isa == rv32i ] && grep -q 'FAIL: 4/48' run.log; then
|
||||
echo -n "##vso[task.logissue type=error]"
|
||||
echo "Expected failure for rv32i, see lowrisc/ibex#100 more more information."
|
||||
else
|
||||
fail=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
exit $fail
|
||||
displayName: Run RISC-V Compliance test for Ibex RV32IMC for ${{ config }}
|
|
@ -11,26 +11,27 @@ set -e
|
|||
[ -f /etc/os-release ] || (echo "/etc/os-release doesn't exist."; exit 1)
|
||||
. /etc/os-release
|
||||
|
||||
[ -n "$VERILATOR_VERSION" ] || (echo "VERILATOR_VERSION must be set."; exit 1)
|
||||
[ -n "$VERIBLE_VERSION" ] || (echo "VERIBLE_VERSION must be set."; exit 1)
|
||||
[ -n "$RISCV_TOOLCHAIN_TAR_VERSION" ] || (echo "RISCV_TOOLCHAIN_TAR_VERSION must be set."; exit 1)
|
||||
[ -n "$RISCV_TOOLCHAIN_TAR_VARIANT" ] || (echo "RISCV_TOOLCHAIN_TAR_VARIANT must be set."; exit 1)
|
||||
[ ! -z "$VERILATOR_VERSION" ] || (echo "VERILATOR_VERSION must be set."; exit 1)
|
||||
[ ! -z "$VERIBLE_VERSION" ] || (echo "VERIBLE_VERSION must be set."; exit 1)
|
||||
[ ! -z "$RISCV_TOOLCHAIN_TAR_VERSION" ] || (echo "RISCV_TOOLCHAIN_TAR_VERSION must be set."; exit 1)
|
||||
[ ! -z "$RISCV_TOOLCHAIN_TAR_VARIANT" ] || (echo "RISCV_TOOLCHAIN_TAR_VARIANT must be set."; exit 1)
|
||||
|
||||
SUDO_CMD=""
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
if [ $(id -u) -ne 0 ]; then
|
||||
SUDO_CMD="sudo "
|
||||
fi
|
||||
|
||||
if [ -z "$GITHUB_ACTIONS" ]; then
|
||||
GITHUB_PATH=/dev/null
|
||||
fi
|
||||
|
||||
case "$ID-$VERSION_ID" in
|
||||
ubuntu-20.04|ubuntu-22.04)
|
||||
ubuntu-16.04|ubuntu-18.04)
|
||||
# Curl must be available to get the repo key below.
|
||||
$SUDO_CMD apt-get update
|
||||
$SUDO_CMD apt-get install -y curl
|
||||
|
||||
# Make Verilator repository available
|
||||
curl -Ls https://download.opensuse.org/repositories/home:phiwag:edatools/xUbuntu_$VERSION_ID/Release.key | $SUDO_CMD apt-key add -
|
||||
$SUDO_CMD sh -c "echo 'deb http://download.opensuse.org/repositories/home:/phiwag:/edatools/xUbuntu_$VERSION_ID/ /' > /etc/apt/sources.list.d/edatools.list"
|
||||
$SUDO_CMD apt-get update
|
||||
|
||||
# Packaged dependencies
|
||||
# Install python3-yaml through apt to get a version with libyaml bindings,
|
||||
# which is significantly faster than the pure Python version.
|
||||
|
@ -41,7 +42,6 @@ case "$ID-$VERSION_ID" in
|
|||
python3-setuptools \
|
||||
python3-wheel \
|
||||
python3-yaml \
|
||||
python3-dev \
|
||||
srecord \
|
||||
zlib1g-dev \
|
||||
git \
|
||||
|
@ -52,41 +52,27 @@ case "$ID-$VERSION_ID" in
|
|||
bison \
|
||||
libelf-dev \
|
||||
clang-format \
|
||||
wget \
|
||||
xz-utils \
|
||||
libcairo2-dev
|
||||
"verilator-$VERILATOR_VERSION" \
|
||||
xz-utils
|
||||
|
||||
wget https://storage.googleapis.com/ibex-cosim-builds/ibex-cosim-"$IBEX_COSIM_VERSION".tar.gz
|
||||
$SUDO_CMD mkdir -p /tools/riscv-isa-sim
|
||||
$SUDO_CMD chmod 777 /tools/riscv-isa-sim
|
||||
$SUDO_CMD tar -C /tools/riscv-isa-sim -xvzf ibex-cosim-"$IBEX_COSIM_VERSION".tar.gz --strip-components=1
|
||||
echo "/tools/riscv-isa-sim/bin" >> $GITHUB_PATH
|
||||
# Python dependencies
|
||||
#
|
||||
# Updating pip and setuptools is required to have these tools properly
|
||||
# parse Python-version metadata, which some packages uses to specify that
|
||||
# an older version of a package must be used for a certain Python version.
|
||||
# If that information is not read, pip installs the latest version, which
|
||||
# then fails to run.
|
||||
$SUDO_CMD pip3 install -U pip setuptools
|
||||
|
||||
wget https://storage.googleapis.com/verilator-builds/verilator-"$VERILATOR_VERSION".tar.gz
|
||||
$SUDO_CMD mkdir -p /tools/verilator
|
||||
$SUDO_CMD chmod 777 /tools/verilator
|
||||
$SUDO_CMD tar -C /tools/verilator -xvzf verilator-"$VERILATOR_VERSION".tar.gz
|
||||
echo "/tools/verilator/$VERILATOR_VERSION/bin" >> $GITHUB_PATH
|
||||
# Python dependencies
|
||||
#
|
||||
# Updating pip and setuptools is required to have these tools properly
|
||||
# parse Python-version metadata, which some packages uses to specify that
|
||||
# an older version of a package must be used for a certain Python version.
|
||||
# If that information is not read, pip installs the latest version, which
|
||||
# then fails to run.
|
||||
$SUDO_CMD pip3 install -U pip "setuptools<66.0.0"
|
||||
$SUDO_CMD pip3 install -r python-requirements.txt
|
||||
|
||||
$SUDO_CMD pip3 install -r python-requirements.txt
|
||||
|
||||
# Install Verible
|
||||
mkdir -p build/verible
|
||||
cd build/verible
|
||||
VERIBLE_URL="https://github.com/chipsalliance/verible/releases/download/$VERIBLE_VERSION/verible-$VERIBLE_VERSION-linux-static-x86_64.tar.gz"
|
||||
$SUDO_CMD mkdir -p /tools/verible
|
||||
curl -sSfL "$VERIBLE_URL" | $SUDO_CMD tar -C /tools/verible -xvzf - --strip-components=1
|
||||
# Fixup bin permission which is broken in tarball.
|
||||
$SUDO_CMD chmod 755 /tools/verible/bin
|
||||
echo "/tools/verible/bin" >> $GITHUB_PATH
|
||||
# Install Verible
|
||||
mkdir -p build/verible
|
||||
cd build/verible
|
||||
curl -Ls -o verible.tar.gz "https://github.com/google/verible/releases/download/$VERIBLE_VERSION/verible-$VERIBLE_VERSION-Ubuntu-$VERSION_ID-$VERSION_CODENAME-x86_64.tar.gz"
|
||||
$SUDO_CMD mkdir -p /tools/verible && $SUDO_CMD chmod 777 /tools/verible
|
||||
tar -C /tools/verible -xf verible.tar.gz --strip-components=1
|
||||
echo "##vso[task.prependpath]/tools/verible/bin"
|
||||
;;
|
||||
|
||||
*)
|
||||
|
@ -100,5 +86,5 @@ TOOLCHAIN_URL="https://github.com/lowRISC/lowrisc-toolchains/releases/download/$
|
|||
mkdir -p build/toolchain
|
||||
curl -Ls -o build/toolchain/rv32-toolchain.tar.xz "$TOOLCHAIN_URL"
|
||||
$SUDO_CMD mkdir -p /tools/riscv && $SUDO_CMD chmod 777 /tools/riscv
|
||||
$SUDO_CMD tar -C /tools/riscv -xf build/toolchain/rv32-toolchain.tar.xz --strip-components=1
|
||||
echo "/tools/riscv/bin" >> $GITHUB_PATH
|
||||
tar -C /tools/riscv -xf build/toolchain/rv32-toolchain.tar.xz --strip-components=1
|
||||
echo "##vso[task.prependpath]/tools/riscv/bin"
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Run an elf against simple system co-simulation and check the UART output for
|
||||
# reported pass/fail reporting as appropriate for use in GitHub Actions
|
||||
|
||||
SKIP_PASS_CHECK=0
|
||||
|
||||
if [ $# -eq 3 ]; then
|
||||
if [ $1 == "--skip-pass-check" ]; then
|
||||
SKIP_PASS_CHECK=1
|
||||
fi
|
||||
|
||||
TEST_NAME=$2
|
||||
TEST_ELF=$3
|
||||
elif [ $# -eq 2 ]; then
|
||||
TEST_NAME=$1
|
||||
TEST_ELF=$2
|
||||
else
|
||||
echo "Usage: $0 [--skip-pass-check] test_name test_elf"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Running $TEST_NAME with co-simulation"
|
||||
build/lowrisc_ibex_ibex_simple_system_cosim_0/sim-verilator/Vibex_simple_system --meminit=ram,$TEST_ELF
|
||||
if [ $? != 0 ]; then
|
||||
echo "::error::Running % failed co-simulation testing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
grep 'FAILURE' ibex_simple_system.log
|
||||
if [ $? != 1 ]; then
|
||||
echo "::error::Failure seen in $TEST_NAME log"
|
||||
echo "Log contents:"
|
||||
cat ibex_simple_system.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $SKIP_PASS_CHECK != 1 ]; then
|
||||
grep 'PASS' ibex_simple_system.log
|
||||
if [ $? != 0 ]; then
|
||||
echo "::error::No pass seen in $TEST_NAME log"
|
||||
echo "Log contents:"
|
||||
cat ibex_simple_system.log
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$TEST_NAME succeeded"
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
export PKG_CONFIG_PATH=/tools/riscv-isa-sim/lib/pkgconfig:$PATH
|
15
ci/vars.env
15
ci/vars.env
|
@ -1,15 +0,0 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Pipeline variables, used by the public and private CI pipelines
|
||||
# Quote values to ensure they are parsed as string (version numbers might
|
||||
# end up as float otherwise).
|
||||
VERILATOR_VERSION=v4.210
|
||||
IBEX_COSIM_VERSION=39612f9
|
||||
RISCV_TOOLCHAIN_TAR_VERSION=20220210-1
|
||||
RISCV_TOOLCHAIN_TAR_VARIANT=lowrisc-toolchain-gcc-rv32imcb
|
||||
RISCV_COMPLIANCE_GIT_VERSION=844c6660ef3f0d9b96957991109dfd80cc4938e2
|
||||
VERIBLE_VERSION=v0.0-3622-g07b310a3
|
||||
# lowRISC-internal version numbers of Ibex-specific Spike builds.
|
||||
SPIKE_IBEX_VERSION=20220817-git-eccdcb15c3e51b4f7906c7b42fb824f24a4338a2
|
15
ci/vars.yml
Normal file
15
ci/vars.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Pipeline variables, used by the public and private CI pipelines
|
||||
# Quote values to ensure they are parsed as string (version numbers might
|
||||
# end up as float otherwise).
|
||||
variables:
|
||||
VERILATOR_VERSION: "4.040"
|
||||
RISCV_TOOLCHAIN_TAR_VERSION: "20200904-1"
|
||||
RISCV_TOOLCHAIN_TAR_VARIANT: "lowrisc-toolchain-gcc-rv32imcb"
|
||||
RISCV_COMPLIANCE_GIT_VERSION: "844c6660ef3f0d9b96957991109dfd80cc4938e2"
|
||||
VERIBLE_VERSION: "v0.0-705-g75249d0"
|
||||
# lowRISC-internal version numbers of Ibex-specific Spike builds.
|
||||
SPIKE_IBEX_VERSION: "20201023-git-255bf1cacc599b1413438c269100f3ecd0eb3352"
|
43
ci/vars_to_logging_cmd.py
Executable file
43
ci/vars_to_logging_cmd.py
Executable file
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Read an Azure Pipelines-compatible variables file, and convert it into
|
||||
# logging commands that Azure Pipelines understands, effectively setting the
|
||||
# variables at runtime.
|
||||
#
|
||||
# This script can be used as a workaround if variables cannot be included in the
|
||||
# Pipeline definition directly.
|
||||
#
|
||||
# See https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands
|
||||
# for more information on logging commands.
|
||||
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
def vars_to_logging_cmd(vars_file):
|
||||
data = {}
|
||||
print(vars_file)
|
||||
with open(vars_file, 'r', encoding="utf-8") as fp:
|
||||
data = yaml.load(fp, Loader=yaml.SafeLoader)
|
||||
|
||||
if not (isinstance(data, dict) and 'variables' in data):
|
||||
print("YAML file wasn't a dictionary with a 'variables' key. Got: {}"
|
||||
.format(data))
|
||||
|
||||
print("Setting variables from {}".format(vars_file))
|
||||
for key, value in data['variables'].items():
|
||||
# Note: These lines won't show up in the Azure Pipelines output unless
|
||||
# "System Diagnostics" are enabled (go to the Azure Pipelines web UI,
|
||||
# click on "Run pipeline" to manually run a pipeline, and check "Enable
|
||||
# system diagnostics".)
|
||||
print("##vso[task.setvariable variable={}]{}".format(key, value))
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: {} VARS_FILE".format(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
sys.exit(vars_to_logging_cmd(sys.argv[1]))
|
|
@ -5,11 +5,10 @@ Ibex is a standards-compliant 32 bit RISC-V processor.
|
|||
It follows these specifications:
|
||||
|
||||
* `RISC-V Instruction Set Manual, Volume I: User-Level ISA, document version 20190608-Base-Ratified (June 8, 2019) <https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMFDQC-and-Priv-v1.11/riscv-spec-20190608.pdf>`_
|
||||
* `RISC-V Instruction Set Manual, Volume II: Privileged Architecture, document version 20211203 (December 4, 2021) <https://github.com/riscv/riscv-isa-manual/releases/download/Priv-v1.12/riscv-privileged-20211203.pdf>`_.
|
||||
Ibex implements the Machine ISA version 1.12.
|
||||
* `RISC-V Instruction Set Manual, Volume II: Privileged Architecture, document version 20190608-Base-Ratified (June 8, 2019) <https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMFDQC-and-Priv-v1.11/riscv-privileged-20190608.pdf>`_.
|
||||
Ibex implements the Machine ISA version 1.11.
|
||||
* `RISC-V External Debug Support, version 0.13.2 <https://content.riscv.org/wp-content/uploads/2019/03/riscv-debug-release.pdf>`_
|
||||
* `RISC-V Bit-Manipulation Extension, version 1.0.0 <https://github.com/riscv/riscv-bitmanip/releases/download/1.0.0/bitmanip-1.0.0-38-g865e7a7.pdf>`_ and `version 0.93 (draft from January 10, 2021) <https://github.com/riscv/riscv-bitmanip/blob/master/bitmanip-0.93.pdf>`_
|
||||
* `PMP Enhancements for memory access and execution prevention on Machine mode (Smepmp) version 1.0 <https://github.com/riscv/riscv-tee/blob/191b563b08b31cc2974d604a3b670d8666a2e093/Smepmp/Smepmp.pdf>`_
|
||||
* `RISC-V Bit Manipulation Extension, version 0.92 (draft from November 8, 2019) <https://github.com/riscv/riscv-bitmanip/blob/master/bitmanip-0.92.pdf>`_
|
||||
|
||||
Many features in the RISC-V specification are optional, and Ibex can be parametrized to enable or disable some of them.
|
||||
|
||||
|
@ -35,8 +34,8 @@ In addition, the following instruction set extensions are available.
|
|||
- 2.0
|
||||
- optional
|
||||
|
||||
* - **B**: Standard Extension for Bit-Manipulation Instructions
|
||||
- 1.0.0 + 0.93 [#B_draft]_
|
||||
* - **B**: Draft Extension for Bit Manipulation Instructions
|
||||
- 0.92 [#B_draft]_
|
||||
- optional
|
||||
|
||||
* - **Zicsr**: Control and Status Register Instructions
|
||||
|
@ -47,11 +46,8 @@ In addition, the following instruction set extensions are available.
|
|||
- 2.0
|
||||
- always enabled
|
||||
|
||||
* - **Smepmp** - PMP Enhancements for memory access and execution prevention on Machine mode
|
||||
- 1.0
|
||||
- always enabled in configurations with PMP see :ref:`PMP Enhancements<pmp-enhancements>`
|
||||
|
||||
Ibex currently supports the following features according to the RISC-V Privileged Specification, version 1.12.
|
||||
Most content of the RISC-V privileged specification is optional.
|
||||
Ibex currently supports the following features according to the RISC-V Privileged Specification, version 1.11.
|
||||
|
||||
* M-Mode and U-Mode
|
||||
* All CSRs listed in :ref:`cs-registers`
|
||||
|
@ -60,9 +56,7 @@ Ibex currently supports the following features according to the RISC-V Privilege
|
|||
|
||||
.. rubric:: Footnotes
|
||||
|
||||
.. [#B_draft] Ibex fully implements the ratified version 1.0.0 of the RISC-V Bit-Manipulation Extension including the Zba, Zbb, Zbc and Zbs sub-extensions.
|
||||
In addition, Ibex also supports the remaining Zbe, Zbf, Zbp, Zbr and Zbt sub-extensions as defined in draft version 0.93 of the RISC-V Bit-Manipulation Extension.
|
||||
Note that the latter sub-extensions may change before being ratified as a standard by the RISC-V Foundation.
|
||||
.. [#B_draft] Note that while Ibex fully implements draft version 0.92 of the RISC-V Bit Manipulation Extension, this extension may change before being ratified as a standard by the RISC-V Foundation.
|
||||
Ibex will be updated to match future versions of the specification.
|
||||
Prior to ratification this may involve backwards incompatible changes.
|
||||
Additionally, neither GCC or Clang have committed to maintaining support upstream for unratified versions of the specification.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Introduction to Ibex
|
||||
====================
|
||||
|
||||
Ibex is a production-quality open source 32-bit RISC-V CPU core written in SystemVerilog.
|
||||
Ibex is a production-quality open source 32 bit RISC-V CPU core written in SystemVerilog.
|
||||
The CPU core is heavily parametrizable and well suited for embedded control applications.
|
||||
Ibex is being extensively verified and has seen multiple tape-outs.
|
||||
|
||||
|
@ -14,4 +14,3 @@ Read on for more information Ibex in general: what standards it implements, what
|
|||
compliance
|
||||
targets
|
||||
licensing
|
||||
verification_overview
|
||||
|
|
|
@ -7,6 +7,8 @@ ASIC Synthesis
|
|||
ASIC synthesis is supported for Ibex.
|
||||
The whole design is completely synchronous and uses positive-edge triggered flip-flops, except for the register file, which can be implemented either with latches or with flip-flops.
|
||||
See :ref:`register-file` for more details.
|
||||
The core occupies an area of roughly 24 kGE when using the latch-based register file and implementing the RV32IMC ISA, or 16 kGE when implementing the RV32EC ISA.
|
||||
|
||||
|
||||
FPGA Synthesis
|
||||
--------------
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
Verification Overview
|
||||
=====================
|
||||
|
||||
Ibex is verified using a :ref:`UVM based testbench<verification>` that employs a :ref:`co-simulation methodology<cosim>` to cross-check Ibex execution against an ISS reference model (`Spike <https://github.com/lowRISC/riscv-isa-sim>`_).
|
||||
The testbench runs binaries built from source produced by the `RISC-DV <https://github.com/chipsalliance/riscv-dv>`_ random instruction generator.
|
||||
Additional stimulus is provided in the form of randomized memory timings, memory errors, interrupts and debug requests by the testbench.
|
||||
A comprehensive :ref:`testplan<testplan>` and :ref:`coverage plan<coverage-plan>` are implemented.
|
||||
|
||||
Verification Status
|
||||
-------------------
|
||||
|
||||
Ibex has a large number of parameters resulting in a large number of possible configurations.
|
||||
The configuration space is too large to fully verify the design for all possible parameter sets.
|
||||
To manage this complexity regressions runs and verification closure target a number of :ref:`supported configurations<ibex-config>`.
|
||||
|
||||
Current verification closure effort is focussed on the ``opentitan`` configuration and is the only configuration with nightly regression runs.
|
||||
Verification maturity is tracked via :ref:`verification_stages` that are `defined by the OpenTitan project <https://opentitan.org/book/doc/project_governance/development_stages.html#hardware-verification-stages-v>`_.
|
||||
Ibex has achieved **V2S** for the `opentitan` configuration, broadly this means verification is almost complete (over 90% code and functional coverage hit with over 90% regression pass rate with test plan and coverage plan fully implemented) but not yet closed.
|
||||
|
||||
Nightly regression results, including a coverage summary and details of test failures, for the ``opentitan`` Ibex configuration are published at https://ibex.reports.lowrisc.org/opentitan/latest/report.html. Below is a summary of these results:
|
||||
|
||||
.. image:: https://ibex.reports.lowrisc.org/opentitan/latest/summary.svg
|
|
@ -1,43 +0,0 @@
|
|||
.. _ibex-config:
|
||||
|
||||
Ibex Configurations
|
||||
===================
|
||||
|
||||
The ``ibex_top`` module has a large number of top-level parameters which configure the core (see :ref:`core-integration`).
|
||||
This gives rise to a huge number of possible Ibex core configurations.
|
||||
To manage this complexity a number of named configurations is provided in the :file:`ibex_configs.yml` file.
|
||||
A subset of these are 'supported configurations' which are the focus of verification and development activities.
|
||||
|
||||
Configuration Tool
|
||||
------------------
|
||||
|
||||
A tool :file:`util/ibex_config.py` is provided to work with the named configurations.
|
||||
This tool provides command line options to set Ibex parameters for various EDA tools for a named configuration.
|
||||
Various Ibex flows (e.g. the DV flow) use this tool internally and can be provided with a configuration name from :file:`util/ibex_config.py` to work with.
|
||||
|
||||
Here is an example of using the configuration tool to get the FuseSoC options required to build the ``opentitan`` configuration.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Request FuseSoC options required to build the 'opentitan' Ibex configuration.
|
||||
./util/ibex_config.py opentitan fusesoc_opts
|
||||
|
||||
# The output of the tool
|
||||
--RV32E=0 --RV32M=ibex_pkg::RV32MSingleCycle --RV32B=ibex_pkg::RV32BOTEarlGrey --RegFile=ibex_pkg::RegFileFF --BranchTargetALU=1 --WritebackStage=1 --ICache=1 --ICacheECC=1 --ICacheScramble=1 --BranchPredictor=0 --DbgTriggerEn=1 --SecureIbex=1 --PMPEnable=1 --PMPGranularity=0 --PMPNumRegions=16 --MHPMCounterNum=10 --MHPMCounterWidth=32
|
||||
|
||||
For further information about using the tool check the help provided on the command line.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Get help on using ibex_config.py
|
||||
./util/ibex_config.py -h
|
||||
|
||||
Supported Configurations
|
||||
------------------------
|
||||
|
||||
The current set of supported configurations are:
|
||||
|
||||
* ``small`` - RV32IMC with two stage pipeline and 3 cycle multiplier
|
||||
* ``opentitan`` - The configuration used by the `OpenTitan <www.opentitan.org>`_ project
|
||||
* ``maxperf`` - RV32IMC with three stage pipeline and single cycle multiplier, maximum performance (using stable features) configuration.
|
||||
* ``maxperf-pmp-bmbalanced`` - ``maxperf`` configuration with PMP and the 'balanced' bit-manipulation configuration (:ref:`core-integration` for details).
|
|
@ -3,25 +3,16 @@
|
|||
Examples
|
||||
========
|
||||
|
||||
There are two examples that demonstrate Ibex usage.
|
||||
To make use of Ibex it has to be integrated as described in :ref:`core-integration`.
|
||||
|
||||
The first is 'Simple System' and is part of the Ibex repository.
|
||||
It demonstrates a minimal system connecting Ibex to some memory with a timer peripheral and is targeted at simulation.
|
||||
FPGA
|
||||
----
|
||||
|
||||
The second is the `'Ibex Demo System' <https://www.github.com/lowrisc/ibex-demo-system>`_ which is a separate repository.
|
||||
It is targeted at FPGA implementation and contains some extra peripherals along with a RISC-V debug module integration.
|
||||
|
||||
Simple System
|
||||
-------------
|
||||
|
||||
Simple system is built via FuseSoC.
|
||||
Verilator is the primary simulator it is designed for, though other simulators are also supported (such as VCS).
|
||||
Its aim is to make running a binary against Ibex RTL, obtaining an instruction trace, wave trace and any other simulation outputs as simple as possible along with demonstrating basic Ibex integration.
|
||||
See the `Simple System README <https://github.com/lowRISC/ibex/tree/master/examples/simple_system>`_ for more information.
|
||||
|
||||
There is an extended version of simple system which adds co-simulation checking.
|
||||
This cross-checks every instruction execution against a RISC-V ISS.
|
||||
It is the same co-simulation method used by our full DV environment but enables its use in a far simpler setup.
|
||||
The simple system co-simulation setup is compatible with Verilator (unlike our full DV environment).
|
||||
See :ref:`cosim` for more information.
|
||||
A minimal example for the `Arty A7 <https://reference.digilentinc.com/reference/programmable-logic/arty-a7/start>`_ FPGA Development board is provided.
|
||||
In this example Ibex is directly linked to a SRAM memory instance.
|
||||
Four LEDs from the board are connected to the data bus and are updated each time when a word is written.
|
||||
The memory is separated into a instruction and data section.
|
||||
The instructions memory is initialized at synthesis time by reading the output from the software build.
|
||||
The software writes to the data section the complementary lower for bits of a word every second resulting in blinking LEDs.
|
||||
|
||||
Find the description of how to build and program the Arty board in ``examples/fpga/artya7/README.md``.
|
||||
|
|
|
@ -3,16 +3,11 @@
|
|||
Getting Started with Ibex
|
||||
=========================
|
||||
|
||||
The Ibex repository contains all the RTL needed to simulate and synthesize an Ibex core.
|
||||
`FuseSoC <https://github.com/olofk/fusesoc>`_ core files list the RTL files required to build Ibex (see :file:`ibex_core.core`).
|
||||
The core itself is contained in the :file:`rtl/` directory, though it utilizes some primitives found in the :file:`vendor/lowrisc_ip/` directory.
|
||||
These primitives come from the `OpenTitan <https://github.com/lowrisc/opentitan>`_ project but are copied into the Ibex repository so the RTL has no external dependencies.
|
||||
You may wish to replace these primitives with your own and some are only required for specific configurations.
|
||||
See :ref:`integration-prims` for more information.
|
||||
This page discusses initial steps and requirements to start using Ibex in your design.
|
||||
|
||||
There are several paths to follow depending on what you wish to accomplish:
|
||||
Register File
|
||||
-------------
|
||||
|
||||
* See :ref:`examples` for a basic simulation setup running the core in isolation and a simple FPGA system.
|
||||
* See :ref:`verification` to begin working with the DV flow.
|
||||
* See :ref:`core-integration` to integrate the Ibex core into your own design.
|
||||
* See :ref:`integration-fusesoc-files` for information on how to get a complete RTL file listing to build Ibex for use outside of FuseSoC based flows.
|
||||
Ibex comes with three different register file implementations that can be selected using the enumerated parameter ``RegFile`` defined in :file:`rtl/ibex_pkg.sv`.
|
||||
Depending on the target technology, either the flip-flop-based ("ibex_pkg::RegFileFF", default), the latch-based ("ibex_pkg::RegFileLatch") or an FPGA-targeted ("ibex_pkg::RegFileFPGA") implementation should be selected.
|
||||
For more information about the three register file implementations and their trade-offs, check out :ref:`register-file`.
|
||||
|
|
|
@ -10,6 +10,5 @@ It is aimed at hardware developers integrating Ibex into a design, and software
|
|||
|
||||
system_requirements
|
||||
getting_started
|
||||
configuration
|
||||
integration
|
||||
examples
|
||||
|
|
|
@ -3,166 +3,75 @@
|
|||
Core Integration
|
||||
================
|
||||
|
||||
The main module is named ``ibex_top`` and can be found in ``ibex_top.sv``.
|
||||
Note that the core logic is split-out from the register file and RAMs under ``ibex_top``.
|
||||
This is to facilitate a dual-core lockstep implementation (see :ref:`security`).
|
||||
|
||||
Register File
|
||||
-------------
|
||||
|
||||
Ibex comes with three different register file implementations that can be selected using the enumerated parameter ``RegFile`` defined in :file:`rtl/ibex_pkg.sv`.
|
||||
Depending on the target technology, either the flip-flop-based ("ibex_pkg::RegFileFF", default), the latch-based ("ibex_pkg::RegFileLatch") or an FPGA-targeted ("ibex_pkg::RegFileFPGA") implementation should be selected.
|
||||
For more information about the three register file implementations and their trade-offs, check out :ref:`register-file`.
|
||||
|
||||
Identification CSRs
|
||||
-------------------
|
||||
|
||||
The RISC-V Privileged Architecture specifies several read-only CSRs that identify the vendor and micro-architecture of a CPU.
|
||||
These are ``mvendorid``, ``marchid`` and ``mimpid``.
|
||||
The fixed, read-only values for these CSRs are defined in :file:`rtl/ibex_pkg.sv`.
|
||||
Implementers should carefully consider appropriate values for these registers.
|
||||
Ibex, as an open source implementation, has an assigned architecture ID (``marchid``) of 22.
|
||||
(Allocations are specified in `marchid.md of the riscv-isa-manual repository <https://github.com/riscv/riscv-isa-manual/blob/master/marchid.md>`_.)
|
||||
If significant changes are made to the micro-architecture a different architecture ID should be used.
|
||||
The vendor ID and implementation ID (``mvendorid`` and ``mimpid``) both read as 0 by default, meaning non-implemented.
|
||||
Implementers may wish to use other values here.
|
||||
Please see the RISC-V Privileged Architecture specification for more details on what these IDs represent and how they should be chosen.
|
||||
|
||||
.. _integration-prims:
|
||||
|
||||
Primitives
|
||||
----------
|
||||
|
||||
Ibex uses a number of primitive modules (that are held outside the :file:`rtl/` which contains the Ibex RTL).
|
||||
Full implementations of these primitives are provided in the Ibex repository but implementors may wish to provide their own implementations.
|
||||
Some of the primitives are only used for specific Ibex configurations so can be ignored/removed if you're not using one of those configurations.
|
||||
|
||||
The mandatory primitives (used by all configurations) are:
|
||||
* ``prim_buf`` - A buffer, used to ensure security critical logic isn't optimized out in synthesis (by applying suitable constraints to prim_buf).
|
||||
In configurations where ``SecureIbex == 0`` it must exist but can be implemented as a straight passthrough.
|
||||
* ``prim_clock_gating`` - A clock gate.
|
||||
|
||||
The configuration dependent primitives are:
|
||||
* ``prim_clock_mux2`` - A clock mux, used by the lockstep duplicate core.
|
||||
Required where ``SecureIbex == 1``.
|
||||
* ``prim_flop`` - A flip flop, used to ensure security critical logic isn't optimized out in synthesis (by applying suitable constraints to prim_flop).
|
||||
Required where ``SecureIbex == 1``.
|
||||
* ``prim_ram_1p`` - A single ported RAM.
|
||||
Required where ``ICache == 1``.
|
||||
* ``prim_ram_1p_scr`` - A single ported RAM which scrambles its contents with cryptographic primitives.
|
||||
Required where ``ICache == 1`` and ``SecureIbex == 1``.
|
||||
* ``prim_lfsr`` - Linear feedback shift register, used for pseudo random number generation for dummy instruction insertion.
|
||||
Required where ``SecureIbex == 1``.
|
||||
* ``prim_onehot_check`` - Checks a onehot signal is correct, for detecting fault injection attacks.
|
||||
Required where ``SecureIbex == 1``.
|
||||
* ``prim_secded_X`` - Various primitives to encode and decode SECDED (single error correct, double error detect) error detection and correction codes.
|
||||
Required where ``SecureIbex == 1``.
|
||||
|
||||
Primitives exclusively used by other primitives:
|
||||
* ``prim_present`` / ``prim_prince`` / ``prim_subst_perm`` - Cryptographic primitives used by ``prim_ram_1p_scr``.
|
||||
* ``prim_ram_1p_adv`` - Wrapper around ``prim_ram_1p`` that adds support for ECC, used by ``prim_ram_1p_scr``.
|
||||
|
||||
.. _integration-fusesoc-files:
|
||||
|
||||
RTL File List
|
||||
-------------
|
||||
|
||||
Ibex flows use `FuseSoC <https://github.com/olofk/fusesoc>`_ to gather needed RTL files and run builds.
|
||||
If you want to use Ibex without FuseSoC the following FuseSoC command will copy all the needed files into a build directory.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
fusesoc --cores-root . run --target=lint --setup --build-root ./build/ibex_out lowrisc:ibex:ibex_top
|
||||
|
||||
FuseSoC uses Python and it can be installed using pip.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install -U -r python-requirements.txt
|
||||
|
||||
Ibex uses a `custom fork of FuseSoC <https://github.com/lowRISC/fusesoc/tree/ot>`_, so you must install it via this method rather than installing FuseSoC separately.
|
||||
|
||||
The RTL will be in :file:`./build/ibex_out/src` which is further divided into different sub-directories.
|
||||
A file list containing paths to all of the RTL files can be found in :file:`./build/ibex_out/ibex-verilator/lowrisc_ibex_ibex_top_0.1.vc`.
|
||||
The main module is named ``ibex_core`` and can be found in ``ibex_core.sv``.
|
||||
Below, the instantiation template is given and the parameters and interfaces are described.
|
||||
|
||||
Instantiation Template
|
||||
----------------------
|
||||
|
||||
.. code-block:: verilog
|
||||
|
||||
ibex_top #(
|
||||
.PMPEnable ( 0 ),
|
||||
.PMPGranularity ( 0 ),
|
||||
.PMPNumRegions ( 4 ),
|
||||
.MHPMCounterNum ( 0 ),
|
||||
.MHPMCounterWidth ( 40 ),
|
||||
.RV32E ( 0 ),
|
||||
.RV32M ( ibex_pkg::RV32MFast ),
|
||||
.RV32B ( ibex_pkg::RV32BNone ),
|
||||
.RegFile ( ibex_pkg::RegFileFF ),
|
||||
.ICache ( 0 ),
|
||||
.ICacheECC ( 0 ),
|
||||
.ICacheScramble ( 0 ),
|
||||
.BranchPrediction ( 0 ),
|
||||
.SecureIbex ( 0 ),
|
||||
.RndCnstLfsrSeed ( ibex_pkg::RndCnstLfsrSeedDefault ),
|
||||
.RndCnstLfsrPerm ( ibex_pkg::RndCnstLfsrPermDefault ),
|
||||
.DbgTriggerEn ( 0 ),
|
||||
.DmBaseAddr ( 32'h1A110000 ),
|
||||
.DmAddrMask ( 32'h00000FFF ),
|
||||
.DmHaltAddr ( 32'h1A110800 ),
|
||||
.DmExceptionAddr ( 32'h1A110808 )
|
||||
) u_top (
|
||||
ibex_core #(
|
||||
.PMPEnable ( 0 ),
|
||||
.PMPGranularity ( 0 ),
|
||||
.PMPNumRegions ( 4 ),
|
||||
.MHPMCounterNum ( 0 ),
|
||||
.MHPMCounterWidth ( 40 ),
|
||||
.RV32E ( 0 ),
|
||||
.RV32M ( ibex_pkg::RV32MFast ),
|
||||
.RV32B ( ibex_pkg::RV32BNone ),
|
||||
.RegFile ( ibex_pkg::RegFileFF ),
|
||||
.ICache ( 0 ),
|
||||
.ICacheECC ( 0 ),
|
||||
.BranchPrediction ( 0 ),
|
||||
.SecureIbex ( 0 ),
|
||||
.DbgTriggerEn ( 0 ),
|
||||
.DmHaltAddr ( 32'h1A110800 ),
|
||||
.DmExceptionAddr ( 32'h1A110808 )
|
||||
) u_core (
|
||||
// Clock and reset
|
||||
.clk_i (),
|
||||
.rst_ni (),
|
||||
.test_en_i (),
|
||||
.scan_rst_ni (),
|
||||
.ram_cfg_i (),
|
||||
.clk_i (),
|
||||
.rst_ni (),
|
||||
.test_en_i (),
|
||||
|
||||
// Configuration
|
||||
.hart_id_i (),
|
||||
.boot_addr_i (),
|
||||
.hart_id_i (),
|
||||
.boot_addr_i (),
|
||||
|
||||
// Instruction memory interface
|
||||
.instr_req_o (),
|
||||
.instr_gnt_i (),
|
||||
.instr_rvalid_i (),
|
||||
.instr_addr_o (),
|
||||
.instr_rdata_i (),
|
||||
.instr_rdata_intg_i (),
|
||||
.instr_err_i (),
|
||||
.instr_req_o (),
|
||||
.instr_gnt_i (),
|
||||
.instr_rvalid_i (),
|
||||
.instr_addr_o (),
|
||||
.instr_rdata_i (),
|
||||
.instr_err_i (),
|
||||
|
||||
// Data memory interface
|
||||
.data_req_o (),
|
||||
.data_gnt_i (),
|
||||
.data_rvalid_i (),
|
||||
.data_we_o (),
|
||||
.data_be_o (),
|
||||
.data_addr_o (),
|
||||
.data_wdata_o (),
|
||||
.data_wdata_intg_o (),
|
||||
.data_rdata_i (),
|
||||
.data_rdata_intg_i (),
|
||||
.data_err_i (),
|
||||
.data_req_o (),
|
||||
.data_gnt_i (),
|
||||
.data_rvalid_i (),
|
||||
.data_we_o (),
|
||||
.data_be_o (),
|
||||
.data_addr_o (),
|
||||
.data_wdata_o (),
|
||||
.data_rdata_i (),
|
||||
.data_err_i (),
|
||||
|
||||
// Interrupt inputs
|
||||
.irq_software_i (),
|
||||
.irq_timer_i (),
|
||||
.irq_external_i (),
|
||||
.irq_fast_i (),
|
||||
.irq_nm_i (),
|
||||
.irq_software_i (),
|
||||
.irq_timer_i (),
|
||||
.irq_external_i (),
|
||||
.irq_fast_i (),
|
||||
.irq_nm_i (),
|
||||
|
||||
// Debug interface
|
||||
.debug_req_i (),
|
||||
.crash_dump_o (),
|
||||
.debug_req_i (),
|
||||
|
||||
// Special control signals
|
||||
.fetch_enable_i (),
|
||||
.alert_minor_o (),
|
||||
.alert_major_internal_o (),
|
||||
.alert_major_bus_o (),
|
||||
.core_sleep_o ()
|
||||
.fetch_enable_i (),
|
||||
.alert_minor_o (),
|
||||
.alert_major_o (),
|
||||
.core_sleep_o ()
|
||||
);
|
||||
|
||||
Parameters
|
||||
|
@ -191,45 +100,34 @@ Parameters
|
|||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``RV32B`` | ibex_pkg::rv32b_e | RV32BNone | B(itmanipulation) extension select: |
|
||||
| | | | "ibex_pkg::RV32BNone": No B-extension |
|
||||
| | | | "ibex_pkg::RV32BBalanced": Sub-extensions Zba, Zbb, Zbs, Zbf and Zbt |
|
||||
| | | | "ibex_pkg::RV32BOTEarlGrey": All sub-extensions except Zbe |
|
||||
| | | | "ibex_pkg::RV32BFull": All sub-extensions |
|
||||
| | | | "ibex_pkg::RV32BBalanced": Sub-extensions Zbb, Zbs, Zbf and Zbt |
|
||||
| | | | "ibex_pkg::RV32Full": All sub-extensions |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``RegFile`` | ibex_pkg::regfile_e | RegFileFF | Register file implementation select: |
|
||||
| | | | "ibex_pkg::RegFileFF": Generic flip-flop-based register file |
|
||||
| | | | "ibex_pkg::RegFileFPGA": Register file for FPGA targets |
|
||||
| | | | "ibex_pkg::RegFileLatch": Latch-based register file for ASIC targets |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``BranchTargetALU`` | bit | 0 | Enables branch target ALU removing a stall cycle from taken branches |
|
||||
| ``BranchTargetALU`` | bit | 0 | *EXPERIMENTAL* - Enables branch target ALU removing a stall |
|
||||
| | | | cycle from taken branches |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``WritebackStage`` | bit | 0 | Enables third pipeline stage (writeback) improving performance of |
|
||||
| | | | loads and stores |
|
||||
| ``WritebackStage`` | bit | 0 | *EXPERIMENTAL* - Enables third pipeline stage (writeback) |
|
||||
| | | | improving performance of loads and stores |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``ICache`` | bit | 0 | Enable instruction cache instead of prefetch buffer |
|
||||
| ``ICache`` | bit | 0 | *EXPERIMENTAL* Enable instruction cache instead of prefetch |
|
||||
| | | | buffer |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``ICacheECC`` | bit | 0 | Enable SECDED ECC protection in ICache (if ICache == 1) |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``ICacheScramble`` | bit | 0 | Enabling this parameter replaces tag and data RAMs of ICache with |
|
||||
| | | | scrambling RAM primitives. |
|
||||
| ``ICacheECC`` | bit | 0 | *EXPERIMENTAL* Enable SECDED ECC protection in ICache (if |
|
||||
| | | | ICache == 1) |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``BranchPrediction`` | bit | 0 | *EXPERIMENTAL* Enable Static branch prediction |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``SecureIbex`` | bit | 0 | Enable various additional features targeting secure code execution. |
|
||||
| | | | Note: SecureIbex == 1'b1 and RV32M == ibex_pkg::RV32MNone is an |
|
||||
| | | | illegal combination. |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``RndCnstLfsrSeed`` | lfsr_seed_t | see above | Set the starting seed of the LFSR used to generate dummy instructions |
|
||||
| | | | (only relevant when SecureIbex == 1'b1) |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``RndCnstLfsrPerm`` | lfsr_perm_t | see above | Set the permutation applied to the output of the LFSR used to |
|
||||
| | | | generate dummy instructions (only relevant when SecureIbex == 1'b1) |
|
||||
| ``SecureIbex`` | bit | 0 | *EXPERIMENTAL* Enable various additional features targeting |
|
||||
| | | | secure code execution. Note: SecureIbex == 1'b1 and |
|
||||
| | | | RV32M == ibex_pkg::RV32MNone is an illegal combination. |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``DbgTriggerEn`` | bit | 0 | Enable debug trigger support (one trigger only) |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``DmBaseAddr`` | int | 0x1A110000 | Base address of the Debug Module |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``DmAddrMask`` | int | 0x1A110000 | Address mask of the Debug Module |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``DmExceptionAddr`` | int | 0x1A110808 | Address to jump to when an exception occurs while in Debug Mode |
|
||||
|
@ -250,75 +148,52 @@ This is well supported by most tools but some care is needed when overriding the
|
|||
Interfaces
|
||||
----------
|
||||
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| Signal(s) | Width | Dir | Description |
|
||||
+============================+=========================+=====+========================================+
|
||||
| ``clk_i`` | 1 | in | Clock signal |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``rst_ni`` | 1 | in | Active-low asynchronous reset |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``test_en_i`` | 1 | in | Test input, enables clock and allows |
|
||||
| | | | test control of reset. |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``scan_rst_ni`` | 1 | in | Test controlled reset. If DFT not |
|
||||
| | | | used, tie off to 1. |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``ram_cfg_i`` | 10 | in | RAM configuration inputs, routed to |
|
||||
| | | | the icache RAMs |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``hart_id_i`` | 32 | in | Hart ID, usually static, can be read |
|
||||
| | | | from :ref:`csr-mhartid` CSR |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``boot_addr_i`` | 32 | in | First program counter after reset |
|
||||
| | | | = ``boot_addr_i`` + 0x80, |
|
||||
| | | | see :ref:`exceptions-interrupts` |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``instr_*`` | Instruction fetch interface, see :ref:`instruction-fetch` |
|
||||
+----------------------------+------------------------------------------------------------------------+
|
||||
| ``data_*`` | Load-store unit interface, see :ref:`load-store-unit` |
|
||||
+----------------------------+------------------------------------------------------------------------+
|
||||
| ``irq_*`` | Interrupt inputs, see :ref:`exceptions-interrupts` |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``scramble_*`` | Scrambling key interface, see :ref:`icache` |
|
||||
+----------------------------+------------------------------------------------------------------------+
|
||||
| ``debug_*`` | Debug interface, see :ref:`debug-support` |
|
||||
+----------------------------+------------------------------------------------------------------------+
|
||||
| ``crash_dump_o`` | A set of signals that can be captured on reset to aid crash debugging. |
|
||||
+----------------------------+------------------------------------------------------------------------+
|
||||
| ``double_fault_seen_o`` | A double fault was observed, see :ref:`double-fault-detect` |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``fetch_enable_i`` | 4 | in | Allow the core to fetch instructions. |
|
||||
| | | | If this bit is set low, the core will |
|
||||
| | | | pause fetching new instructions and |
|
||||
| | | | immediately halt once any in-flight |
|
||||
| | | | instructions in the ID/EX and WB |
|
||||
| | | | stages have finished. A multi-bit |
|
||||
| | | | encoding scheme is used. See |
|
||||
| | | | `IbexMuBiOn` / `IbexMuBiOff` in |
|
||||
| | | | :file:`rtl/ibex_pkg.sv` |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``core_sleep_o`` | 1 | out | Core in WFI with no outstanding data |
|
||||
| | | | or instruction accesses. Deasserts |
|
||||
| | | | if an external event (interrupt or |
|
||||
| | | | debug req) wakes the core up |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``alert_minor_o`` | 1 | out | Core has detected a fault which it can |
|
||||
| | | | safely recover from. Can be used by a |
|
||||
| | | | system to log errors over time and |
|
||||
| | | | detect tampering / attack. This signal |
|
||||
| | | | is a pulse, one cycle per alert. |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``alert_major_internal_o`` | 1 | out | Core has detected an internal fault |
|
||||
| | | | which cannot be recovered from. Can be |
|
||||
| | | | used by a system to reset the core and |
|
||||
| | | | possibly take other remedial action. |
|
||||
| | | | This signal is a pulse, but might be |
|
||||
| | | | set for multiple cycles per alert. |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``alert_major_bus_o`` | 1 | out | Core has detected a bus fault |
|
||||
| | | | which cannot be recovered from. Can be |
|
||||
| | | | used by a system to reset the core and |
|
||||
| | | | possibly take other remedial action. |
|
||||
| | | | This signal is a pulse, but might be |
|
||||
| | | | set for multiple cycles per alert. |
|
||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| Signal(s) | Width | Dir | Description |
|
||||
+=========================+=========================+=====+========================================+
|
||||
| ``clk_i`` | 1 | in | Clock signal |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``rst_ni`` | 1 | in | Active-low asynchronous reset |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``test_en_i`` | 1 | in | Test input, enables clock |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``hart_id_i`` | 32 | in | Hart ID, usually static, can be read |
|
||||
| | | | from :ref:`csr-mhartid` CSR |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``boot_addr_i`` | 32 | in | First program counter after reset |
|
||||
| | | | = ``boot_addr_i`` + 0x80, |
|
||||
| | | | see :ref:`exceptions-interrupts` |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``instr_*`` | Instruction fetch interface, see :ref:`instruction-fetch` |
|
||||
+-------------------------+------------------------------------------------------------------------+
|
||||
| ``data_*`` | Load-store unit interface, see :ref:`load-store-unit` |
|
||||
+-------------------------+------------------------------------------------------------------------+
|
||||
| ``irq_*`` | Interrupt inputs, see :ref:`exceptions-interrupts` |
|
||||
+-------------------------+------------------------------------------------------------------------+
|
||||
| ``debug_*`` | Debug interface, see :ref:`debug-support` |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``fetch_enable_i`` | 1 | in | When it comes out of reset, the core |
|
||||
| | | | will not start fetching and executing |
|
||||
| | | | instructions until it sees this pin |
|
||||
| | | | set to 1'b1. Once started, it will |
|
||||
| | | | continue until the next reset, |
|
||||
| | | | regardless of the value of this pin. |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``core_sleep_o`` | 1 | out | Core in WFI with no outstanding data |
|
||||
| | | | or instruction accesses. Deasserts |
|
||||
| | | | if an external event (interrupt or |
|
||||
| | | | debug req) wakes the core up |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``alert_minor_o`` | 1 | out | Core has detected a fault which it can |
|
||||
| | | | safely recover from. Can be used by a |
|
||||
| | | | system to log errors over time and |
|
||||
| | | | detect tampering / attack. This signal |
|
||||
| | | | is a pulse, one cycle per alert. |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``alert_major_o`` | 1 | out | Core has detected a fault which cannot |
|
||||
| | | | be recovered from. Can be used by a |
|
||||
| | | | system to reset the core and possibly |
|
||||
| | | | take other remedial action. This |
|
||||
| | | | signal is a pulse, but might be set |
|
||||
| | | | for multiple cycles per alert. |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
|
|
|
@ -8,10 +8,9 @@ The following tools are known to work with the RTL code of Ibex.
|
|||
Please `file an issue <https://github.com/lowRISC/ibex/issues>`_ if you experience problems with any of the listed tools, or if you have successfully used a tool with Ibex which is not listed here.
|
||||
|
||||
- Synopsys Design Compiler
|
||||
- Cadence Genus
|
||||
- Xilinx Vivado, version |tool_requirements.vivado| and up.
|
||||
- Xilinx Vivado
|
||||
- Verilator, version |tool_requirements.verilator| and up.
|
||||
- Synopsys VCS, version at least |tool_requirements.vcs|.
|
||||
- Synopsys VCS
|
||||
- Cadence Incisive/Xcelium
|
||||
- Mentor Questa
|
||||
- Aldec Riviera Pro
|
||||
|
@ -19,10 +18,6 @@ Please `file an issue <https://github.com/lowRISC/ibex/issues>`_ if you experien
|
|||
To run the UVM testbench a RTL simulator which supports SystemVerilog and UVM 1.2 is required.
|
||||
The `documentation of riscv-dv <https://github.com/google/riscv-dv#prerequisites>`_ contains a list of supported simulators.
|
||||
|
||||
To compile code that runs on Ibex, you'll need a RISC-V toolchain.
|
||||
This isn't part of the core as such, but is necessary for verification.
|
||||
See the :doc:`Verification <../03_reference/verification>` section of the Reference Guide for more details about which toolchains the project currently uses for testing.
|
||||
|
||||
Tools with known issues
|
||||
-----------------------
|
||||
|
||||
|
|
|
@ -1,177 +0,0 @@
|
|||
.. _cosim:
|
||||
|
||||
Co-simulation System
|
||||
====================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
A co-simulation system is provided that can run in either the Ibex UVM DV environment or with Simple System.
|
||||
This system runs a RISC-V ISS (currently only Spike is supported) in lockstep with an Ibex core.
|
||||
All instructions executed by Ibex and memory transactions generated are checked against the behaviour of the ISS.
|
||||
This system supports memory errors, interrupt and debug requests which are observed in the RTL simulation and forwarded to the ISS so the ISS and RTL remain in sync.
|
||||
The system uses a generic interface to allow support of multiple ISSes.
|
||||
Only VCS is supported as a simulator, though no VCS specific functionality is required so adding support for another simulator should be straight-forward.
|
||||
|
||||
To run the co-simulation system, a particular version of Spike is required (see the Setup and Usage section, below).
|
||||
|
||||
The RISC-V Formal Interface (RVFI) is used to provide information about retired instructions and instructions that produce synchronous traps for checking.
|
||||
The RVFI has been extended to provide interrupt and debug information and the value of various CSRs that are harder to model (e.g. ``mcycle``).
|
||||
These extended signals have the prefix ``rvfi_ext``
|
||||
|
||||
Setup and Usage
|
||||
---------------
|
||||
|
||||
Clone the `lowRISC fork of Spike <https://github.com/lowRISC/riscv-isa-sim>`_ and check out the ``ibex-cosim-v0.5`` tag.
|
||||
Other, later, versions called ``ibex-cosim-v*`` may also work but there's no guarantee of backwards compatibility.
|
||||
Follow the Spike build instructions to build and install Spike.
|
||||
The ``--enable-commitlog`` and ``--enable-misaligned`` options must be passed to ``configure``.
|
||||
We recommend using a custom install location (using ``--prefix=<path>`` with ``configure``) to avoid cluttering system directories.
|
||||
Note that, if you do this, you will also need to add an entry to ``PKG_CONFIG_PATH`` so that ``pkg-config`` can tell us how to build against the installed Spike libraries.
|
||||
|
||||
To build/run the UVM DV environment with the co-simulator, add the ``COSIM=1`` argument to the make command.
|
||||
To build Simple System with the co-simulator, build the ``lowrisc:ibex:ibex_simple_system_cosim`` core.
|
||||
|
||||
Quick Build and Run Instructions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Build and install the co-simulator
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Get the Ibex co-simulation spike branch
|
||||
git clone -b ibex_cosim https://github.com/lowRISC/riscv-isa-sim.git riscv-isa-sim-cosim
|
||||
|
||||
# Setup build directory
|
||||
cd riscv-isa-sim-cosim
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
# Configure and build spike
|
||||
../configure --enable-commitlog --enable-misaligned --prefix=/opt/spike-cosim
|
||||
sudo make -j8 install
|
||||
|
||||
Run the UVM DV regression with co-simulation enabled
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Run regression with co-simulation enabled
|
||||
cd <ibex_area>/dv/uvm/core_ibex
|
||||
make COSIM=1
|
||||
|
||||
Build and run Simple System with the co-simulation enabled
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Build simulator
|
||||
fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_simple_system_cosim --RV32E=0 --RV32M=ibex_pkg::RV32MFast
|
||||
|
||||
# Build coremark test binary, with performance counter dump disabled. The
|
||||
# co-simulator system doesn't produce matching performance counters in spike so
|
||||
# any read of those CSRs results in a mismatch and a failure.
|
||||
make -C ./examples/sw/benchmarks/coremark SUPPRESS_PCOUNT_DUMP=1
|
||||
|
||||
# Run coremark binary with co-simulation checking
|
||||
build/lowrisc_ibex_ibex_simple_system_cosim_0/sim-verilator/Vibex_simple_system --meminit=ram,examples/sw/benchmarks/coremark/coremark.elf
|
||||
|
||||
Co-simulation details
|
||||
----------------------
|
||||
|
||||
The co-simulation system uses DPI calls to link the DV and ISS sides together.
|
||||
A C++ interface is defined in ``dv/cosim/cosim.h`` with a DPI wrapper provided by ``dv/cosim/cosim_dpi.cc`` and ``dv/cosim/cosim_dpi.h``.
|
||||
A ``chandle``, which points to some class instance that implements the interface, must be provided by the DV environment.
|
||||
All the co-simulation DPI calls take this ``chandle`` as a first argument.
|
||||
|
||||
The details below discuss the C++ interface.
|
||||
The DPI version of the interface is almost identical, with all functions prefaced with ``riscv_cosim`` and taking a ``chandle`` of the co-simulation instance to use.
|
||||
|
||||
The core function of the co-simulation interface is the ``step`` function:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
virtual bool step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc, bool sync_trap);
|
||||
|
||||
``step`` takes arguments giving the PC of the most recently retired or synchronously trapping instruction in the DUT along with details of any register write that occurred.
|
||||
|
||||
Where ``step`` is provided with a retired (successfully executed) instruction it steps the ISS by one instruction and checks it executed the same instruction, with the same register write result, as the DUT.
|
||||
|
||||
When ``step`` is provided with an instruction that produces a synchronous trap, it checks the ISS also traps on the same instruction but does not step to the next executed instruction.
|
||||
That instruction will be the first instruction of the trap handler and will be checked/stepped by the next call to ``step`` when it retires from the DUT.
|
||||
|
||||
Any data memory accesses that the ISS produces during the ``step`` are checked against observed DUT memory accesses.
|
||||
|
||||
``step`` returns false if any checks have failed.
|
||||
If any errors occur during the step they can be accessed via ``get_errors`` which returns a vector of error messages.
|
||||
For the DPI interface errors are accessed using ``riscv_cosim_get_num_errors`` and ``riscv_cosim_get_error``.
|
||||
When errors have been checked they can be cleared with ``clear_errors``.
|
||||
|
||||
Trap Handling
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Traps are separated into two categories, synchronous and asynchronous.
|
||||
Synchronous traps are caused by a particular instruction's execution (e.g. an illegal instruction).
|
||||
Asynchronous traps are caused by external interrupts.
|
||||
Note that in Ibex error responses to both loads and store produce a synchronous trap so the co-simulation system has the same behaviour.
|
||||
|
||||
A synchronous trap is associated with a particular instruction and prevents that instruction from completing its execution.
|
||||
That instruction doesn't retire, but is still made visible on the RVFI.
|
||||
The ``rvfi_trap`` signal is asserted for an instruction that causes a synchronous trap.
|
||||
As described above ``step`` should be called for any instruction that causes a synchronous trap to check the trap is also seen by the ISS.
|
||||
|
||||
An asynchronous trap can be seen as occurring between instructions and as such doesn't have an associated instruction, nothing will be seen on RVFI with ``rvfi_trap`` set.
|
||||
The co-simulation system will immediately take any pending asynchronous trap when ``step`` is called, expecting the instruction checked with ``step`` to be the first instruction of the trap handler.
|
||||
|
||||
While a debug request is not strictly an asynchronous trap (it doesn't use the same exception handling mechanism), they work identically to asynchronous traps for the co-simulation system.
|
||||
When a debug request is pending when ``step`` is called the co-simulation will expect the instruction checked by ``step`` to be the first instruction of the debug handler.
|
||||
|
||||
Interrupts and Debug Requests
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The DV environment must observe any incoming interrupts and debug requests generated by the testbench and notify the co-simulation system of them using ``set_mip``, ``set_debug_req`` and ``set_nmi``.
|
||||
An interrupt or debug request will take immediate effect at the next ``step`` (if architecturally required to do so).
|
||||
The DV environment is responsible for determining when to call ``set_mip``, ``set_debug_req`` and ``set_nmi`` to ensure a RTL and co-simulation match.
|
||||
|
||||
The state of the incoming interrupts and debug request is sampled when an instruction moves from IF to ID/EX.
|
||||
The sampled state is tracked with the rest of the RVFI pipeline and used to call ``set_mip``, ``set_debug_req`` and ``set_nmi`` when the instruction is output by the RVFI.
|
||||
|
||||
A complication occurs when more than one interrupt or debug requests occur between individual instruction fetches.
|
||||
One interrupt or debug request may take priority over another when they all occur together but when they occur in time is important as well.
|
||||
If interrupt and debug request notification is associated exclusively with retired instructions the co-simulation system cannot correctly prioritise multiple interrupts and debug requests.
|
||||
To deal with this the RVFI can also signal an interrupt event not associated with an instruction by setting ``rvfi_ext_irq_valid`` without setting ``rvfi_valid``.
|
||||
When this is set the interrupt related RVFI signals are valid and provide the interrupt state.
|
||||
The RVFI is used in this way, as opposed to a separate notification interface, so the interrupt notifications are ordered relative to the retired instructions.
|
||||
|
||||
See the comments in :file:`rtl/ibex_core.sv`, around the ``new_debug_req``, ``new_nmi``, ``new_irq`` and ``rvfi_irq_valid`` signals for further details.
|
||||
|
||||
Memory Access Checking and Bus Errors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The co-simulation system must be informed of all Dside accesses performed by the RTL using ``notify_dside_access``.
|
||||
See :file:`dv/cosim/cosim.h` for further details.
|
||||
As Ibex doesn't perform speculative Dside memory accesses, all notified accesses are expected to match with accesses performed by the ISS in the same order they are notified.
|
||||
|
||||
Accesses notified via ``notify_dside_access`` can specify they saw an error response, the co-simulation system will produce the appropriate trap when the ISS attempts to access the address that saw the error.
|
||||
|
||||
Accesses must be notified before they occur in the ISS for the access matching and trapping on errors to work.
|
||||
|
||||
Iside accesses from Ibex can be speculative, so there is no simple link between accesses produced by the RTL and the accesses performed by the ISS for the Iside.
|
||||
This means no direct checking of Iside accesses is done, however errors on the Iside accesses that result in an instruction fault trap need to be notified to the co-simulation system.
|
||||
``set_iside_error`` does this, it is provided with the address that saw the bus error and it should be called immediately before the ``step`` that will process the trap.
|
||||
The co-simulation system will produce an instruction fault trap if it attempts to access the provided error address in the ``step`` call following the ``set_iside_error`` call.
|
||||
|
||||
Two methods are available for dealing with bus errors on the Iside, they differ in where they probe.
|
||||
One probes on the external instr_X memory interface, the other probes internally within the IF stage.
|
||||
The probe used is selected by the ``probe_imem_for_err`` field of the ``core_ibex_cosim_cfg`` structure.
|
||||
When set external probing is used, otherwise internal probing is used.
|
||||
|
||||
Both probe points look for addresses that have seen bus errors.
|
||||
If an instruction entering ID/EX fetches from an address that has seen a bus error (as recorded by one of the probing methods) its ``rvfi_order_id`` is recorded.
|
||||
When a faulting instruction is reported on the RVFI and its ``rvfi_order_id`` matches a recorded faulting one ``set_iside_error`` is called with the faulting address before the next ``step``.
|
||||
|
||||
The external interface probe should be used when it is guaranteed that a bus error to address A on the external interface results in a fetch error the next time an instruction with address A is observed entering the ID/EX stage (providing no successful access to A has occurred in the mean time).
|
||||
Otherwise the internal probe should be used.
|
||||
When Ibex is used with the prefetch buffer this guarantee holds and the external probe can be used.
|
||||
When Ibex is used with the instruction cache this guarantee does not hold and the internal probe must be used.
|
||||
|
||||
Care should be taken when using the internal probe as it will miss any bug that causes instruction faults to be ignored by the prefetch buffer or ICache (or whatever else has been used in place of these by a custom implementation).
|
||||
In the case of the Ibex ICache a separate testbench ensures instruction faults are dealt with appropriately within the ICache.
|
|
@ -1,446 +0,0 @@
|
|||
.. _coverage-plan:
|
||||
|
||||
Coverage Plan
|
||||
=============
|
||||
|
||||
.. todo::
|
||||
Branch prediction hasn't yet been considered, this will add more coverage points and alter some others
|
||||
|
||||
Introduction
|
||||
------------
|
||||
Ibex functional coverage is split into two major categories:
|
||||
|
||||
* Architectural coverage - which is concerned with instructions being executed and exercising various features of the RISC-V architecture (e.g. PMP) and does not consider the details of how this execution occurs.
|
||||
* Microarchitectural coverage - which is concerned with the specifics of the RTL operation, ensuring interesting corner cases are seen along with various micro-architectural events (e.g. the different kinds of stall) and combinations of them.
|
||||
|
||||
Architectural coverage is not Ibex specific. It can be determined directly from a trace of executed instructions and is handled by RISCV-DV, details can be found in the `RISCV-DV documentation <https://htmlpreview.github.io/?https://github.com/google/riscv-dv/blob/master/docs/build/singlehtml/index.html#document-coverage_model>`_.
|
||||
|
||||
Microarchitectural coverage will probe the Ibex RTL directly and is described here.
|
||||
There is some inevitable overlap between architectural and microarchitectural coverage but we aim to minimise it.
|
||||
|
||||
Coverage Implementation
|
||||
-----------------------
|
||||
All coverpoints and cross coverage defined below is associated with a name ``cp_name``.
|
||||
This is the name of the coverpoint or cross that implements the described coverage.
|
||||
Coverage is implemented in two files; :file:`dv/uvm/core_ibex/fcov/core_ibex_pmp_fcov_if.sv` for PMP related coverage and :file:`dv/uvm/core_ibex/fcov/core_ibex_fcov_if.sv` for everything else.
|
||||
|
||||
Microarchitectural Events and Behaviour
|
||||
---------------------------------------
|
||||
Below are lists of specific things from the microarchitecture that will be included in functional coverage.
|
||||
Each of the points listed below must be covered.
|
||||
This will be further combined using cross coverage which is described in the section below.
|
||||
|
||||
Instructions
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Categories
|
||||
""""""""""
|
||||
``cp_id_instr_category``
|
||||
|
||||
Instructions can be grouped into a number of categories.
|
||||
Each category exercises different data and control paths in the core.
|
||||
For example the ``ADD`` and ``SUB`` instructions are in the same category as they are almost identical for the microarchitecture (both read two registers and write to one, both feed operands to the ALU and take their result from it, both have the same response to interrupts etc; the only difference is the ALU operation).
|
||||
|
||||
Instructions can be compressed or uncompressed but that isn't factored into the instruction categories below (excepting for illegal instructions).
|
||||
The decompression occurs in the IF stage and is invisible to the ID/EX stage so isn't relevant for instruction execution.
|
||||
A separate set of category-agnostic compressed instruction behaviour is considered instead.
|
||||
|
||||
An instruction category is sampled at the ID/EX stage (which is where all the varying behaviours actually occur).
|
||||
Some categories are just a single instruction, which is named without further description.
|
||||
|
||||
|
||||
* **ALU** - All of the reg/reg reg/imm instructions that use the ALU.
|
||||
This is any RISC-V instruction with an opcode of ``7'b0010011`` or ``7'b0110011`` (``ibex_pkg::OPCODE_OP`` and ``ibex_pkg::OPCODE_OP_IMM``) other than the ``MUL*`` and ``DIV*`` family of instructions (from RV32M).
|
||||
* **Mul** - Any ``MUL*`` instruction (from RV32M).
|
||||
* **Div** - Any ``DIV*`` instruction (from RV32M).
|
||||
* **Branch** - Any ``B*`` family branch instruction.
|
||||
* **Jump** - ``JAL``/``JALR``
|
||||
* **Load** - Any ``L*`` family load instruction.
|
||||
* **Store** - Any ``S*`` family load instruction.
|
||||
* **CSRAccess** - Any instruction from Zicsr.
|
||||
* **EBreakDbg**/**EBreakExc** - An ``EBREAK`` instruction that either enters debug mode (Dbg) or causes an exception (Exc).
|
||||
Which occurs depends upon the setting of ``dcsr.ebreakm`` / ``dcsr.ebreaku`` combined with the privilege level of executed instruction.
|
||||
* **ECall** - ``ECALL`` is an environment call used for escalation of privilege.
|
||||
* **MRet** - ``MRET`` return out of M-mode
|
||||
* **DRet** - ``DRET`` ruturn from debug mode.
|
||||
* **WFI** - wait for interrupt.
|
||||
* **Fence** - ``FENCE`` memory fence on the data side.
|
||||
* **FenceI** - ``FENCE.I`` instruction fence instruction.
|
||||
* **FetchError** - Any instruction that saw a fetch error.
|
||||
* **CompressedIllegal** - Any compressed instruction with an illegal encoding.
|
||||
* **UncompressedIllegal** - Any uncompressed instruction with an illegal encoding.
|
||||
* **CSRIllegal** - Any instruction attempting a CSR access that is not allowed.
|
||||
* **PrivIllegal** - Illegal due to privilege level or being in/out of debug mode.
|
||||
* **OtherIllegal** - Any other instruction that raises an Illegal instruction exception that isn't in the other categories.
|
||||
* **None** - No instruction in ID/EX stage.
|
||||
|
||||
Stalls
|
||||
""""""
|
||||
``cp_stall_type_id``
|
||||
|
||||
Not all instructions can see all kinds of stalls.
|
||||
A stall category is sampled at the ID/EX stage only (as stalls in IF and WB don't break down into categories).
|
||||
|
||||
* **Instr** - A stall caused by a multi-cycle instruction.
|
||||
This can be seen by instructions from categories:
|
||||
|
||||
* **MUL**
|
||||
* **DIV**
|
||||
* **Branch**
|
||||
* **Jump**
|
||||
|
||||
* **LdHz** - A load hazard, the instruction in ID/EX depends upon the result of a load that is awaiting a response in writeback.
|
||||
This can be seen by instructions from categories:
|
||||
|
||||
* **ALU**
|
||||
* **Mul**
|
||||
* **Div**
|
||||
* **Branch**
|
||||
* **Jump**
|
||||
* **Load**
|
||||
* **Store**
|
||||
* **CSRAccess**
|
||||
|
||||
* **Mem** - Memory stall, the instruction in ID/EX is awaiting a prior memory request to complete before it can begin (to allow precise interrupts on a memory error response). This can be seen for all instruction categories
|
||||
|
||||
Privilege Level
|
||||
"""""""""""""""
|
||||
Ibex can operate at either the M (machine) or U (user) privilege levels.
|
||||
Different aspects of the Ibex microarchitecture can be using different privilege levels at once.
|
||||
|
||||
* ``cp_priv_mode_id`` - Privilege level of ID/EX stage instruction.
|
||||
* ``cp_priv_mode_lsu`` - Privilege level of LSU operation (ID/EX privilege level modified by ``mstatus.mprv`` and ``mstatus.mpp`` settings).
|
||||
|
||||
Note that the privilege level of the instruction in WB isn't retained by the microarchitecture and is not relevant to coverage.
|
||||
The privilege level of the IF instruction is effectively unknown.
|
||||
The instruction is checked when moving from IF to ID/EX against the ID stage privilege level to check if execution is permitted by PMP.
|
||||
Any instruction that reaches WB can be considered bound to retire and any relevant checks and functionality altered by the privilege mode is dealt with at an earlier stage.
|
||||
|
||||
Hazards
|
||||
"""""""
|
||||
Ibex hazards all occur in the interaction between the ID and EX stage.
|
||||
|
||||
* RAW Reg - Read after write hazard, instruction in ID/EX reads a register that writeback is writing.
|
||||
Split into two versions:
|
||||
|
||||
* RAW load - Instruction in ID/EX reading from destination of load in writeback.
|
||||
Produces a stall (Category LdHz) and shouldn't forward data.
|
||||
Covered by ``cp_stall_type_id``
|
||||
* ``cp_wb_reg_no_load_hz`` - Instruction in writeback isn't a load.
|
||||
Handled with data forwarding and no stall.
|
||||
|
||||
* RAW Load/Store bytes - Load with bytes overlapping a store immediately before it.
|
||||
Covered by ``cp_mem_raw_hz``
|
||||
|
||||
State Specific Behaviour
|
||||
""""""""""""""""""""""""
|
||||
Some instructions will behave differently depending upon the state of the processor (e.g. the privilege level the instruction executes at, CSR settings or whether the processor is in debug mode).
|
||||
|
||||
* Instruction illegal in U Mode.
|
||||
|
||||
* ``cp_mret_in_umode`` - ``MRET``
|
||||
* ``cp_wfi_in_umode`` - ``WFI``
|
||||
* Read and write to M-mode CSR - Covered by crosses ``csr_write_priv_cross`` and ``csr_read_only_priv_cross```
|
||||
|
||||
* Debug mode instructions (cover execution in and out of debug mode).
|
||||
|
||||
* ``DRET``
|
||||
* ``csr_read_only_debug_cross``, ``csr_write_debug_cross`` - Access to debug CSRs.
|
||||
|
||||
* ``dcsr``
|
||||
* ``dpc``
|
||||
* ``dscratch0``
|
||||
* ``dscratch1``
|
||||
|
||||
* Access to trigger CSRs (also possible in M mode: cover execution in M mode, debug mode and U mode).
|
||||
Covered by ``csr_read_only_debug_cross``, ``csr_write_debug_cross``, ``csr_read_only_priv_cross``, ``csr_write_priv_cross``.
|
||||
|
||||
* ``tselect``
|
||||
* ``tdata1``
|
||||
* ``tdata2``
|
||||
* ``tdata3``
|
||||
|
||||
* Loads/stores with ``mstatus.mprv`` set and unset.
|
||||
Covered by ``mprv_effect_cross``
|
||||
* EBreak behaviour in U/M mode with different ``dcsr.ebreakm`` / ``dcsr.ebreaku`` settings.
|
||||
Covered by ``priv_mode_instr_cross``
|
||||
* ``cp_single_step_instr`` - Single step over every instruction category
|
||||
|
||||
Pipeline State
|
||||
^^^^^^^^^^^^^^
|
||||
Each pipeline stage has some associated state.
|
||||
|
||||
* ``cp_if_stage_state`` - IF stage full and fetching, full and idle, empty and fetching, or empty and idle.
|
||||
General IF stage full and stalled uninteresting as will only occur when ID stage is full and stalled.
|
||||
* ``cp_wb_stage_state`` - WB stage full and stalled, full and unstalled, or empty
|
||||
* ``cp_id_stage_state`` - ID stage full and stalled, full and unstalled, or empty.
|
||||
* Controller (within ID stage) state machine states
|
||||
|
||||
* ``cp_controller_fsm`` - Possible transitions between these states.
|
||||
|
||||
* ``RESET`` -> ``BOOT_SET``
|
||||
* ``BOOT_SET`` -> ``FIRST_FETCH``
|
||||
* ``FIRST_FETCH`` -> ``DECODE``
|
||||
* ``FIRST_FETCH`` -> ``IRQ_TAKEN``
|
||||
* ``FIRST_FETCH`` -> ``DBG_TAKEN_IF``
|
||||
* ``DECODE`` -> ``FLUSH``
|
||||
* ``DECODE`` -> ``DBG_TAKEN_IF``
|
||||
* ``DECODE`` -> ``IRQ_TAKEN``
|
||||
* ``IRQ_TAKEN`` -> ``DECODE``
|
||||
* ``DBG_TAKEN_IF`` -> ``DECODE``
|
||||
* ``DBG_TAKEN_ID`` -> ``DECODE``
|
||||
* ``FLUSH`` -> ``DECODE``
|
||||
* ``FLUSH`` -> ``DBG_TAKEN_ID``
|
||||
* ``FLUSH`` -> ``WAIT_SLEEP``
|
||||
* ``FLUSH`` -> ``DBG_TAKEN_IF``
|
||||
* ``WAIT_SLEEP`` -> ``SLEEP``
|
||||
* ``SLEEP`` -> ``FIRST_FETCH``
|
||||
|
||||
Exceptions/Interrupts/Debug
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Exceptions, interrupts and debug entry can all cause control flow changes combined with CSR writes and privilege level changes and work quite similarly within the controller but not identically.
|
||||
Furthermore they can all occur together and must be appropriately prioritised (consider an instruction with hardware trigger point matching it, that causes some exception and an interrupt is raised the cycle it enters the ID/EX stage).
|
||||
|
||||
* Exception from instruction fetch error (covered by the **FetchError** instruction category).
|
||||
* ``pmp_iside_mode_cross`` - Exception from instruction PMP violation.
|
||||
* Exception from illegal instruction (covered by the illegal instruction categories).
|
||||
* ``cp_ls_error_exception`` - Exception from memory fetch error.
|
||||
* ``cp_ls_pmp_exception`` - Load store unit exception from PMP.
|
||||
* ``pmp_dside_mode_cross`` - Exception from memory access PMP violation.
|
||||
* Unaligned memory access
|
||||
|
||||
* ``misaligned_insn_bus_err_cross``, ``misaligned_data_bus_err_cross`` - Cover all error and no error scenarios for memory fetch error; first access saw error, second
|
||||
access saw error, neither access saw error
|
||||
|
||||
* Interrupt raised/taken.
|
||||
|
||||
* ``cp_interrupt_taken`` - Interrupt raised/taken for each available interrupt line.
|
||||
For cross coverage, the precise interrupt that's raised/taken is not relevant and it only needs to be grouped by NMI vs non-NMI.
|
||||
This is done by using ``cp_nmi_taken`` coverpoint in the crosses.
|
||||
* ``interrupt_taken_instr_cross`` - Interrupt raised/taken the first cycle an instruction is in ID/EX or some other cycle the instruction is in ID/EX.
|
||||
|
||||
* ``cp_debug_req`` - External debug request.
|
||||
* ``cp_single_step_taken`` - Instruction executed when debug single step enabled.
|
||||
* ``cp_single_step_exception`` - Single step over an instruction that takes an exception.
|
||||
* ``cp_insn_trigger_enter_debug`` - Instruction matches hardware trigger point.
|
||||
* ``cp_debug_mode`` - Ibex operating in debug mode.
|
||||
* ``cp_debug_wakeup`` - Ibex wakes up after being halted from debug request.
|
||||
* ``irq_wfi_cross``, ``debug_wfi_cross`` - Debug and Interrupt whilst sleeping with WFI
|
||||
|
||||
* Cover with global interrupts enabled and disabled
|
||||
* Cover with specific interrupt enabled and disabled (Should exit sleep when
|
||||
interrupt is enabled but global interrupts set to disabled, should continue
|
||||
sleeping when both are disabled).
|
||||
Continuing to sleep in the case explained above is covered by ``cp_irq_continue_sleep``, otherwise the behaviour is captured in ``irq_wfi_cross``
|
||||
|
||||
* Debug and interrupt occurring whilst entering WFI
|
||||
|
||||
* Covering period between WFI entering ID/EX stage and going into sleep
|
||||
Covered by bin ``enter_sleep`` of ``cp_controller_fsm_sleep`` that is used by ``irq_wfi_cross`` and ``debug_wfi_cross``.
|
||||
|
||||
* ``cp_double_fault`` - Double fault
|
||||
|
||||
PMP
|
||||
^^^
|
||||
* ``cp_region_mode`` - Each region configured with different matching modes.
|
||||
|
||||
* Off
|
||||
* TOR
|
||||
* NA4
|
||||
* NAPOT
|
||||
|
||||
* ``cp_napot_addr_modes`` - When NAPOT is enabled check that each address mode is seen at least once.
|
||||
|
||||
* ``cp_region_priv_bits`` - Each region configured with all possible permissions including locked/unlocked.
|
||||
|
||||
* Different permissions with MML enabled and disabled, separate cover points for R/W/X/L values with and without MML.
|
||||
|
||||
* Access fail & pass.
|
||||
|
||||
* ``misaligned_lsu_access_cross`` - All combinations of unaligned access split across a boundary, both halves pass, neither pass, just the first passes, just the second passes.
|
||||
|
||||
* Two possible boundary splits; across a 32-bit boundary within a region or a boundary between PMP regions.
|
||||
|
||||
* ``cp_pmp_iside_region_override``, ``cp_pmp_iside2_region_override``, ``cp_pmp_dside_region_override`` - Higher priority entry allows access that lower priority entry prevents.
|
||||
* ``pmp_instr_edge_cross`` - Compressed instruction access (16-bit) passes PMP but 32-bit access at same address crosses PMP region boundary.
|
||||
|
||||
* Each field of mssecfg enabled/disabled, as well as written to using a CSR write, with relevant functionality tested.
|
||||
|
||||
* RLB - rule locking bypass.
|
||||
|
||||
* ``cp_edit_locked_pmpcfg``, ``cp_edit_locked_pmpaddr`` - Modify locked region with RLB set.
|
||||
* ``rlb_csr_cross`` - Try to enable RLB when RLB is disabled and locked regions present.
|
||||
|
||||
* MMWP - machine mode whitelist policy.
|
||||
|
||||
* ``pmp_dside/iside/iside2_nomatch_cross`` - M-mode access fail due to not matching any PMP regions.
|
||||
* ``mmwp_csr_cross`` - Try to disable when enabled.
|
||||
|
||||
* MML - machine mode lockdown policy.
|
||||
|
||||
* ``mml_sticky_cross`` - Try to disable when enabled.
|
||||
|
||||
* Access close to PMP region modification that allows/disallows that access.
|
||||
|
||||
* ``pmp_wr_exec_region`` - Explores behaviour around adding executable regions when MML is enabled.
|
||||
Cross of current region configuration with region configuration that is being written and RLB setting.
|
||||
It only considers regions that aren't currently executable with writes attempted to make them executable.
|
||||
Non MML configurations are not sampled.
|
||||
|
||||
CSRs
|
||||
^^^^
|
||||
Basic read/write functionality must be tested on all implemented CSRs.
|
||||
|
||||
* ``cp_csr_read_only`` - Read from CSR, there is also ``cp_csr_invalid_read_only`` for illegal CSRs.
|
||||
* ``cp_csr_write`` - Write to CSR, there is also ``cp_csr_invalid_write`` for illegal CSRs.
|
||||
|
||||
* Write to read only CSR.
|
||||
Covered by ensuring ``cp_csr_write`` is seen for read-only CSRs
|
||||
|
||||
* ``cp_warl_check_CSRNAME`` - Write illegal/unsupported value to WARL field for CSR named ``CSRNAME``.
|
||||
* ``csr_read_only_priv_cross``, ``csr_write_priv_cross``, ``csr_read_only_debug_cross``, ``csr_write_debug_cross`` - Crosses of reads and writes to CSRs from different privilege levels/debug mode.
|
||||
|
||||
* Access to CSR disallowed due to privilege levels/debug mode
|
||||
Covered by ensuring within the crosses
|
||||
|
||||
CSRs addresses do not need to be crossed with the variety of CSR instructions as these all use the same basic read & write interface into ``ibex_cs_registers``.
|
||||
Coverage of the above points will be sampled at the ``ibex_cs_registers`` interface (as opposed to sampling CSR instructions).
|
||||
|
||||
Security Countermeasures
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
For more detail about each security countermeasure in Ibex see :ref:`security`
|
||||
|
||||
* ``cp_data_ind_timing`` - Enabling/Disabling "Data Independent Timing" feature.
|
||||
|
||||
* ``cp_data_ind_timing_instr`` - Executing each instruction category while data independent timing feature is enabled.
|
||||
|
||||
* ``cp_dummy_instr_en`` - Enabling/Disabling "Dummy Instruction Insertion" feature.
|
||||
|
||||
* ``cp_dummy_instr_mask`` - Frequency of injection for the dummy instructions.
|
||||
|
||||
* ``cp_dummy_instr_type`` - Type of the injected dummy instruction.
|
||||
|
||||
* ``cp_dummy_instr`` - Executing each instruction category while dummy instruction insertion feature is enabled.
|
||||
|
||||
* ``cp_dummy_instr_if_stage`` - The IF stage handles a dummy instruction.
|
||||
|
||||
* ``cp_dummy_instr_id_stage`` - The ID/EX stage handles a dummy instruction.
|
||||
|
||||
* ``cp_dummy_instr_wb_stage`` - The WB stage handles a dummy instruction.
|
||||
|
||||
* ``cp_rf_a_ecc_err``, ``cp_rf_b_ecc_err`` - Register file integrity (ECC) fault is seen for port A/B.
|
||||
|
||||
* ``cp_icache_ecc_err`` - ICache has seen an integrity (ECC) fault.
|
||||
|
||||
* ``cp_mem_load_ecc_err`` - An ECC error has been seen on a load response
|
||||
|
||||
* ``cp_mem_store_ecc_err`` - An ECC error has been seen on a store response
|
||||
|
||||
* ``cp_lockstep_err`` - Lockstep glitch fault seen.
|
||||
|
||||
* ``cp_rf_we_glitch_err`` - Register file write enable glitch fault seen.
|
||||
|
||||
* ``cp_pc_mismatch_err`` - PC mismatch error seen.
|
||||
|
||||
The :ref:`security features Ibex implements <security>` are given specific security countermeasure names in OpenTitan (see 'Security Countermeasures' in the `Comportability Definition and Specification <https://opentitan.org/book/doc/contributing/hw/comportability/index.html#security-countermeasures>`_ documentation section).
|
||||
The mapping between security countermeasures and coverpoints that demonstrate it being used is given below.
|
||||
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| Security Countermeasure | Coverpoint(s) |
|
||||
+================================+=======================================================+
|
||||
| BUS.INTEGRITY | ``cp_mem_load_ecc_err`` ``cp_mem_store_ecc_err`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| SCRAMBLE.KEY.SIDELOAD | ``FENCE.I`` of ``cp_id_instr_category`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| CORE.DATA_REG_SW.SCA | ``cp_data_ind_timing`` ``cp_data_ind_timining_instr`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| PC.CTRL_FLOW.CONSISTENCY | ``cp_pc_mismatch_err`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| CTRL_FLOW.UNPREDICTABLE | ``cp_dummy_instr`` and related coverpoints |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| DATA_REG_SW.INTEGRITY | ``cp_rf_a_ecc_err`` ``cp_rf_b_ecc_err`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| DATA_REG_SW.GLITCH_DETECT | ``cp_rf_we_glitch_err`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| LOGIC.SHADOW | ``cp_lockstep_err`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| FETCH.CTRL.LC_GATED | ``cp_fetch_enable`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| EXCEPTION.CTRL_FLOW.LOCAL_ESC | ``cp_double_fault`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| EXCEPTION.CTRL_FLOW.GLOBAL_ESC | ``cp_double_fault`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| ICACHE.MEM.SCRAMBLE | ``FENCE.I`` of ``cp_id_instr_category`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
| ICACHE.MEM.INTEGRITY | ``cp_icache_ecc_err`` |
|
||||
+--------------------------------+-------------------------------------------------------+
|
||||
|
||||
Memory Interface Behaviour
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Covering different scenarios around timing of memory requests and responses and
|
||||
related behaviour
|
||||
|
||||
* ``cp_dmem_response_latency``/``cp_imem_response_latency`` - Latency of response from request for dmem and imem.
|
||||
Separated into two bins ``single_cycle`` (immediate response after request) and ``multi_cycle`` (all other latencies).
|
||||
* ``dmem_req_gnt_valid``/``imem_req_gnt_rvalid`` - Request, grant and rvalid all seen in the same cycle for dmem and imem.
|
||||
This means a response is seen the same cycle a new request is being granted.
|
||||
|
||||
|
||||
Miscellaneous
|
||||
^^^^^^^^^^^^^
|
||||
Various points of interest do not fit into the categories above.
|
||||
|
||||
* ``instr_unstalled`` - Instruction unstalled - Cover the cycle an instruction is unstalled having just been stalled.
|
||||
* ``cp_icache_enable`` - Enabling/Disabling ICache.
|
||||
* ``cp_fetch_enable`` - Fetch enabled and disabled via top-level ``fetch_enable_i`` input.
|
||||
|
||||
Cross Coverage
|
||||
--------------
|
||||
Much of the more complex behaviour lies at the combination of the individual microarchitectural behaviours above.
|
||||
Cross coverage is used to capture that.
|
||||
Crosses listed below are ones that don't already fit into the above categories.
|
||||
There are some broad crosses containing many bins aiming to capture all combinations of some generalised behaviours as well as some more specific ones to capture all combinations of behaviours focused on a particular area.
|
||||
|
||||
Cross coverage will be intentionally broad.
|
||||
Where it is proving hard to hit particular bins they will be reviewed in more detail to determine if they're impossible to hit or if simply hard to hit and whether hitting them provides meaningful gains to verification quality.
|
||||
|
||||
Excluded bins will either become illegal bins (where they are impossible to hit, so a failure will be seen if they are hit) or ignore bins (where they don't factor into coverage statistics).
|
||||
There must be a documented reason a particular bin is added to the illegal or ignore bins.
|
||||
|
||||
* ``pipe_cross`` - Instruction Categories x Pipeline stage states across IF, ID/EX and WB
|
||||
|
||||
* Covers all possibilities of instruction combinations that could fill the pipeline. State only for IF/WB suffices to cover this as all the interesting per instruction behaviour occurs in ID/EX.
|
||||
* All bins containing instruction categories other than **None** ignored when ID/EX stage is empty.
|
||||
|
||||
* ``priv_mode_instr_cross`` - Instructions Categories x ID/EX Privilege level
|
||||
* ``stall_cross`` - Instruction Categories x Stall Categories
|
||||
|
||||
* Illegal bins will be used to exclude instruction and stall categories that cannot occur.
|
||||
|
||||
* ``wb_reg_no_load_hz_instr_cross`` - Instruction Categories x Hazards
|
||||
|
||||
* ``stall_cross`` covers the RAW load hazard (as it produces a LdHz stall).
|
||||
* RAW hazard between load/store requires no cross coverage as it's only seen for load and store instructions so the single coverpoint suffices.
|
||||
|
||||
* ``debug_instruction_cross`` - Instruction Categories x Debug Mode
|
||||
* ``controller_instr_cross`` - Instruction Categories x Controller state transitions of interest
|
||||
* ``interrupt_taken_instr_cross``, ``debug_entry_if_instr_cross``, ``pipe_flush_instr_cross`` - Interrupt taken/Debug mode entry/Pipe flush x instruction unstalled x instruction category
|
||||
|
||||
* Three separate cross coverage groups: one for interrupt, debug and pipe flush.
|
||||
* Covers all instruction categories being interrupted/entering debug mode/flushing the pipeline both where this occurs during a stall and when it occurs just when they've unstalled.
|
||||
|
||||
* ``exception_stall_instr_cross`` - PMP exception x load/store error exception x instruction category x stall type x unstalled x irq pending x debug req
|
||||
|
||||
* Large cross to cover all possibilities of combinations between interrupt, debug and exceptions for all instruction categories across all stall behaviours.
|
||||
|
||||
* ``pmp_iside_priv_bits_cross``, ``pmp_iside2_priv_bits_cross``, ``pmp_dside_priv_bits_cross``, PMP regions x permissions x access fail/pass x privilege level
|
||||
|
||||
* Three crosses, one for each PMP channel (instruction, instruction 2 and data).
|
||||
|
||||
* ``dummy_instr_config_cross`` - Dummy Instruction Type x Dummy Instruction Insertion Frequency to explore all possible configurations.
|
||||
|
||||
* ``rf_ecc_err_cross`` - ECC Error on Port A x ECC Error on Port B to explore all possible combinations of reported ECC errors.
|
||||
|
||||
* ``debug_req_dummy_instr_{if,id,wb}_stage_cross`` - The IF, ID/EX, or WB stage handles a dummy instruction while a debug request arrives.
|
||||
|
||||
* ``irq_pending_dummy_instr_{if,id,wb}_stage_cross`` - The IF, ID/EX, or WB stage handles a dummy instruction while an IRQ is pending.
|
|
@ -46,12 +46,6 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow
|
|||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x3BF | ``pmpaddr15`` | WARL | PMP Address Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x5A8 | ``scontext`` | WARL | Supervisor Context Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x747 | ``mseccfg`` | WARL | Machine Security Configuration |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x757 | ``mseccfgh`` | WARL | Upper 32 bits of ``mseccfg`` |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x7A0 | ``tselect`` | WARL | Trigger Select Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x7A1 | ``tdata1`` | WARL | Trigger Data Register 1 |
|
||||
|
@ -62,7 +56,7 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow
|
|||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x7A8 | ``mcontext`` | WARL | Machine Context Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x7AA | ``mscontext`` | WARL | Machine Supervisor Context Register |
|
||||
| 0x7AA | ``scontext`` | WARL | Supervisor Context Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x7B0 | ``dcsr`` | WARL | Debug Control and Status Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
|
@ -72,7 +66,7 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow
|
|||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x7B3 | ``dscratch1`` | RW | Debug Scratch Register 1 |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x7C0 | ``cpuctrlsts`` | WARL | CPU Control and Status Register (Custom CSR) |
|
||||
| 0x7C0 | ``cpuctrl`` | WARL | CPU Control Register (Custom CSR) |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x7C1 | ``secureseed`` | WARL | Security feature random seed (Custom CSR) |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
|
@ -96,12 +90,6 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow
|
|||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0xB9F | ``mhpmcounter31h`` | WARL | Upper 32 bits of ``mhmpcounter31`` |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0xF11 | ``mvendorid`` | R | Machine Vendor ID |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0xF12 | ``marchid`` | R | Machine Architecture ID |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0xF13 | ``mimpid`` | R | Machine Implementation ID |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0xF14 | ``mhartid`` | R | Hardware Thread ID |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
|
||||
|
@ -113,7 +101,7 @@ Machine Status (mstatus)
|
|||
|
||||
CSR Address: ``0x300``
|
||||
|
||||
Reset Value: ``0x0000_0080``
|
||||
Reset Value: ``0x0000_1800``
|
||||
|
||||
+-------+-----+---------------------------------------------------------------------------------+
|
||||
| Bit# | R/W | Description |
|
||||
|
@ -310,29 +298,6 @@ Reset Value: ``0x0000_0000``
|
|||
| address[33:2] |
|
||||
+----------------+
|
||||
|
||||
Machine Security Configuration (mseccfg/mseccfgh)
|
||||
-------------------------------------------------
|
||||
|
||||
CSR Address: ``mseccfg``: ``0x747`` ``mseccfg``: ``0x757``
|
||||
|
||||
Reset Value: ``0x0000_0000_0000_0000``
|
||||
|
||||
+------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Bit# | Definition |
|
||||
+------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
| 2 | **Rule Locking Bypass (RLB):** If set locked PMP entries can be modified |
|
||||
+------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
| 1 | **Machine Mode Whitelist Policy (MMWP):** If set default policy for PMP is deny for M-Mode accesses that don't match a PMP region |
|
||||
+------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
| 0 | **Machine Mode Lockdown (MML):** Alters behaviour of ``pmpcfgX`` bits |
|
||||
+------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
``mseccfg`` is specified in the Trusted Execution Environment (TEE) working group proposal `PMP Enhancements for memory access and execution prevention on Machine mode (Smepmp) version 0.9.3 <https://github.com/riscv/riscv-tee/blob/61455747230a26002d741f64879dd78cc9689323/Smepmp/Smepmp.pdf>`_, which gives the full details of it's functionality including the new PMP behaviour when ``mseccfg.MML`` is set.
|
||||
Note that the reset value means PMP behavior out of reset matches the RISC-V Privileged Architecture.
|
||||
A write to ``mseccfg`` is required to change it.
|
||||
Note ``mseccfgh`` reads as all 0s and ignores all writes.
|
||||
Any access to ``mseccfg`` or ``mseccfgh`` when using an Ibex configuration without PMP (``PMPEnable`` is 0) will trigger an illegal instruction exception.
|
||||
|
||||
.. _csr-tselect:
|
||||
|
||||
Trigger Select Register (tselect)
|
||||
|
@ -526,8 +491,8 @@ Reset Value: ``0x0000_0000``
|
|||
Scratch register to be used by the debug module.
|
||||
Accessible in Debug Mode only.
|
||||
|
||||
CPU Control and Status Register (cpuctrlsts)
|
||||
--------------------------------------------
|
||||
CPU Control Register (cpuctrl)
|
||||
------------------------------
|
||||
|
||||
CSR Address: ``0x7C0``
|
||||
|
||||
|
@ -540,21 +505,6 @@ Other bit fields read as zero.
|
|||
|
||||
+-------+------+------------------------------------------------------------------+
|
||||
| Bit# | R/W | Description |
|
||||
+=======+======+==================================================================+
|
||||
| 8 | R | **ic_scr_key_valid:** The icache scrambling key is valid. A |
|
||||
| | | ``fence.i`` instruction is guaranteed to fetch a new key. If |
|
||||
| | | the instruction cache has not been configured or the core has |
|
||||
| | | not been configured with security features (ICache parameter |
|
||||
| | | == 0 or SecureIbex parameter == 0), this field will always read |
|
||||
| | | as zero. (see :ref:`icache-scramble-key`) |
|
||||
+-------+------+------------------------------------------------------------------+
|
||||
| 7 | RW | **double_fault_seen:** A synchronous exception was observed when |
|
||||
| | | the ``sync_exc_seen`` field was set. This field must be manually |
|
||||
| | | cleared, hardware only sets it (see :ref:`double-fault-detect`). |
|
||||
+-------+------+------------------------------------------------------------------+
|
||||
| 6 | RW | **sync_exc_seen:** A synchronous exception has been observed. |
|
||||
| | | This flag is cleared when ``mret`` is executed. |
|
||||
| | | (see :ref:`double-fault-detect`). |
|
||||
+-------+------+------------------------------------------------------------------+
|
||||
| 5:3 | WARL | **dummy_instr_mask:** Mask to control frequency of dummy |
|
||||
| | | instruction insertion. If the core has not been configured with |
|
||||
|
@ -599,38 +549,6 @@ The User Mode ``time(h)`` registers are not implemented in Ibex.
|
|||
Any access to these registers will trap.
|
||||
It is recommended that trap handler software provides a means of accessing platform-defined ``mtime(h)`` timers where available.
|
||||
|
||||
Machine Vendor ID (mvendorid)
|
||||
-----------------------------
|
||||
|
||||
CSR Address: ``0xF11``
|
||||
|
||||
Reset Value: ``0x0000_0000``
|
||||
|
||||
Use the ``CSR_MVENDORID_VALUE`` parameter in :file:`rtl/ibex_pkg.sv` to change the fixed value.
|
||||
Details of what the ID represents can be found in the RISC-V Privileged Specification.
|
||||
|
||||
Machine Architecture ID (marchid)
|
||||
---------------------------------
|
||||
|
||||
CSR Address: ``0xF12``
|
||||
|
||||
Reset Value: ``0x0000_0016``
|
||||
|
||||
Use the ``CSR_MARCHID_VALUE`` parameter in :file:`rtl/ibex_pkg.sv` to change the fixed value.
|
||||
The value used is allocated specifically to Ibex.
|
||||
If significant changes are made a different ID should be used.
|
||||
Details of what the ID represents can be found in the RISC-V Privileged Specification.
|
||||
|
||||
Machine Implementation ID (mimpid)
|
||||
----------------------------------
|
||||
|
||||
CSR Address: ``0xF13``
|
||||
|
||||
Reset Value: ``0x0000_0000``
|
||||
|
||||
Use the ``CSR_MIMPID_VALUE`` parameter in :file:`rtl/ibex_pkg.sv` to change the fixed value.
|
||||
Details of what the ID represents can be found in the RISC-V Privileged Specification.
|
||||
|
||||
.. _csr-mhartid:
|
||||
|
||||
Hardware Thread ID (mhartid)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Debug Support
|
||||
=============
|
||||
|
||||
Ibex offers support for execution-based debug according to the `RISC-V Debug Specification <https://github.com/riscv/riscv-debug-spec/blob/0.13-test-release/riscv-debug-spec.pdf>`_, version 0.13.
|
||||
Ibex offers support for execution-based debug according to the `RISC-V Debug Specification <https://riscv.org/specifications/debug-specification/>`_, version 0.13.
|
||||
|
||||
|
||||
.. note::
|
||||
|
@ -32,10 +32,6 @@ Parameters
|
|||
+---------------------+-----------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+=====================+=================================================================+
|
||||
| ``DmBaseAddr`` | Base address of the Debug Module |
|
||||
+---------------------+-----------------------------------------------------------------+
|
||||
| ``DmAddrMask`` | Address mask of the Debug Module |
|
||||
+---------------------+-----------------------------------------------------------------+
|
||||
| ``DmHaltAddr`` | Address to jump to when entering Debug Mode |
|
||||
+---------------------+-----------------------------------------------------------------+
|
||||
| ``DmExceptionAddr`` | Address to jump to when an exception occurs while in Debug Mode |
|
||||
|
|
|
@ -50,8 +50,7 @@ To enable interrupts, both the global interrupt enable (MIE) bit in the ``mstatu
|
|||
For more information, see the :ref:`cs-registers` documentation.
|
||||
|
||||
If multiple interrupts are pending, they are handled in the priority order defined by the RISC-V Privileged Specification, version 1.11 (see Machine Interrupt Registers, Section 3.1.9).
|
||||
The fast interrupts have a platform defined priority.
|
||||
In Ibex they take priority over all other interrupts and between fast interrupts the highest priority is given to the interrupt with the lowest ID.
|
||||
The highest priority is given to the interrupt with the highest ID, except for timer interrupts, which have the lowest priority.
|
||||
|
||||
The NMI is enabled independent of the values in the ``mstatus`` and ``mie`` CSRs, and it is not visible through the ``mip`` CSR.
|
||||
It has interrupt ID 31, i.e., it has the highest priority of all interrupts and the core jumps to the trap-handler base address (in ``mtvec``) plus 0x7C to handle the NMI.
|
||||
|
@ -63,32 +62,6 @@ It is assumed that the interrupt handler signals completion of the handling rout
|
|||
|
||||
In Debug Mode, all interrupts including the NMI are ignored independent of ``mstatus``.MIE and the content of the ``mie`` CSR.
|
||||
|
||||
.. _internal-interrupts:
|
||||
|
||||
Internal Interrupts
|
||||
-------------------
|
||||
|
||||
Some events produce an 'internal interrupt'.
|
||||
An internal interrupt produces an NMI (using the same vector as the external NMI) with ``mcause`` and ``mtval`` being set to indicate the cause of the internal interrupt.
|
||||
The external NMI takes priority over all internal interrupts.
|
||||
Entering the handler for an internal interrupt automatically clears the internal interrupt.
|
||||
Internal interrupts are considered to be non-recoverable in general.
|
||||
Specific details of how an internal interrupt relates to the event that triggers it are listed below.
|
||||
Given these details it may be possible for software to recover from an internal interrupt under specific circumstances.
|
||||
|
||||
The possible ``mcause`` values for an internal interrupt are listed below:
|
||||
|
||||
+-------------+-------------------------------------------------------------------------------------------------------------+
|
||||
| ``mcause`` | Description |
|
||||
+-------------+-------------------------------------------------------------------------------------------------------------+
|
||||
| 0xFFFFFFE0 | Load integrity error internal interrupt. |
|
||||
| | Only generated when SecureIbex == 1. |
|
||||
| | ``mtval`` gives the faulting address. |
|
||||
| | The interrupt will be taken at most one instruction after the faulting load. |
|
||||
| | In particular a load or store immediately after a faulting load may execute before the interrupt is taken. |
|
||||
+-------------+-------------------------------------------------------------------------------------------------------------+
|
||||
| 0x8000001F | External NMI |
|
||||
+-------------+-------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Recoverable Non-Maskable Interrupt
|
||||
----------------------------------
|
||||
|
@ -125,9 +98,6 @@ Ibex can trigger an exception due to the following exception causes:
|
|||
|
||||
The illegal instruction exception, instruction access fault, LSU error exceptions and ECALL instruction exceptions cannot be disabled and are always active.
|
||||
|
||||
Note that Ibex cannot generated an 'instruction address misaligned' exception as all configurations implement the 'C' extension.
|
||||
Under the RISC-V architecture it is simply not possible to branch or otherwise start executing from a PC that isn't 16-bit aligned.
|
||||
So with 'C' implemented all possible PCs are appropriately aligned.
|
||||
|
||||
Nested Interrupt/Exception Handling
|
||||
-----------------------------------
|
||||
|
@ -177,19 +147,3 @@ The purpose of the nonstandard ``mstack`` CSRs in Ibex is only to support recove
|
|||
These CSRs are not accessible by software.
|
||||
While handling an NMI, all interrupts are ignored independent of ``mstatus``.MIE.
|
||||
Nested NMIs are not supported.
|
||||
|
||||
.. _double-fault-detect:
|
||||
|
||||
Double Fault Detection
|
||||
----------------------
|
||||
|
||||
Ibex has a mechanism to detect when a double fault has occurred.
|
||||
A double fault is defined as a synchronous exception occurring whilst handling a previous synchronous exception.
|
||||
The ``cpuctrl`` custom CSR has fields to provide software visibility and access to this mechanism.
|
||||
|
||||
When a synchronous exception occurs, Ibex sets ``cpuctrl``.sync_exception_seen.
|
||||
Ibex clears ``cpuctrl``.sync_exception_seen when ``mret`` is executed.
|
||||
If a synchronous exception occurs whilst ``cpuctrl``.sync_exception_seen is set, a double fault has been detected.
|
||||
|
||||
When a double fault is detected, the ``double_fault_seen_o`` output is asserted for one cycle and ``cpuctrl``.double_fault_seen is set.
|
||||
Note that writing the ``cpuctrl``.double_fault_seen field has no effect on the ``double_fault_seen_o`` output.
|
||||
|
|
|
@ -93,32 +93,6 @@ Indicative RAM sizes for common configurations are given in the table below:
|
|||
| 4kB, 4 way, 64bit line | 4 x 128 x 22bit | 4 x 128 x 64bit |
|
||||
+------------------------------+-----------------+------------------+
|
||||
|
||||
ICache Scrambling
|
||||
^^^^^^^^^^^^^^^^^
|
||||
If ICacheScramble parameter is enabled, all RAM primitives are replaced with scrambling RAM primitive.
|
||||
For more information about how scrambling works internally (see :file:`vendor/lowrisc_ip/ip/prim/doc/prim_ram_1p_scr.md`).
|
||||
Interface for receiving scrambling key follows req / ack protocol.
|
||||
Ibex first requests a new ephemeral key by asserting the request (``scramble_req_o``) and when a fresh valid key is indicated by ``scramble_key_valid_i``, it deasserts the request.
|
||||
Note that in current implementation, it is assumed req/ack protocol is synchronized before arriving to Ibex top level.
|
||||
|
||||
.. _icache-scramble-key:
|
||||
|
||||
Scramble Key Renewal
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To get a new scrambling key execute a FENCE.I instruction.
|
||||
With a new scrambling key the existing cache contents are effectively corrupt and will be invalidated by the FENCE.I.
|
||||
Following a FENCE.I cache lookups will always miss until the invalidation is complete.
|
||||
This allows CPU fetch and execution to continue using direct memory accesses whilst the scramble key request and cache invalidation proceeds in the background.
|
||||
Should a second FENCE.I be executed before the first invalidation completes there are two possibilities
|
||||
|
||||
1. The request for a new scramble key is still in progress.
|
||||
As a new request cannot begin whilst one is in progress the FENCE.I is ignored.
|
||||
2. The request for a new scramble key has completed and the invalidation is in progress.
|
||||
The invalidation stops and a new scramble key requested and the process starts over.
|
||||
|
||||
To guarantee a new scramble key ensure the ``ic_scr_key_valid`` bit in the ``cpuctrlsts`` CSR is set before executing the FENCE.I instruction.
|
||||
|
||||
Sub Unit Description
|
||||
--------------------
|
||||
|
||||
|
@ -184,8 +158,6 @@ The remaining data from hits is buffered in the fill buffer data storage and sup
|
|||
|
||||
To deal with misalignment caused by compressed instructions, there is a 16bit skid buffer to store the upper halfword.
|
||||
|
||||
.. _icache-ecc:
|
||||
|
||||
Cache ECC protection
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -215,7 +187,6 @@ Any error (single or double bit) in any RAM will effectively cancel a cache hit
|
|||
The request which observed an error will fetch it's data from the main instruction memory as normal for a cache miss.
|
||||
The cache index and way (or ways) with errors are stored in IC1, and a cache write is forced the next cycle to invalidate that line.
|
||||
Lookup requests will be blocked in IC0 while the invalidation write is performed.
|
||||
If an ECC error is seen a minor alert will be signaled.
|
||||
|
||||
Cache invalidation
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
@ -233,7 +204,7 @@ This isn't an attempt to describe the cache's performance characteristics.
|
|||
The I$ has a single clock (``clk_i``) and asynchronous reset (``rst_ni``).
|
||||
|
||||
Data is requested from the instruction memory with the ports prefixed by ``instr_``. These work as described in :ref:`instruction-fetch`.
|
||||
Note that there's one extra port on the I$, which doesn't appear at the ``ibex_top`` top-level.
|
||||
Note that there's one extra port on the I$, which doesn't appear at the ``ibex_core`` top-level.
|
||||
This is ``instr_pmp_err_i``.
|
||||
If the PMP block disallows a fetch for a certain address, it will squash the outgoing memory request entirely and set ``instr_pmp_err_i``.
|
||||
If that happens, the cache drops ``instr_req_o`` and stops making any further requests for that cache line.
|
||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 72 KiB |
File diff suppressed because it is too large
Load diff
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 62 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 148 KiB |
|
@ -22,9 +22,5 @@ It describes the design in detail, discusses the verification approach and the r
|
|||
debug
|
||||
tracer
|
||||
verification
|
||||
verification_stages
|
||||
cosim
|
||||
testplan
|
||||
coverage_plan
|
||||
rvfi
|
||||
history
|
||||
|
|
|
@ -56,7 +56,7 @@ Arithmetic Logic Unit (ALU)
|
|||
---------------------------
|
||||
Source File: :file:`rtl/ibex_alu.sv`
|
||||
|
||||
The Arithmetic Logic Unit (ALU) is a purely combinational block that implements operations required for the Integer Computational Instructions and the comparison operations required for the Control Transfer Instructions in the RV32I RISC-V Specification.
|
||||
The Arithmetic Logic Logic (ALU) is a purely combinational block that implements operations required for the Integer Computational Instructions and the comparison operations required for the Control Transfer Instructions in the RV32I RISC-V Specification.
|
||||
Other blocks use the ALU for the following tasks:
|
||||
|
||||
* Mult/Div uses it to perform addition as part of the multiplication and division algorithms
|
||||
|
@ -64,45 +64,46 @@ Other blocks use the ALU for the following tasks:
|
|||
* It computes memory addresses for loads and stores with a Reg + Imm calculation
|
||||
* The LSU uses it to increment addresses when performing two accesses to handle an unaligned access
|
||||
|
||||
Bit-Manipulation Extension
|
||||
Support for the `RISC-V Bit-Manipulation Extension version 1.0.0 <https://github.com/riscv/riscv-bitmanip/releases/download/1.0.0/bitmanip-1.0.0-38-g865e7a7.pdf>`_ and `draft version 0.93 from January 10, 2021 <https://github.com/riscv/riscv-bitmanip/blob/master/bitmanip-0.93.pdf>`_ is optional. [#B_draft]_
|
||||
Bit Manipulation Extension
|
||||
Support for the `RISC-V Bit Manipulation Extension (draft version 0.92 from November 8, 2019) <https://github.com/riscv/riscv-bitmanip/blob/master/bitmanip-0.92.pdf>`_ is optional. [#B_draft]_
|
||||
It can be enabled via the enumerated parameter ``RV32B`` defined in :file:`rtl/ibex_pkg.sv`.
|
||||
By default, this parameter is set to "ibex_pkg::RV32BNone" to disable the bit-manipulation extension.
|
||||
By default, this parameter is set to "ibex_pkg::RV32BNone" to disable the bit manipulation extension.
|
||||
|
||||
There are three versions of the bit-manipulation extension available:
|
||||
The balanced version comprises a set of sub-extensions aiming for good benefits at a reasonable area overhead.
|
||||
There are two versions of the bit manipulation extension available:
|
||||
The balanced implementation comprises a set of sub-extensions aiming for good benefits at a reasonable area overhead.
|
||||
It can be selected by setting the ``RV32B`` parameter to "ibex_pkg::RV32BBalanced".
|
||||
The OTEarlGrey version comprises all sub-extensions except for the Zbe.
|
||||
This version can be selected by setting the ``RV32B`` parameter to "ibex_pkg::RV32BOTEarlGrey".
|
||||
The full version comprises all sub-extensions and can be selected by setting the ``RV32B`` parameter to "ibex_pkg::RV32BFull".
|
||||
The following table gives an overview of which sub-extensions are implemented in each version and of which instructions are implemented as multi-cycle instructions.
|
||||
The full implementation comprises all 32 bit instructions defined in the extension.
|
||||
This version can be selected by setting the ``RV32B`` parameter to "ibex_pkg::RV32BFull".
|
||||
The following table lists the implemented instructions in each version.
|
||||
Multi-cycle instructions are completed in 2 cycles.
|
||||
All remaining instructions complete in a single cycle.
|
||||
|
||||
+--------------------------------+---------+----------+------------+------+--------------------+
|
||||
| Bit-Manipulation Sub-Extension | Spec. | Balanced | OTEarlGrey | Full | Multi-Cycle Instr. |
|
||||
+================================+=========+==========+============+======+====================+
|
||||
| Zba (Address generation) | v.1.0.0 | X | X | X | None |
|
||||
+--------------------------------+---------+----------+------------+------+--------------------+
|
||||
| Zbb (Base) | v.1.0.0 | X | X | X | rol, ror[i] |
|
||||
+--------------------------------+---------+----------+------------+------+--------------------+
|
||||
| Zbc (Carry-less multiply) | v.1.0.0 | | X | X | None |
|
||||
+--------------------------------+---------+----------+------------+------+--------------------+
|
||||
| Zbs (Single-bit) | v.1.0.0 | X | X | X | None |
|
||||
+--------------------------------+---------+----------+------------+------+--------------------+
|
||||
| Zbe (Bit compress/decompress) | v.0.93 | | | X | All |
|
||||
+--------------------------------+---------+----------+------------+------+--------------------+
|
||||
| Zbf (Bit-field place) | v.0.93 | X | X | X | All |
|
||||
+--------------------------------+---------+----------+------------+------+--------------------+
|
||||
| Zbp (Permutation) | v.0.93 | | X | X | None |
|
||||
+--------------------------------+---------+----------+------------+------+--------------------+
|
||||
| Zbr (CRC) | v.0.93 | | X | X | All |
|
||||
+--------------------------------+---------+----------+------------+------+--------------------+
|
||||
| Zbt (Ternary) | v.0.93 | X | X | X | All |
|
||||
+--------------------------------+---------+----------+------------+------+--------------------+
|
||||
+---------------------------------+---------------+--------------------------+
|
||||
| Z-Extension | Version | Multi-Cycle Instructions |
|
||||
+=================================+===============+==========================+
|
||||
| Zbb (Base) | Balanced/Full | rol, ror[i] |
|
||||
+---------------------------------+---------------+--------------------------+
|
||||
| Zbs (Single-bit) | Balanced/Full | None |
|
||||
+---------------------------------+---------------+--------------------------+
|
||||
| Zbp (Permutation) | Full | None |
|
||||
+---------------------------------+---------------+--------------------------+
|
||||
| Zbe (Bit extract/deposit) | Full | All |
|
||||
+---------------------------------+---------------+--------------------------+
|
||||
| Zbf (Bit-field place) | Balanced/Full | All |
|
||||
+---------------------------------+---------------+--------------------------+
|
||||
| Zbc (Carry-less multiply) | Full | None |
|
||||
+---------------------------------+---------------+--------------------------+
|
||||
| Zbr (CRC) | Full | All |
|
||||
+---------------------------------+---------------+--------------------------+
|
||||
| Zbt (Ternary) | Balanced/Full | All |
|
||||
+---------------------------------+---------------+--------------------------+
|
||||
| Zb_tmp (Temporary) [#B_zb_tmp]_ | Balanced/Full | None |
|
||||
+---------------------------------+---------------+--------------------------+
|
||||
|
||||
The implementation of the Bit-Manipulation Extension comes with an area overhead of 2.7 kGE for the balanced version, 6.1 kGE for the OTEarlGrey version, and 7.5 kGE for the full version.
|
||||
These numbers were obtained by synthesizing the design with Yosys and relaxed timing constraints.
|
||||
The implementation of the B-extension comes with an area overhead of 1.8 to 3.0 kGE for the balanced version and 6.0 to 8.7 kGE for the full version.
|
||||
That corresponds to an approximate percentage increase in area of 9 to 14 % and 25 to 30 % for the balanced and full versions respectively.
|
||||
The ranges correspond to synthesis results generated using relaxed and maximum frequency targets respectively.
|
||||
The designs have been synthesized using Synopsys Design Compiler targeting TSMC 65 nm technology.
|
||||
|
||||
|
||||
.. _mult-div:
|
||||
|
@ -172,9 +173,11 @@ See :ref:`load-store-unit` for more details.
|
|||
|
||||
.. rubric:: Footnotes
|
||||
|
||||
.. [#B_draft] Ibex fully implements the ratified version 1.0.0 of the RISC-V Bit-Manipulation Extension including the Zba, Zbb, Zbc and Zbs sub-extensions.
|
||||
In addition, Ibex also supports the remaining Zbe, Zbf, Zbp, Zbr and Zbt sub-extensions as defined in draft version 0.93 of the RISC-V Bit-Manipulation Extension.
|
||||
Note that the latter sub-extensions may change before being ratified as a standard by the RISC-V Foundation.
|
||||
.. [#B_draft] Ibex fully implements draft version 0.92 of the RISC-V Bit Manipulation Extension.
|
||||
This extension may change before being ratified as a standard by the RISC-V Foundation.
|
||||
Ibex will be updated to match future versions of the specification.
|
||||
Prior to ratification this may involve backwards incompatible changes.
|
||||
Additionally, neither GCC or Clang have committed to maintaining support upstream for unratified versions of the specification.
|
||||
|
||||
.. [#B_zb_tmp] The sign-extend instructions `sext.b/sext.h` are defined but not unambiguously categorized in draft version 0.92 of the extension.
|
||||
Temporarily, they have been assigned a separate Z-extension (Zb_tmp) both in Ibex and the RISCV-DV random instruction generator used to verify the bit manipulation instructions in Ibex.
|
||||
|
|
|
@ -45,28 +45,26 @@ The main difference is that the instruction interface does not allow for write t
|
|||
|
||||
.. tabularcolumns:: |p{4cm}|l|p{9cm}|
|
||||
|
||||
+-----------------------------+-----------+-----------------------------------------------+
|
||||
| Signal | Direction | Description |
|
||||
+=============================+===========+===============================================+
|
||||
| ``instr_req_o`` | output | Request valid, must stay high until |
|
||||
| | | ``instr_gnt_i`` is high for one cycle |
|
||||
+-----------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_addr_o[31:0]`` | output | Address, word aligned |
|
||||
+-----------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_gnt_i`` | input | The other side accepted the request. |
|
||||
| | | ``instr_req_o`` may be deasserted in the next |
|
||||
| | | cycle. |
|
||||
+-----------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_rvalid_i`` | input | ``instr_rdata_i`` holds valid data when |
|
||||
| | | ``instr_rvalid_i`` is high. This signal will |
|
||||
| | | be high for exactly one cycle per request. |
|
||||
+-----------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_rdata_i[31:0]`` | input | Data read from memory |
|
||||
+-----------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_rdata_intg_i[6:0]`` | input | Data integrity bits from memory |
|
||||
+-----------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_err_i`` | input | Memory access error |
|
||||
+-----------------------------+-----------+-----------------------------------------------+
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| Signal | Direction | Description |
|
||||
+=========================+===========+===============================================+
|
||||
| ``instr_req_o`` | output | Request valid, must stay high until |
|
||||
| | | ``instr_gnt_i`` is high for one cycle |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_addr_o[31:0]`` | output | Address, word aligned |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_gnt_i`` | input | The other side accepted the request. |
|
||||
| | | ``instr_req_o`` may be deasserted in the next |
|
||||
| | | cycle. |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_rvalid_i`` | input | ``instr_rdata_i`` holds valid data when |
|
||||
| | | ``instr_rvalid_i`` is high. This signal will |
|
||||
| | | be high for exactly one cycle per request. |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_rdata_i[31:0]`` | input | Data read from memory |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_err_i`` | input | Memory access error |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
|
||||
|
||||
Misaligned Accesses
|
||||
|
|
|
@ -14,60 +14,39 @@ Data-Side Memory Interface
|
|||
|
||||
Signals that are used by the LSU:
|
||||
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| Signal | Direction | Description |
|
||||
+============================+===========+===============================================+
|
||||
| ``data_req_o`` | output | Request valid, must stay high until |
|
||||
| | | ``data_gnt_i`` is high for one cycle |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_addr_o[31:0]`` | output | Address, word aligned |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_we_o`` | output | Write Enable, high for writes, low for |
|
||||
| | | reads. Sent together with ``data_req_o`` |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_be_o[3:0]`` | output | Byte Enable. Is set for the bytes to |
|
||||
| | | write/read, sent together with ``data_req_o`` |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_wdata_o[31:0]`` | output | Data to be written to memory, sent together |
|
||||
| | | with ``data_req_o`` |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_wdata_intg_o[6:0]`` | output | Integrity bits to be written to memory, sent |
|
||||
| | | together with ``data_req_o`` (not used unless |
|
||||
| | | the SecureIbex parameter is set) |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_gnt_i`` | input | The other side accepted the request. |
|
||||
| | | Outputs may change in the next cycle. |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_rvalid_i`` | input | ``data_err_i`` and ``data_rdata_i`` hold |
|
||||
| | | valid data when ``data_rvalid_i`` is high. |
|
||||
| | | This signal will be high for exactly one |
|
||||
| | | cycle per request. |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_err_i`` | input | Error response from the bus or the memory: |
|
||||
| | | request cannot be handled. High in case of an |
|
||||
| | | error. |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_rdata_i[31:0]`` | input | Data read from memory |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_rdata_intg_i[6:0]`` | input | Integrity bits read from memory (ignored |
|
||||
| | | unless the SecureIbex parameter is set) |
|
||||
+----------------------------+-----------+-----------------------------------------------+
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| Signal | Direction | Description |
|
||||
+=========================+===========+===============================================+
|
||||
| ``data_req_o`` | output | Request valid, must stay high until |
|
||||
| | | ``data_gnt_i`` is high for one cycle |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_addr_o[31:0]`` | output | Address, word aligned |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_we_o`` | output | Write Enable, high for writes, low for |
|
||||
| | | reads. Sent together with ``data_req_o`` |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_be_o[3:0]`` | output | Byte Enable. Is set for the bytes to |
|
||||
| | | write/read, sent together with ``data_req_o`` |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_wdata_o[31:0]`` | output | Data to be written to memory, sent together |
|
||||
| | | with ``data_req_o`` |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_gnt_i`` | input | The other side accepted the request. |
|
||||
| | | Outputs may change in the next cycle. |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_rvalid_i`` | input | ``data_err_i`` and ``data_rdata_i`` hold |
|
||||
| | | valid data when ``data_rvalid_i`` is high. |
|
||||
| | | This signal will be high for exactly one |
|
||||
| | | cycle per request. |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_err_i`` | input | Error response from the bus or the memory: |
|
||||
| | | request cannot be handled. High in case of an |
|
||||
| | | error. |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``data_rdata_i[31:0]`` | input | Data read from memory |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
|
||||
|
||||
Bus Integrity Checking
|
||||
----------------------
|
||||
|
||||
The core can optionally generate and verify check bits sent alongside the data for memory accesses.
|
||||
Checkbits are generated and checked using an inverted 39/32 Hsaio code (see :file:`vendor/lowrisc_ip/ip/prim/rtl/prim_secded_inv_39_32_enc.sv`).
|
||||
An :ref:`internal interrupt<internal-interrupts>` will be generated and a bus major alert signalled if there is a mismatch.
|
||||
Where load data has bad checkbits the write to the load's destination register will be suppressed.
|
||||
Ibex checks the integrity against the response data for both loads and stores.
|
||||
For stores the response data is otherwise ignored so the data can be any value provided the integrity is valid (``data_rdata_intg_i`` must match with ``data_rdata_i``).
|
||||
It is recommended for write responses some fixed value is placed on ``data_rdata_i`` and ``data_rdata_intg_i`` by the memory system Ibex is connected to in configurations where integrity is used.
|
||||
|
||||
This feature is only used if the core is configured with the SecureIbex parameter set.
|
||||
For all other configurations, the integrity signals can be ignored.
|
||||
|
||||
Misaligned Accesses
|
||||
-------------------
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ See Multi- and Single-Cycle Instructions below for the details.
|
|||
Third Pipeline Stage
|
||||
--------------------
|
||||
Ibex can be configured to have a third pipeline stage (Writeback) which has major effects on performance and instruction behaviour.
|
||||
The details of its impact are not yet documented here.
|
||||
This feature is *EXPERIMENTAL* and the details of its impact are not yet documented here.
|
||||
All of the information presented below applies only to the two stage pipeline provided in the default configurations.
|
||||
|
||||
Multi- and Single-Cycle Instructions
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Physical Memory Protection (PMP)
|
||||
================================
|
||||
|
||||
The Physical Memory Protection (PMP) unit implements region-based memory access checking in-accordance with the RISC-V Privileged Specification, version 1.12 and implements the `PMP Enhancements for memory access and execution prevention on Machine mode (Smepmp) version 1.0 <https://github.com/riscv/riscv-tee/blob/191b563b08b31cc2974d604a3b670d8666a2e093/Smepmp/Smepmp.pdf>`_ extension.
|
||||
The Physical Memory Protection (PMP) unit implements region-based memory access checking in-accordance with the RISC-V Privileged Specification, version 1.11.
|
||||
The following configuration parameters are available to control PMP checking:
|
||||
|
||||
+----------------+---------------+----------------------------------------------------------+
|
||||
|
@ -30,31 +30,3 @@ PMP Granularity
|
|||
|
||||
The PMP granularity parameter is used to reduce the size of the address matching comparators by increasing the minimum region size.
|
||||
When the granularity is greater than zero, NA4 mode is not available and will be treated as OFF mode.
|
||||
|
||||
.. _pmp-enhancements:
|
||||
|
||||
PMP Enhancements
|
||||
----------------
|
||||
|
||||
These are described in more detail in `PMP Enhancements for memory access and execution prevention on Machine mode (Smepmp) version 1.0 <https://github.com/riscv/riscv-tee/blob/191b563b08b31cc2974d604a3b670d8666a2e093/Smepmp/Smepmp.pdf>`_.
|
||||
If Ibex is configured to include PMP (PMPEnable is not zero) the PMP enhancements are always included.
|
||||
Use of the enhanced behavior is optional, if no writes to ``mseccfg`` occur PMP behavior will remain exactly as if Smepmp was not implemented.
|
||||
The enhancements add:
|
||||
|
||||
* A new CSR ``mseccfg`` providing functionality to allow locked regions to be modified and to implement default deny for M-mode accesses.
|
||||
* New PMP region configurations which are U-Mode or M-Mode accessible only with varying read/write/execute settings along with some shared U and M mode accessible configurations.
|
||||
These new configurations supersede the original ones and are enabled via ``mseccfg``.
|
||||
|
||||
Custom Reset Values
|
||||
-------------------
|
||||
|
||||
By default all PMP CSRs (include ``mseccfg``) are reset to 0.
|
||||
Some applications may want other reset values.
|
||||
Default reset values are defined in :file:`ibex_pkg.sv`.
|
||||
An implementation can either modify this file or pass custom reset values as a module parameter.
|
||||
|
||||
Debug Mode
|
||||
----------
|
||||
|
||||
In debug mode, the PMP allows all accesses to addresses of the Debug Module, as defined by the `DmBaseAddr` and `DmAddrMask` module parameters.
|
||||
This is mandated by the RISC-V Debug Specification (v1.0.0).
|
||||
|
|
|
@ -9,9 +9,8 @@ All features are runtime configurable via bits in the **cpuctrl** custom CSR.
|
|||
Outputs
|
||||
-------
|
||||
|
||||
Ibex has three alert outputs for signalling security issues.
|
||||
The internal major alert (**alert_major_internal_o**) indicates a critical security issue from which the core cannot recover which was detected internally in `ibex_top`.
|
||||
The bus major alert (**alert_major_internal_o**) indicates a critical security issue from which the core cannot recover which was detected on incoming bus data.
|
||||
Ibex has two alert outputs for signalling security issues.
|
||||
The major alert (**alert_major_o**) indicates a critical security issue from which the core cannot recover.
|
||||
The minor alert (**alert_minor_o**) indicates potential security issues which can be monitored over time by a system.
|
||||
|
||||
Data Independent Timing
|
||||
|
@ -22,20 +21,10 @@ This makes it more difficult for an external observer to infer secret data by ob
|
|||
|
||||
In Ibex, most instructions already execute independent of their input operands.
|
||||
When data-independent timing is enabled:
|
||||
|
||||
* Branches execute identically regardless of their taken/not-taken status
|
||||
* Early completion of multiplication by zero/one is removed
|
||||
* Early completion of divide by zero is removed
|
||||
|
||||
Note that data memory operations to unaligned addresses might result in multiple bus accesses being made.
|
||||
This in turn could expose information about the address as a timing side-channel.
|
||||
It is therefore recommended to stick to aligned memory accesses when using this feature for critical code regions.
|
||||
|
||||
When Ibex is configured to use an instruction cache, stalls on instruction fetch can see variable latency (depending on whether or not they hit in the cache).
|
||||
Software that has need of data independent timing may wish to disable the instruction cache to avoid this or to carefully analyse execution to determine if variable latency introduced by the cache causes unacceptable leakage.
|
||||
The instruction cache is controlled by the **icache_enable** bit in the **cpuctrl** register.
|
||||
Precise details of fetch timing will depend upon the memory system Ibex is connected to.
|
||||
|
||||
Dummy Instruction Insertion
|
||||
---------------------------
|
||||
|
||||
|
@ -60,51 +49,18 @@ The frequency of injected instructions can be tuned via the **dummy_instr_mask**
|
|||
Other values of **dummy_instr_mask** are legal, but will have a less predictable impact.
|
||||
|
||||
The interval between instruction insertion is randomized in the core using an LFSR.
|
||||
The initial seed and output permutation for this LFSR can be set using parameters from the top-level of Ibex.
|
||||
Sofware can periodically re-seed this LFSR with true random numbers (if available) via the **secureseed** CSR.
|
||||
This will make the insertion interval of dummy instructions much harder for an attacker to predict.
|
||||
|
||||
Note that the dummy instruction feature inserts multiply and divide instructions.
|
||||
The core must be configured with a multiplier (`RV32M != ibex_pkg::RV32MNone`) or errors will occur using this feature.
|
||||
|
||||
Bus integrity checking
|
||||
----------------------
|
||||
|
||||
Extra signals are available alongside the instruction and data side memory channels to support bus integrity checking.
|
||||
When the SecureIbex parameter is set, incoming data will be checked against the supplied checkbits.
|
||||
An :ref:`internal interrupt<internal-interrupts>` will be generated and a bus major alert signalled if there is a mismatch.
|
||||
Where load data has bad checkbits the write to the load's destination register will be suppressed.
|
||||
Write data can be checked against the supplied checkbits at its destination to confirm integrity.
|
||||
|
||||
Register file ECC
|
||||
-----------------
|
||||
|
||||
When Ibex is configured with the SecureIbex parameter, ECC checking is added to all reads of the register file.
|
||||
This can be useful to detect fault injection attacks since the register file covers a reasonably large area.
|
||||
No attempt is made to correct detected errors, but an internal major alert is signaled for the system to take action.
|
||||
|
||||
Register file write enable glitch detection
|
||||
-------------------------------------------
|
||||
|
||||
When Ibex is configured with the SecureIbex parameter, the write enable signal into the register file is checked to be one-hot.
|
||||
This can be useful to detect fault injection attacks.
|
||||
No attempt is made to correct detected errors, but an internal major alert is signaled for the system to take action.
|
||||
|
||||
Register file read addresses glitch detection
|
||||
-------------------------------------------
|
||||
|
||||
When Ibex is configured with the SecureIbex parameter, the read addresses provided to the register file are converted to one-hot encoded signals, and a one-hot encoded MUX is used to select the register to read from.
|
||||
By using one-hot encoding checkers, glitches in the one-hot encoded signals are detected.
|
||||
Bit-flips inside the plain read addresses before the one-hot conversion happens are detected by the dual core lockstep.
|
||||
This can be useful to detect fault injection attacks.
|
||||
No attempt is made to correct detected errors, but an internal major alert is signaled for the system to take action.
|
||||
|
||||
ICache ECC
|
||||
----------
|
||||
|
||||
The ICache can be configured with ECC protection.
|
||||
When an ECC error is detected a minor alert is signaled.
|
||||
See :ref:`icache-ecc` for more information.
|
||||
No attempt is made to correct detected errors, but an external alert is raised for the system to take action.
|
||||
|
||||
Hardened PC
|
||||
-----------
|
||||
|
@ -112,22 +68,11 @@ Hardened PC
|
|||
This adds a check that the PC driven from the IF stage has not been modified.
|
||||
A check is asserted that the current IF stage PC equals the previous PC plus the correct increment.
|
||||
The check is disabled after branches and after reset.
|
||||
If a mismatch is detected, an internal major alert is signaled.
|
||||
If a mismatch is detected, a major alert is signaled.
|
||||
|
||||
Shadow CSRs
|
||||
-----------
|
||||
|
||||
Certain critical CSRs (`mstatus`, `mtvec`, `cpuctrl`, `pmpcfg` and `pmpaddr`) have extra glitch detection enabled.
|
||||
This creates a second copy of the register which stores a complemented version of the main CSR data.
|
||||
A constant check is made that the two copies are consistent, and an internal major alert is signalled if not.
|
||||
Note that this feature is not currently used when the SecureIbex parameter is set due to overlap with dual core lockstep.
|
||||
|
||||
Dual core lockstep
|
||||
------------------
|
||||
|
||||
This configuration option instantiates a second copy of the core logic, referred to as the shadow core.
|
||||
The shadow core executes using a delayed version of all inputs supplied to the main core.
|
||||
All outputs of the shadow core are compared against a delayed version of the outputs of the main core.
|
||||
Any mismatch between the two sets of outputs will trigger an internal major alert.
|
||||
|
||||
Note that the register file and icache RAMs are not duplicated since these units are covered by ECC protection.
|
||||
A constant check is made that the two copies are consistent, and a major alert is signalled if not.
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
.. _testplan:
|
||||
|
||||
.. todo::
|
||||
|
||||
Add detail about security hardening verification.
|
||||
|
||||
.. note::
|
||||
|
||||
This testplan is a work in progress still being implemented so this document may not match the implemented verification in the repository.
|
||||
|
||||
Test Plan
|
||||
=========
|
||||
|
||||
Goals
|
||||
-----
|
||||
|
||||
* Verify compliance with all the RISC-V specifications Ibex supports.
|
||||
* Verify Ibex's security hardening features.
|
||||
* Ensure correct functionality is maintained across all possible behaviours of external interfaces (interrupts, memory responses, debug requests etc).
|
||||
* Hit all functional coverage points, described in :ref:`coverage-plan`.
|
||||
|
||||
Testbench Architecture
|
||||
----------------------
|
||||
|
||||
.. figure:: images/tb2.svg
|
||||
:alt: Testbench Architecture
|
||||
|
||||
Architecture of the UVM testbench for Ibex core
|
||||
|
||||
Ibex utilises a co-simulation checking approach described in detail in :ref:`cosim`.
|
||||
With the co-simulation system all instructions Ibex executes and all external events such as an interrupts or memory errors are fed to a golden model.
|
||||
The results of every instruction execution and every memory access are crossed checked against the golden model with any mismatches resulting in a test failure.
|
||||
The aim is to check all possible externally observable behaviours of ``ibex_top`` against the golden model.
|
||||
The golden model used is the `Spike RISC-V ISS <https://github.com/riscv-software-src/riscv-isa-sim>`_.
|
||||
|
||||
The testbench uses UVM.
|
||||
It consists of 3 agents:
|
||||
|
||||
Co-simulation Agent:
|
||||
This has multiple monitors.
|
||||
One monitors the RVFI interface which provides details of retired instructions.
|
||||
The other monitors relate to fetched instructions and instruction memory errors; more details are provided in :ref:`coverage-plan`.
|
||||
Additionally it connects to the monitor of the Memory Interface Agent for the instruction and data side via analysis ports.
|
||||
The monitored transactions are used by a scoreboard to provide information to the co-simulation system allowing it to step the golden model and check its execution and memory activity against Ibex's behaviour.
|
||||
|
||||
Memory Interface Agent
|
||||
This provides a driver and a monitor for the :ref:`Ibex Memory Interface Protocol<lsu-protocol>`.
|
||||
The driver provides fully randomised and configurable timings for responses and randomisation of error responses.
|
||||
Two agents are instantiated; one for the data memory interface the other for the instruction memory interface.
|
||||
Read data for memory responses is provided from a backing memory; write requests update the contents of the backing memory.
|
||||
This is separate from the memory used by the golden model in the co-simulation agent.
|
||||
The contents of these two memories will be identical unless there is a mismatch resulting in a failure.
|
||||
The backing memory is held in a memory model as a separate UVM component.
|
||||
The two agents use the same backing memory so they have a coherent view of memory.
|
||||
|
||||
IRQ Agent
|
||||
This provides a driver and a monitor for the IRQ interface.
|
||||
It provides randomised interrupt stimulus to Ibex when a test requests it.
|
||||
Constraints can be used to control types of interrupts generated (e.g. NMI or not) and whether multiple interrupts should be raised together.
|
||||
|
||||
Debug and reset signals are a single wire each so do not have a dedicated agent.
|
||||
Instead any sequence that wishes to use them will directly manipulate them via a virtual interface
|
||||
|
||||
The testbench instantiates the agents described above along with the memory model used by both the data and instruction side memory agents.
|
||||
A test consists of executing a pre-built binary (which is loaded into the memory model at the start of the test via backdoor accesses) along with configuring agents to provide appropriate stimulus for the test.
|
||||
Some tests may use the agents to generate stimulus at particular times (e.g. interrupts).
|
||||
A test may perform additional checking on top of the co-simulation golden model comparison where appropriate (e.g. ensuring a raised interrupt has caused an exception).
|
||||
|
||||
Stimulus Strategy
|
||||
-----------------
|
||||
|
||||
Stimulus falls into two categories:
|
||||
|
||||
* Instructions to execute: These are generated by the `RISC-V DV random instruction <https://github.com/google/riscv-dv>`_ generator and provided to the testbench via a raw binary file.
|
||||
* Activity on external interfaces.
|
||||
|
||||
Instructions are generated ahead of time so the test has no control over them at run time.
|
||||
All external interfaces have their stimulus generated at run time so can be controlled by the test.
|
||||
It is the responsibility of the regression run environment to ensure generated instructions are matched with appropriate tests (e.g. ensuring an exception handler is present where interrupts are expected).
|
||||
|
||||
Stimulus generation will use a coverage based approach.
|
||||
Stimulus is developed based upon the :ref:`coverage-plan`.
|
||||
Where coverage is not being hit stimulus will be added to hit it.
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
||||
As with stimulus, test sequence development uses a coverage based approach.
|
||||
Tests will be added such that all coverage in the :ref:`coverage-plan` can be hit.
|
||||
Not all the details of specific tests will be documented here.
|
||||
The test list (`dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml <https://github.com/lowRISC/ibex/blob/master/dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml>`_), provides an exhaustive list of all tests along with a brief description of what the test does.
|
||||
|
||||
A test will execute a binary whilst running zero or more sequences that provide stimulus to external interfaces of ``ibex_top``.
|
||||
As the memory interfaces are all driven by Ibex, with any testbench generated activity in response to a request from Ibex, they do not require explicit sequences run by the test.
|
||||
Instead the test can configure the randomisation of memory delays as it wishes.
|
||||
Memory errors can be configured to always occur in statically defined areas of the memory map or a sequence can be used to inject them via the memory interface agent.
|
||||
|
||||
The following sequences are available for tests to use.
|
||||
Each sequence is derived from a base sequence which provides controls to repeat the sequence at fixed or random internals, forever or after a random number of repeats.
|
||||
Full details can be found in `dv/uvm/core_ibex/tests/core_ibex_seq_lib.sv <https://github.com/lowRISC/ibex/blob/master/dv/uvm/core_ibex/tests/core_ibex_seq_lib.sv>`_.
|
||||
|
||||
* ``irq_raise_seq`` - Raises one or more interrupts.
|
||||
The testbench binary can write to a special memory location to acknowledge the interrupt and cause it to drop.
|
||||
Alternatively the testbench can drop it after a given amount of time.
|
||||
* ``debug_seq`` - Raises the external debug request.
|
||||
The testbench binary can write to a special memory location to acknowledge the request and cause it to drop.
|
||||
Alternatively the testbench can drop it after a given amount of time.
|
||||
* ``mem_error_seq`` - Injects a memory error in either the instruction side or data side, so the next access results in an error response.
|
||||
* ``reset_seq`` - Resets the core.
|
|
@ -4,7 +4,7 @@ Tracer
|
|||
======
|
||||
|
||||
The module ``ibex_tracer`` can be used to create a log of the executed instructions.
|
||||
It is used by ``ibex_top_tracing`` which forwards the `RVFI signals <https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/rvfi.md>`_ to the tracer (see also :ref:`rvfi`).
|
||||
It is used by ``ibex_core_tracing`` which forwards the `RVFI signals <https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/rvfi.md>`_ to the tracer (see also :ref:`rvfi`).
|
||||
|
||||
Output file
|
||||
-----------
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
.. _verification:
|
||||
|
||||
Verification
|
||||
============
|
||||
|
||||
|
@ -19,14 +17,6 @@ At a high level, this testbench uses the open source `RISCV-DV random instructio
|
|||
simple memory model, stimulates the Ibex core to run this program in memory, and then compares the
|
||||
core trace log against a golden model ISS trace log to check for correctness of execution.
|
||||
|
||||
Verification maturity is tracked via :ref:`verification_stages` that are `defined by the OpenTitan project <https://opentitan.org/book/doc/project_governance/development_stages.html#hardware-verification-stages-v>`_.
|
||||
|
||||
Ibex has achieved **V2S** for the ``opentitan`` configuration, broadly this means verification almost complete (over 90% code and functional coverage hit with over 90% regression pass rate with test plan and coverage plan fully implemented) but not yet closed.
|
||||
|
||||
Nightly regression results, including a coverage summary and details of test failures, for the ``opentitan`` Ibex configuration are published at https://ibex.reports.lowrisc.org/opentitan/latest/report.html. Below is a summary of these results:
|
||||
|
||||
.. image:: https://ibex.reports.lowrisc.org/opentitan/latest/summary.svg
|
||||
|
||||
Testbench Architecture
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -88,7 +78,6 @@ coverage. This includes testing all RV32IMCB instructions, privileged
|
|||
spec compliance, exception and interrupt testing, Debug Mode operation etc.
|
||||
The complete test list can be found in the file `dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml
|
||||
<https://github.com/lowRISC/ibex/blob/master/dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml>`_.
|
||||
For details on coverage see the :ref:`coverage-plan`.
|
||||
|
||||
Please note that verification is still a work in progress.
|
||||
|
||||
|
@ -101,27 +90,18 @@ Prerequisites & Environment Setup
|
|||
In order to run the co-simulation flow, you'll need:
|
||||
|
||||
- A SystemVerilog simulator that supports UVM.
|
||||
|
||||
The flow is currently tested with VCS.
|
||||
|
||||
- The Spike RISC-V instruction set simulator
|
||||
|
||||
lowRISC maintains a `lowRISC-specific Spike fork <LRSpike_>`_, needed to model:
|
||||
+ Cosimulation (needed for verification)
|
||||
+ Some custom CSRs
|
||||
+ Custom NMI behavior
|
||||
|
||||
Ibex verification should work with the Spike version that named ``ibex_cosim``.
|
||||
|
||||
Spike must be built with the ``--enable-commitlog`` and ``--enable-misaligned`` options.
|
||||
- A RISC-V instruction set simulator, such as Spike_ or OVPsim_.
|
||||
Note that when building Spike the ``--enable-commitlog`` and ``--enable-misaligned`` options must be passed to the ``configure`` script.
|
||||
``--enable-commitlog`` is needed to produce log output to track the instructions that were executed.
|
||||
``--enable-misaligned`` tells Spike to simulate a core that handles misaligned accesses in hardware (rather than jumping to a trap handler).
|
||||
|
||||
Note that Ibex used to support the commercial OVPsim simulator.
|
||||
This is not currently possible because OVPsim doesn't support the co-simulation approach that we use.
|
||||
If it is desired to simulate the core with the Icache enabled, a `lowRISC-specific branch of Spike <https://github.com/lowRISC/riscv-isa-sim/tree/ibex>`_ must be used.
|
||||
Ibex supports v0.92 of the Bitmanip specification.
|
||||
The ``master`` branch of Spike_ and OVPSim_ may support a different version.
|
||||
It is recommended the `lowRISC-specific branch of Spike <https://github.com/lowRISC/riscv-isa-sim/tree/ibex>`_ is used when using a configuration with Bitmanip to ensure the simulated version of the Bitmanip specification matches with the RTL implemented version.
|
||||
|
||||
- A working RISC-V toolchain (to compile / assemble the generated programs before simulating them).
|
||||
|
||||
Either download a `pre-built toolchain <riscv-toolchain-releases_>`_ (quicker) or download and build the `RISC-V GNU compiler toolchain <riscv-toolchain-source_>`_.
|
||||
For the latter, the Bitmanip patches have to be manually installed to enable support for the Bitmanip draft extension.
|
||||
For further information, checkout the `Bitmanip Extension on GitHub <bitmanip_>`_ and `how we create the pre-built toolchains <bitmanip-patches_>`_.
|
||||
|
@ -135,12 +115,16 @@ to tell the RISCV-DV code where to find them:
|
|||
export RISCV_GCC="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-gcc"
|
||||
export RISCV_OBJCOPY="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-objcopy"
|
||||
export SPIKE_PATH=/path/to/spike/bin
|
||||
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/path/to/spike/lib/pkgconfig
|
||||
export OVPSIM_PATH=/path/to/ovpsim/bin
|
||||
|
||||
.. _LRSpike: https://github.com/lowRISC/riscv-isa-sim
|
||||
(Obviously, you only need to set ``SPIKE_PATH`` or ``OVPSIM_PATH`` if
|
||||
you have installed the corresponding instruction set simulator)
|
||||
|
||||
.. _Spike: https://github.com/riscv/riscv-isa-sim
|
||||
.. _OVPsim: https://github.com/riscv/riscv-ovpsim
|
||||
.. _riscv-toolchain-source: https://github.com/riscv/riscv-gnu-toolchain
|
||||
.. _riscv-toolchain-releases: https://github.com/lowRISC/lowrisc-toolchains/releases
|
||||
.. _bitmanip-patches: https://github.com/lowRISC/lowrisc-toolchains#how-to-generate-the-bitmanip-patch
|
||||
.. _bitmanip-patches: https://github.com/lowRISC/lowrisc-toolchains#how-to-generate-the-bitmanip-patches
|
||||
.. _bitmanip: https://github.com/riscv/riscv-bitmanip
|
||||
|
||||
End-to-end RTL/ISS co-simulation flow
|
||||
|
@ -165,11 +149,11 @@ proper interrupt handler, entered Debug Mode properly, updated any CSRs correctl
|
|||
handshaking mechanism provided by the RISCV-DV instruction generator is heavily used, which
|
||||
effectively allows the core to send status information to the testbench during program execution for
|
||||
any analysis that is required to increase verification effectiveness.
|
||||
This mechanism is explained in detail at https://github.com/google/riscv-dv/blob/master/docs/source/handshake.rst.
|
||||
This mechanism is explained in detail at https://github.com/google/riscv-dv/blob/master/HANDSHAKE.md.
|
||||
As a sidenote, the signature address that this testbench uses for the handshaking is ``0x8ffffffc``.
|
||||
Additionally, as is mentioned in the RISCV-DV documentation of this handshake, a small set of API
|
||||
tasks are provided in `dv/uvm/core_ibex/tests/core_ibex_base_test.sv
|
||||
<https://github.com/lowRISC/ibex/blob/master/dv/uvm/core_ibex/tests/core_ibex_base_test.sv>`_ to enable easy
|
||||
<https://github.com/lowRISC/ibex/blob/master/dv/uvm/core_ibex/tests/core_ibex_base_tests.sv>`_ to enable easy
|
||||
and efficient integration and usage of this mechanism in this test environment.
|
||||
To see how this handshake is used during real simulations, look in
|
||||
`dv/uvm/core_ibex/tests/core_ibex_test_lib.sv
|
||||
|
@ -215,9 +199,15 @@ The entirety of this flow is controlled by the Makefile found at
|
|||
# Generate the assembly tests only
|
||||
make gen
|
||||
|
||||
# Pass addtional options to the generator
|
||||
make GEN_OPTS="xxxx" ...
|
||||
|
||||
# Compile and run RTL simulation
|
||||
make TEST=xxx compile,rtl_sim
|
||||
|
||||
# Use a different ISS (default is spike)
|
||||
make ... ISS=ovpsim
|
||||
|
||||
# Run a full regression with coverage
|
||||
make COV=1
|
||||
|
||||
|
|
|
@ -1,224 +0,0 @@
|
|||
.. _verification_stages:
|
||||
|
||||
Verification Stages
|
||||
===================
|
||||
|
||||
Ibex is being verified as part of the `OpenTitan <https://www.opentitan.org>`_ project and follows the `verification stages used in OpenTitan <https://opentitan.org/book/doc/project_governance/development_stages.html#hardware-verification-stages-v>`_.
|
||||
The current verification stage of the 'opentitan' configuration of Ibex is **V2S**.
|
||||
The full definition of V2S can be found at the `OpenTitan V2 <https://opentitan.org/book/doc/project_governance/checklist/index.html#v2>`_ and `OpenTitan V2S <https://opentitan.org/book/doc/project_governance/checklist/index.html#v2s>`_ checklists.
|
||||
Other Ibex configurations do not have a formal verification stage at present.
|
||||
|
||||
V1 Checklist
|
||||
------------
|
||||
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Type | Item | Resolution | Notes |
|
||||
+===============+====================================+============+=======================================================+
|
||||
| Documentation | DV_DOC_DRAFT_COMPLETE | Waived | Plan created, but does not conform to other templates |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Documentation | TESTPLAN_COMPLETED | Done | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Testbench | TB_TOP_CREATED | Done | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Testbench | PRELIMINARY_ASSERTION_CHECKS_ADDED | N/A | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Testbench | SIM_TB_ENV_CREATED | Done | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Testbench | SIM_RAL_MODEL_GEN_AUTOMATED | N/A | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Testbench | CSR_CHECK_GEN_AUTOMATED | N/A | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Testbench | TB_GEN_AUTOMATED | N/A | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Tests | SIM_SMOKE_TEST_PASSING | Done | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Tests | SIM_CSR_MEM_TEST_SUITE_PASSING | Done | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Tests | FPV_MAIN_ASSERTIONS_PROVEN | N/A | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Tool Setup | SIM_ALT_TOOL_SETUP | Waived | waived for now, doesn’t follow standard tool flow |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Regression | SIM_SMOKE_REGRESSION_SETUP | Done | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Regression | SIM_NIGHTLY_REGRESSION_SETUP | Done | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Regression | FPV_REGRESSION_SETUP | N/A | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Coverage | SIM_COVERAGE_MODEL_ADDED | Done | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Code Quality | TB_LINT_SETUP | Waived | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Integration | PRE_VERIFIED_SUB_MODULES_V1 | N/A | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Review | DESIGN_SPEC_REVIEWED | Done | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Review | TESTPLAN_REVIEWED | Waived | Not done, will be reviewed in V2 |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Review | STD_TEST_CATEGORIES_PLANNED | Done | different format than comportable modules |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
| Review | V2_CHECKLIST_SCOPED | Done | |
|
||||
+---------------+------------------------------------+------------+-------------------------------------------------------+
|
||||
|
||||
V2 Checklist
|
||||
------------
|
||||
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Type | Item | Resolution | Notes |
|
||||
+===============+=====================================+============+======================================================================================================================================================================+
|
||||
| Documentation | DESIGN_DELTAS_CAPTURED_V2 | Complete | |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Testbench | FUNCTIONAL_COVERAGE_IMPLEMENTED | Complete | |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Testbench | ALL_INTERFACES_EXERCISED | Complete | |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Testbench | ALL_ASSERTION_CHECKS_ADDED | Complete | |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Testbench | SIM_TB_ENV_COMPLETED | Complete | |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Tests | SIM_ALL_TESTS_PASSING | Complete | Note the ``riscv_assorted_traps_interrupts_debug`` test sees many failures (but does have some seeds that pass). |
|
||||
| | | | The test attempts to generally combine many different stimuli and under OpenTitan classification would be considered a V3 test. |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Tests | FPV_ALL_ASSERTIONS_WRITTEN | N/A | No formal applied for non-security features in Ibex. |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Tests | FPV_ALL_ASSUMPTIONS_REVIEWED | N/A | No formal applied for non-security features in Ibex. |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Tests | SIM_FW_SIMULATED | N/A | No ROM or firmware present. |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Regression | SIM_NIGHTLY_REGRESSION_V2 | Complete | Regression run in GitHub Actions only accessible to OpenTitan members. |
|
||||
| | | | Publicly viewable reports on the `OpenTitan regression dashboard <https://reports.opentitan.org/hw/top_earlgrey/dv/summary/latest/report.html>`_ are planned for V3. |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Coverage | SIM_CODE_COVERAGE_V2 | Complete | Coverage results available in nightly regression run. |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Coverage | SIM_FUNCTIONAL_COVERAGE_V2 | Complete | Coverage results available in nightly regression run. |
|
||||
| | | | Note the average grade (the average of coverage % for each individual coverpoint and cross) is used for the 90% figure. |
|
||||
| | | | As the functional coverage contains some very large crosses a simple % of all bins hit biases too much toward these crosses. |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Coverage | FPV_CODE_COVERAGE_V2 | N/A | No formal applied for non-security features in Ibex. |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Coverage | FPV_COI_COVERAGE_V2 | N/A | No formal applied for non-security features in Ibex. |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Integration | PRE_VERIFIED_SUB_MODULES_V2 | Complete | ICache is verified in a seperate testbench. |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Issues | NO_HIGH_PRIORITY_ISSUES_PENDING | Complete | |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Issues | ALL_LOW_PRIORITY_ISSUES_ROOT_CAUSED | Complete | |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Review | DV_DOC_TESTPLAN_REVIEWED | Complete | |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Review | V3_CHECKLIST_SCOPED | Complete | |
|
||||
+---------------+-------------------------------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
**PMP Testing Note**: A large number of iterations of ``pmp_full_random_test`` are required to meet coverage goals and timed out tests must be included in the coverage collection.
|
||||
This is because of the large cross bins for PMP that aim to explore the full space of possible behaviour.
|
||||
The current strategy of random generation is very inefficient at exploring this space.
|
||||
It is also complex to write a randomly generated test that can deal with all possible scenarios without hitting a double faulting or time out scenarios (e.g. consider a random configuration that gives you no executable regions and ePMP modes like machine mode lockdown and machine mode whitelist policy).
|
||||
Co-simulation checking is enabled when this test is run (as it is for all block level verification tests) so would detect any incorrect behaviour.
|
||||
From investigation we are confident the time-outs seen are simply badly performing tests (e.g. very slowly working its way through an instruction block with no execute permissions by attempting to execute one instruction, faulting, trying the next and getting the same result over and over).
|
||||
For future work we will explore more efficient strategies for exploring this space as well as employing formal methods to achieve full verification closure.
|
||||
|
||||
V2S Checklist
|
||||
-------------
|
||||
|
||||
+---------------+--------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Type | Item | Resolution | Notes |
|
||||
+===============+==========================+============+======================================================================================================================================+
|
||||
| Documentation | SEC_CM_TESTPLAN_COMPLETE | Complete | The security counter measure to test mapping can be found below |
|
||||
+---------------+--------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Tests | FPV_SEC_CM_VERIFIED | Complete | See the `OpenTitan FPV Results Dashboard <https://reports.opentitan.org/hw/top_earlgrey/formal/sec_cm/summary/latest/report.html>`_. |
|
||||
+---------------+--------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Tests | SIM_SEC_CM_VERIFIED | Complete | |
|
||||
+---------------+--------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Coverage | SIM_COVERAGE_REVIEWED | Complete | |
|
||||
+---------------+--------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Review | SEC_CM_DV_REVIEWED | Complete | |
|
||||
+---------------+--------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Ibex SEC_CM Test Mapping
|
||||
------------------------
|
||||
|
||||
The :ref:`security features Ibex implements <security>` are given specific security countermeasure names in OpenTitan (see 'Security Countermeasures' in the `Comportability Definition and Specification <https://opentitan.org/book/doc/contributing/hw/comportability/index.html#security-countermeasures>`_ documentation section).
|
||||
Each countermeasure has a test that exercises it.
|
||||
The mapping between countermeasures and tests is given below
|
||||
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Security Countermeasure | Test |
|
||||
+================================+============================================================================================================================================================================================================================================================================================================+
|
||||
| BUS.INTEGRITY | ``riscv_mem_intg_error_test`` in Ibex DV. |
|
||||
| | The ``chip_sw_data_integrity`` OpenTitan top-level test will trigger integrity errors within the OpenTitan specific ``rv_core_ibex`` wrapper. |
|
||||
| | The TL-UL host adapter used in the OpenTitan specific ``rv_core_ibex`` is fully verified elsewhere in OpenTitan. |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| SCRAMBLE.KEY.SIDELOAD | ``riscv_rand_instr_test`` in Ibex DV. |
|
||||
| | This test executes ``FENCE.I`` which rotates the scramble key. |
|
||||
| | The ``rv_core_ibex_icache_invalidate_test`` OpenTitan top-level test covers assertions within the OpenTitan specific ``rv_core_ibex`` wrapper that check that a ``FENCE.I`` results in an icache scramble key request and that the returned key is correctly supplied to the scrambling memory primitives. |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| CORE.DATA_REG_SW.SCA | ``dit_test`` directed test run against simple system cosimulation. |
|
||||
| | The test runs functions that whose timing is data dependent with data independent timing disabled. |
|
||||
| | It passes where the runs with data independent timing enabled all execute in the same amount of time and the runs without it enabled take different amounts of time. |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| PC.CTRL_FLOW.CONSISTENCY | ``riscv_pc_intg_test`` in Ibex DV. |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| CTRL_FLOW.UNPREDICTABLE | ``dummy_instr_test`` directed test run against simple system cosimulation. |
|
||||
| | The test runs a function with dummy instructions disabled and enabled. |
|
||||
| | It passes where the runs without dummy instructions all have the same timing and runs with dummy instructions all have different timing. |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| DATA_REG_SW.INTEGRITY | ``riscv_rf_intg_test`` in Ibex DV. |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| DATA_REG_SW.GLITCH_DETECT | Covered by formal verification of security countermeasures within OpenTitan. |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| LOGIC.SHADOW | ``chip_sw_rv_core_ibex_lockstep_glitch`` top-level test in OpenTitan |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| FETCH.CTRL.LC_GATED | ``riscv_rand_instr_test`` in Ibex DV. |
|
||||
| | Fetch enable is randomly toggled in various tests and correct behaviour checked via an assertion. |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| EXCEPTION.CTRL_FLOW.LOCAL_ESC | ``riscv_pmp_full_random_test`` in Ibex DV. |
|
||||
| | This test produces double faults, which are checked by an assertion. |
|
||||
| | ``chip_sw_rv_core_ibex_double_fault`` top-level test in OpenTitan demonstrates escalation on a double fault |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| EXCEPTION.CTRL_FLOW.GLOBAL_ESC | ``riscv_pmp_full_random_test`` in Ibex DV. |
|
||||
| | This test produces double faults, which are checked by an assertion. |
|
||||
| | ``chip_sw_rv_core_ibex_double_fault`` top-level test in OpenTitan demonstrates escalation on a double fault |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| ICACHE.MEM.SCRAMBLE | No explicit testing, the scrambling memory primitive is seperately verified within OpenTitan. |
|
||||
| | Assertions in the OpenTitan specific ``rv_core_ibex`` wrapper ensure a newly requested scramble key is correctly applied to the scrambling memories. |
|
||||
| | The ``rv_core_ibex_icache_invalidate_test`` OpenTitan top-level test covers assertions within the OpenTitan specific ``rv_core_ibex`` wrapper that check that a ``FENCE.I`` results in an icache scramble key request and that the returned key is correctly supplied to the scrambling memory primitives. |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| ICACHE.MEM.INTEGRITY | ``riscv_icache_intg_test`` in Ibex DV. |
|
||||
+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
V3 Checklist
|
||||
------------
|
||||
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Type | Item | Resolution | Notes |
|
||||
+===============+================================+=============+=======+
|
||||
| Documentation | DESIGN_DELTAS_CAPTURED_V3 | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Tests | X_PROP_ANALYSIS_COMPLETED | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Tests | FPV_ASSERTIONS_PROVEN_AT_V3 | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Regression | SIM_NIGHTLY_REGRESSION_AT_V3 | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Coverage | SIM_CODE_COVERAGE_AT_100 | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Coverage | SIM_FUNCTIONAL_COVERAGE_AT_100 | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Coverage | FPV_CODE_COVERAGE_AT_100 | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Coverage | FPV_COI_COVERAGE_AT_100 | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Code Quality | ALL_TODOS_RESOLVED | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Code Quality | NO_TOOL_WARNINGS_THROWN | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Code Quality | TB_LINT_COMPLETE | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Integration | PRE_VERIFIED_SUB_MODULES_V3 | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Issues | NO_ISSUES_PENDING | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Review | Reviewer(s) | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
| Review | Signoff date | Not Started | |
|
||||
+---------------+--------------------------------+-------------+-------+
|
||||
|
|
@ -25,8 +25,10 @@ The concierge duties rotate between several core developers on a weekly basis.
|
|||
You can find today's concierge on duty in a `public calendar <https://calendar.google.com/calendar/embed?src=lowrisc.org_s0pdodkddnggdp40jusjij27h4%40group.calendar.google.com>`_.
|
||||
|
||||
* Greg Chadwick (`@GregAC <https://github.com/gregac>`_)
|
||||
* Tom Roberts (`@tomroberts-lowrisc <https://github.com/tomroberts-lowrisc>`_)
|
||||
* Rupert Swarbrick (`@rswarbrick <https://github.com/rswarbrick>`_)
|
||||
* Pirmin Vogel (`@vogelpi <https://github.com/vogelpi>`_)
|
||||
* Philipp Wagner (`@imphil <https://github.com/imphil>`_)
|
||||
|
||||
You can be Ibex Concierge, too.
|
||||
Please talk to any of the current concierges to discuss!
|
||||
|
|
5
doc/_static/theme_overrides.css
vendored
5
doc/_static/theme_overrides.css
vendored
|
@ -11,8 +11,3 @@
|
|||
overflow: visible !important;
|
||||
}
|
||||
}
|
||||
|
||||
.wy-nav-content {
|
||||
max-width: 1000px !important;
|
||||
}
|
||||
|
||||
|
|
28
doc/conf.py
28
doc/conf.py
|
@ -12,19 +12,12 @@
|
|||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# Source top directory
|
||||
topsrcdir = os.path.join(os.path.dirname(__file__), '..')
|
||||
|
||||
old_sys_path = sys.path
|
||||
try:
|
||||
sys.path.append(os.path.join(topsrcdir, 'util'))
|
||||
import check_tool_requirements as ctr
|
||||
finally:
|
||||
sys.path = old_sys_path
|
||||
|
||||
|
||||
numfig=True
|
||||
numfig_format = {'figure': 'Figure %s', 'table': 'Table %s', 'code-block': 'Listing %s'}
|
||||
|
||||
|
@ -42,9 +35,7 @@ extensions = [
|
|||
'sphinx.ext.todo',
|
||||
]
|
||||
|
||||
# Wavedrom
|
||||
wavedrom_html_jsinline = False
|
||||
render_using_wavedrompy = True
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
@ -114,9 +105,11 @@ html_logo = 'images/logo.svg'
|
|||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
html_css_files = [
|
||||
'theme_overrides.css', # Fix wide tables in RTD theme
|
||||
]
|
||||
html_context = {
|
||||
'css_files' : [
|
||||
'_static/theme_overrides.css', # Fix wide tables in RTD theme
|
||||
],
|
||||
}
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
|
@ -173,8 +166,7 @@ texinfo_documents = [
|
|||
|
||||
# Add minimum versions of required tools as variables for use inside the
|
||||
# documentation.
|
||||
tool_reqs = ctr.read_tool_requirements()
|
||||
exec(open(os.path.join(topsrcdir, 'tool_requirements.py')).read())
|
||||
rst_epilog = ""
|
||||
for tool, req in tool_reqs.items():
|
||||
rst_epilog += (".. |tool_requirements.{}| replace:: {}\n"
|
||||
.format(tool, req.min_version))
|
||||
for tool_name, tool_version in __TOOL_REQUIREMENTS__.items():
|
||||
rst_epilog += ".. |tool_requirements.{}| replace:: {}\n".format(tool_name, tool_version)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
setuptools_scm
|
||||
sphinx>=7.0
|
||||
sphinx>=2.1.0
|
||||
sphinx_rtd_theme
|
||||
sphinxcontrib-wavedrom
|
||||
wavedrom>=1.9.0rc1
|
||||
jinja2 == 3.0.3
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: "lowrisc:dv:cosim"
|
||||
description: "Co-simulator framework"
|
||||
filesets:
|
||||
files_cpp:
|
||||
files:
|
||||
- cosim.h: { is_include_file: true }
|
||||
- spike_cosim.cc
|
||||
- spike_cosim.h: { is_include_file: true }
|
||||
file_type: cppSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_cpp
|
166
dv/cosim/cosim.h
166
dv/cosim/cosim.h
|
@ -1,166 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifndef COSIM_H_
|
||||
#define COSIM_H_
|
||||
|
||||
// Information about a dside transaction observed on the DUT memory interface
|
||||
struct DSideAccessInfo {
|
||||
// set when the access is a store, in which case `data` is the store data from
|
||||
// the DUT. Otherwise `data` is the load data provided to the DUT.
|
||||
bool store;
|
||||
// `addr` is the address and must be 32-bit aligned. `data` and `be` are
|
||||
// aligned to the address. For example an 8-bit store of 0xff to 0x12 has
|
||||
// `data` as 0x00ff0000, `addr` as 0x10 and `be` as 0b0100.
|
||||
uint32_t data;
|
||||
uint32_t addr;
|
||||
uint32_t be;
|
||||
|
||||
// set if an error response to the transaction is seen.
|
||||
bool error;
|
||||
|
||||
// `misaligned_first` and `misaligned_second` are set when the transaction is
|
||||
// generated for a misaligned store or load instruction. `misaligned_first`
|
||||
// is true when the transaction is for the lower half and `misaligned_second`
|
||||
// is true when the transaction is for the upper half, if it exists.
|
||||
//
|
||||
// For example an unaligned 32-bit load to 0x3 produces a transaction with
|
||||
// `addr` as 0x0 and `misaligned_first` set to true, then a transaction with
|
||||
// `addr` as 0x4 and `misaligned_second` set to true. An unaligned 16-bit load
|
||||
// to 0x01 only produces a transaction with `addr` as 0x0 and
|
||||
// `misaligned_first` set to true, there is no second half.
|
||||
bool misaligned_first;
|
||||
bool misaligned_second;
|
||||
|
||||
bool misaligned_first_saw_error;
|
||||
|
||||
bool m_mode_access;
|
||||
};
|
||||
|
||||
class Cosim {
|
||||
public:
|
||||
virtual ~Cosim() {}
|
||||
|
||||
// Add a memory to the co-simulator environment.
|
||||
//
|
||||
// Use `backdoor_write_mem`/`backdoor_read_mem` to access it from the
|
||||
// simulation environment.
|
||||
virtual void add_memory(uint32_t base_addr, size_t size) = 0;
|
||||
|
||||
// Write bytes to co-simulator memory.
|
||||
//
|
||||
// returns false if write fails (e.g. because no memory exists at the bytes
|
||||
// being written).
|
||||
virtual bool backdoor_write_mem(uint32_t addr, size_t len,
|
||||
const uint8_t *data_in) = 0;
|
||||
|
||||
// Read bytes from co-simulator memory.
|
||||
//
|
||||
// returns false if read fails (e.g. because no memory exists at the bytes
|
||||
// being read).
|
||||
virtual bool backdoor_read_mem(uint32_t addr, size_t len,
|
||||
uint8_t *data_out) = 0;
|
||||
|
||||
// Step the co-simulator, checking register write and PC of executed
|
||||
// instruction match the supplied values. `write_reg` gives the index of the
|
||||
// written register along with `write_reg_data` which provides the data. A
|
||||
// `write_reg` of 0 indicates no register write occurred.
|
||||
//
|
||||
// `sync_trap` is set to true when the instruction caused a synchronous trap.
|
||||
// In this case the instruction doesn't retire so no register write occurs (so
|
||||
// `write_reg` must be 0).
|
||||
//
|
||||
// Returns false if there are any errors; use `get_errors` to obtain details
|
||||
virtual bool step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc,
|
||||
bool sync_trap, bool suppress_reg_write) = 0;
|
||||
|
||||
// When more than one of `set_mip`, `set_nmi` or `set_debug_req` is called
|
||||
// before `step` which one takes effect is chosen by the co-simulator. Which
|
||||
// should take priority is architecturally defined by the RISC-V
|
||||
// specification.
|
||||
|
||||
// Set the value of MIP.
|
||||
//
|
||||
// Two versions of MIP must be supplied the `pre_mip` and the `post_mip`. The
|
||||
// `pre_mip` is the value of MIP that is used to determine if an interrupt is
|
||||
// pending. The `post_mip` is the value of MIP that the next instruction
|
||||
// executed (which will be the first instruction of the interrupt vector when
|
||||
// an interrupt ir triggered) observes. These will be different in the case
|
||||
// where an interrupt is raised triggering an interrupt handler but then
|
||||
// drops before the first instruction of the handler has executed.
|
||||
//
|
||||
// At the next call of `step`, the MIP values will take effect (i.e. if it's a
|
||||
// new interrupt that is enabled it will step straight to that handler).
|
||||
virtual void set_mip(uint32_t pre_mip, uint32_t post_mip) = 0;
|
||||
|
||||
// Set the state of the NMI (non-maskable interrupt) line.
|
||||
//
|
||||
// The NMI signal is a level triggered interrupt. When the NMI is taken the
|
||||
// CPU ignores the NMI line until an `mret` instruction is executed. If the
|
||||
// NMI is high following the `mret` (regardless of whether it has been low or
|
||||
// not whilst the first NMI is being handled) a new NMI is taken.
|
||||
//
|
||||
// When an NMI is due to be taken that will occur at the next call of `step`.
|
||||
virtual void set_nmi(bool nmi) = 0;
|
||||
|
||||
// Set the state of the internal NMI (non-maskable interrupt) line.
|
||||
// Behaviour wise this is almost as same as external NMI case explained at
|
||||
// set_nmi method. Difference is that this one is a response from Ibex rather
|
||||
// than an input.
|
||||
virtual void set_nmi_int(bool nmi_int) = 0;
|
||||
|
||||
// Set the debug request.
|
||||
//
|
||||
// When set to true the core will enter debug mode at the next step
|
||||
virtual void set_debug_req(bool debug_req) = 0;
|
||||
|
||||
// Set the value of mcycle.
|
||||
//
|
||||
// The co-simulation model doesn't alter the value of mcycle itself (other
|
||||
// than instructions that do a direct CSR write). mcycle should be set to the
|
||||
// correct value before any `step` call that may execute an instruction that
|
||||
// observes the value of mcycle.
|
||||
//
|
||||
// A full 64-bit value is provided setting both the mcycle and mcycleh CSRs.
|
||||
virtual void set_mcycle(uint64_t mcycle) = 0;
|
||||
|
||||
// Set the value of a CSR. This is used when it is needed to have direct
|
||||
// communication between DUT and Spike (e.g. Performance counters).
|
||||
virtual void set_csr(const int csr_num, const uint32_t new_val) = 0;
|
||||
|
||||
// Set the ICache scramble key valid bit that is visible in CPUCTRLSTS.
|
||||
virtual void set_ic_scr_key_valid(bool valid) = 0;
|
||||
|
||||
// Tell the co-simulation model about observed transactions on the dside
|
||||
// memory interface of the DUT. Accesses are notified once the response to a
|
||||
// transaction is seen.
|
||||
//
|
||||
// Observed transactions for the DUT are checked against accesses from the
|
||||
// co-simulation model when a memory access occurs during a `step`. If there
|
||||
// is a mismatch an error is reported which can be obtained via `get_errors`.
|
||||
virtual void notify_dside_access(const DSideAccessInfo &access_info) = 0;
|
||||
|
||||
// Tell the co-simulation model about an error response to an iside fetch.
|
||||
//
|
||||
// `addr` must be 32-bit aligned.
|
||||
//
|
||||
// The next step following a call to `set_iside_error` must produce an
|
||||
// instruction fault at the given address.
|
||||
virtual void set_iside_error(uint32_t addr) = 0;
|
||||
|
||||
// Get a vector of strings describing errors that have occurred during `step`
|
||||
virtual const std::vector<std::string> &get_errors() = 0;
|
||||
|
||||
// Clear internal vector of error descriptions
|
||||
virtual void clear_errors() = 0;
|
||||
|
||||
// Returns a count of instructions executed by co-simulator and DUT without
|
||||
// failures.
|
||||
virtual unsigned int get_insn_cnt() = 0;
|
||||
};
|
||||
|
||||
#endif // COSIM_H_
|
|
@ -1,128 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "cosim_dpi.h"
|
||||
|
||||
#include <svdpi.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "cosim.h"
|
||||
|
||||
int riscv_cosim_step(Cosim *cosim, const svBitVecVal *write_reg,
|
||||
const svBitVecVal *write_reg_data, const svBitVecVal *pc,
|
||||
svBit sync_trap, svBit suppress_reg_write) {
|
||||
assert(cosim);
|
||||
|
||||
return cosim->step(write_reg[0], write_reg_data[0], pc[0], sync_trap,
|
||||
suppress_reg_write)
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
void riscv_cosim_set_mip(Cosim *cosim, const svBitVecVal *pre_mip,
|
||||
const svBitVecVal *post_mip) {
|
||||
assert(cosim);
|
||||
|
||||
cosim->set_mip(pre_mip[0], post_mip[0]);
|
||||
}
|
||||
|
||||
void riscv_cosim_set_nmi(Cosim *cosim, svBit nmi) {
|
||||
assert(cosim);
|
||||
|
||||
cosim->set_nmi(nmi);
|
||||
}
|
||||
|
||||
void riscv_cosim_set_nmi_int(Cosim *cosim, svBit nmi_int) {
|
||||
assert(cosim);
|
||||
|
||||
cosim->set_nmi_int(nmi_int);
|
||||
}
|
||||
void riscv_cosim_set_debug_req(Cosim *cosim, svBit debug_req) {
|
||||
assert(cosim);
|
||||
|
||||
cosim->set_debug_req(debug_req);
|
||||
}
|
||||
|
||||
void riscv_cosim_set_mcycle(Cosim *cosim, svBitVecVal *mcycle) {
|
||||
assert(cosim);
|
||||
|
||||
uint64_t mcycle_full = mcycle[0] | (uint64_t)mcycle[1] << 32;
|
||||
cosim->set_mcycle(mcycle_full);
|
||||
}
|
||||
|
||||
void riscv_cosim_set_csr(Cosim *cosim, const int csr_id,
|
||||
const svBitVecVal *csr_val) {
|
||||
assert(cosim);
|
||||
|
||||
cosim->set_csr(csr_id, (uint32_t)csr_val[0]);
|
||||
}
|
||||
|
||||
void riscv_cosim_set_ic_scr_key_valid(Cosim *cosim, svBit valid) {
|
||||
assert(cosim);
|
||||
|
||||
cosim->set_ic_scr_key_valid(valid);
|
||||
}
|
||||
|
||||
void riscv_cosim_notify_dside_access(Cosim *cosim, svBit store,
|
||||
svBitVecVal *addr, svBitVecVal *data,
|
||||
svBitVecVal *be, svBit error,
|
||||
svBit misaligned_first,
|
||||
svBit misaligned_second,
|
||||
svBit misaligned_first_saw_error,
|
||||
svBit m_mode_access) {
|
||||
assert(cosim);
|
||||
|
||||
cosim->notify_dside_access(DSideAccessInfo{
|
||||
.store = store != 0,
|
||||
.data = data[0],
|
||||
.addr = addr[0],
|
||||
.be = be[0],
|
||||
.error = error != 0,
|
||||
.misaligned_first = misaligned_first != 0,
|
||||
.misaligned_second = misaligned_second != 0,
|
||||
.misaligned_first_saw_error = misaligned_first_saw_error != 0,
|
||||
.m_mode_access = m_mode_access != 0});
|
||||
}
|
||||
|
||||
void riscv_cosim_set_iside_error(Cosim *cosim, svBitVecVal *addr) {
|
||||
assert(cosim);
|
||||
|
||||
cosim->set_iside_error(addr[0]);
|
||||
}
|
||||
|
||||
int riscv_cosim_get_num_errors(Cosim *cosim) {
|
||||
assert(cosim);
|
||||
|
||||
return cosim->get_errors().size();
|
||||
}
|
||||
|
||||
const char *riscv_cosim_get_error(Cosim *cosim, int index) {
|
||||
assert(cosim);
|
||||
|
||||
if (index >= cosim->get_errors().size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return cosim->get_errors()[index].c_str();
|
||||
}
|
||||
|
||||
void riscv_cosim_clear_errors(Cosim *cosim) {
|
||||
assert(cosim);
|
||||
|
||||
cosim->clear_errors();
|
||||
}
|
||||
|
||||
void riscv_cosim_write_mem_byte(Cosim *cosim, const svBitVecVal *addr,
|
||||
const svBitVecVal *d) {
|
||||
assert(cosim);
|
||||
uint8_t byte = d[0] & 0xff;
|
||||
cosim->backdoor_write_mem(addr[0], 1, &byte);
|
||||
}
|
||||
|
||||
unsigned int riscv_cosim_get_insn_cnt(Cosim *cosim) {
|
||||
assert(cosim);
|
||||
|
||||
return cosim->get_insn_cnt();
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: "lowrisc:dv:cosim_dpi"
|
||||
description: "DPI wrapper for Co-simulator framework"
|
||||
filesets:
|
||||
files_cpp:
|
||||
depend:
|
||||
- lowrisc:dv:cosim
|
||||
files:
|
||||
- cosim_dpi.cc: { file_type: cppSource }
|
||||
- cosim_dpi.h: { file_type: cppSource, is_include_file: true }
|
||||
- cosim_dpi.svh: {file_type: systemVerilogSource }
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_cpp
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef COSIM_DPI_H_
|
||||
#define COSIM_DPI_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <svdpi.h>
|
||||
|
||||
#include "cosim.h"
|
||||
|
||||
// This adapts the C++ interface of the `Cosim` class to be used via DPI. See
|
||||
// the documentation in cosim.h for further details
|
||||
|
||||
extern "C" {
|
||||
int riscv_cosim_step(Cosim *cosim, const svBitVecVal *write_reg,
|
||||
const svBitVecVal *write_reg_data, const svBitVecVal *pc,
|
||||
svBit sync_trap, svBit suppress_reg_write);
|
||||
void riscv_cosim_set_mip(Cosim *cosim, const svBitVecVal *pre_mip,
|
||||
const svBitVecVal *post_mip);
|
||||
void riscv_cosim_set_nmi(Cosim *cosim, svBit nmi);
|
||||
void riscv_cosim_set_nmi_int(Cosim *cosim, svBit nmi_int);
|
||||
void riscv_cosim_set_debug_req(Cosim *cosim, svBit debug_req);
|
||||
void riscv_cosim_set_mcycle(Cosim *cosim, svBitVecVal *mcycle);
|
||||
void riscv_cosim_set_csr(Cosim *cosim, const int csr_id,
|
||||
const svBitVecVal *csr_val);
|
||||
void riscv_cosim_set_ic_scr_key_valid(Cosim *cosim, svBit valid);
|
||||
void riscv_cosim_notify_dside_access(Cosim *cosim, svBit store,
|
||||
svBitVecVal *addr, svBitVecVal *data,
|
||||
svBitVecVal *be, svBit error,
|
||||
svBit misaligned_first,
|
||||
svBit misaligned_second,
|
||||
svBit misaligned_first_saw_error,
|
||||
svBit m_mode_access);
|
||||
void riscv_cosim_set_iside_error(Cosim *cosim, svBitVecVal *addr);
|
||||
int riscv_cosim_get_num_errors(Cosim *cosim);
|
||||
const char *riscv_cosim_get_error(Cosim *cosim, int index);
|
||||
void riscv_cosim_clear_errors(Cosim *cosim);
|
||||
void riscv_cosim_write_mem_byte(Cosim *cosim, const svBitVecVal *addr,
|
||||
const svBitVecVal *d);
|
||||
unsigned int riscv_cosim_get_insn_cnt(Cosim *cosim);
|
||||
}
|
||||
|
||||
#endif // COSIM_DPI_H_
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// DPI interface to co-simulation model, see `cosim.h` for the interface description.
|
||||
|
||||
// Implemented as a header file as VCS needs `import` declarations included in each verilog file
|
||||
// that uses them.
|
||||
|
||||
`ifndef COSIM_DPI_SVH
|
||||
`define COSIM_DPI_SVH
|
||||
|
||||
import "DPI-C" function int riscv_cosim_step(chandle cosim_handle, bit [4:0] write_reg,
|
||||
bit [31:0] write_reg_data, bit [31:0] pc, bit sync_trap, bit suppress_reg_write);
|
||||
import "DPI-C" function void riscv_cosim_set_mip(chandle cosim_handle, bit [31:0] pre_mip,
|
||||
bit [31:0] post_mip);
|
||||
import "DPI-C" function void riscv_cosim_set_nmi(chandle cosim_handle, bit nmi);
|
||||
import "DPI-C" function void riscv_cosim_set_nmi_int(chandle cosim_handle, bit nmi_int);
|
||||
import "DPI-C" function void riscv_cosim_set_debug_req(chandle cosim_handle, bit debug_req);
|
||||
import "DPI-C" function void riscv_cosim_set_mcycle(chandle cosim_handle, bit [63:0] mcycle);
|
||||
import "DPI-C" function void riscv_cosim_set_csr(chandle cosim_handle, int csr_id,
|
||||
bit [31:0] csr_val);
|
||||
import "DPI-C" function void riscv_cosim_set_ic_scr_key_valid(chandle cosim_handle, bit valid);
|
||||
import "DPI-C" function void riscv_cosim_notify_dside_access(chandle cosim_handle, bit store,
|
||||
bit [31:0] addr, bit [31:0] data, bit [3:0] be, bit error, bit misaligned_first,
|
||||
bit misaligned_second, bit misaligned_first_saw_error, bit m_mode_access);
|
||||
import "DPI-C" function int riscv_cosim_set_iside_error(chandle cosim_handle, bit [31:0] addr);
|
||||
import "DPI-C" function int riscv_cosim_get_num_errors(chandle cosim_handle);
|
||||
import "DPI-C" function string riscv_cosim_get_error(chandle cosim_handle, int index);
|
||||
import "DPI-C" function void riscv_cosim_clear_errors(chandle cosim_handle);
|
||||
import "DPI-C" function void riscv_cosim_write_mem_byte(chandle cosim_handle, bit [31:0] addr,
|
||||
bit [7:0] d);
|
||||
import "DPI-C" function int unsigned riscv_cosim_get_insn_cnt(chandle cosim_handle);
|
||||
|
||||
`endif
|
File diff suppressed because it is too large
Load diff
|
@ -1,147 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef SPIKE_COSIM_H_
|
||||
#define SPIKE_COSIM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cosim.h"
|
||||
#include "riscv/devices.h"
|
||||
#include "riscv/log_file.h"
|
||||
#include "riscv/processor.h"
|
||||
#include "riscv/simif.h"
|
||||
|
||||
#define IBEX_MARCHID 22
|
||||
|
||||
class SpikeCosim : public simif_t, public Cosim {
|
||||
private:
|
||||
// A sigsegv has been observed when deleting isa_parser_t instances under
|
||||
// Xcelium on CentOS 7. The root cause is unknown so for a workaround simply
|
||||
// use a raw pointer for isa_parser that never gets deleted. This produces a
|
||||
// minor memory leak but it is of little consequence as when SpikeCosim is
|
||||
// being deleted it is the end of simulation and the process will be
|
||||
// terminated shortly anyway.
|
||||
#ifdef COSIM_SIGSEGV_WORKAROUND
|
||||
isa_parser_t *isa_parser;
|
||||
#else
|
||||
std::unique_ptr<isa_parser_t> isa_parser;
|
||||
#endif
|
||||
std::unique_ptr<processor_t> processor;
|
||||
std::unique_ptr<log_file_t> log;
|
||||
bus_t bus;
|
||||
std::vector<std::unique_ptr<mem_t>> mems;
|
||||
std::vector<std::string> errors;
|
||||
bool nmi_mode;
|
||||
|
||||
typedef struct {
|
||||
uint8_t mpp;
|
||||
bool mpie;
|
||||
uint32_t epc;
|
||||
uint32_t cause;
|
||||
} mstack_t;
|
||||
|
||||
mstack_t mstack;
|
||||
|
||||
void fixup_csr(int csr_num, uint32_t csr_val);
|
||||
|
||||
struct PendingMemAccess {
|
||||
DSideAccessInfo dut_access_info;
|
||||
uint32_t be_spike;
|
||||
};
|
||||
|
||||
std::vector<PendingMemAccess> pending_dside_accesses;
|
||||
|
||||
bool pending_iside_error;
|
||||
uint32_t pending_iside_err_addr;
|
||||
|
||||
typedef enum {
|
||||
kCheckMemOk, // Checks passed and access succeded in RTL
|
||||
kCheckMemCheckFailed, // Checks failed
|
||||
kCheckMemBusError // Checks passed, but access generated bus error in RTL
|
||||
} check_mem_result_e;
|
||||
|
||||
check_mem_result_e check_mem_access(bool store, uint32_t addr, size_t len,
|
||||
const uint8_t *bytes);
|
||||
|
||||
bool pc_is_mret(uint32_t pc);
|
||||
bool pc_is_load(uint32_t pc, uint32_t &rd_out);
|
||||
|
||||
bool pc_is_debug_ebreak(uint32_t pc);
|
||||
bool check_debug_ebreak(uint32_t write_reg, uint32_t pc, bool sync_trap);
|
||||
|
||||
bool check_gpr_write(const commit_log_reg_t::value_type ®_change,
|
||||
uint32_t write_reg, uint32_t write_reg_data);
|
||||
|
||||
bool check_suppress_reg_write(uint32_t write_reg, uint32_t pc,
|
||||
uint32_t &suppressed_write_reg);
|
||||
|
||||
void on_csr_write(const commit_log_reg_t::value_type ®_change);
|
||||
|
||||
void leave_nmi_mode();
|
||||
|
||||
bool change_cpuctrlsts_sync_exc_seen(bool flag);
|
||||
void set_cpuctrlsts_double_fault_seen();
|
||||
void handle_cpuctrl_exception_entry();
|
||||
|
||||
void initial_proc_setup(uint32_t start_pc, uint32_t start_mtvec,
|
||||
uint32_t mhpm_counter_num);
|
||||
|
||||
void early_interrupt_handle();
|
||||
|
||||
void misaligned_pmp_fixup();
|
||||
|
||||
unsigned int insn_cnt;
|
||||
|
||||
public:
|
||||
SpikeCosim(const std::string &isa_string, uint32_t start_pc,
|
||||
uint32_t start_mtvec, const std::string &trace_log_path,
|
||||
bool secure_ibex, bool icache_en, uint32_t pmp_num_regions,
|
||||
uint32_t pmp_granularity, uint32_t mhpm_counter_num);
|
||||
|
||||
// simif_t implementation
|
||||
virtual char *addr_to_mem(reg_t addr) override;
|
||||
virtual bool mmio_load(reg_t addr, size_t len, uint8_t *bytes) override;
|
||||
virtual bool mmio_store(reg_t addr, size_t len,
|
||||
const uint8_t *bytes) override;
|
||||
virtual void proc_reset(unsigned id) override;
|
||||
virtual const char *get_symbol(uint64_t addr) override;
|
||||
|
||||
// Cosim implementation
|
||||
void add_memory(uint32_t base_addr, size_t size) override;
|
||||
bool backdoor_write_mem(uint32_t addr, size_t len,
|
||||
const uint8_t *data_in) override;
|
||||
bool backdoor_read_mem(uint32_t addr, size_t len, uint8_t *data_out) override;
|
||||
bool step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc,
|
||||
bool sync_trap, bool suppress_reg_write) override;
|
||||
|
||||
bool check_retired_instr(uint32_t write_reg, uint32_t write_reg_data,
|
||||
uint32_t dut_pc, bool suppress_reg_write);
|
||||
bool check_sync_trap(uint32_t write_reg, uint32_t pc,
|
||||
uint32_t initial_spike_pc);
|
||||
void set_mip(uint32_t pre_mip, uint32_t post_mip) override;
|
||||
void set_nmi(bool nmi) override;
|
||||
void set_nmi_int(bool nmi_int) override;
|
||||
void set_debug_req(bool debug_req) override;
|
||||
void set_mcycle(uint64_t mcycle) override;
|
||||
void set_csr(const int csr_num, const uint32_t new_val) override;
|
||||
void set_ic_scr_key_valid(bool valid) override;
|
||||
void notify_dside_access(const DSideAccessInfo &access_info) override;
|
||||
// The spike co-simulator assumes iside and dside accesses within a step are
|
||||
// disjoint. If both access the same address within a step memory faults may
|
||||
// be incorrectly cause on one rather than the other or the access checking
|
||||
// will break.
|
||||
// TODO: Work on spike changes to remove this restriction
|
||||
void set_iside_error(uint32_t addr) override;
|
||||
const std::vector<std::string> &get_errors() override;
|
||||
void clear_errors() override;
|
||||
unsigned int get_insn_cnt() override;
|
||||
};
|
||||
|
||||
#endif // SPIKE_COSIM_H_
|
|
@ -9,7 +9,7 @@
|
|||
// 'rtl' directory), see verilator_waiver_rtl.vlt in the same
|
||||
// directory.
|
||||
//
|
||||
// See https://verilator.org/guide/latest/exe_verilator.html#configuration-files
|
||||
// See https://www.veripool.org/projects/verilator/wiki/Manual-verilator#CONFIGURATION-FILES
|
||||
// for documentation.
|
||||
//
|
||||
// Important: This file must included *before* any other Verilog file is read.
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "base_register.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
BaseRegister::BaseRegister(
|
||||
|
@ -33,8 +32,8 @@ uint32_t BaseRegister::RegisterClear(uint32_t newval) {
|
|||
return read_value;
|
||||
}
|
||||
|
||||
bool BaseRegister::MatchAddr(uint32_t addr, uint32_t addr_mask) {
|
||||
return ((addr & addr_mask) == (register_address_ & addr_mask));
|
||||
bool BaseRegister::MatchAddr(uint32_t addr) {
|
||||
return (addr == register_address_);
|
||||
}
|
||||
|
||||
bool BaseRegister::ProcessTransaction(bool *match, RegisterTransaction *trans) {
|
||||
|
@ -83,62 +82,7 @@ uint32_t BaseRegister::RegisterRead() { return register_value_; }
|
|||
|
||||
uint32_t BaseRegister::GetLockMask() { return 0; }
|
||||
|
||||
BaseRegister *BaseRegister::GetRegisterFromMap(uint32_t addr) {
|
||||
for (auto ® : *map_pointer_) {
|
||||
if (reg->MatchAddr(addr)) {
|
||||
return reg.get();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MSeccfgRegister::MSeccfgRegister(
|
||||
uint32_t addr, std::vector<std::unique_ptr<BaseRegister>> *map_pointer)
|
||||
: BaseRegister(addr, map_pointer) {}
|
||||
|
||||
bool MSeccfgRegister::AnyPmpCfgsLocked() {
|
||||
for (auto ® : *map_pointer_) {
|
||||
// Iterate through PMPCfgX CSRs, returning true is any has a lock bit set
|
||||
if (reg->MatchAddr(kCSRPMPCfg0, 0xfffffffc)) {
|
||||
if ((reg->RegisterRead() & 0x80808080) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t MSeccfgRegister::GetLockMask() {
|
||||
uint32_t lock_mask = 0xFFFFFFF8;
|
||||
|
||||
// When RLB == 0 and any PMPCfgX has a lock bit set RLB must remain 0
|
||||
if (AnyPmpCfgsLocked() && ((register_value_ & kMSeccfgRlb) == 0)) {
|
||||
lock_mask |= kMSeccfgRlb;
|
||||
}
|
||||
|
||||
// Once set MMWP cannot be unset
|
||||
if (register_value_ & kMSeccfgMmwp) {
|
||||
lock_mask |= kMSeccfgMmwp;
|
||||
}
|
||||
|
||||
// Once set MML cannot be unset
|
||||
if (register_value_ & kMSeccfgMml) {
|
||||
lock_mask |= kMSeccfgMml;
|
||||
}
|
||||
|
||||
return lock_mask;
|
||||
}
|
||||
|
||||
uint32_t PmpCfgRegister::GetLockMask() {
|
||||
BaseRegister *mseccfg = GetRegisterFromMap(kCSRMSeccfg);
|
||||
assert(mseccfg);
|
||||
|
||||
if (mseccfg->RegisterRead() & kMSeccfgRlb) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t lock_mask = 0;
|
||||
if (register_value_ & 0x80)
|
||||
lock_mask |= 0xFF;
|
||||
|
@ -154,53 +98,44 @@ uint32_t PmpCfgRegister::GetLockMask() {
|
|||
uint32_t PmpCfgRegister::RegisterWrite(uint32_t newval) {
|
||||
uint32_t lock_mask = GetLockMask();
|
||||
uint32_t read_value = register_value_;
|
||||
|
||||
register_value_ &= lock_mask;
|
||||
register_value_ |= (newval & ~lock_mask);
|
||||
register_value_ = HandleReservedVals(register_value_);
|
||||
|
||||
register_value_ &= raz_mask_;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// Reserved check, W = 1, R = 0
|
||||
if (((register_value_ >> (8 * i)) & 0x3) == 0x2) {
|
||||
register_value_ &= ~(0x3 << (8 * i));
|
||||
}
|
||||
}
|
||||
return read_value;
|
||||
}
|
||||
|
||||
uint32_t PmpCfgRegister::RegisterSet(uint32_t newval) {
|
||||
uint32_t lock_mask = GetLockMask();
|
||||
uint32_t read_value = register_value_;
|
||||
|
||||
register_value_ |= (newval & ~lock_mask);
|
||||
register_value_ = HandleReservedVals(register_value_);
|
||||
|
||||
register_value_ &= raz_mask_;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// Reserved check, W = 1, R = 0
|
||||
if (((register_value_ >> (8 * i)) & 0x3) == 0x2) {
|
||||
register_value_ &= ~(0x3 << (8 * i));
|
||||
}
|
||||
}
|
||||
return read_value;
|
||||
}
|
||||
|
||||
uint32_t PmpCfgRegister::RegisterClear(uint32_t newval) {
|
||||
uint32_t lock_mask = GetLockMask();
|
||||
uint32_t read_value = register_value_;
|
||||
|
||||
register_value_ &= (~newval | lock_mask);
|
||||
register_value_ = HandleReservedVals(register_value_);
|
||||
|
||||
return read_value;
|
||||
}
|
||||
|
||||
uint32_t PmpCfgRegister::HandleReservedVals(uint32_t cfg_val) {
|
||||
BaseRegister *mseccfg = GetRegisterFromMap(kCSRMSeccfg);
|
||||
assert(mseccfg);
|
||||
|
||||
cfg_val &= raz_mask_;
|
||||
|
||||
if (mseccfg->RegisterRead() & kMSeccfgMml) {
|
||||
// No reserved L/R/W/X values when MML Set
|
||||
return cfg_val;
|
||||
}
|
||||
|
||||
register_value_ &= raz_mask_;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// Reserved check, W = 1, R = 0
|
||||
if (((cfg_val >> (8 * i)) & 0x3) == 0x2) {
|
||||
cfg_val &= ~(0x3 << (8 * i));
|
||||
if (((register_value_ >> (8 * i)) & 0x3) == 0x2) {
|
||||
register_value_ &= ~(0x3 << (8 * i));
|
||||
}
|
||||
}
|
||||
|
||||
return cfg_val;
|
||||
return read_value;
|
||||
}
|
||||
|
||||
uint32_t PmpAddrRegister::GetLockMask() {
|
||||
|
|
|
@ -26,30 +26,13 @@ class BaseRegister {
|
|||
virtual uint32_t RegisterClear(uint32_t newval);
|
||||
virtual uint32_t RegisterRead();
|
||||
virtual bool ProcessTransaction(bool *match, RegisterTransaction *trans);
|
||||
virtual bool MatchAddr(uint32_t addr, uint32_t addr_mask = 0xFFFFFFFF);
|
||||
virtual bool MatchAddr(uint32_t addr);
|
||||
virtual uint32_t GetLockMask();
|
||||
|
||||
protected:
|
||||
uint32_t register_value_;
|
||||
uint32_t register_address_;
|
||||
std::vector<std::unique_ptr<BaseRegister>> *map_pointer_;
|
||||
BaseRegister *GetRegisterFromMap(uint32_t addr);
|
||||
};
|
||||
|
||||
/**
|
||||
* Machine Security Configuration class
|
||||
*
|
||||
* Has special behaviour for when bits are locked so requires a custom
|
||||
* `GetLockMask` implementation
|
||||
*/
|
||||
class MSeccfgRegister : public BaseRegister {
|
||||
public:
|
||||
MSeccfgRegister(uint32_t addr,
|
||||
std::vector<std::unique_ptr<BaseRegister>> *map_pointer);
|
||||
uint32_t GetLockMask();
|
||||
|
||||
private:
|
||||
bool AnyPmpCfgsLocked();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -65,7 +48,6 @@ class PmpCfgRegister : public BaseRegister {
|
|||
uint32_t RegisterClear(uint32_t newval);
|
||||
|
||||
private:
|
||||
uint32_t HandleReservedVals(uint32_t cfg_val);
|
||||
const uint32_t raz_mask_ = 0x9F9F9F9F;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
#include <iostream>
|
||||
|
||||
RegisterModel::RegisterModel(SimCtrl *sc, CSRParams *params) : simctrl_(sc) {
|
||||
register_map_.push_back(
|
||||
std::make_unique<MSeccfgRegister>(kCSRMSeccfg, ®ister_map_));
|
||||
register_map_.push_back(
|
||||
std::make_unique<NonImpRegister>(kCSRMSeccfgh, ®ister_map_));
|
||||
// Instantiate all the registers
|
||||
for (unsigned int i = 0; i < 4; i++) {
|
||||
uint32_t reg_addr = 0x3A0 + i;
|
||||
|
@ -33,11 +29,11 @@ RegisterModel::RegisterModel(SimCtrl *sc, CSRParams *params) : simctrl_(sc) {
|
|||
}
|
||||
}
|
||||
// mcountinhibit
|
||||
// - MSBs are always 0: unused counters cannot be inhibited
|
||||
// - MSBs are always 1: unused counters cannot be enabled
|
||||
// - Bit 1 is always 0: time cannot be disabled
|
||||
uint32_t mcountinhibit_mask =
|
||||
(~((0x1 << params->MHPMCounterNum) - 1) << 3) | 0x2;
|
||||
uint32_t mcountinhibit_resval = 0;
|
||||
uint32_t mcountinhibit_resval = ~((0x1 << params->MHPMCounterNum) - 1) << 3;
|
||||
register_map_.push_back(std::make_unique<WARLRegister>(
|
||||
0x320, ®ister_map_, mcountinhibit_mask, mcountinhibit_resval));
|
||||
// Performance counter setup
|
||||
|
@ -45,7 +41,7 @@ RegisterModel::RegisterModel(SimCtrl *sc, CSRParams *params) : simctrl_(sc) {
|
|||
uint32_t reg_addr = 0x320 + i;
|
||||
if (i < (params->MHPMCounterNum + 3)) {
|
||||
register_map_.push_back(std::make_unique<WARLRegister>(
|
||||
reg_addr, ®ister_map_, 0xFFFFFFFF, 0x1 << (i - 3)));
|
||||
reg_addr, ®ister_map_, 0xFFFFFFFF, 0x1 << i));
|
||||
} else {
|
||||
register_map_.push_back(
|
||||
std::make_unique<NonImpRegister>(reg_addr, ®ister_map_));
|
||||
|
|
|
@ -58,8 +58,6 @@ CSR(MHPMEvent28, 0x33C)
|
|||
CSR(MHPMEvent29, 0x33D)
|
||||
CSR(MHPMEvent30, 0x33E)
|
||||
CSR(MHPMEvent31, 0x33F)
|
||||
CSR(MSeccfg, 0x747)
|
||||
CSR(MSeccfgh, 0x757)
|
||||
CSR(MCycle, 0xB00)
|
||||
CSR(MInstret, 0xB02)
|
||||
CSR(MHPMCounter3, 0xB03)
|
||||
|
|
|
@ -15,11 +15,6 @@ enum CSRegisterAddr : int {
|
|||
#include "csr_listing.def"
|
||||
};
|
||||
|
||||
// Individual bits for MSECCFG CSR
|
||||
const int kMSeccfgMml = 0x1;
|
||||
const int kMSeccfgMmwp = 0x2;
|
||||
const int kMSeccfgRlb = 0x4;
|
||||
|
||||
// Create an indexable array of all CSR addresses
|
||||
static const uint16_t CSRAddresses[] = {
|
||||
#define CSR(reg, addr) addr,
|
||||
|
|
|
@ -33,11 +33,6 @@ module tb_cs_registers #(
|
|||
|
||||
logic illegal_csr_insn_o;
|
||||
|
||||
logic csr_access_d;
|
||||
ibex_pkg::csr_num_e csr_addr_d;
|
||||
logic [31:0] csr_wdata_d;
|
||||
ibex_pkg::csr_op_e csr_op_d;
|
||||
logic csr_op_en_d;
|
||||
//-----------------
|
||||
// Reset generation
|
||||
//-----------------
|
||||
|
@ -126,26 +121,12 @@ module tb_cs_registers #(
|
|||
csr_addr_i,
|
||||
csr_wdata_i,
|
||||
csr_rdata_o);
|
||||
|
||||
reg_dpi::driver_tick("reg_driver",
|
||||
csr_access_d,
|
||||
csr_op_d,
|
||||
csr_op_en_d,
|
||||
csr_addr_d,
|
||||
csr_wdata_d);
|
||||
|
||||
// Use NBA to drive inputs to ensure correct scheduling.
|
||||
// This always_ff block will be executed on the positive edge of the clock with undefined order
|
||||
// vs all other always_ff triggered on the positive edge of the clock. If `driver_tick` drives
|
||||
// the inputs directly some of the always_ff blocks will see the old version of the inputs and
|
||||
// others will see the new version depending on scheduling order. This schedules all the inputs
|
||||
// to be NBA updates to avoid the race condition (in effect acting like any other always_ff
|
||||
// block with the _d values being computed via DPI rather than combinational logic).
|
||||
csr_access_i <= csr_access_d;
|
||||
csr_addr_i <= csr_addr_d;
|
||||
csr_wdata_i <= csr_wdata_d;
|
||||
csr_op_i <= csr_op_d;
|
||||
csr_op_en_i <= csr_op_en_d;
|
||||
csr_access_i,
|
||||
csr_op_i,
|
||||
csr_op_en_i,
|
||||
csr_addr_i,
|
||||
csr_wdata_i);
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -13,11 +13,9 @@ int main(int argc, char **argv) {
|
|||
simctrl.SetTop(&top, &top.IO_CLK, &top.IO_RST_N,
|
||||
VerilatorSimCtrlFlags::ResetPolarityNegative);
|
||||
|
||||
MemArea ram(
|
||||
"TOP.ibex_riscv_compliance.u_ram.u_ram.gen_generic.u_impl_generic",
|
||||
64 * 1024 / 4, 4);
|
||||
|
||||
memutil.RegisterMemoryArea("ram", 0x0, &ram);
|
||||
memutil.RegisterMemoryArea(
|
||||
"ram",
|
||||
"TOP.ibex_riscv_compliance.u_ram.u_ram.gen_generic.u_impl_generic");
|
||||
simctrl.RegisterExtension(&memutil);
|
||||
|
||||
return simctrl.Exec(argc, argv).first;
|
||||
|
|
|
@ -5,23 +5,24 @@ CAPI=2:
|
|||
name: "lowrisc:ibex:ibex_riscv_compliance:0.1"
|
||||
description: "Ibex simulation for RISC-V compliance testing (using Verilator)"
|
||||
filesets:
|
||||
files_sim:
|
||||
depend:
|
||||
- lowrisc:ibex:ibex_top_tracing
|
||||
- lowrisc:ibex:sim_shared
|
||||
files:
|
||||
- rtl/ibex_riscv_compliance.sv
|
||||
- rtl/riscv_testutil.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_verilator:
|
||||
files_sim_verilator:
|
||||
depend:
|
||||
- lowrisc:dv_verilator:memutil_verilator
|
||||
- lowrisc:dv_verilator:simutil_verilator
|
||||
- lowrisc:ibex:ibex_core_tracing
|
||||
- lowrisc:ibex:sim_shared
|
||||
|
||||
files:
|
||||
- rtl/ibex_riscv_compliance.sv
|
||||
- ibex_riscv_compliance.cc: { file_type: cppSource }
|
||||
- rtl/riscv_testutil.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_verilator_waiver:
|
||||
files:
|
||||
- lint/verilator_waiver.vlt: {file_type: vlt}
|
||||
|
||||
|
||||
parameters:
|
||||
RV32E:
|
||||
datatype: int
|
||||
|
@ -77,24 +78,6 @@ parameters:
|
|||
default: 0
|
||||
description: "Enables static branch prediction (EXPERIMENTAL)"
|
||||
|
||||
DbgTriggerEn:
|
||||
datatype: int
|
||||
default: 0
|
||||
paramtype: vlogparam
|
||||
description: "Enable support for debug triggers. "
|
||||
|
||||
SecureIbex:
|
||||
datatype: int
|
||||
default: 0
|
||||
paramtype: vlogparam
|
||||
description: "Enables security hardening features (EXPERIMENTAL) [0/1]"
|
||||
|
||||
ICacheScramble:
|
||||
datatype: int
|
||||
default: 0
|
||||
paramtype: vlogparam
|
||||
description: "Enables ICache scrambling feature (EXPERIMENTAL) [0/1]"
|
||||
|
||||
PMPEnable:
|
||||
datatype: int
|
||||
default: 0
|
||||
|
@ -113,24 +96,12 @@ parameters:
|
|||
paramtype: vlogparam
|
||||
description: "Number of PMP regions"
|
||||
|
||||
MHPMCounterNum:
|
||||
datatype: int
|
||||
paramtype: vlogparam
|
||||
default: 0
|
||||
description: Number of performance monitor event counters [0/29]
|
||||
|
||||
MHPMCounterWidth:
|
||||
datatype: int
|
||||
paramtype: vlogparam
|
||||
default: 40
|
||||
description: Bit width of performance monitor event counters [32/64]
|
||||
|
||||
targets:
|
||||
sim:
|
||||
default_tool: verilator
|
||||
filesets:
|
||||
- files_sim
|
||||
- tool_verilator ? (files_verilator)
|
||||
- tool_verilator ? (files_verilator_waiver)
|
||||
- files_sim_verilator
|
||||
parameters:
|
||||
- RV32E
|
||||
- RV32M
|
||||
|
@ -141,14 +112,9 @@ targets:
|
|||
- BranchTargetALU
|
||||
- WritebackStage
|
||||
- BranchPredictor
|
||||
- DbgTriggerEn
|
||||
- SecureIbex
|
||||
- ICacheScramble
|
||||
- PMPEnable
|
||||
- PMPGranularity
|
||||
- PMPNumRegions
|
||||
- MHPMCounterNum
|
||||
- MHPMCounterWidth
|
||||
toplevel: ibex_riscv_compliance
|
||||
tools:
|
||||
verilator:
|
||||
|
@ -161,6 +127,6 @@ targets:
|
|||
- '--trace-structs'
|
||||
- '--trace-params'
|
||||
- '--trace-max-array 1024'
|
||||
- '-CFLAGS "-std=c++14 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=ibex_riscv_compliance -g"'
|
||||
- '-CFLAGS "-std=c++11 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=ibex_riscv_compliance -g"'
|
||||
- '-LDFLAGS "-pthread -lutil -lelf"'
|
||||
- "-Wall"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// 'rtl' directory), see verilator_waiver_rtl.vlt in the same
|
||||
// directory.
|
||||
//
|
||||
// See https://verilator.org/guide/latest/exe_verilator.html#configuration-files
|
||||
// See https://www.veripool.org/projects/verilator/wiki/Manual-verilator#CONFIGURATION-FILES
|
||||
// for documentation.
|
||||
//
|
||||
// Important: This file must included *before* any other Verilog file is read.
|
||||
|
|
|
@ -15,23 +15,18 @@ module ibex_riscv_compliance (
|
|||
input IO_RST_N
|
||||
);
|
||||
|
||||
parameter bit PMPEnable = 1'b0;
|
||||
parameter int unsigned PMPGranularity = 0;
|
||||
parameter int unsigned PMPNumRegions = 4;
|
||||
parameter int unsigned MHPMCounterNum = 0;
|
||||
parameter int unsigned MHPMCounterWidth = 40;
|
||||
parameter bit RV32E = 1'b0;
|
||||
parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast;
|
||||
parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone;
|
||||
parameter ibex_pkg::regfile_e RegFile = ibex_pkg::RegFileFF;
|
||||
parameter bit BranchTargetALU = 1'b0;
|
||||
parameter bit WritebackStage = 1'b0;
|
||||
parameter bit ICache = 1'b0;
|
||||
parameter bit ICacheECC = 1'b0;
|
||||
parameter bit BranchPredictor = 1'b0;
|
||||
parameter bit SecureIbex = 1'b0;
|
||||
parameter bit ICacheScramble = 1'b0;
|
||||
parameter bit DbgTriggerEn = 1'b0;
|
||||
parameter bit PMPEnable = 1'b0;
|
||||
parameter int unsigned PMPGranularity = 0;
|
||||
parameter int unsigned PMPNumRegions = 4;
|
||||
parameter bit RV32E = 1'b0;
|
||||
parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast;
|
||||
parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone;
|
||||
parameter ibex_pkg::regfile_e RegFile = ibex_pkg::RegFileFF;
|
||||
parameter bit BranchTargetALU = 1'b0;
|
||||
parameter bit WritebackStage = 1'b0;
|
||||
parameter bit ICache = 1'b0;
|
||||
parameter bit ICacheECC = 1'b0;
|
||||
parameter bit BranchPredictor = 1'b0;
|
||||
|
||||
logic clk_sys, rst_sys_n;
|
||||
|
||||
|
@ -66,9 +61,6 @@ module ibex_riscv_compliance (
|
|||
logic [31:0] host_rdata [NrHosts];
|
||||
logic host_err [NrHosts];
|
||||
|
||||
logic [6:0] ibex_data_rdata_intg;
|
||||
logic [6:0] ibex_instr_rdata_intg;
|
||||
|
||||
// devices (slaves)
|
||||
logic device_req [NrDevices];
|
||||
logic [31:0] device_addr [NrDevices];
|
||||
|
@ -87,6 +79,7 @@ module ibex_riscv_compliance (
|
|||
assign cfg_device_addr_base[TestUtilDevice] = 32'h20000;
|
||||
assign cfg_device_addr_mask[TestUtilDevice] = ~32'h3FF; // 1 kB
|
||||
|
||||
|
||||
bus #(
|
||||
.NrDevices (NrDevices),
|
||||
.NrHosts (NrHosts ),
|
||||
|
@ -119,98 +112,60 @@ module ibex_riscv_compliance (
|
|||
.cfg_device_addr_mask
|
||||
);
|
||||
|
||||
if (SecureIbex) begin : g_mem_rdata_ecc
|
||||
logic [31:0] unused_data_rdata;
|
||||
logic [31:0] unused_instr_rdata;
|
||||
ibex_core_tracing #(
|
||||
.PMPEnable (PMPEnable ),
|
||||
.PMPGranularity (PMPGranularity ),
|
||||
.PMPNumRegions (PMPNumRegions ),
|
||||
.RV32E (RV32E ),
|
||||
.RV32M (RV32M ),
|
||||
.RV32B (RV32B ),
|
||||
.RegFile (RegFile ),
|
||||
.BranchTargetALU (BranchTargetALU ),
|
||||
.WritebackStage (WritebackStage ),
|
||||
.ICache (ICache ),
|
||||
.ICacheECC (ICacheECC ),
|
||||
.BranchPredictor (BranchPredictor ),
|
||||
.DmHaltAddr (32'h00000000 ),
|
||||
.DmExceptionAddr (32'h00000000 )
|
||||
) u_core (
|
||||
.clk_i (clk_sys ),
|
||||
.rst_ni (rst_sys_n ),
|
||||
|
||||
prim_secded_inv_39_32_enc u_data_rdata_intg_gen (
|
||||
.data_i (host_rdata[CoreD]),
|
||||
.data_o ({ibex_data_rdata_intg, unused_data_rdata})
|
||||
);
|
||||
.test_en_i ('b0 ),
|
||||
|
||||
prim_secded_inv_39_32_enc u_instr_rdata_intg_gen (
|
||||
.data_i (host_rdata[CoreI]),
|
||||
.data_o ({ibex_instr_rdata_intg, unused_instr_rdata})
|
||||
);
|
||||
end else begin : g_no_mem_rdata_ecc
|
||||
assign ibex_data_rdata_intg = '0;
|
||||
assign ibex_instr_rdata_intg = '0;
|
||||
end
|
||||
|
||||
ibex_top_tracing #(
|
||||
.PMPEnable (PMPEnable ),
|
||||
.PMPGranularity (PMPGranularity ),
|
||||
.PMPNumRegions (PMPNumRegions ),
|
||||
.MHPMCounterNum (MHPMCounterNum ),
|
||||
.MHPMCounterWidth (MHPMCounterWidth ),
|
||||
.RV32E (RV32E ),
|
||||
.RV32M (RV32M ),
|
||||
.RV32B (RV32B ),
|
||||
.RegFile (RegFile ),
|
||||
.BranchTargetALU (BranchTargetALU ),
|
||||
.WritebackStage (WritebackStage ),
|
||||
.ICache (ICache ),
|
||||
.ICacheECC (ICacheECC ),
|
||||
.BranchPredictor (BranchPredictor ),
|
||||
.DbgTriggerEn (DbgTriggerEn ),
|
||||
.SecureIbex (SecureIbex ),
|
||||
.ICacheScramble (ICacheScramble ),
|
||||
.DmBaseAddr (32'h00000000 ),
|
||||
.DmAddrMask (32'h00000003 ),
|
||||
.DmHaltAddr (32'h00000000 ),
|
||||
.DmExceptionAddr (32'h00000000 )
|
||||
) u_top (
|
||||
.clk_i (clk_sys ),
|
||||
.rst_ni (rst_sys_n ),
|
||||
|
||||
.test_en_i ('b0 ),
|
||||
.scan_rst_ni (1'b1 ),
|
||||
.ram_cfg_i ('b0 ),
|
||||
|
||||
.hart_id_i (32'b0 ),
|
||||
.hart_id_i (32'b0 ),
|
||||
// First instruction executed is at 0x0 + 0x80
|
||||
.boot_addr_i (32'h00000000 ),
|
||||
.boot_addr_i (32'h00000000 ),
|
||||
|
||||
.instr_req_o (host_req[CoreI] ),
|
||||
.instr_gnt_i (host_gnt[CoreI] ),
|
||||
.instr_rvalid_i (host_rvalid[CoreI] ),
|
||||
.instr_addr_o (host_addr[CoreI] ),
|
||||
.instr_rdata_i (host_rdata[CoreI] ),
|
||||
.instr_rdata_intg_i (ibex_instr_rdata_intg),
|
||||
.instr_err_i (host_err[CoreI] ),
|
||||
.instr_req_o (host_req[CoreI] ),
|
||||
.instr_gnt_i (host_gnt[CoreI] ),
|
||||
.instr_rvalid_i (host_rvalid[CoreI]),
|
||||
.instr_addr_o (host_addr[CoreI] ),
|
||||
.instr_rdata_i (host_rdata[CoreI] ),
|
||||
.instr_err_i (host_err[CoreI] ),
|
||||
|
||||
.data_req_o (host_req[CoreD] ),
|
||||
.data_gnt_i (host_gnt[CoreD] ),
|
||||
.data_rvalid_i (host_rvalid[CoreD] ),
|
||||
.data_we_o (host_we[CoreD] ),
|
||||
.data_be_o (host_be[CoreD] ),
|
||||
.data_addr_o (host_addr[CoreD] ),
|
||||
.data_wdata_o (host_wdata[CoreD] ),
|
||||
.data_wdata_intg_o ( ),
|
||||
.data_rdata_i (host_rdata[CoreD] ),
|
||||
.data_rdata_intg_i (ibex_data_rdata_intg ),
|
||||
.data_err_i (host_err[CoreD] ),
|
||||
.data_req_o (host_req[CoreD] ),
|
||||
.data_gnt_i (host_gnt[CoreD] ),
|
||||
.data_rvalid_i (host_rvalid[CoreD]),
|
||||
.data_we_o (host_we[CoreD] ),
|
||||
.data_be_o (host_be[CoreD] ),
|
||||
.data_addr_o (host_addr[CoreD] ),
|
||||
.data_wdata_o (host_wdata[CoreD] ),
|
||||
.data_rdata_i (host_rdata[CoreD] ),
|
||||
.data_err_i (host_err[CoreD] ),
|
||||
|
||||
.irq_software_i (1'b0 ),
|
||||
.irq_timer_i (1'b0 ),
|
||||
.irq_external_i (1'b0 ),
|
||||
.irq_fast_i (15'b0 ),
|
||||
.irq_nm_i (1'b0 ),
|
||||
.irq_software_i (1'b0 ),
|
||||
.irq_timer_i (1'b0 ),
|
||||
.irq_external_i (1'b0 ),
|
||||
.irq_fast_i (15'b0 ),
|
||||
.irq_nm_i (1'b0 ),
|
||||
|
||||
.scramble_key_valid_i ('0 ),
|
||||
.scramble_key_i ('0 ),
|
||||
.scramble_nonce_i ('0 ),
|
||||
.scramble_req_o ( ),
|
||||
.debug_req_i ('b0 ),
|
||||
|
||||
.debug_req_i ('b0 ),
|
||||
.crash_dump_o ( ),
|
||||
.double_fault_seen_o ( ),
|
||||
|
||||
.fetch_enable_i (ibex_pkg::IbexMuBiOn ),
|
||||
.alert_minor_o ( ),
|
||||
.alert_major_internal_o ( ),
|
||||
.alert_major_bus_o ( ),
|
||||
.core_sleep_o ( )
|
||||
.fetch_enable_i ('b1 ),
|
||||
.alert_minor_o ( ),
|
||||
.alert_major_o ( ),
|
||||
.core_sleep_o ( )
|
||||
);
|
||||
|
||||
// SRAM block for instruction and data storage
|
||||
|
|
|
@ -5,20 +5,14 @@
|
|||
project: ibex
|
||||
|
||||
// These keys are expected by dvsim.py, so we have to set them to something.
|
||||
book: bogus.book.domain
|
||||
doc_server: bogus.doc.server
|
||||
results_server: bogus.results.server
|
||||
results_html_name: report.html
|
||||
doc_server: bogus.doc.server
|
||||
results_server: bogus.results.server
|
||||
|
||||
// Default directory structure for the output
|
||||
scratch_base_path: "{scratch_root}/{dut}.{flow}.{tool}"
|
||||
scratch_path: "{scratch_base_path}/{branch}"
|
||||
tool_srcs_dir: "{scratch_path}/{tool}"
|
||||
|
||||
// Common DVSIM data structures
|
||||
build_pass_patterns: []
|
||||
build_fail_patterns: []
|
||||
|
||||
// The current design level
|
||||
design_level: "ip"
|
||||
}
|
||||
|
|
25
dv/uvm/core_ibex/.gitignore
vendored
25
dv/uvm/core_ibex/.gitignore
vendored
|
@ -1,25 +0,0 @@
|
|||
# This is generated by VCS when running DV simulations with WAVE=1.
|
||||
ucli.key
|
||||
|
||||
# This is generated by UVM when running simulations and doesn't seem
|
||||
# to be something you can disable.
|
||||
tr_db.log
|
||||
|
||||
# This is the default output directory in dv/uvm/core_ibex and
|
||||
# contains auto-generated files from building and running tests.
|
||||
out
|
||||
|
||||
# This is generated by the Makefile based on the ibex configuration
|
||||
riscv_dv_extension/riscv_core_setting.sv
|
||||
|
||||
# This is generated by Xcelium when running DV simulations, even with WAVE=0
|
||||
waves.shm
|
||||
|
||||
# Log files generated by Cadence tools when running DV simulations
|
||||
xrun.history
|
||||
xrun.log
|
||||
xmsc.log
|
||||
|
||||
# Generated by coverage
|
||||
imc.key
|
||||
mdv.log
|
|
@ -2,20 +2,11 @@
|
|||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Top-Level Makefile
|
||||
###############################################################################
|
||||
|
||||
.SUFFIXES:
|
||||
export
|
||||
GEN_DIR := $(realpath ../../../vendor/google_riscv-dv)
|
||||
TOOLCHAIN := ${RISCV_TOOLCHAIN}
|
||||
|
||||
# Explicitly ask for the bash shell
|
||||
SHELL := bash
|
||||
|
||||
# Build the 'all' target by default, override with e.g. GOAL=rtl_tb_compile
|
||||
GOAL ?= all
|
||||
|
||||
###############################################################################
|
||||
# CONFIGURATION KNOBS
|
||||
SHELL := bash
|
||||
|
||||
# Seed for instruction generator and RTL simulation
|
||||
#
|
||||
|
@ -26,79 +17,423 @@ GOAL ?= all
|
|||
# start passing again without fixing the bug).
|
||||
SEED := $(shell echo $$RANDOM)
|
||||
|
||||
# This is the top-level output directory. Everything we generate goes in
|
||||
# here. Most generated stuff actually goes in $(OUT)/seed-$(SEED), which allows
|
||||
# us to run multiple times without deleting existing results.
|
||||
OUT := out
|
||||
OUT-SEED := $(OUT)/seed-$(SEED)
|
||||
|
||||
# Run time options for the instruction generator
|
||||
GEN_OPTS :=
|
||||
# Compile time options for ibex RTL simulation
|
||||
COMPILE_OPTS +=
|
||||
# Run time options for ibex RTL simulation
|
||||
SIM_OPTS :=
|
||||
# Enable waveform dumping
|
||||
WAVES := 0
|
||||
WAVES := 1
|
||||
# Enable coverage dump
|
||||
COV := 0
|
||||
# RTL simulator (xlm, vcs, questa, dsim, )
|
||||
SIMULATOR := xlm
|
||||
# RTL simulator
|
||||
SIMULATOR := vcs
|
||||
# ISS (spike, ovpsim)
|
||||
ISS := spike
|
||||
# ISS runtime options
|
||||
ISS_OPTS :=
|
||||
# ISA
|
||||
ISA := rv32imcb
|
||||
# Test name (default: full regression)
|
||||
TEST := all
|
||||
RISCV-DV-TESTLIST := riscv_dv_extension/testlist.yaml
|
||||
DIRECTED-TESTLIST := directed_tests/directed_testlist.yaml
|
||||
TESTLIST := riscv_dv_extension/testlist.yaml
|
||||
# Verbose logging
|
||||
VERBOSE := 0
|
||||
# Number of iterations for each test, assign a non-empty value to override the
|
||||
VERBOSE :=
|
||||
# Number of iterations for each test, assign a non-zero value to override the
|
||||
# iteration count in the test list
|
||||
ITERATIONS :=
|
||||
# Pass/fail signature address at the end of test (see riscv_dv handshake documentation)
|
||||
ITERATIONS := 0
|
||||
# LSF CMD
|
||||
LSF_CMD :=
|
||||
# Generator timeout limit in seconds
|
||||
TIMEOUT := 1800
|
||||
# Privileged CSR YAML description file
|
||||
CSR_FILE := riscv_dv_extension/csr_description.yaml
|
||||
# Pass/fail signature address at the end of test
|
||||
SIGNATURE_ADDR := 8ffffffc
|
||||
|
||||
### Ibex top level parameters ###
|
||||
IBEX_CONFIG := opentitan
|
||||
### Required by RISCV-DV, some ISS, and RTL ###
|
||||
# PMP Regions
|
||||
PMP_REGIONS := 16
|
||||
# PMP Granularity
|
||||
PMP_GRANULARITY := 0
|
||||
|
||||
# Path to DUT used for coverage reports
|
||||
DUT_COV_RTL_PATH := "ibex_top"
|
||||
IBEX_CONFIG := experimental-maxperf-pmp-bmfull-icache
|
||||
|
||||
export EXTRA_COSIM_CFLAGS ?=
|
||||
|
||||
ifeq ($(COSIM_SIGSEGV_WORKAROUND), 1)
|
||||
EXTRA_COSIM_CFLAGS += -DCOSIM_SIGSEGV_WORKAROUND
|
||||
# TODO(udinator) - might need options for SAIL/Whisper/Spike
|
||||
ifeq (${ISS},ovpsim)
|
||||
ISS_OPTS += --override riscvOVPsim/cpu/PMP_registers=${PMP_REGIONS}
|
||||
ISS_OPTS += --override riscvOVPsim/cpu/PMP_grain=${PMP_GRANULARITY}
|
||||
endif
|
||||
|
||||
###############################################################################
|
||||
# A version of $(OUT) with a trailing '/'. The point is that this will
|
||||
# never match the name of a phony targets like "sim" (which causes
|
||||
# strange rebuilds otherwise). The call to $(dir ) avoids adding
|
||||
# another trailing slash if $(OUT) had one already.
|
||||
OUT-DIR := $(dir $(OUT)/)
|
||||
|
||||
# Setup the necessary paths for all python scripts to find all other relevant modules.
|
||||
export PYTHONPATH := $(shell python3 -c 'from scripts.setup_imports import get_pythonpath; get_pythonpath()')
|
||||
# This expands to '@' if VERBOSE is 0 or not set, and to the empty
|
||||
# string otherwise. Prefix commands with it in order that they only
|
||||
# get printed when VERBOSE.
|
||||
verb = $(if $(filter-out 0,$(VERBOSE)),,@)
|
||||
|
||||
# We run the 'create_metadata' step in this top-level makefile, so the sub-make
|
||||
# invocations can query the generated metadata objects. Since the targets/dependencies
|
||||
# are extracted from this metadata, it must be query-able in the makefile 'immediate' stage.
|
||||
.PHONY: run
|
||||
run:
|
||||
@env PYTHONPATH=$(PYTHONPATH) python3 ./scripts/metadata.py \
|
||||
--op "create_metadata" \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--dir-out $(OUT-DIR) \
|
||||
--args-list "\
|
||||
SEED=$(SEED) WAVES=$(WAVES) COV=$(COV) SIMULATOR=$(SIMULATOR) \
|
||||
ISS=$(ISS) TEST=$(TEST) VERBOSE=$(VERBOSE) ITERATIONS=$(ITERATIONS) \
|
||||
SIGNATURE_ADDR=$(SIGNATURE_ADDR) IBEX_CONFIG=$(IBEX_CONFIG) \
|
||||
DUT_COV_RTL_PATH=$(DUT_COV_RTL_PATH)"
|
||||
@$(MAKE) --file wrapper.mk --environment-overrides --no-print-directory $(GOAL)
|
||||
SHELL=/bin/bash
|
||||
|
||||
###############################################################################
|
||||
export PRJ_DIR:= $(realpath ../../..)
|
||||
|
||||
# This is the top-level output directory. Everything we generate goes in
|
||||
# here.
|
||||
OUT := out
|
||||
all: sim
|
||||
|
||||
# Derived directories from $(OUT), used for stuff that's built once or
|
||||
# stuff that gets run for each seed, respectively. Using OUT-DIR on
|
||||
# the way avoids ugly double slashes if $(OUT) happens to end in a /.
|
||||
export OUT-DIR := $(dir $(OUT)/)
|
||||
export METADATA-DIR := $(OUT-DIR)metadata
|
||||
instr: iss_sim
|
||||
|
||||
# riscv-dv extension directory
|
||||
export EXT_DIR := riscv_dv_extension
|
||||
|
||||
###############################################################################
|
||||
sim: post_compare cov
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OUT-DIR)
|
||||
rm -f $(EXT_DIR)/riscv_core_setting.sv
|
||||
|
||||
# Common options for all targets
|
||||
COMMON_OPTS := $(if $(call equal,$(VERBOSE),1),--verbose,)
|
||||
|
||||
# Options for all targets that depend on the tests we're running.
|
||||
TEST_OPTS := $(COMMON_OPTS) \
|
||||
--start_seed=${SEED} \
|
||||
--test="${TEST}" \
|
||||
--testlist=${TESTLIST} \
|
||||
--iterations=${ITERATIONS}
|
||||
|
||||
# Options used for privileged CSR test generation
|
||||
CSR_OPTS=--csr_yaml=${CSR_FILE} \
|
||||
--isa="${ISA}" \
|
||||
--end_signature_addr=${SIGNATURE_ADDR}
|
||||
|
||||
RISCV_DV_OPTS=--custom_target=riscv_dv_extension \
|
||||
--isa="${ISA}" \
|
||||
--mabi=ilp32 \
|
||||
|
||||
# To avoid cluttering the output directory with stamp files, we place them in
|
||||
# $(metadata).
|
||||
metadata := $(OUT-SEED)/.metadata
|
||||
|
||||
# This is a list of directories that are automatically generated by some
|
||||
# targets. To ensure the directory has been built, add a order-only dependency
|
||||
# (with the pipe symbol before it) on the directory name and add the directory
|
||||
# to this list.
|
||||
gen-dirs := $(OUT-DIR) $(OUT-SEED) $(metadata) $(OUT-DIR)rtl_sim
|
||||
|
||||
$(gen-dirs): %:
|
||||
mkdir -p $@
|
||||
|
||||
# sim-cfg-mk is a makefile fragment that sets-up anything simulator specific, it
|
||||
# is generated by sim_makefrag_gen.py
|
||||
sim-cfg-mk = $(OUT-DIR).sim-cfg.mk
|
||||
|
||||
# The include of $(sim-cfg-mk) below tells Make that it should ensure the file
|
||||
# exists. This rule tells Make how to build it. We also want to ensure it's
|
||||
# built on every run. Declaring the rule to be .PHONY doesn't work because it
|
||||
# causes Make to no longer think the rule actually generates the file. If you
|
||||
# do that, the file gets re-built, but Make doesn't read the new contents. So
|
||||
# instead we depend on FORCE (a phony target). This ensures a rebuild, but also
|
||||
# causes an infinite recursion: when we re-read this file to include the new
|
||||
# contents of $(sim-cfg-mk), we run the rule again. To avoid that, we check for
|
||||
# MAKE_RESTARTS, which is defined on re-runs. Phew!
|
||||
ifndef MAKE_RESTARTS
|
||||
$(sim-cfg-mk): FORCE | $(OUT-DIR)
|
||||
@./sim_makefrag_gen.py $(SIMULATOR) $(IBEX_CONFIG) $(PRJ_DIR) $@
|
||||
endif
|
||||
|
||||
include $(sim-cfg-mk)
|
||||
|
||||
.PHONY: test-cfg
|
||||
test-cfg:
|
||||
@echo "COMPILE_OPTS" $(COMPILE_OPTS)
|
||||
@echo "SIM_OPTS" $(SIM_OPTS)
|
||||
|
||||
###############################################################################
|
||||
# Utility functions.
|
||||
#
|
||||
# If VS is a list of variable names, P is a path and X is a string, then $(call
|
||||
# dump-vars,P,X,VS) will expand to a list of 'file' commands that write each
|
||||
# variable to P in Makefile syntax, but with "last-X-" prepended. At the start
|
||||
# of the file, we also define last-X-vars-loaded to 1. You can use this to
|
||||
# check whether there was a dump file at all.
|
||||
#
|
||||
# Note that this doesn't work by expanding to a command. Instead, *evaluating*
|
||||
# dump-vars causes the variables to be dumped.
|
||||
dump-var = $(file >>$(1),last-$(2)-$(3) := $($(3)))
|
||||
dump-vars = $(file >$(1),last-$(2)-vars-loaded := .) \
|
||||
$(foreach name,$(3),$(call dump-var,$(1),$(2),$(name)))
|
||||
|
||||
# equal checks whether two strings are equal, evaluating to '.' if they are and
|
||||
# '' otherwise.
|
||||
both-empty = $(if $(1),,$(if $(2),,.))
|
||||
find-find = $(if $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))),.,)
|
||||
equal = $(or $(call both-empty,$(1),$(2)),$(call find-find,$(1),$(2)))
|
||||
|
||||
# var-differs is used to check whether a variable has changed since it was
|
||||
# dumped. If it has changed, the function evaluates to '.' (with some
|
||||
# whitespace) and prints a message to the console; if not, it evaluates to ''.
|
||||
#
|
||||
# Call it as $(call var-differs,X,TGT,V).
|
||||
var-differs = \
|
||||
$(if $(call equal,$(strip $($(3))),$(strip $(last-$(1)-$(3)))),,\
|
||||
.$(info Repeating $(2) because variable $(3) has changed value.))
|
||||
|
||||
# vars-differ is used to check whether several variables have the same value as
|
||||
# they had when they were dumped. If we haven't loaded the dumpfile, it
|
||||
# silently evaluates to '!'. Otherwise, if all the variables match, it
|
||||
# evaluates to '.'. If not, it evaluates to '.' and prints some messages to the
|
||||
# console explaining why a rebuild is happening.
|
||||
#
|
||||
# Call it as $(call vars-differ,X,TGT,VS).
|
||||
vars-differ-lst = $(foreach v,$(3),$(call var-differs,$(1),$(2),$(v)))
|
||||
vars-differ-sp = \
|
||||
$(if $(last-$(1)-vars-loaded),\
|
||||
$(if $(strip $(call vars-differ-lst,$(1),$(2),$(3))),.,),\
|
||||
!)
|
||||
vars-differ = $(strip $(call vars-differ-sp,$(1),$(2),$(3)))
|
||||
|
||||
# A phony target which can be used to force recompilation.
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
||||
|
||||
# vars-prereq is empty if every variable in VS matches the last run (loaded
|
||||
# with tag X), otherwise it is set to FORCE (which will force a recompile and
|
||||
# might print a message to the console explaining why we're rebuilding TGT).
|
||||
#
|
||||
# Call it as $(call vars-prereq,X,TGT,VS)
|
||||
vars-prereq = $(if $(call vars-differ,$(1),$(2),$(3)),FORCE,)
|
||||
|
||||
###############################################################################
|
||||
# Generate random instructions
|
||||
#
|
||||
# This depends on the vendored in code in $(GEN_DIR). It also depends on the
|
||||
# values of some variables (we want to regenerate things if, for example, the
|
||||
# simulator changes). Since we're writing out to $(OUT-SEED), we don't have to
|
||||
# depend on the value of SEED. However, we do have to make sure that the
|
||||
# variables whose names are listed in $(gen-var-deps) haven't changed.
|
||||
#
|
||||
# To do this variable tracking, we dump each of the variables to a Makefile
|
||||
# fragment and try to load it up the next time around.
|
||||
gen-var-deps := GEN_OPTS SIMULATOR RISCV_DV_OPTS CSR_OPTS \
|
||||
SIGNATURE_ADDR PMP_REGIONS PMP_GRANULARITY TEST_OPTS
|
||||
|
||||
# Load up the generation stage's saved variable values. If this fails, that's
|
||||
# no problem: we'll assume that the previous run either doesn't exist or
|
||||
# something went wrong.
|
||||
-include $(metadata)/gen-vars.mk
|
||||
|
||||
# gen-vars-prereq is empty if every variable in gen-var-deps matches the last run,
|
||||
# otherwise it is set to FORCE (which will force a recompile). Note that we
|
||||
# define it with '=', not ':=', so we don't evaluate it if we're not trying to
|
||||
# run the gen target.
|
||||
gen-vars-prereq = \
|
||||
$(call vars-prereq,gen,building instruction generator,$(gen-var-deps))
|
||||
|
||||
# A variable containing a file list for the riscv-dv vendored-in module.
|
||||
# Depending on these files gives a safe over-approximation that will ensure we
|
||||
# rebuild things if that module changes.
|
||||
#
|
||||
# Note that this is defined with ":=". As a result, we'll always run the find
|
||||
# command exactly once. Wasteful if we're trying to make clean, but much better
|
||||
# than running it for every target otherwise.
|
||||
risc-dv-files := $(shell find $(GEN_DIR) -type f)
|
||||
|
||||
# This actually runs the instruction generator. Note that the rule depends on
|
||||
# the (phony) FORCE target if any variables have changed. If the rule actually
|
||||
# runs, it starts by deleting any existing contents of $(OUT-SEED)/instr_gen.
|
||||
$(metadata)/instr_gen.gen.stamp: \
|
||||
$(gen-vars-prereq) $(risc-dv-files) $(TESTLIST) | $(metadata)
|
||||
$(verb)rm -rf $(OUT-SEED)/instr_gen
|
||||
$(verb)python3 ${GEN_DIR}/run.py \
|
||||
--output=$(OUT-SEED)/instr_gen ${GEN_OPTS} \
|
||||
--steps=gen \
|
||||
--gen_timeout=${TIMEOUT} \
|
||||
--lsf_cmd="${LSF_CMD}" \
|
||||
--simulator="${SIMULATOR}" \
|
||||
${RISCV_DV_OPTS} \
|
||||
${TEST_OPTS} \
|
||||
${CSR_OPTS} \
|
||||
--sim_opts="+uvm_set_inst_override=riscv_asm_program_gen,ibex_asm_program_gen,"uvm_test_top.asm_gen" \
|
||||
+signature_addr=${SIGNATURE_ADDR} +pmp_num_regions=${PMP_REGIONS} \
|
||||
+pmp_granularity=${PMP_GRANULARITY} +tvec_alignment=8"
|
||||
$(call dump-vars,$(metadata)/gen-vars.mk,gen,$(gen-var-deps))
|
||||
@touch $@
|
||||
|
||||
.PHONY: gen
|
||||
gen: $(metadata)/instr_gen.gen.stamp
|
||||
|
||||
###############################################################################
|
||||
# Compile the generated assembly programs
|
||||
#
|
||||
# We don't explicitly track dependencies on the RISCV toolchain, so this
|
||||
# doesn't depend on anything more than the instr_gen stage did.
|
||||
$(metadata)/instr_gen.compile.stamp: \
|
||||
$(metadata)/instr_gen.gen.stamp $(TESTLIST)
|
||||
$(verb)python3 ${GEN_DIR}/run.py \
|
||||
--o=$(OUT-SEED)/instr_gen ${GEN_OPTS} \
|
||||
--steps=gcc_compile \
|
||||
${TEST_OPTS} \
|
||||
--gcc_opts=-mno-strict-align \
|
||||
${RISCV_DV_OPTS} && \
|
||||
touch $@
|
||||
|
||||
.PHONY: gcc_compile
|
||||
gcc_compile: $(metadata)/instr_gen.compile.stamp
|
||||
|
||||
###############################################################################
|
||||
# Run the instruction set simulator
|
||||
#
|
||||
# This (obviously) depends on having compiled the generated programs, so we
|
||||
# don't have to worry about variables that affect the 'gen' stage. However, the
|
||||
# ISS and ISS_OPTS variables do affect the output, so we need to dump them. See
|
||||
# the 'gen' stage for more verbose explanations of how this works.
|
||||
iss-var-deps := ISS ISS_OPTS
|
||||
-include $(metadata)/iss-vars.mk
|
||||
iss-vars-prereq = $(call vars-prereq,iss,running ISS,$(iss-var-deps))
|
||||
|
||||
$(metadata)/instr_gen.iss.stamp: \
|
||||
$(iss-vars-prereq) $(TESTLIST) $(metadata)/instr_gen.compile.stamp
|
||||
$(verb)python3 ${GEN_DIR}/run.py \
|
||||
--o=$(OUT-SEED)/instr_gen ${GEN_OPTS} \
|
||||
--steps=iss_sim \
|
||||
${TEST_OPTS} \
|
||||
--iss="${ISS}" \
|
||||
--iss_opts="${ISS_OPTS}" \
|
||||
${RISCV_DV_OPTS}
|
||||
$(call dump-vars,$(metadata)/iss-vars.mk,iss,$(iss-var-deps))
|
||||
@touch $@
|
||||
|
||||
.PHONY: iss_sim
|
||||
iss_sim: $(metadata)/instr_gen.iss.stamp
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Compile ibex core TB
|
||||
#
|
||||
# Note that (unlike everything else) this doesn't depend on the seed: the DUT
|
||||
# doesn't depend on which test we're running!
|
||||
#
|
||||
# It does, however, depend on various variables. These are listed in
|
||||
# compile-var-deps. See the 'gen' stage for more verbose explanations of how
|
||||
# the variable dumping works.
|
||||
#
|
||||
# The compiled ibex testbench (obviously!) also depends on the design and the
|
||||
# DV code. The clever way of doing this would be to look at a dependency
|
||||
# listing generated by the simulator as a side-effect of doing the compile (a
|
||||
# bit like using the -M flags with a C compiler). Unfortunately, that doesn't
|
||||
# look like it's particularly easy, so we'll just depend on every .v, .sv or
|
||||
# .svh file in the dv or rtl directories. Note that this variable is set with
|
||||
# '=', rather than ':='. This means that we don't bother running the find
|
||||
# commands unless we need the compiled testbench.
|
||||
all-verilog = \
|
||||
$(shell find ../../../rtl -name '*.v' -o -name '*.sv' -o -name '*.svh') \
|
||||
$(shell find ../.. -name '*.v' -o -name '*.sv' -o -name '*.svh')
|
||||
|
||||
compile-var-deps := COMMON_OPTS SIMULATOR COV WAVES COMPILE_OPTS
|
||||
-include $(OUT-DIR)rtl_sim/.compile-vars.mk
|
||||
compile-vars-prereq = $(call vars-prereq,comp,compiling TB,$(compile-var-deps))
|
||||
|
||||
$(call dump-vars-match,$(compile-var-deps),comp)
|
||||
|
||||
cov-arg := $(if $(call equal,$(COV),1),--en_cov,)
|
||||
wave-arg := $(if $(call equal,$(WAVES),1),--en_wave,)
|
||||
lsf-arg := $(if $(LSF_CMD),--lsf_cmd="$(LSF_CMD)",)
|
||||
|
||||
$(OUT-DIR)rtl_sim/.compile.stamp: \
|
||||
$(compile-vars-prereq) $(all-verilog) $(risc-dv-files) \
|
||||
sim.py yaml/rtl_simulation.yaml \
|
||||
| $(OUT-DIR)rtl_sim
|
||||
$(verb)./sim.py \
|
||||
--o=$(OUT-DIR) \
|
||||
--steps=compile \
|
||||
${COMMON_OPTS} \
|
||||
--simulator="${SIMULATOR}" --simulator_yaml=yaml/rtl_simulation.yaml \
|
||||
$(cov-arg) $(wave-arg) $(lsf-arg) \
|
||||
--cmp_opts="${COMPILE_OPTS}"
|
||||
$(call dump-vars,$(OUT-DIR)rtl_sim/.compile-vars.mk,comp,$(compile-var-deps))
|
||||
@touch $@
|
||||
|
||||
.PHONY: compile
|
||||
compile: $(OUT-DIR)rtl_sim/.compile.stamp
|
||||
|
||||
###############################################################################
|
||||
# Run ibex RTL simulation with generated programs
|
||||
#
|
||||
# Because we compile a TB once rather than for each seed, we have to copy in
|
||||
# that directory before we start. We make this step (rather than actually
|
||||
# running the test) dependent on having the right variables. That way, we'll
|
||||
# correctly delete the sim directory and re-copy it if necessary.
|
||||
#
|
||||
# Note that the variables we depend on are gen-vars-prereq. We also depend on
|
||||
# COV and WAVES, but these dependencies will come for free from the dependency
|
||||
# on the compiled TB.
|
||||
$(metadata)/rtl_sim.compile.stamp: \
|
||||
$(gen-vars-prereq) $(risc-dv-files) $(OUT-DIR)rtl_sim/.compile.stamp
|
||||
rm -rf $(OUT-SEED)/rtl_sim
|
||||
cp -r $(OUT-DIR)rtl_sim $(OUT-SEED)
|
||||
@touch $@
|
||||
|
||||
# This rule actually runs the simulation. It depends on the copied-in testbench
|
||||
# and also on us having already compiled the test programs.
|
||||
$(metadata)/rtl_sim.run.stamp: \
|
||||
$(metadata)/rtl_sim.compile.stamp \
|
||||
$(metadata)/instr_gen.compile.stamp $(TESTLIST) \
|
||||
sim.py yaml/rtl_simulation.yaml
|
||||
$(verb)./sim.py \
|
||||
--o=$(OUT-SEED) \
|
||||
--steps=sim \
|
||||
${TEST_OPTS} \
|
||||
--simulator="${SIMULATOR}" --simulator_yaml=yaml/rtl_simulation.yaml \
|
||||
$(cov-arg) $(wave-arg) $(lsf-arg) \
|
||||
--sim_opts="+signature_addr=${SIGNATURE_ADDR} ${SIM_OPTS}"
|
||||
@touch $@
|
||||
|
||||
.PHONY: rtl_sim
|
||||
rtl_sim: $(metadata)/rtl_sim.run.stamp
|
||||
|
||||
###############################################################################
|
||||
# Compare ISS and RTL sim results
|
||||
$(OUT-SEED)/regr.log: \
|
||||
$(metadata)/instr_gen.iss.stamp \
|
||||
$(metadata)/rtl_sim.run.stamp $(TESTLIST)
|
||||
$(verb)rm -f $@
|
||||
$(verb)./sim.py \
|
||||
--o=$(OUT-SEED) \
|
||||
--steps=compare \
|
||||
${TEST_OPTS} \
|
||||
--simulator="${SIMULATOR}" \
|
||||
--iss="${ISS}"
|
||||
|
||||
.PHONY: post_compare
|
||||
post_compare: $(OUT-SEED)/regr.log
|
||||
|
||||
###############################################################################
|
||||
# Generate RISCV-DV functional coverage
|
||||
# TODO(udi) - add B extension
|
||||
fcov:
|
||||
$(verb)python3 ${GEN_DIR}/cov.py \
|
||||
--core ibex \
|
||||
--dir ${OUT-SEED}/rtl_sim \
|
||||
-o ${OUT-SEED}/fcov \
|
||||
--isa rv32imcb \
|
||||
--custom_target riscv_dv_extension
|
||||
|
||||
# Merge all output coverage directories into the <out>/rtl_sim directory
|
||||
cov:
|
||||
$(verb)rm -rf $(OUT-DIR)rtl_sim/test.vdb
|
||||
$(verb)./sim.py \
|
||||
--steps=cov \
|
||||
${TEST_OPTS} \
|
||||
--simulator="${SIMULATOR}" \
|
||||
$(lsf-arg) \
|
||||
--o="$(OUT-DIR)"
|
||||
@if [ -d "test.vdb" ]; then \
|
||||
mv -f test.vdb $(OUT-DIR)rtl_sim/; \
|
||||
fi
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
# DV for the ibex core
|
||||
|
||||
For detailed documention on how Ibex's verification works, please have a look at [the dedicated documentation page](https://ibex-core.readthedocs.io/en/latest/03_reference/verification.html).
|
||||
This README provides a quick start guide to get things running.
|
||||
|
||||
## Prerequisites
|
||||
You need to have Xcelium available on your machine.
|
||||
You can check whether you have it available by running: `xrun --verison`
|
||||
|
||||
You also need Spike to be able to compare to in the cosimulation.
|
||||
We use a lowRISC specific Spike which you can find [on its own GitHub page](https://github.com/lowRISC/riscv-isa-sim/tree/ibex_cosim).
|
||||
Some quick build instructions from within the `riscv-isa-sim` repo:
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
../configure --enable-commitlog --enable-misaligned --prefix=$SPIKE_INSTALL_DIR
|
||||
make
|
||||
make install
|
||||
export SPIKE_PATH=$SPIKE_INSTALL_DIR/bin
|
||||
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$SPIKE_INSTALL_DIR/lib/pkgconfig
|
||||
```
|
||||
|
||||
You will need the [RISC-V toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain).
|
||||
You'll need to add this to your path and then also set the following environment variables:
|
||||
```bash
|
||||
export RISCV_GCC=riscv32-unknown-elf-gcc
|
||||
export RISCV_OBJCOPY=riscv32-unknown-elf-objcopy
|
||||
```
|
||||
|
||||
## Running tests
|
||||
|
||||
To run tests you can make variations of the following command, where you replace `$TEST_NAME` with the test (or a series of comma-separated tests) that you would like to run as specified in `dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml`:
|
||||
```bash
|
||||
make --keep-going IBEX_CONFIG=opentitan SIMULATOR=xlm ISS=spike ITERATIONS=1 SEED=1 TEST=$TEST_NAME WAVES=0 COV=0
|
||||
```
|
|
@ -1,10 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`ifndef DATE_DPI_SVH
|
||||
`define DATE_DPI_SVH
|
||||
|
||||
import "DPI-C" function longint get_unix_timestamp();
|
||||
|
||||
`endif
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
interface core_ibex_ifetch_if(input logic clk);
|
||||
logic reset;
|
||||
|
||||
logic fetch_ready;
|
||||
logic fetch_valid;
|
||||
logic [31:0] fetch_rdata;
|
||||
logic [31:0] fetch_addr;
|
||||
logic fetch_err;
|
||||
logic fetch_err_plus2;
|
||||
|
||||
clocking monitor_cb @(posedge clk);
|
||||
input reset;
|
||||
input fetch_ready;
|
||||
input fetch_valid;
|
||||
input fetch_rdata;
|
||||
input fetch_addr;
|
||||
input fetch_err;
|
||||
input fetch_err_plus2;
|
||||
endclocking
|
||||
|
||||
task automatic wait_clks(input int num);
|
||||
repeat (num) @(posedge clk);
|
||||
endtask
|
||||
endinterface
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
interface core_ibex_ifetch_pmp_if(input logic clk);
|
||||
logic reset;
|
||||
|
||||
logic fetch_valid;
|
||||
logic [31:0] fetch_addr;
|
||||
logic fetch_pmp_err;
|
||||
|
||||
clocking monitor_cb @(posedge clk);
|
||||
input reset;
|
||||
input fetch_valid;
|
||||
input fetch_addr;
|
||||
input fetch_pmp_err;
|
||||
endclocking
|
||||
|
||||
task automatic wait_clks(input int num);
|
||||
repeat (num) @(posedge clk);
|
||||
endtask
|
||||
endinterface : core_ibex_ifetch_pmp_if
|
|
@ -1,80 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`include "cosim_dpi.svh"
|
||||
|
||||
class ibex_cosim_agent extends uvm_agent;
|
||||
ibex_rvfi_monitor rvfi_monitor;
|
||||
ibex_ifetch_monitor ifetch_monitor;
|
||||
ibex_ifetch_pmp_monitor ifetch_pmp_monitor;
|
||||
ibex_cosim_scoreboard scoreboard;
|
||||
|
||||
uvm_analysis_export#(ibex_mem_intf_seq_item) dmem_port;
|
||||
uvm_analysis_export#(ibex_mem_intf_seq_item) imem_port;
|
||||
|
||||
`uvm_component_utils(ibex_cosim_agent)
|
||||
|
||||
function new(string name="", uvm_component parent=null);
|
||||
super.new(name, parent);
|
||||
|
||||
dmem_port = new("dmem_port", this);
|
||||
imem_port = new("imem_port", this);
|
||||
endfunction
|
||||
|
||||
virtual function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
rvfi_monitor = ibex_rvfi_monitor::type_id::create("rvfi_monitor", this);
|
||||
scoreboard = ibex_cosim_scoreboard::type_id::create("scoreboard", this);
|
||||
ifetch_monitor = ibex_ifetch_monitor::type_id::create("ifetch_monitor", this);
|
||||
ifetch_pmp_monitor = ibex_ifetch_pmp_monitor::type_id::create("ifetch_pmp_monitor", this);
|
||||
endfunction: build_phase
|
||||
|
||||
virtual function void connect_phase(uvm_phase phase);
|
||||
super.connect_phase(phase);
|
||||
|
||||
rvfi_monitor.item_collected_port.connect(scoreboard.rvfi_port.analysis_export);
|
||||
ifetch_monitor.item_collected_port.connect(scoreboard.ifetch_port.analysis_export);
|
||||
ifetch_pmp_monitor.item_collected_port.connect(scoreboard.ifetch_pmp_port.analysis_export);
|
||||
dmem_port.connect(scoreboard.dmem_port.analysis_export);
|
||||
imem_port.connect(scoreboard.imem_port.analysis_export);
|
||||
endfunction: connect_phase
|
||||
|
||||
function void write_mem_byte(bit [31:0] addr, bit [7:0] d);
|
||||
riscv_cosim_write_mem_byte(scoreboard.cosim_handle, addr, d);
|
||||
endfunction
|
||||
|
||||
function void write_mem_word(bit [31:0] addr, bit [DATA_WIDTH-1:0] d);
|
||||
for (int i = 0; i < DATA_WIDTH / 8; i++) begin
|
||||
write_mem_byte(addr + i, d[7:0]);
|
||||
d = d >> 8;
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Backdoor-load the test binary file into the cosim memory model
|
||||
function void load_binary_to_mem(bit[31:0] base_addr, string bin);
|
||||
bit [7:0] r8;
|
||||
bit [31:0] addr = base_addr;
|
||||
int bin_fd;
|
||||
bin_fd = $fopen(bin,"rb");
|
||||
if (!bin_fd)
|
||||
`uvm_fatal(get_full_name(), $sformatf("Cannot open file %0s", bin))
|
||||
while ($fread(r8,bin_fd)) begin
|
||||
`uvm_info(`gfn, $sformatf("Init mem [0x%h] = 0x%0h", addr, r8), UVM_FULL)
|
||||
write_mem_byte(addr, r8);
|
||||
addr++;
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void reset();
|
||||
scoreboard.rvfi_port.flush();
|
||||
scoreboard.dmem_port.flush();
|
||||
scoreboard.imem_port.flush();
|
||||
scoreboard.ifetch_port.flush();
|
||||
scoreboard.ifetch_pmp_port.flush();
|
||||
|
||||
scoreboard.reset_e.trigger();
|
||||
endfunction : reset
|
||||
|
||||
endclass : ibex_cosim_agent
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package ibex_cosim_agent_pkg;
|
||||
import uvm_pkg::*;
|
||||
import ibex_mem_intf_pkg::*;
|
||||
|
||||
`include "uvm_macros.svh"
|
||||
|
||||
`include "ibex_cosim_cfg.sv"
|
||||
`include "ibex_rvfi_seq_item.sv"
|
||||
`include "ibex_rvfi_monitor.sv"
|
||||
`include "ibex_ifetch_seq_item.sv"
|
||||
`include "ibex_ifetch_monitor.sv"
|
||||
`include "ibex_ifetch_pmp_seq_item.sv"
|
||||
`include "ibex_ifetch_pmp_monitor.sv"
|
||||
`include "ibex_cosim_scoreboard.sv"
|
||||
`include "ibex_cosim_agent.sv"
|
||||
endpackage
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class core_ibex_cosim_cfg extends uvm_object;
|
||||
string isa_string;
|
||||
bit [31:0] start_pc;
|
||||
bit [31:0] start_mtvec;
|
||||
bit probe_imem_for_errs;
|
||||
string log_file;
|
||||
bit [31:0] pmp_num_regions;
|
||||
bit [31:0] pmp_granularity;
|
||||
bit [31:0] mhpm_counter_num;
|
||||
bit relax_cosim_check;
|
||||
bit secure_ibex;
|
||||
bit icache;
|
||||
|
||||
`uvm_object_utils_begin(core_ibex_cosim_cfg)
|
||||
`uvm_field_string(isa_string, UVM_DEFAULT)
|
||||
`uvm_field_int(start_pc, UVM_DEFAULT)
|
||||
`uvm_field_int(start_mtvec, UVM_DEFAULT)
|
||||
`uvm_field_int(probe_imem_for_errs, UVM_DEFAULT)
|
||||
`uvm_field_string(log_file, UVM_DEFAULT)
|
||||
`uvm_field_int(pmp_num_regions, UVM_DEFAULT)
|
||||
`uvm_field_int(pmp_granularity, UVM_DEFAULT)
|
||||
`uvm_field_int(mhpm_counter_num, UVM_DEFAULT)
|
||||
`uvm_field_int(secure_ibex, UVM_DEFAULT)
|
||||
`uvm_field_int(icache, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
`uvm_object_new
|
||||
endclass
|
|
@ -1,358 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`include "spike_cosim_dpi.svh"
|
||||
`include "cosim_dpi.svh"
|
||||
|
||||
class ibex_cosim_scoreboard extends uvm_scoreboard;
|
||||
chandle cosim_handle;
|
||||
|
||||
core_ibex_cosim_cfg cfg;
|
||||
|
||||
uvm_tlm_analysis_fifo #(ibex_rvfi_seq_item) rvfi_port;
|
||||
uvm_tlm_analysis_fifo #(ibex_mem_intf_seq_item) dmem_port;
|
||||
uvm_tlm_analysis_fifo #(ibex_mem_intf_seq_item) imem_port;
|
||||
uvm_tlm_analysis_fifo #(ibex_ifetch_seq_item) ifetch_port;
|
||||
uvm_tlm_analysis_fifo #(ibex_ifetch_pmp_seq_item) ifetch_pmp_port;
|
||||
|
||||
virtual core_ibex_instr_monitor_if instr_vif;
|
||||
virtual core_ibex_dut_probe_if dut_vif;
|
||||
|
||||
uvm_event reset_e;
|
||||
uvm_event check_inserted_iside_error_e;
|
||||
|
||||
bit failed_iside_accesses [bit[31:0]];
|
||||
bit iside_pmp_failure [bit[31:0]];
|
||||
|
||||
typedef struct {
|
||||
bit [63:0] order;
|
||||
bit [31:0] addr;
|
||||
} iside_err_t;
|
||||
|
||||
iside_err_t iside_error_queue [$];
|
||||
|
||||
`uvm_component_utils(ibex_cosim_scoreboard)
|
||||
|
||||
function new(string name="", uvm_component parent=null);
|
||||
super.new(name, parent);
|
||||
|
||||
rvfi_port = new("rvfi_port", this);
|
||||
dmem_port = new("dmem_port", this);
|
||||
imem_port = new("imem_port", this);
|
||||
ifetch_port = new("ifetch_port", this);
|
||||
ifetch_pmp_port = new("ifetch_pmp_port", this);
|
||||
cosim_handle = null;
|
||||
reset_e = new();
|
||||
check_inserted_iside_error_e = new();
|
||||
endfunction
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
if (!uvm_config_db#(core_ibex_cosim_cfg)::get(this, "", "cosim_cfg", cfg)) begin
|
||||
`uvm_fatal(`gfn, "Cannot get cosim configuration")
|
||||
end
|
||||
|
||||
if (!uvm_config_db#(virtual core_ibex_instr_monitor_if)::get(null, "", "instr_monitor_if",
|
||||
instr_vif)) begin
|
||||
`uvm_fatal(`gfn, "Cannot get instr_monitor_if")
|
||||
end
|
||||
|
||||
if (!uvm_config_db#(virtual core_ibex_dut_probe_if)::get(null, "", "dut_if",
|
||||
dut_vif)) begin
|
||||
`uvm_fatal(`gfn, "Cannot get dut_probe_if")
|
||||
end
|
||||
|
||||
init_cosim();
|
||||
endfunction : build_phase
|
||||
|
||||
protected function void init_cosim();
|
||||
cleanup_cosim();
|
||||
|
||||
// TODO: Ensure log file on reset gets append rather than overwrite?
|
||||
cosim_handle = spike_cosim_init(cfg.isa_string, cfg.start_pc, cfg.start_mtvec, cfg.log_file,
|
||||
cfg.pmp_num_regions, cfg.pmp_granularity, cfg.mhpm_counter_num, cfg.secure_ibex, cfg.icache);
|
||||
|
||||
if (cosim_handle == null) begin
|
||||
`uvm_fatal(`gfn, "Could not initialise cosim")
|
||||
end
|
||||
endfunction
|
||||
|
||||
protected function void cleanup_cosim();
|
||||
if (cosim_handle) begin
|
||||
spike_cosim_release(cosim_handle);
|
||||
end
|
||||
cosim_handle = null;
|
||||
endfunction
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
forever begin
|
||||
@(negedge instr_vif.reset)
|
||||
fork : isolation_fork
|
||||
run_cosim_rvfi();
|
||||
run_cosim_dmem();
|
||||
run_cosim_imem_errors();
|
||||
run_cosim_prune_imem_errors();
|
||||
if (cfg.probe_imem_for_errs) begin
|
||||
run_cosim_imem();
|
||||
end else begin
|
||||
fork
|
||||
run_cosim_ifetch();
|
||||
run_cosim_ifetch_pmp();
|
||||
join_any
|
||||
end
|
||||
join_none
|
||||
reset_e.wait_trigger();
|
||||
disable fork;
|
||||
handle_reset();
|
||||
end // forever
|
||||
endtask : run_phase
|
||||
|
||||
task run_cosim_rvfi();
|
||||
ibex_rvfi_seq_item rvfi_instr;
|
||||
|
||||
forever begin
|
||||
rvfi_port.get(rvfi_instr);
|
||||
|
||||
if (rvfi_instr.irq_only) begin
|
||||
// RVFI item is only notifying about new interrupts, not a retired instruction, so provide
|
||||
// cosim with interrupt information and loop back to await the next item.
|
||||
riscv_cosim_set_nmi(cosim_handle, rvfi_instr.nmi);
|
||||
riscv_cosim_set_nmi_int(cosim_handle, rvfi_instr.nmi_int);
|
||||
riscv_cosim_set_mip(cosim_handle, rvfi_instr.pre_mip, rvfi_instr.pre_mip);
|
||||
|
||||
continue;
|
||||
end
|
||||
|
||||
if (iside_error_queue.size() > 0) begin
|
||||
// Remove entries from iside_error_queue where the instruction never reaches the RVFI
|
||||
// interface because it was flushed.
|
||||
while (iside_error_queue.size() > 0 && iside_error_queue[0].order < rvfi_instr.order) begin
|
||||
iside_error_queue.pop_front();
|
||||
end
|
||||
|
||||
// Check if the top of the iside_error_queue relates to the current RVFI instruction. If so
|
||||
// notify the cosim environment of an instruction error.
|
||||
if (iside_error_queue.size() !=0 && iside_error_queue[0].order == rvfi_instr.order) begin
|
||||
riscv_cosim_set_iside_error(cosim_handle, iside_error_queue[0].addr);
|
||||
iside_error_queue.pop_front();
|
||||
end
|
||||
end
|
||||
|
||||
// Note these must be called in this order to ensure debug vs nmi vs normal interrupt are
|
||||
// handled with the correct priority when they occur together.
|
||||
riscv_cosim_set_debug_req(cosim_handle, rvfi_instr.debug_req);
|
||||
riscv_cosim_set_nmi(cosim_handle, rvfi_instr.nmi);
|
||||
riscv_cosim_set_nmi_int(cosim_handle, rvfi_instr.nmi_int);
|
||||
riscv_cosim_set_mip(cosim_handle, rvfi_instr.pre_mip, rvfi_instr.post_mip);
|
||||
riscv_cosim_set_mcycle(cosim_handle, rvfi_instr.mcycle);
|
||||
|
||||
// Set performance counters through a pseudo-backdoor write
|
||||
for (int i=0; i < 10; i++) begin
|
||||
riscv_cosim_set_csr(cosim_handle,
|
||||
ibex_pkg::CSR_MHPMCOUNTER3 + i, rvfi_instr.mhpmcounters[i]);
|
||||
riscv_cosim_set_csr(cosim_handle,
|
||||
ibex_pkg::CSR_MHPMCOUNTER3H + i, rvfi_instr.mhpmcountersh[i]);
|
||||
end
|
||||
|
||||
riscv_cosim_set_ic_scr_key_valid(cosim_handle, rvfi_instr.ic_scr_key_valid);
|
||||
|
||||
if (!riscv_cosim_step(cosim_handle, rvfi_instr.rd_addr, rvfi_instr.rd_wdata, rvfi_instr.pc,
|
||||
rvfi_instr.trap, rvfi_instr.rf_wr_suppress)) begin
|
||||
// cosim instruction step doesn't match rvfi captured instruction, report a fatal error
|
||||
// with the details
|
||||
if (cfg.relax_cosim_check) begin
|
||||
`uvm_info(`gfn, get_cosim_error_str(), UVM_LOW)
|
||||
end else begin
|
||||
`uvm_fatal(`gfn, get_cosim_error_str())
|
||||
end
|
||||
end
|
||||
end
|
||||
endtask: run_cosim_rvfi
|
||||
|
||||
task run_cosim_dmem();
|
||||
ibex_mem_intf_seq_item mem_op;
|
||||
|
||||
forever begin
|
||||
dmem_port.get(mem_op);
|
||||
// Notify the cosim of all dside accesses emitted by the RTL
|
||||
riscv_cosim_notify_dside_access(cosim_handle, mem_op.read_write == WRITE, mem_op.addr,
|
||||
mem_op.data, mem_op.be, mem_op.error, mem_op.misaligned_first, mem_op.misaligned_second,
|
||||
mem_op.misaligned_first_saw_error, mem_op.m_mode_access);
|
||||
end
|
||||
endtask: run_cosim_dmem
|
||||
|
||||
task run_cosim_imem();
|
||||
ibex_mem_intf_seq_item mem_op;
|
||||
|
||||
forever begin
|
||||
// Take stream of transaction from imem monitor. Where an imem access has an error record it
|
||||
// in failed_iside_accesses. If an access has succeeded remove it from failed_imem_accesses if
|
||||
// it's there.
|
||||
// Note all transactions are 32-bit aligned.
|
||||
imem_port.get(mem_op);
|
||||
if (mem_op.error) begin
|
||||
failed_iside_accesses[mem_op.addr] = 1'b1;
|
||||
end else begin
|
||||
if (failed_iside_accesses.exists(mem_op.addr)) begin
|
||||
failed_iside_accesses.delete(mem_op.addr);
|
||||
end
|
||||
end
|
||||
end
|
||||
endtask: run_cosim_imem
|
||||
|
||||
task run_cosim_ifetch();
|
||||
ibex_ifetch_seq_item ifetch;
|
||||
bit [31:0] aligned_fetch_addr;
|
||||
bit [31:0] aligned_fetch_addr_next;
|
||||
|
||||
forever begin
|
||||
ifetch_port.get(ifetch);
|
||||
aligned_fetch_addr = {ifetch.fetch_addr[31:2], 2'b0};
|
||||
aligned_fetch_addr_next = aligned_fetch_addr + 32'd4;
|
||||
|
||||
if (ifetch.fetch_err) begin
|
||||
// Instruction error observed in fetch stage
|
||||
bit [31:0] failing_addr;
|
||||
|
||||
// Determine which address failed.
|
||||
if (ifetch.fetch_err_plus2) begin
|
||||
// Instruction crosses a 32-bit boundary and second half failed
|
||||
failing_addr = aligned_fetch_addr_next;
|
||||
end else begin
|
||||
failing_addr = aligned_fetch_addr;
|
||||
end
|
||||
|
||||
failed_iside_accesses[failing_addr] = 1'b1;
|
||||
end else begin
|
||||
if (ifetch.fetch_addr[1:0] != 0 && ifetch.fetch_rdata[1:0] == 2'b11) begin
|
||||
// Instruction crosses 32-bit boundary, so remove any failed accesses on the other side of
|
||||
// the 32-bit boundary.
|
||||
if (failed_iside_accesses.exists(aligned_fetch_addr_next)) begin
|
||||
failed_iside_accesses.delete(aligned_fetch_addr_next);
|
||||
end
|
||||
end
|
||||
|
||||
if (failed_iside_accesses.exists(aligned_fetch_addr)) begin
|
||||
failed_iside_accesses.delete(aligned_fetch_addr);
|
||||
end
|
||||
end
|
||||
end
|
||||
endtask: run_cosim_ifetch
|
||||
|
||||
task run_cosim_ifetch_pmp();
|
||||
ibex_ifetch_pmp_seq_item ifetch_pmp;
|
||||
|
||||
// Keep track of which addresses have seen PMP failures.
|
||||
forever begin
|
||||
ifetch_pmp_port.get(ifetch_pmp);
|
||||
|
||||
if (ifetch_pmp.fetch_pmp_err) begin
|
||||
iside_pmp_failure[ifetch_pmp.fetch_addr] = 1'b1;
|
||||
end else begin
|
||||
if (iside_pmp_failure.exists(ifetch_pmp.fetch_addr)) begin
|
||||
iside_pmp_failure.delete(ifetch_pmp.fetch_addr);
|
||||
end
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task run_cosim_imem_errors();
|
||||
bit [63:0] latest_order = 64'hffffffff_ffffffff;
|
||||
bit [31:0] aligned_addr;
|
||||
bit [31:0] aligned_next_addr;
|
||||
forever begin
|
||||
// Wait for new instruction to appear in ID stage
|
||||
wait (instr_vif.instr_cb.valid_id &&
|
||||
instr_vif.instr_cb.instr_new_id &&
|
||||
latest_order != instr_vif.instr_cb.rvfi_order_id);
|
||||
|
||||
latest_order = instr_vif.instr_cb.rvfi_order_id;
|
||||
|
||||
if (dut_vif.dut_cb.wb_exception)
|
||||
// If an exception in writeback occurs the instruction in ID will be flushed and hence not
|
||||
// produce an iside error so skip the rest of the loop. A writeback exception may occur
|
||||
// after this cycle before the instruction in ID moves out of the ID stage. The
|
||||
// `run_cosim_prune_imem_errors` task deals with this case.
|
||||
continue;
|
||||
|
||||
// Determine if the instruction comes from an address that has seen an error that wasn't a PMP
|
||||
// error (the icache records both PMP errors and fetch errors with the same error bits). If a
|
||||
// fetch error was seen add the instruction order ID and address to iside_error_queue.
|
||||
aligned_addr = instr_vif.instr_cb.pc_id & 32'hfffffffc;
|
||||
aligned_next_addr = aligned_addr + 32'd4;
|
||||
|
||||
if (failed_iside_accesses.exists(aligned_addr) && !iside_pmp_failure.exists(aligned_addr))
|
||||
begin
|
||||
iside_error_queue.push_back('{order : instr_vif.instr_cb.rvfi_order_id,
|
||||
addr : aligned_addr});
|
||||
check_inserted_iside_error_e.trigger();
|
||||
end else if (!instr_vif.instr_cb.is_compressed_id &&
|
||||
(instr_vif.instr_cb.pc_id & 32'h3) != 0 &&
|
||||
failed_iside_accesses.exists(aligned_next_addr) &&
|
||||
!iside_pmp_failure.exists(aligned_next_addr))
|
||||
begin
|
||||
// Where an instruction crosses a 32-bit boundary, check if an error was seen on the other
|
||||
// side of the boundary
|
||||
iside_error_queue.push_back('{order : instr_vif.instr_cb.rvfi_order_id,
|
||||
addr : aligned_next_addr});
|
||||
check_inserted_iside_error_e.trigger();
|
||||
end
|
||||
|
||||
end
|
||||
endtask: run_cosim_imem_errors;
|
||||
|
||||
task run_cosim_prune_imem_errors();
|
||||
// Errors are added to the iside error queue the first cycle the instruction that sees the error
|
||||
// is in the ID stage. Cycles following this the writeback stage may cause an exception flushing
|
||||
// the ID stage so the iside error never occurs. When this happens we need to pop the new iside
|
||||
// error off the queue.
|
||||
forever begin
|
||||
// Wait until the `run_cosim_imem_errors` task notifies us it's added a error to the queue
|
||||
check_inserted_iside_error_e.wait_ptrigger();
|
||||
// Wait for the next clock
|
||||
@(instr_vif.instr_cb);
|
||||
// Wait for a new instruction or a writeback exception. When a new instruction has entered the
|
||||
// ID stage and we haven't seen a writeback exception we know the instruction associated with the
|
||||
// error just added to the queue isn't getting flushed.
|
||||
wait (instr_vif.instr_cb.instr_new_id || dut_vif.dut_cb.wb_exception);
|
||||
|
||||
if (!instr_vif.instr_cb.instr_new_id && dut_vif.dut_cb.wb_exception) begin
|
||||
// If we hit a writeback exception without seeing a new instruction then the newly added
|
||||
// error relates to an instruction just flushed from the ID stage so pop it from the
|
||||
// queue.
|
||||
iside_error_queue.pop_back();
|
||||
end
|
||||
end
|
||||
endtask: run_cosim_prune_imem_errors
|
||||
|
||||
function string get_cosim_error_str();
|
||||
string error = "Cosim mismatch ";
|
||||
for (int i = 0; i < riscv_cosim_get_num_errors(cosim_handle); ++i) begin
|
||||
error = {error, riscv_cosim_get_error(cosim_handle, i), "\n"};
|
||||
end
|
||||
riscv_cosim_clear_errors(cosim_handle);
|
||||
|
||||
return error;
|
||||
endfunction : get_cosim_error_str
|
||||
|
||||
function void final_phase(uvm_phase phase);
|
||||
super.final_phase(phase);
|
||||
|
||||
`uvm_info(`gfn, $sformatf("Co-simulation matched %d instructions",
|
||||
riscv_cosim_get_insn_cnt(cosim_handle)), UVM_LOW)
|
||||
|
||||
cleanup_cosim();
|
||||
endfunction : final_phase
|
||||
|
||||
// If the UVM_EXIT action is triggered (such as by reaching max_quit_count), this callback is run.
|
||||
// This ensures proper cleanup, such as commiting the logfile to disk.
|
||||
function void pre_abort();
|
||||
cleanup_cosim();
|
||||
endfunction
|
||||
|
||||
task handle_reset();
|
||||
init_cosim();
|
||||
endtask
|
||||
endclass : ibex_cosim_scoreboard
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class ibex_ifetch_monitor extends uvm_monitor;
|
||||
protected virtual core_ibex_ifetch_if vif;
|
||||
|
||||
uvm_analysis_port#(ibex_ifetch_seq_item) item_collected_port;
|
||||
|
||||
`uvm_component_utils(ibex_ifetch_monitor)
|
||||
`uvm_component_new
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
item_collected_port = new("item_collected_port", this);
|
||||
|
||||
if(!uvm_config_db#(virtual core_ibex_ifetch_if)::get(this, "", "ifetch_if", vif)) begin
|
||||
`uvm_fatal("NOVIF", {"virtual interface must be set for: ", get_full_name(), ".vif"});
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
ibex_ifetch_seq_item trans_collected;
|
||||
|
||||
wait (vif.monitor_cb.reset === 1'b0);
|
||||
|
||||
forever begin
|
||||
while(!(vif.monitor_cb.fetch_valid && vif.monitor_cb.fetch_ready)) vif.wait_clks(1);
|
||||
|
||||
trans_collected = ibex_ifetch_seq_item::type_id::create("trans_collected");
|
||||
trans_collected.fetch_rdata = vif.monitor_cb.fetch_rdata;
|
||||
trans_collected.fetch_addr = vif.monitor_cb.fetch_addr;
|
||||
trans_collected.fetch_err = vif.monitor_cb.fetch_err;
|
||||
trans_collected.fetch_err_plus2 = vif.monitor_cb.fetch_err_plus2;
|
||||
|
||||
`uvm_info(`gfn, $sformatf("Seen ifetch:\n%s", trans_collected.sprint()),
|
||||
UVM_HIGH)
|
||||
|
||||
item_collected_port.write(trans_collected);
|
||||
|
||||
vif.wait_clks(1);
|
||||
end
|
||||
endtask: run_phase
|
||||
endclass : ibex_ifetch_monitor
|
|
@ -1,43 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class ibex_ifetch_pmp_monitor extends uvm_monitor;
|
||||
protected virtual core_ibex_ifetch_pmp_if vif;
|
||||
|
||||
uvm_analysis_port#(ibex_ifetch_pmp_seq_item) item_collected_port;
|
||||
|
||||
`uvm_component_utils(ibex_ifetch_pmp_monitor)
|
||||
`uvm_component_new
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
item_collected_port = new("item_collected_port", this);
|
||||
|
||||
if(!uvm_config_db#(virtual core_ibex_ifetch_pmp_if)::get(this, "", "ifetch_pmp_if", vif)) begin
|
||||
`uvm_fatal("NOVIF", {"virtual interface must be set for: ", get_full_name(), ".vif"});
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
ibex_ifetch_pmp_seq_item trans_collected;
|
||||
|
||||
wait (vif.monitor_cb.reset === 1'b0);
|
||||
|
||||
forever begin
|
||||
while(!vif.monitor_cb.fetch_valid) vif.wait_clks(1);
|
||||
|
||||
trans_collected = ibex_ifetch_pmp_seq_item::type_id::create("trans_collected");
|
||||
trans_collected.fetch_addr = vif.monitor_cb.fetch_addr;
|
||||
trans_collected.fetch_pmp_err = vif.monitor_cb.fetch_pmp_err;
|
||||
|
||||
`uvm_info(`gfn, $sformatf("Seen ifetch:\n%s", trans_collected.sprint()),
|
||||
UVM_HIGH)
|
||||
|
||||
item_collected_port.write(trans_collected);
|
||||
|
||||
vif.wait_clks(1);
|
||||
end
|
||||
endtask: run_phase
|
||||
endclass : ibex_ifetch_pmp_monitor
|
|
@ -1,15 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class ibex_ifetch_pmp_seq_item extends uvm_sequence_item;
|
||||
bit [31:0] fetch_addr;
|
||||
bit fetch_pmp_err;
|
||||
|
||||
`uvm_object_utils_begin(ibex_ifetch_pmp_seq_item)
|
||||
`uvm_field_int (fetch_addr, UVM_DEFAULT)
|
||||
`uvm_field_int (fetch_pmp_err, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
`uvm_object_new
|
||||
endclass : ibex_ifetch_pmp_seq_item
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class ibex_ifetch_seq_item extends uvm_sequence_item;
|
||||
bit [31:0] fetch_rdata;
|
||||
bit [31:0] fetch_addr;
|
||||
bit fetch_err;
|
||||
bit fetch_err_plus2;
|
||||
|
||||
`uvm_object_utils_begin(ibex_ifetch_seq_item)
|
||||
`uvm_field_int (fetch_rdata, UVM_DEFAULT)
|
||||
`uvm_field_int (fetch_addr, UVM_DEFAULT)
|
||||
`uvm_field_int (fetch_err, UVM_DEFAULT)
|
||||
`uvm_field_int (fetch_err_plus2, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
`uvm_object_new
|
||||
endclass : ibex_ifetch_seq_item
|
|
@ -1,62 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class ibex_rvfi_monitor extends uvm_monitor;
|
||||
protected virtual core_ibex_rvfi_if vif;
|
||||
|
||||
uvm_analysis_port#(ibex_rvfi_seq_item) item_collected_port;
|
||||
|
||||
`uvm_component_utils(ibex_rvfi_monitor)
|
||||
`uvm_component_new
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
item_collected_port = new("item_collected_port", this);
|
||||
|
||||
if(!uvm_config_db#(virtual core_ibex_rvfi_if)::get(this, "", "rvfi_if", vif)) begin
|
||||
`uvm_fatal("NOVIF", {"virtual interface must be set for: ", get_full_name(), ".vif"});
|
||||
end
|
||||
endfunction: build_phase
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
ibex_rvfi_seq_item trans_collected;
|
||||
|
||||
wait (vif.monitor_cb.reset === 1'b0);
|
||||
|
||||
forever begin
|
||||
// Wait for a retired instruction
|
||||
while(!(vif.monitor_cb.valid || vif.monitor_cb.ext_irq_valid)) vif.wait_clks(1);
|
||||
|
||||
// Read instruction details from RVFI interface
|
||||
trans_collected = ibex_rvfi_seq_item::type_id::create("trans_collected");
|
||||
trans_collected.irq_only = !vif.monitor_cb.valid && vif.monitor_cb.ext_irq_valid;
|
||||
trans_collected.trap = vif.monitor_cb.trap;
|
||||
trans_collected.pc = vif.monitor_cb.pc_rdata;
|
||||
trans_collected.rd_addr = vif.monitor_cb.rd_addr;
|
||||
trans_collected.rd_wdata = vif.monitor_cb.rd_wdata;
|
||||
trans_collected.order = vif.monitor_cb.order;
|
||||
trans_collected.pre_mip = vif.monitor_cb.ext_pre_mip;
|
||||
trans_collected.post_mip = vif.monitor_cb.ext_post_mip;
|
||||
trans_collected.nmi = vif.monitor_cb.ext_nmi;
|
||||
trans_collected.nmi_int = vif.monitor_cb.ext_nmi_int;
|
||||
trans_collected.debug_req = vif.monitor_cb.ext_debug_req;
|
||||
trans_collected.rf_wr_suppress = vif.monitor_cb.ext_rf_wr_suppress;
|
||||
trans_collected.mcycle = vif.monitor_cb.ext_mcycle;
|
||||
trans_collected.ic_scr_key_valid = vif.monitor_cb.ext_ic_scr_key_valid;
|
||||
|
||||
for (int i=0; i < 10; i++) begin
|
||||
trans_collected.mhpmcounters[i] = vif.monitor_cb.ext_mhpmcounters[i];
|
||||
trans_collected.mhpmcountersh[i] = vif.monitor_cb.ext_mhpmcountersh[i];
|
||||
end
|
||||
|
||||
`uvm_info(get_full_name(), $sformatf("Seen instruction:\n%s", trans_collected.sprint()),
|
||||
UVM_HIGH)
|
||||
|
||||
item_collected_port.write(trans_collected);
|
||||
|
||||
vif.wait_clks(1);
|
||||
end
|
||||
endtask : run_phase
|
||||
endclass : ibex_rvfi_monitor
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class ibex_rvfi_seq_item extends uvm_sequence_item;
|
||||
bit irq_only;
|
||||
bit trap;
|
||||
bit [31:0] pc;
|
||||
bit [4:0] rd_addr;
|
||||
bit [31:0] rd_wdata;
|
||||
bit [63:0] order;
|
||||
bit [31:0] pre_mip;
|
||||
bit [31:0] post_mip;
|
||||
bit nmi;
|
||||
bit nmi_int;
|
||||
bit debug_req;
|
||||
bit rf_wr_suppress;
|
||||
bit [63:0] mcycle;
|
||||
|
||||
bit [31:0] mhpmcounters [10];
|
||||
bit [31:0] mhpmcountersh [10];
|
||||
bit ic_scr_key_valid;
|
||||
|
||||
`uvm_object_utils_begin(ibex_rvfi_seq_item)
|
||||
`uvm_field_int (trap, UVM_DEFAULT)
|
||||
`uvm_field_int (pc, UVM_DEFAULT)
|
||||
`uvm_field_int (rd_addr, UVM_DEFAULT)
|
||||
`uvm_field_int (rd_wdata, UVM_DEFAULT)
|
||||
`uvm_field_int (order, UVM_DEFAULT)
|
||||
`uvm_field_int (pre_mip, UVM_DEFAULT)
|
||||
`uvm_field_int (post_mip, UVM_DEFAULT)
|
||||
`uvm_field_int (nmi, UVM_DEFAULT)
|
||||
`uvm_field_int (nmi_int, UVM_DEFAULT)
|
||||
`uvm_field_int (debug_req, UVM_DEFAULT)
|
||||
`uvm_field_int (rf_wr_suppress, UVM_DEFAULT)
|
||||
`uvm_field_int (mcycle, UVM_DEFAULT)
|
||||
`uvm_field_sarray_int (mhpmcounters, UVM_DEFAULT)
|
||||
`uvm_field_sarray_int (mhpmcountersh, UVM_DEFAULT)
|
||||
`uvm_field_int (ic_scr_key_valid, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
`uvm_object_new
|
||||
|
||||
endclass : ibex_rvfi_seq_item
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include <svdpi.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "cosim.h"
|
||||
#include "spike_cosim.h"
|
||||
|
||||
extern "C" {
|
||||
void *spike_cosim_init(const char *isa_string, svBitVecVal *start_pc,
|
||||
svBitVecVal *start_mtvec, const char *log_file_path_cstr,
|
||||
svBitVecVal *pmp_num_regions,
|
||||
svBitVecVal *pmp_granularity,
|
||||
svBitVecVal *mhpm_counter_num, svBit secure_ibex,
|
||||
svBit icache) {
|
||||
assert(isa_string);
|
||||
|
||||
std::string log_file_path;
|
||||
|
||||
if (log_file_path_cstr) {
|
||||
log_file_path = log_file_path_cstr;
|
||||
}
|
||||
|
||||
SpikeCosim *cosim = new SpikeCosim(
|
||||
isa_string, start_pc[0], start_mtvec[0], log_file_path, secure_ibex,
|
||||
icache, pmp_num_regions[0], pmp_granularity[0], mhpm_counter_num[0]);
|
||||
cosim->add_memory(0x80000000, 0x80000000);
|
||||
cosim->add_memory(0x00000000, 0x80000000);
|
||||
return static_cast<Cosim *>(cosim);
|
||||
}
|
||||
|
||||
void spike_cosim_release(void *cosim_handle) {
|
||||
auto cosim = static_cast<Cosim *>(cosim_handle);
|
||||
|
||||
delete cosim;
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`ifndef SPIKE_COSIM_DPI_SVH
|
||||
`define SPIKE_COSIM_DPI_SVH
|
||||
|
||||
import "DPI-C" function
|
||||
chandle spike_cosim_init(string isa_string,
|
||||
bit [31:0] start_pc,
|
||||
bit [31:0] start_mtvec,
|
||||
string log_file_path,
|
||||
bit [31:0] pmp_num_regions,
|
||||
bit [31:0] pmp_granularity,
|
||||
bit [31:0] mhpm_counter_num,
|
||||
bit secure_ibex,
|
||||
bit icache);
|
||||
|
||||
import "DPI-C" function void spike_cosim_release(chandle cosim_handle);
|
||||
|
||||
`endif
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
interface ibex_mem_intf#(
|
||||
parameter int ADDR_WIDTH = 32,
|
||||
parameter int DATA_WIDTH = 32,
|
||||
parameter int INTG_WIDTH = 7
|
||||
parameter int DATA_WIDTH = 32
|
||||
) (
|
||||
input clk
|
||||
);
|
||||
|
@ -18,15 +17,8 @@ interface ibex_mem_intf#(
|
|||
wire [DATA_WIDTH/8-1:0] be;
|
||||
wire rvalid;
|
||||
wire [DATA_WIDTH-1:0] wdata;
|
||||
wire [INTG_WIDTH-1:0] wintg;
|
||||
wire [DATA_WIDTH-1:0] rdata;
|
||||
wire [INTG_WIDTH-1:0] rintg;
|
||||
wire error;
|
||||
wire misaligned_first;
|
||||
wire misaligned_second;
|
||||
wire misaligned_first_saw_error;
|
||||
wire m_mode_access;
|
||||
wire spurious_response;
|
||||
|
||||
clocking request_driver_cb @(posedge clk);
|
||||
input reset;
|
||||
|
@ -37,11 +29,8 @@ interface ibex_mem_intf#(
|
|||
output be;
|
||||
input rvalid;
|
||||
output wdata;
|
||||
output wintg;
|
||||
input rdata;
|
||||
input rintg;
|
||||
input error;
|
||||
input spurious_response;
|
||||
endclocking
|
||||
|
||||
clocking response_driver_cb @(posedge clk);
|
||||
|
@ -53,11 +42,8 @@ interface ibex_mem_intf#(
|
|||
input be;
|
||||
output rvalid;
|
||||
input wdata;
|
||||
input wintg;
|
||||
output rdata;
|
||||
output rintg;
|
||||
output error;
|
||||
output spurious_response;
|
||||
endclocking
|
||||
|
||||
clocking monitor_cb @(posedge clk);
|
||||
|
@ -69,15 +55,8 @@ interface ibex_mem_intf#(
|
|||
input be;
|
||||
input rvalid;
|
||||
input wdata;
|
||||
input wintg;
|
||||
input rdata;
|
||||
input rintg;
|
||||
input error;
|
||||
input misaligned_first;
|
||||
input misaligned_second;
|
||||
input misaligned_first_saw_error;
|
||||
input m_mode_access;
|
||||
input spurious_response;
|
||||
endclocking
|
||||
|
||||
task automatic wait_clks(input int num);
|
||||
|
|
|
@ -5,16 +5,19 @@
|
|||
package ibex_mem_intf_agent_pkg;
|
||||
|
||||
import uvm_pkg::*;
|
||||
import ibex_mem_intf_pkg::*;
|
||||
import mem_model_pkg::*;
|
||||
import ibex_cosim_agent_pkg::*;
|
||||
|
||||
parameter int DATA_WIDTH = 32;
|
||||
parameter int ADDR_WIDTH = 32;
|
||||
|
||||
typedef enum { READ, WRITE } rw_e;
|
||||
|
||||
`include "uvm_macros.svh"
|
||||
`include "ibex_mem_intf_seq_item.sv"
|
||||
|
||||
typedef uvm_sequencer#(ibex_mem_intf_seq_item) ibex_mem_intf_request_sequencer;
|
||||
|
||||
`include "ibex_mem_intf_monitor.sv"
|
||||
`include "ibex_mem_intf_response_agent_cfg.sv"
|
||||
`include "ibex_mem_intf_response_driver.sv"
|
||||
`include "ibex_mem_intf_response_sequencer.sv"
|
||||
`include "ibex_mem_intf_response_seq_lib.sv"
|
||||
|
@ -22,8 +25,4 @@ package ibex_mem_intf_agent_pkg;
|
|||
`include "ibex_mem_intf_request_driver.sv"
|
||||
`include "ibex_mem_intf_request_agent.sv"
|
||||
|
||||
// Re-export parameters from ibex_mem_intf_pkg so that other packages can access them through this
|
||||
// package.
|
||||
export ibex_mem_intf_pkg::*;
|
||||
|
||||
endpackage
|
||||
|
|
|
@ -10,28 +10,18 @@ class ibex_mem_intf_monitor extends uvm_monitor;
|
|||
|
||||
protected virtual ibex_mem_intf vif;
|
||||
|
||||
// The monitor tick event fires every clock cycle once any writes to
|
||||
// outstanding_access_port and addr_ph_ports have occurred.
|
||||
event monitor_tick;
|
||||
|
||||
mailbox #(ibex_mem_intf_seq_item) collect_response_queue;
|
||||
mailbox #(ibex_mem_intf_seq_item) collect_data_queue;
|
||||
uvm_analysis_port#(ibex_mem_intf_seq_item) item_collected_port;
|
||||
uvm_analysis_port#(ibex_mem_intf_seq_item) addr_ph_port;
|
||||
// The number of outstanding accesses is written to this port every clock cycle
|
||||
uvm_analysis_port#(int) outstanding_accesses_port;
|
||||
|
||||
`uvm_component_utils(ibex_mem_intf_monitor)
|
||||
`uvm_component_new
|
||||
|
||||
int outstanding_accesses = 0;
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
item_collected_port = new("item_collected_port", this);
|
||||
addr_ph_port = new("addr_ph_port_monitor", this);
|
||||
collect_response_queue = new();
|
||||
outstanding_accesses_port = new("outstanding_accesses_port", this);
|
||||
|
||||
collect_data_queue = new();
|
||||
if(!uvm_config_db#(virtual ibex_mem_intf)::get(this, "", "vif", vif)) begin
|
||||
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
|
||||
end
|
||||
|
@ -40,15 +30,13 @@ class ibex_mem_intf_monitor extends uvm_monitor;
|
|||
virtual task run_phase(uvm_phase phase);
|
||||
wait (vif.monitor_cb.reset === 1'b0);
|
||||
forever begin
|
||||
fork begin : isolation_fork
|
||||
fork : check_mem_intf
|
||||
collect_address_phase();
|
||||
collect_response_phase();
|
||||
wait (vif.monitor_cb.reset === 1'b1);
|
||||
join_any
|
||||
// Will only reach this point when mid-test reset is asserted
|
||||
disable fork;
|
||||
end join
|
||||
fork : check_mem_intf
|
||||
collect_address_phase();
|
||||
collect_data_phase();
|
||||
wait (vif.monitor_cb.reset === 1'b1);
|
||||
join_any
|
||||
// Will only reach this point when mid-test reset is asserted
|
||||
disable fork;
|
||||
handle_reset();
|
||||
end
|
||||
endtask : run_phase
|
||||
|
@ -56,74 +44,45 @@ class ibex_mem_intf_monitor extends uvm_monitor;
|
|||
virtual protected task handle_reset();
|
||||
ibex_mem_intf_seq_item mailbox_result;
|
||||
// Clear the mailbox of any content
|
||||
while (collect_response_queue.try_get(mailbox_result));
|
||||
while (collect_data_queue.try_get(mailbox_result));
|
||||
wait (vif.monitor_cb.reset === 1'b0);
|
||||
endtask
|
||||
|
||||
virtual protected task collect_address_phase();
|
||||
ibex_mem_intf_seq_item trans_collected;
|
||||
|
||||
|
||||
forever begin
|
||||
@(vif.monitor_cb);
|
||||
|
||||
trans_collected = ibex_mem_intf_seq_item::type_id::create("trans_collected");
|
||||
|
||||
while (!(vif.monitor_cb.request && vif.monitor_cb.grant)) begin
|
||||
if (vif.monitor_cb.rvalid && !vif.monitor_cb.spurious_response) begin
|
||||
outstanding_accesses--;
|
||||
end
|
||||
outstanding_accesses_port.write(outstanding_accesses);
|
||||
|
||||
-> monitor_tick;
|
||||
@(vif.monitor_cb);
|
||||
end
|
||||
|
||||
trans_collected.addr = vif.monitor_cb.addr;
|
||||
trans_collected.be = vif.monitor_cb.be;
|
||||
trans_collected.misaligned_first = vif.monitor_cb.misaligned_first;
|
||||
trans_collected.misaligned_second = vif.monitor_cb.misaligned_second;
|
||||
trans_collected.misaligned_first_saw_error = vif.monitor_cb.misaligned_first_saw_error;
|
||||
trans_collected.m_mode_access = vif.monitor_cb.m_mode_access;
|
||||
while(!(vif.monitor_cb.request && vif.monitor_cb.grant)) vif.wait_clks(1);
|
||||
trans_collected.addr = vif.monitor_cb.addr;
|
||||
trans_collected.be = vif.monitor_cb.be;
|
||||
`uvm_info(get_full_name(), $sformatf("Detect request with address: %0x",
|
||||
trans_collected.addr), UVM_HIGH)
|
||||
if (vif.monitor_cb.we) begin
|
||||
if(vif.monitor_cb.we) begin
|
||||
trans_collected.read_write = WRITE;
|
||||
trans_collected.data = vif.monitor_cb.wdata;
|
||||
trans_collected.intg = vif.monitor_cb.wintg;
|
||||
end else begin
|
||||
trans_collected.read_write = READ;
|
||||
end
|
||||
addr_ph_port.write(trans_collected);
|
||||
`uvm_info(get_full_name(),"Send through addr_ph_port", UVM_HIGH)
|
||||
collect_response_queue.put(trans_collected);
|
||||
|
||||
outstanding_accesses++;
|
||||
if (vif.monitor_cb.rvalid && !vif.monitor_cb.spurious_response) begin
|
||||
outstanding_accesses--;
|
||||
end
|
||||
outstanding_accesses_port.write(outstanding_accesses);
|
||||
|
||||
-> monitor_tick;
|
||||
if(trans_collected.read_write == WRITE)
|
||||
item_collected_port.write(trans_collected);
|
||||
else
|
||||
collect_data_queue.put(trans_collected);
|
||||
vif.wait_clks(1);
|
||||
end
|
||||
endtask : collect_address_phase
|
||||
|
||||
virtual protected task collect_response_phase();
|
||||
virtual protected task collect_data_phase();
|
||||
ibex_mem_intf_seq_item trans_collected;
|
||||
forever begin
|
||||
collect_response_queue.get(trans_collected);
|
||||
collect_data_queue.get(trans_collected);
|
||||
do
|
||||
@(vif.monitor_cb);
|
||||
while(vif.monitor_cb.rvalid === 0 || vif.monitor_cb.spurious_response === 1);
|
||||
|
||||
if (trans_collected.read_write == READ) begin
|
||||
trans_collected.data = vif.monitor_cb.rdata;
|
||||
trans_collected.intg = vif.monitor_cb.rintg;
|
||||
end
|
||||
|
||||
trans_collected.error = vif.monitor_cb.error;
|
||||
vif.wait_clks(1);
|
||||
while(vif.monitor_cb.rvalid === 0);
|
||||
trans_collected.data = vif.monitor_cb.rdata;
|
||||
item_collected_port.write(trans_collected);
|
||||
end
|
||||
endtask : collect_response_phase
|
||||
endtask : collect_data_phase
|
||||
|
||||
endclass : ibex_mem_intf_monitor
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package ibex_mem_intf_pkg;
|
||||
|
||||
import uvm_pkg::*;
|
||||
|
||||
parameter int DATA_WIDTH = 32;
|
||||
parameter int ADDR_WIDTH = 32;
|
||||
parameter int INTG_WIDTH = 7;
|
||||
|
||||
typedef enum { READ, WRITE } rw_e;
|
||||
|
||||
`include "uvm_macros.svh"
|
||||
`include "ibex_mem_intf_seq_item.sv"
|
||||
|
||||
endpackage
|
|
@ -49,7 +49,6 @@ class ibex_mem_intf_request_driver extends uvm_driver #(ibex_mem_intf_seq_item);
|
|||
vif.request_driver_cb.request <= 'h0;
|
||||
vif.request_driver_cb.addr <= 'hz;
|
||||
vif.request_driver_cb.wdata <= 'hz;
|
||||
vif.request_driver_cb.wintg <= 'hz;
|
||||
vif.request_driver_cb.be <= 'bz;
|
||||
vif.request_driver_cb.we <= 'bz;
|
||||
end
|
||||
|
@ -64,13 +63,11 @@ class ibex_mem_intf_request_driver extends uvm_driver #(ibex_mem_intf_seq_item);
|
|||
vif.request_driver_cb.be <= trans.be;
|
||||
vif.request_driver_cb.we <= trans.read_write;
|
||||
vif.request_driver_cb.wdata <= trans.data;
|
||||
vif.request_driver_cb.wintg <= trans.intg;
|
||||
wait (vif.request_driver_cb.grant === 1'b1);
|
||||
vif.wait_clks(1);
|
||||
vif.request_driver_cb.request <= 'h0;
|
||||
vif.request_driver_cb.addr <= 'hz;
|
||||
vif.request_driver_cb.wdata <= 'hz;
|
||||
vif.request_driver_cb.wintg <= 'hz;
|
||||
vif.request_driver_cb.be <= 'bz;
|
||||
vif.request_driver_cb.we <= 'bz;
|
||||
rdata_queue.put(trans);
|
||||
|
@ -81,10 +78,9 @@ class ibex_mem_intf_request_driver extends uvm_driver #(ibex_mem_intf_seq_item);
|
|||
forever begin
|
||||
rdata_queue.get(tr);
|
||||
vif.wait_clks(1);
|
||||
while((vif.rvalid !== 1'b1 || vif.spurious_response === 1'b1)) vif.wait_clks(1);
|
||||
while(vif.rvalid !== 1'b1) vif.wait_clks(1);
|
||||
if(tr.read_write == READ)
|
||||
tr.data = vif.request_driver_cb.rdata;
|
||||
tr.intg = vif.request_driver_cb.rintg;
|
||||
seq_item_port.put_response(tr);
|
||||
end
|
||||
endtask : collect_response
|
||||
|
|
|
@ -10,33 +10,18 @@ class ibex_mem_intf_response_agent extends uvm_agent;
|
|||
|
||||
ibex_mem_intf_response_driver driver;
|
||||
ibex_mem_intf_response_sequencer sequencer;
|
||||
ibex_mem_intf_monitor monitor;
|
||||
ibex_mem_intf_response_agent_cfg cfg;
|
||||
ibex_mem_intf_monitor monitor;
|
||||
|
||||
`uvm_component_utils(ibex_mem_intf_response_agent)
|
||||
`uvm_component_new
|
||||
|
||||
virtual function void build_phase(uvm_phase phase);
|
||||
bit secure_ibex;
|
||||
|
||||
super.build_phase(phase);
|
||||
monitor = ibex_mem_intf_monitor::type_id::create("monitor", this);
|
||||
if (cfg == null)
|
||||
if(!uvm_config_db #(ibex_mem_intf_response_agent_cfg)::get(this, "", "cfg", cfg))
|
||||
`uvm_fatal(`gfn, "Could not locate mem_intf cfg object in uvm_config_db!")
|
||||
|
||||
if(get_is_active() == UVM_ACTIVE) begin
|
||||
driver = ibex_mem_intf_response_driver::type_id::create("driver", this);
|
||||
sequencer = ibex_mem_intf_response_sequencer::type_id::create("sequencer", this);
|
||||
end
|
||||
if(!uvm_config_db#(virtual ibex_mem_intf)::get(this, "", "vif", cfg.vif))
|
||||
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
|
||||
|
||||
if (!uvm_config_db#(bit)::get(null, "", "SecureIbex", secure_ibex)) begin
|
||||
secure_ibex = 1'b0;
|
||||
end
|
||||
|
||||
cfg.fixed_data_write_response = secure_ibex;
|
||||
endfunction : build_phase
|
||||
|
||||
function void connect_phase(uvm_phase phase);
|
||||
|
@ -44,12 +29,7 @@ class ibex_mem_intf_response_agent extends uvm_agent;
|
|||
if(get_is_active() == UVM_ACTIVE) begin
|
||||
driver.seq_item_port.connect(sequencer.seq_item_export);
|
||||
monitor.addr_ph_port.connect(sequencer.addr_ph_port.analysis_export);
|
||||
monitor.outstanding_accesses_port.connect(sequencer.outstanding_accesses_imp);
|
||||
end
|
||||
driver.cfg = cfg;
|
||||
sequencer.cfg = cfg;
|
||||
|
||||
sequencer.monitor_tick = monitor.monitor_tick;
|
||||
endfunction : connect_phase
|
||||
|
||||
function void reset();
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CLASS: ibex_mem_intf_response_agent_cfg
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ibex_mem_intf_response_agent_cfg extends uvm_object;
|
||||
|
||||
// interface handle used by driver & monitor
|
||||
virtual ibex_mem_intf vif;
|
||||
|
||||
// When set write responses have a fixed 32'hffffffff for rdata and matching correct rintg. When
|
||||
// unset both rdata and rintg fields are x for write responses
|
||||
bit fixed_data_write_response = 1'b0;
|
||||
|
||||
// delay between request and grant
|
||||
int unsigned gnt_delay_min = 0;
|
||||
int unsigned gnt_delay_max = 10;
|
||||
// Pick the weight assigned to choosing medium and long gaps between request and grant
|
||||
int unsigned gnt_pick_medium_speed_weight = 1;
|
||||
int unsigned gnt_pick_slow_speed_weight = 1;
|
||||
|
||||
// delay between grant and rvalid
|
||||
int unsigned valid_delay_min = 0;
|
||||
int unsigned valid_delay_max = 20;
|
||||
// Pick the weight assigned to choosing medium and long gaps between grant and rvalid
|
||||
int unsigned valid_pick_medium_speed_weight = 1;
|
||||
int unsigned valid_pick_slow_speed_weight = 1;
|
||||
|
||||
// Enables/disable all protocol delays.
|
||||
rand bit zero_delays;
|
||||
|
||||
// Knob to enable percentage of zero delay in auto-response sequence.
|
||||
// Default set to 50% for zero delay to be picked
|
||||
int unsigned zero_delay_pct = 50;
|
||||
|
||||
// CONTROL_KNOB : enable/disable to generation of bad integrity upon uninit accesses
|
||||
bit enable_bad_intg_on_uninit_access = 0;
|
||||
|
||||
int unsigned spurious_response_delay_min = 0;
|
||||
int unsigned spurious_response_delay_max = 100;
|
||||
|
||||
constraint zero_delays_c {
|
||||
zero_delays dist {1 :/ zero_delay_pct,
|
||||
0 :/ 100 - zero_delay_pct};
|
||||
}
|
||||
|
||||
`uvm_object_utils_begin(ibex_mem_intf_response_agent_cfg)
|
||||
`uvm_field_int(fixed_data_write_response, UVM_DEFAULT)
|
||||
`uvm_field_int(gnt_delay_min, UVM_DEFAULT)
|
||||
`uvm_field_int(gnt_delay_max, UVM_DEFAULT)
|
||||
`uvm_field_int(valid_delay_min, UVM_DEFAULT)
|
||||
`uvm_field_int(valid_delay_max, UVM_DEFAULT)
|
||||
`uvm_field_int(zero_delays, UVM_DEFAULT)
|
||||
`uvm_field_int(zero_delay_pct, UVM_DEFAULT)
|
||||
`uvm_field_int(spurious_response_delay_min, UVM_DEFAULT)
|
||||
`uvm_field_int(spurious_response_delay_max, UVM_DEFAULT)
|
||||
|
||||
`uvm_object_utils_end
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
endclass
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue