Update lowrisc_ibex to lowRISC/ibex@d14312c
Ibex top-level interface has changed, single hart_id replaces
cluster_id/core_id.
Update code from upstream repository
https://github.com/lowRISC/ibex.git to revision
d14312c3cc47a7d4b34943e4febb96312353b2cc
* Replace cluster_id/core_id with hart_id (lowRISC/ibex#29) (Greg
Chadwick)
* CSR: Access checks on Debug CSRs (Rahul Behl)
* [RTL] - Add PMP module (Tom Roberts)
* Register file: update comments (Pirmin Vogel)
* Controller: change behavior of DRET instruction (Pirmin Vogel)
* Update interrupt mode, add debug mode WFI test (lowRISC/ibex#268)
(udinator)
* Lint: Update Verilator waiver file (Philipp Wagner)
* Update google_riscv-dv to 102791d (lowRISC/ibex#266) (taoliug)
* Mention CREDITS.md in license header (Philipp Wagner)
* Replace author credits in files with CREDITS.md (Philipp Wagner)
* Add link to CREDITS.md from README.md (Philipp Wagner)
* Add CREDITS.md file (Philipp Wagner)
* Integrate risc-v stream generator handshake into Ibex sim flow
(lowRISC/ibex#264) (udinator)
* Update google_riscv-dv to google/riscv-dv@faddfa4 (lowRISC/ibex#263)
(udinator)
* Correct a typo in doc/verification.rst (Felix Yan)
* Update documentation how to run riscv-compliance (Philipp Wagner)
* CI: Run the compliance tests for all ISA variants (Philipp Wagner)
* Update google_riscv-dv to e81acc9 (lowRISC/ibex#257) (taoliug)
* Make mtvec writable, remove previous workaround (lowRISC/ibex#256)
(taoliug)
* Test cleanup (lowRISC/ibex#255) (taoliug)
* Update google_riscv-dv to 73274f2 (lowRISC/ibex#254) (taoliug)
* Consolidate some debug generation options, and make the
signature_addr handshake optional (lowRISC/ibex#253) (udinator)
* Add more debug tests (lowRISC/ibex#251) (udinator)
* src_files.yml: Add ibex_core_tracing.sv (Pirmin Vogel)
* ram_1p.sv: Fix rvalid_o generation (Pirmin Vogel)
* Remove unused signal data_reg_offset (Ivan Ribeiro)
* Add Azure Pipelines build badge to README.md (Philipp Wagner)
* CI: Use Azure Pipelines to run lint and some DV (Philipp Wagner)
* Update google_riscv-dv to google/riscv-dv@7cce16c (lowRISC/ibex#246)
(udinator)
* ID stage: rework CSR-related pipeline flushes (Pirmin Vogel)
* Adapt Verilator lint waiver (Pirmin Vogel)
* Add basic debug test and modify sim flow (lowRISC/ibex#243)
(udinator)
* [DV] Enable aligned load/store test (lowRISC/ibex#242) (taoliug)
* Update google_riscv-dv to 63fa0ca (lowRISC/ibex#241) (taoliug)
* Update google_riscv-dv to google/riscv-dv@07599f6 (lowRISC/ibex#240)
(udinator)
* Fix the verbose logging issue, fix coverage/waveform options
(lowRISC/ibex#235) (taoliug)
* Update google_riscv-dv to google/riscv-dv@e905e9f (lowRISC/ibex#234)
(udinator)
* update ibex testbench (lowRISC/ibex#232) (udinator)
* update ibex simulation flow (lowRISC/ibex#233) (udinator)
* [rtl] Add support for instruction fetch errors (Tom Roberts)
diff --git a/hw/ip/rv_core_ibex/dv/tb/core_ibex_tb_top.sv b/hw/ip/rv_core_ibex/dv/tb/core_ibex_tb_top.sv
index f838482..545dd93 100644
--- a/hw/ip/rv_core_ibex/dv/tb/core_ibex_tb_top.sv
+++ b/hw/ip/rv_core_ibex/dv/tb/core_ibex_tb_top.sv
@@ -21,8 +21,7 @@
.clk_i(clk),
.rst_ni(rst_n),
.test_en_i(1'b1),
- .core_id_i('0),
- .cluster_id_i('0),
+ .hart_id_i(32'b0),
.boot_addr_i(`BOOT_ADDR), // align with spike boot address
.irq_i('0),
.irq_id_i('0),
diff --git a/hw/ip/rv_core_ibex/rtl/rv_core_ibex.sv b/hw/ip/rv_core_ibex/rtl/rv_core_ibex.sv
index 3bba30f..c9660c9 100644
--- a/hw/ip/rv_core_ibex/rtl/rv_core_ibex.sv
+++ b/hw/ip/rv_core_ibex/rtl/rv_core_ibex.sv
@@ -22,9 +22,7 @@
input logic test_en_i, // enable all clock gates for testing
- // Core ID, Cluster ID and boot address are considered more or less static
- input logic [ 3:0] core_id_i,
- input logic [ 5:0] cluster_id_i,
+ input logic [31:0] hart_id_i,
input logic [31:0] boot_addr_i,
// Instruction memory interface
@@ -105,8 +103,7 @@
.test_en_i,
- .core_id_i,
- .cluster_id_i,
+ .hart_id_i,
.boot_addr_i,
.instr_req_o,
@@ -244,8 +241,7 @@
.rst_ni ( rst_ni ),
.fetch_enable_i ( fetch_enable_i ),
- .core_id_i ( core_id_i ),
- .cluster_id_i ( cluster_id_i ),
+ .hart_id_i ( hart_id_i ),
.valid_i ( rvfi_valid ),
.pc_i ( rvfi_pc_rdata ),
diff --git a/hw/top_earlgrey/doc/top_earlgrey.tpl.sv b/hw/top_earlgrey/doc/top_earlgrey.tpl.sv
index da28906..bae971b 100644
--- a/hw/top_earlgrey/doc/top_earlgrey.tpl.sv
+++ b/hw/top_earlgrey/doc/top_earlgrey.tpl.sv
@@ -116,8 +116,7 @@
.rst_ni (ndmreset_n),
.test_en_i (1'b0),
// static pinning
- .core_id_i (4'b0000),
- .cluster_id_i (6'b000000),
+ .hart_id_i (32'b0),
.boot_addr_i (ADDR_SPACE_ROM),
// TL-UL buses
.tl_i_o (tl_corei_h_h2d),
diff --git a/hw/top_earlgrey/rtl/top_earlgrey.sv b/hw/top_earlgrey/rtl/top_earlgrey.sv
index a64c23f..8128ba7 100644
--- a/hw/top_earlgrey/rtl/top_earlgrey.sv
+++ b/hw/top_earlgrey/rtl/top_earlgrey.sv
@@ -128,8 +128,7 @@
.rst_ni (ndmreset_n),
.test_en_i (1'b0),
// static pinning
- .core_id_i (4'b0000),
- .cluster_id_i (6'b000000),
+ .hart_id_i (32'b0),
.boot_addr_i (ADDR_SPACE_ROM),
// TL-UL buses
.tl_i_o (tl_corei_h_h2d),
diff --git a/hw/top_earlgrey/rtl/top_earlgrey_usb.sv b/hw/top_earlgrey/rtl/top_earlgrey_usb.sv
index a9b0b67..fd79548 100644
--- a/hw/top_earlgrey/rtl/top_earlgrey_usb.sv
+++ b/hw/top_earlgrey/rtl/top_earlgrey_usb.sv
@@ -93,8 +93,7 @@
.rst_ni (ndmreset_n),
.test_en_i (1'b0),
// static pinning
- .core_id_i (4'b0000),
- .cluster_id_i (6'b000000),
+ .hart_id_i (32'b0),
.boot_addr_i (ADDR_SPACE_RAM_MAIN + 'h1000), // no ROM for now, straight out of SRAM
// TL-UL buses
.tl_i_o (tl_h_h2d[TlCorei]),
diff --git a/hw/vendor/lowrisc_ibex.lock.hjson b/hw/vendor/lowrisc_ibex.lock.hjson
index 14d5505..37908b0 100644
--- a/hw/vendor/lowrisc_ibex.lock.hjson
+++ b/hw/vendor/lowrisc_ibex.lock.hjson
@@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/lowRISC/ibex.git
- rev: ca97cfb58ee8fe94382372e6c3c766218a200a24
+ rev: d14312c3cc47a7d4b34943e4febb96312353b2cc
}
}
diff --git a/hw/vendor/lowrisc_ibex/CREDITS.md b/hw/vendor/lowrisc_ibex/CREDITS.md
new file mode 100644
index 0000000..2d27294
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/CREDITS.md
@@ -0,0 +1,44 @@
+Credits
+=======
+
+Ibex has originally been developed by the PULP team at ETH Zürich and
+University of Bologna under the name Zero-riscy. In December 2018, Ibex has
+been contributed to lowRISC who is maintaining and advancing the design since
+then.
+
+Throughout the years, Ibex has seen contributions from many people and we at
+lowRISC are very thankful for all of them. This file lists the many people who
+contributed to what is called Ibex today. If you made a contribution to Ibex
+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 Traber
+- Antonio Pullini
+- Eunchan Kim
+- Florian Zaruba
+- Francesco Conti
+- Germain Haugou
+- Igor Loi
+- Ioannis Karageorgos
+- Markus Wegmann
+- Ivan Ribeiro
+- Matthias Baer
+- Michael Gautschi
+- Michael Schaffner
+- Nils Graf
+- Noah Huesser
+- Pasquale Davide Schiavone
+- Philipp Wagner
+- Pirmin Vogel
+- Rahul Behl
+- Rhys Thomas
+- Renzo Andri
+- Robert Schilling
+- Scott Johnson
+- Stefan Wallentowitz
+- Sven Stucki
+- Tao Liu
+- Tobias Wölfel
+- Tom Roberts
+- Udi Jonnalagadda
diff --git a/hw/vendor/lowrisc_ibex/README.md b/hw/vendor/lowrisc_ibex/README.md
index cf5bcf1..c044ef2 100644
--- a/hw/vendor/lowrisc_ibex/README.md
+++ b/hw/vendor/lowrisc_ibex/README.md
@@ -1,3 +1,5 @@
+[](https://dev.azure.com/lowrisc/ibex/_build/latest?definitionId=3&branchName=master)
+
# Ibex RISC-V Core
Ibex is a small and efficient, 32-bit, in-order RISC-V core with a 2-stage pipeline that implements
@@ -57,6 +59,11 @@
Unless otherwise noted, everything in this repository is covered by the Apache
License, Version 2.0 (see LICENSE for full text).
+## Credits
+
+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."
diff --git a/hw/vendor/lowrisc_ibex/azure-pipelines.yml b/hw/vendor/lowrisc_ibex/azure-pipelines.yml
new file mode 100644
index 0000000..e95f9f1
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/azure-pipelines.yml
@@ -0,0 +1,135 @@
+# 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:
+ VERILATOR_VERSION: 4.016
+ VERILATOR_PATH: /opt/buildcache/verilator/$(VERILATOR_VERSION)
+ RISCV_TOOLCHAIN_TAR_VERSION: 20190807-1
+
+trigger:
+ batch: true
+ branches:
+# Combine builds on master as long as another build is running
+ include:
+ - master
+
+# 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-16.04"
+ steps:
+ # Installing six is a workaround for pip dependency resolution: six is already
+ # installed as system package with a version below the required one.
+ # Explicitly installing six through pip gets us a supported version.
+ - bash: |
+ sudo apt-get install -y \
+ python3 \
+ python3-pip \
+ python3-setuptools \
+ srecord \
+ zlib1g-dev \
+ git \
+ make \
+ autoconf \
+ g++ \
+ flex \
+ bison \
+ curl \
+ && sudo pip3 install -U six fusesoc
+ displayName: Install dependencies
+
+ - bash: |
+ set -e
+ if [ ! -d $(VERILATOR_PATH) ]; then
+ echo "Building verilator (no cached build found)"
+ mkdir -p build/verilator
+ cd build/verilator
+ curl -Ls -o verilator.tgz https://www.veripool.org/ftp/verilator-$(VERILATOR_VERSION).tgz
+ tar -xf verilator.tgz
+ cd verilator-$(VERILATOR_VERSION)
+ ./configure --prefix=$(VERILATOR_PATH)
+ make -j$(nproc)
+ mkdir -p $VERILATOR_PATH
+ make install
+ else
+ echo "Re-using cached verilator build"
+ fi
+ echo "##vso[task.setvariable variable=PATH]$VERILATOR_PATH/bin:$PATH"
+ displayName: Build and install Verilator
+
+ - bash: |
+ export TOOLCHAIN_URL=https://github.com/lowRISC/lowrisc-toolchains/releases/download/${RISCV_TOOLCHAIN_TAR_VERSION}/lowrisc-toolchain-gcc-rv32imc-${RISCV_TOOLCHAIN_TAR_VERSION}.tar.xz
+ mkdir -p build/toolchain
+ curl -Ls -o build/toolchain/rv32-toolchain.tar.xz $TOOLCHAIN_URL
+ sudo mkdir -p /tools/riscv && sudo chmod 777 /tools/riscv
+ tar -C /tools/riscv -xf build/toolchain/rv32-toolchain.tar.xz --strip-components=1
+ echo "##vso[task.setvariable variable=PATH]/tools/riscv/bin:$PATH"
+ displayName: Get precompiled RISC-V toolchain
+
+ - bash: |
+ echo $PATH
+ python3 --version
+ echo -n "fusesoc "
+ fusesoc --version
+ verilator --version
+ riscv32-unknown-elf-gcc --version
+ displayName: Display environment
+
+ - bash: |
+ fusesoc --cores-root . run --target=lint lowrisc:ibex:ibex_core
+ if [ $? != 0 ]; then
+ echo -n "##vso[task.logissue type=error]"
+ echo "Verilog lint failed. Run 'fusesoc --cores-root . run --target=lint lowrisc:ibex:ibex_core' to check and fix all errors."
+ exit 1
+ fi
+ displayName: Lint Verilog source files with Verilator
+
+ - bash: |
+ cd build
+ git clone https://github.com/riscv/riscv-compliance.git
+ displayName: Get RISC-V Compliance test suite
+
+ - bash: |
+ # Build simulation model of Ibex
+ fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_riscv_compliance --RV32M=1 --RV32E=0
+ 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; 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: 5/55' 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"
diff --git a/hw/vendor/lowrisc_ibex/doc/cs_registers.rst b/hw/vendor/lowrisc_ibex/doc/cs_registers.rst
index 067607a..9f29a7c 100644
--- a/hw/vendor/lowrisc_ibex/doc/cs_registers.rst
+++ b/hw/vendor/lowrisc_ibex/doc/cs_registers.rst
@@ -34,6 +34,18 @@
+---------+--------------------+--------+-----------------------------------------------+
| 0x344 | ``mip`` | R | Machine Interrupt Pending Register |
+---------+--------------------+--------+-----------------------------------------------+
+| 0x3A0 | ``pmpcfg0`` | WARL | PMP Configuration Register |
++---------+--------------------+--------+-----------------------------------------------+
+| . . . . |
++---------+--------------------+--------+-----------------------------------------------+
+| 0x3A3 | ``pmpcfg3`` | WARL | PMP Configuration Register |
++---------+--------------------+--------+-----------------------------------------------+
+| 0x3B0 | ``pmpaddr0`` | WARL | PMP Address Register |
++---------+--------------------+--------+-----------------------------------------------+
+| . . . . |
++---------+--------------------+--------+-----------------------------------------------+
+| 0x3BF | ``pmpaddr15`` | WARL | PMP Address Register |
++---------+--------------------+--------+-----------------------------------------------+
| 0x7B0 | ``dcsr`` | RW | Debug Control and Status Register |
+---------+--------------------+--------+-----------------------------------------------+
| 0x7B1 | ``dpc`` | RW | Debug PC |
@@ -212,6 +224,57 @@
| 3 | **Machine Software Interrupt Pending (MSIP):** if set, ``irq_software_i`` is pending. |
+-------+---------------------------------------------------------------------------------------+
+PMP Configuration Register (pmpcfgx)
+----------------------------------------
+
+CSR Address: ``0x3A0 - 0x3A3``
+
+Reset Value: ``0x0000_0000``
+
+``pmpcfgx`` are registers to configure PMP regions. Each register configures 4 PMP regions.
+
++---------------------------------------+
+| 31:24 | 23:16 | 15:8 | 7:0 |
++---------------------------------------+
+| pmp3cfg | pmp2cfg | pmp1cfg | pmp0cfg |
++---------------------------------------+
+
+The configuration fields for each region are as follows:
+
++-------+--------------------------+
+| Bit# | Definition |
++-------+--------------------------+
+| 7 | Lock |
++-------+--------------------------+
+| 6:5 | Reserved (Read as zero) |
++-------+--------------------------+
+| 4:3 | Mode |
++-------+--------------------------+
+| 2 | Execute permission |
++-------+--------------------------+
+| 1 | Write permission |
++-------+--------------------------+
+| 0 | Read permission |
++-------+--------------------------+
+
+Details of these configuration bits can be found in the RISC-V Privileged Specification, version 1.11 (see Physical Memory Protection CSRs, Section 3.6.1).
+
+Note that the combination of Write permission = 1, Read permission = 0 is reserved, and will be treated by the core as Read/Write permission = 0.
+
+PMP Address Register (pmpaddrx)
+----------------------------------------
+
+CSR Address: ``0x3B0 - 0x3BF``
+
+Reset Value: ``0x0000_0000``
+
+``pmpaddrx`` are registers to set address matching for PMP regions.
+
++----------------+
+| 31:0 |
++----------------+
+| address[33:2] |
++----------------+
.. _csr-mhartid:
diff --git a/hw/vendor/lowrisc_ibex/doc/exception_interrupts.rst b/hw/vendor/lowrisc_ibex/doc/exception_interrupts.rst
index a0e1212..99be67e 100644
--- a/hw/vendor/lowrisc_ibex/doc/exception_interrupts.rst
+++ b/hw/vendor/lowrisc_ibex/doc/exception_interrupts.rst
@@ -70,6 +70,8 @@
+----------------+---------------------------------------------------------------+
| Exception Code | Description |
+----------------+---------------------------------------------------------------+
+| 1 | Instruction access fault |
++----------------+---------------------------------------------------------------+
| 2 | Illegal instruction |
+----------------+---------------------------------------------------------------+
| 3 | Breakpoint |
@@ -81,7 +83,7 @@
| 11 | Environment call from M-mode (ECALL) |
+----------------+---------------------------------------------------------------+
-The illegal instruction exception, LSU error exceptions and ECALL instruction exceptions cannot be disabled and are always active.
+The illegal instruction exception, instruction access fault, LSU error exceptions and ECALL instruction exceptions cannot be disabled and are always active.
Handling
diff --git a/hw/vendor/lowrisc_ibex/doc/index.rst b/hw/vendor/lowrisc_ibex/doc/index.rst
index 2dfb674..7b241fd 100644
--- a/hw/vendor/lowrisc_ibex/doc/index.rst
+++ b/hw/vendor/lowrisc_ibex/doc/index.rst
@@ -14,6 +14,7 @@
cs_registers
performance_counters
exception_interrupts
+ pmp
debug
tracer
rvfi
diff --git a/hw/vendor/lowrisc_ibex/doc/instruction_fetch.rst b/hw/vendor/lowrisc_ibex/doc/instruction_fetch.rst
index f55bc4d..3c62b85 100644
--- a/hw/vendor/lowrisc_ibex/doc/instruction_fetch.rst
+++ b/hw/vendor/lowrisc_ibex/doc/instruction_fetch.rst
@@ -30,6 +30,8 @@
+-------------------------+-----------+-----------------------------------------------+
| ``instr_rdata_i[31:0]`` | input | Data read from memory |
+-------------------------+-----------+-----------------------------------------------+
+| ``instr_err_i`` | input | Memory access error |
++-------------------------+-----------+-----------------------------------------------+
Misaligned Accesses
diff --git a/hw/vendor/lowrisc_ibex/doc/integration.rst b/hw/vendor/lowrisc_ibex/doc/integration.rst
index fb39b59..b737da3 100644
--- a/hw/vendor/lowrisc_ibex/doc/integration.rst
+++ b/hw/vendor/lowrisc_ibex/doc/integration.rst
@@ -12,6 +12,9 @@
.. code-block:: verilog
ibex_core #(
+ .PMPEnable (0),
+ .PMPGranularity (0),
+ .PMPNumRegions (4),
.MHPMCounterNum (0),
.MHPMCounterWidth (40),
.RV32E (0),
@@ -25,8 +28,7 @@
.test_en_i (),
// Configuration
- .core_id_i (),
- .cluster_id_i (),
+ .hart_id_i (),
.boot_addr_i (),
// Instruction memory interface
@@ -35,6 +37,7 @@
.instr_rvalid_i (),
.instr_addr_o (),
.instr_rdata_i (),
+ .instr_err_i (),
// Data memory interface
.data_req_o (),
@@ -67,6 +70,12 @@
+-----------------------+-------------+------------+-----------------------------------------------------------------+
| Name | Type/Range | Default | Description |
+=======================+=============+============+=================================================================+
+| ``PMPEnable`` | bit | 0 | Enable PMP support |
++-----------------------+-------------+------------+-----------------------------------------------------------------+
+| ``PMPGranularity`` | int (0..31) | 0 | Minimum granularity of PMP address matching |
++-----------------------+-------------+------------+-----------------------------------------------------------------+
+| ``PMPNumRegions`` | int (1..16) | 4 | Number implemented PMP regions (ignored if PMPEnable == 0) |
++-----------------------+-------------+------------+-----------------------------------------------------------------+
| ``MHPMCounterNum`` | int (0..8) | 0 | Number of performance monitor event counters |
+-----------------------+-------------+------------+-----------------------------------------------------------------+
| ``MHPMCounterWidth`` | int (64..1) | 40 | Bit width of performance monitor event counters |
@@ -80,7 +89,6 @@
| ``DmExceptionAddr`` | int | 0x1A110808 | Address to jump to when an exception occurs while in debug mode |
+-----------------------+-------------+------------+-----------------------------------------------------------------+
-
Interfaces
----------
@@ -93,10 +101,8 @@
+-------------------------+-------------------------+-----+----------------------------------------+
| ``test_en_i`` | 1 | in | Test input, enables clock |
+-------------------------+-------------------------+-----+----------------------------------------+
-| ``core_id_i`` | 4 | in | Core ID, usually static, can be read |
+| ``hart_id_i`` | 32 | in | Hart ID, usually static, can be read |
| | | | from :ref:`csr-mhartid` CSR |
-+-------------------------+-------------------------+-----+ +
-| ``cluster_id_i`` | 6 | in | |
+-------------------------+-------------------------+-----+----------------------------------------+
| ``boot_addr_i`` | 32 | in | First program counter after reset |
| | | | = ``boot_addr_i`` + 0x80, |
diff --git a/hw/vendor/lowrisc_ibex/doc/introduction.rst b/hw/vendor/lowrisc_ibex/doc/introduction.rst
index 22ed619..3744422 100644
--- a/hw/vendor/lowrisc_ibex/doc/introduction.rst
+++ b/hw/vendor/lowrisc_ibex/doc/introduction.rst
@@ -82,6 +82,7 @@
The control and status registers are explained in :ref:`cs-registers`.
:ref:`performance-counters` gives an overview of the performance monitors and event counters available in Ibex.
:ref:`exceptions-interrupts` deals with the infrastructure for handling exceptions and interrupts,
+:ref:`pmp` gives a brief overview of PMP support.
:ref:`debug-support` gives a brief overview on the debug infrastructure.
:ref:`tracer` gives a brief overview of the tracer module.
For information regarding formal verification support, check out :ref:`rvfi`.
diff --git a/hw/vendor/lowrisc_ibex/doc/pmp.rst b/hw/vendor/lowrisc_ibex/doc/pmp.rst
new file mode 100644
index 0000000..eaa69b4
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/doc/pmp.rst
@@ -0,0 +1,33 @@
+.. _pmp:
+
+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.11.
+The following configuration parameters are available to control PMP checking:
+
++----------------+---------------+-------------------------------------------------+
+| Parameter | Default value | Description |
++================+===============+=================================================+
+| PMPEnable | 0 | PMP support enabled |
++----------------+---------------+-------------------------------------------------+
+| PMPNumRegions | 4 | Number of implemented regions (1 - 16) |
++----------------+---------------+-------------------------------------------------+
+| PMPGranularity | 0 | Minimum match granularity 2^G\+2 bytes (0 - 31) |
++----------------+---------------+-------------------------------------------------+
+
+When PMPEnable is zero, the PMP module is not instantiated and all PMP registers read as zero (regardless of the value of PMPNumRegions)
+
+PMP Integration
+---------------
+
+Addresses from the instruction fetch unit and load-store unit are passed to the PMP module for checking, and the output of the PMP check is used to gate the external request.
+To maintain consistency with external errors, the instruction fetch unit and load-store unit progress with their request as if it was granted externally.
+The PMP error is registered and consumed by the core when the data would have been consumed.
+
+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.
+
diff --git a/hw/vendor/lowrisc_ibex/doc/verification.rst b/hw/vendor/lowrisc_ibex/doc/verification.rst
index 62d74d2..66cd79b 100644
--- a/hw/vendor/lowrisc_ibex/doc/verification.rst
+++ b/hw/vendor/lowrisc_ibex/doc/verification.rst
@@ -64,7 +64,7 @@
# Verbose logging
make ... VERBOSE=1
- # Run multipe tests in parallel through LSF
+ # Run multiple tests in parallel through LSF
make ... LSF_CMD="bsub -Is"
# Get command reference of the simulation script
diff --git a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/README.md b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/README.md
index 99b89e6..b958e43 100644
--- a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/README.md
+++ b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/README.md
@@ -28,14 +28,16 @@
pip3 install --user -U fusesoc
```
- We recommend installing Verilator from source as versions from Linux distributions are often outdated.
- See https://www.veripool.org/projects/verilator/wiki/Installing for installation instructions.
+ We recommend installing Verilator from source as versions from Linux
+ distributions are often outdated. See
+ https://www.veripool.org/projects/verilator/wiki/Installing for installation
+ instructions.
1. Build a simulation of Ibex
```sh
cd $IBEX_REPO_BASE
- fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_riscv_compliance --RV32M=0 --RV32E=0
+ fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_riscv_compliance --RV32M=1 --RV32E=0
```
You can use the two compile-time options `--RV32M` and `--RV32E` to
@@ -45,31 +47,33 @@
2. Get the RISC-V Compliance test suite
- The compliance test suite currently needs workarounds for Ibex.
- Get a modified version of it.
+ The upstream RISC-V compliance test suite supports Ibex out of the box.
```
- git clone https://github.com/imphil/riscv-compliance.git
+ git clone https://github.com/riscv/riscv-compliance.git
cd riscv-compliance
- git checkout ibex
```
3. Run the test suite
```sh
cd $RISCV_COMPLIANCE_REPO_BASE
- export RISCV_TARGET=ibex
- export RISCV_ISA=rv32i
+ # adjust to match your compiler name
export RISCV_PREFIX=riscv32-unknown-elf-
+ # give the path to the simulation binary compiled in step 1
export TARGET_SIM=path/to/your/Vibex_riscv_compliance
- make clean
- make
+
+ export RISCV_DEVICE=rv32imc
+ export RISCV_TARGET=ibex
+
+ # Note: rv32imc does not include the I and M extension tests
+ make RISCV_ISA=rv32i && make RISCV_ISA=rv32im && make RISCV_ISA=rv32imc
```
Compliance test suite system
----------------------------
-This directory contains a system designed especially to run the compliance test suite.
-The system consists of
+This directory contains a system designed especially to run the compliance test
+suite. The system consists of
- an Ibex core,
- a bus,
diff --git a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv
index d8e88a2..58d1ec8 100644
--- a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv
+++ b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv
@@ -110,8 +110,7 @@
.test_en_i ('b0),
- .core_id_i (4'b0),
- .cluster_id_i (6'b0),
+ .hart_id_i (32'b0),
// First instruction executed is at 0x0 + 0x80
.boot_addr_i (32'h00000000),
@@ -120,6 +119,7 @@
.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]),
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/Makefile b/hw/vendor/lowrisc_ibex/dv/uvm/Makefile
index d02788a..b113a3c 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/Makefile
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/Makefile
@@ -2,35 +2,41 @@
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
-DV_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-GEN_DIR := $(realpath ${DV_DIR}/../../vendor/google_riscv-dv)
-TOOLCHAIN := ${RISCV_TOOLCHAIN}
-OUT := "${DV_DIR}/out"
+DV_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
+GEN_DIR := $(realpath ${DV_DIR}/../../vendor/google_riscv-dv)
+TOOLCHAIN := ${RISCV_TOOLCHAIN}
+OUT := "${DV_DIR}/out"
# Run time options for the instruction generator
-GEN_OPTS :=
+GEN_OPTS :=
# Run time options for ibex RTL simulation
-SIM_OPTS :=
+SIM_OPTS :=
# Enable waveform dumping
-WAVES := 1
+WAVES := 1
# Enable coverage dump
-COV := 0
+COV := 0
# RTL simulator
-SIMULATOR := "vcs"
+SIMULATOR := "vcs"
# ISS (spike, ovpsim)
-ISS := "spike"
+ISS := "spike"
# ISA
-ISA := "rv32imc"
+ISA := "rv32imc"
# Test name (default: full regression)
-TEST := "all"
+TEST := "all"
# Seed for instruction generator and RTL simulation
-SEED := -1
+SEED := -1
# Verbose logging
-VERBOSE := 0
+VERBOSE :=
# Number of iterations for each test, assign a non-zero value to override the
# iteration count in the test list
-ITERATIONS := 0
+ITERATIONS := 0
# LSF CMD
-LSF_CMD :=
+LSF_CMD :=
+# Generator timeout limit in seconds
+TIMEOUT := 1800
+# Privileged CSR YAML description file
+CSR_FILE := ${DV_DIR}/riscv_dv_extension/csr_description.yaml
+# Pass/fail signature address at the end of test
+SIGNATURE_ADDR := 8ffffffc
SHELL=/bin/bash
@@ -44,25 +50,36 @@
rm -rf ${OUT}
# Common options for all targets
-COMMON_OPTS=--seed=${SEED} \
- --test=${TEST} \
- --verbose=${VERBOSE} \
- --testlist=${DV_DIR}/riscv_dv_extension/testlist.yaml \
- --iterations=${ITERATIONS}
+COMMON_OPTS:=--seed=${SEED} \
+ --test=${TEST} \
+ --testlist=${DV_DIR}/riscv_dv_extension/testlist.yaml \
+ --iterations=${ITERATIONS}
+
+ifeq ($(VERBOSE), 1)
+ COMMON_OPTS+=--verbose
+endif
+
+# Options used for privileged CSR test generation
+CSR_OPTS=--csr_yaml=${CSR_FILE} \
+ --isa=${ISA} \
+ --end_signature_addr=0x${SIGNATURE_ADDR}
# Generate random instructions
.SILENT gen:
mkdir -p ${OUT}
cd ${GEN_DIR}; \
python3 ./run.py \
- --o=${OUT}/instr_gen ${GEN_OPTS} \
+ --output=${OUT}/instr_gen ${GEN_OPTS} \
--steps=gen \
+ --gen_timeout=${TIMEOUT} \
--lsf_cmd="${LSF_CMD}" \
${COMMON_OPTS} \
+ ${CSR_OPTS} \
--cmp_opts="+define+RISCV_CORE_SETTING=${DV_DIR}/riscv_dv_extension/ibex_core_setting.sv \
+define+RISCV_DV_EXT_FILE_LIST=${DV_DIR}/riscv_dv_extension/flist \
+incdir+${DV_DIR}/riscv_dv_extension/ " \
- --sim_opts="+uvm_set_type_override=riscv_asm_program_gen,ibex_asm_program_gen";
+ --sim_opts="+uvm_set_type_override=riscv_asm_program_gen,ibex_asm_program_gen \
+ +signature_addr=${SIGNATURE_ADDR}";
# Compile the generated assmebly programs to ELF/BIN
gcc_compile:
@@ -71,6 +88,7 @@
--o=${OUT}/instr_gen ${GEN_OPTS} \
--steps=gcc_compile \
${COMMON_OPTS} \
+ --gcc_opts=-mno-strict-align \
--isa=${ISA} \
--mabi=ilp32
@@ -103,8 +121,9 @@
--steps=sim \
${COMMON_OPTS} \
--simulator=${SIMULATOR} \
- --en_cov=${COV} \
- --en_wave=${WAVES} \
+ --en_cov ${COV} \
+ --en_wave ${WAVES} \
+ --sim_opts="+signature_addr=0x${SIGNATURE_ADDR}" \
${SIM_OPTS}
# Compare the regression result between ISS and RTL sim
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_master_driver.sv b/hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_master_driver.sv
index 64e58b3..23ad25a 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_master_driver.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_master_driver.sv
@@ -52,7 +52,10 @@
vif.irq_external <= trans.irq_external;
vif.irq_fast <= trans.irq_fast;
vif.irq_nm <= trans.irq_nm;
- @(posedge vif.clock);
+ // We hold the interrupt high for two cycles as Ibex is level sensitive,
+ // so this guarantees that Ibex will respond appropriately to the
+ // interrupt
+ repeat (2) @(posedge vif.clock);
drive_reset_value();
endtask : drive_seq_item
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/compare b/hw/vendor/lowrisc_ibex/dv/uvm/compare
deleted file mode 100755
index ddcfb95..0000000
--- a/hw/vendor/lowrisc_ibex/dv/uvm/compare
+++ /dev/null
@@ -1,57 +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_DIR="$1"
-report_file="$1/regr.log"
-rm -rf "$report_file"
-script_path="../../vendor/google_riscv-dv"
-
-compare_log () {
- spike_log="$1"
- ibex_log="$2"
- # -----------------------------------------------------------------------------
- # Convert spike log to standard instruction trace csv
- # -----------------------------------------------------------------------------
- # Remove all the init spike boot instructions
- # 0xffffffff80000080 is the first user instruction
- sed -i '/0xffffffff80000080/,$!d' "$spike_log"
- # Remove all instructions after ecall (end of program excecution)
- sed -i '/ecall/q' "$spike_log"
- # Convert the spike log to riscv_instr_trace.proto format
- spike_csv=$(echo "$spike_log" | sed 's/\.log/.csv/g')
- python $script_path/scripts/spike_log_to_trace_csv.py \
- --log $spike_log --csv $spike_csv >> $report_file
-
- # -----------------------------------------------------------------------------
- # Convert ibex log to standard instruction trace csv
- # -----------------------------------------------------------------------------
- # Remove all instructions after ecall (end of program excecution)
- sed -i '/ecall/q' "$ibex_log"
- # Convert the spike log to riscv_instr_trace.proto format
- ibex_csv=$(echo "$ibex_log" | sed 's/\.log/.csv/g')
- python ./riscv_dv_extension/ibex_log_to_trace_csv.py \
- --log $ibex_log --csv $ibex_csv >> $report_file
-
- # -----------------------------------------------------------------------------
- # Compare the trace log
- # -----------------------------------------------------------------------------
- python $script_path/scripts/instr_trace_compare.py $spike_csv $ibex_csv \
- "spike" "ibex" >> $report_file
-}
-
-echo "compare simulation result under $RUN_DIR"
-while read asm_test; do
- SRC=$(echo "$asm_test" | sed 's/^.*\///g' | sed 's/\.S>*$//g')
- echo "Test: $asm_test" >> $report_file
- compare_log $RUN_DIR/instr_gen/spike_sim/$SRC.S.o.log \
- $RUN_DIR/rtl_sim/$SRC/trace_core_00_0.log
-done <"$RUN_DIR/asm_test_list"
-
-passed_cnt="$(grep -c PASS $report_file)"
-failed_cnt="$(grep -c FAIL $report_file)"
-echo "$passed_cnt tests PASSED, $failed_cnt tests FAILED" >> $report_file
-
-cat $report_file
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_dut_probe_if.sv b/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_dut_probe_if.sv
index d285b7f..48fa34c 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_dut_probe_if.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_dut_probe_if.sv
@@ -6,6 +6,10 @@
interface core_ibex_dut_probe_if(input logic clk);
logic illegal_instr;
logic ecall;
+ logic wfi;
+ logic ebreak;
+ logic dret;
+ logic mret;
logic fetch_enable;
logic debug_req;
endinterface
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env.sv b/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env.sv
index f2b04f1..58af297 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env.sv
@@ -25,7 +25,7 @@
create("data_if_slave_agent", this);
instr_if_slave_agent = ibex_mem_intf_slave_agent::type_id::
create("instr_if_slave_agent", this);
- if (cfg.enable_irq_seq) begin
+ if (cfg.enable_irq_stress_seq || cfg.enable_irq_single_seq) begin
irq_agent = irq_master_agent::type_id::create("irq_agent", this);
end
// Create virtual sequencer
@@ -36,7 +36,7 @@
super.connect_phase(phase);
vseqr.data_if_seqr = data_if_slave_agent.sequencer;
vseqr.instr_if_seqr = instr_if_slave_agent.sequencer;
- if (cfg.enable_irq_seq) begin
+ if (cfg.enable_irq_stress_seq || cfg.enable_irq_single_seq) begin
vseqr.irq_seqr = irq_agent.sequencer;
end
endfunction : connect_phase
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_cfg.sv b/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_cfg.sv
index 8c352d8..388bc24 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_cfg.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_cfg.sv
@@ -4,18 +4,33 @@
class core_ibex_env_cfg extends uvm_object;
- bit enable_irq_seq;
- bit enable_debug_seq;
+ bit enable_irq_stress_seq;
+ bit enable_irq_single_seq;
+ bit enable_debug_stress_seq;
+ bit enable_debug_single_seq;
+ bit[31:0] max_interval;
+ bit require_signature_addr;
+ bit[31:0] signature_addr;
`uvm_object_utils_begin(core_ibex_env_cfg)
- `uvm_field_int(enable_irq_seq, UVM_DEFAULT)
- `uvm_field_int(enable_debug_seq, UVM_DEFAULT)
+ `uvm_field_int(enable_irq_stress_seq, UVM_DEFAULT)
+ `uvm_field_int(enable_irq_single_seq, UVM_DEFAULT)
+ `uvm_field_int(enable_debug_single_seq, UVM_DEFAULT)
+ `uvm_field_int(enable_debug_stress_seq, UVM_DEFAULT)
+ `uvm_field_int(max_interval, UVM_DEFAULT)
+ `uvm_field_int(require_signature_addr, UVM_DEFAULT)
+ `uvm_field_int(signature_addr, UVM_DEFAULT)
`uvm_object_utils_end
function new(string name = "");
super.new(name);
- void'($value$plusargs("enable_irq_seq=%0d", enable_irq_seq));
- void'($value$plusargs("enable_debug_seq=%0d", enable_debug_seq));
+ void'($value$plusargs("enable_irq_stress_seq=%0d", enable_irq_stress_seq));
+ void'($value$plusargs("enable_irq_single_seq=%0d", enable_irq_single_seq));
+ void'($value$plusargs("enable_debug_stress_seq=%0d", enable_debug_stress_seq));
+ void'($value$plusargs("enable_debug_single_seq=%0d", enable_debug_single_seq));
+ void'($value$plusargs("max_interval=%0d", max_interval));
+ void'($value$plusargs("require_signature_addr=%0d", require_signature_addr));
+ void'($value$plusargs("signature_addr=%0h", signature_addr));
endfunction
endclass
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_vseqr.sv b/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_vseqr.sv
index 068b20a..f3af18e 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_vseqr.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_vseqr.sv
@@ -7,9 +7,9 @@
// ---------------------------------------------
class core_ibex_vseqr extends uvm_sequencer;
- ibex_mem_intf_slave_sequencer data_if_seqr;
- ibex_mem_intf_slave_sequencer instr_if_seqr;
- irq_master_sequencer irq_seqr;
+ ibex_mem_intf_slave_sequencer data_if_seqr;
+ ibex_mem_intf_slave_sequencer instr_if_seqr;
+ irq_master_sequencer irq_seqr;
`uvm_component_utils(core_ibex_vseqr)
`uvm_component_new
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f b/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f
index 4f260a8..2ee06d2 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f
@@ -31,6 +31,7 @@
${PRJ_DIR}/ibex/rtl/ibex_core_tracing.sv
// Core DV files
+${PRJ_DIR}/ibex/vendor/google_riscv-dv/src/riscv_signature_pkg.sv
+incdir+${PRJ_DIR}/ibex/dv/uvm/env
+incdir+${PRJ_DIR}/ibex/dv/uvm/tests
+incdir+${PRJ_DIR}/ibex/dv/uvm/common/ibex_mem_intf_agent
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/csr_description.yaml b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/csr_description.yaml
new file mode 100644
index 0000000..9e7b0bc
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/csr_description.yaml
@@ -0,0 +1,280 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+#
+#
+# Base CSR template that should be followed when describing all processor supported CSRs to enable correct generation of directed test sequences
+#- csr: CSR_NAME
+# description: >
+# BRIEF_DESCRIPTION
+# address: 0x###
+# privilege_mode: MODE (D/M/S/H/U)
+# rv32:
+# - MSB_FIELD_NAME:
+# - description: >
+# BRIEF_DESCRIPTION
+# - type: TYPE (WPRI/WLRL/WARL)
+# - reset_val: RESET_VAL
+# - msb: MSB_POS
+# - lsb: LSB_POS
+# - ...
+# - ...
+# - LSB_FIELD_NAME:
+# - description: ...
+# - type: ...
+# - ...
+# rv64:
+# - MSB_FIELD_NAME:
+# - description: >
+# BRIEF_DESCRIPTION
+# - type: TYPE (WPRI/WLRL/WARL)
+# - reset_val: RESET_VAL
+# - msb: MSB_POS
+# - lsb: LSB_POS
+# - ...
+# - ...
+# - LSB_FIELD_NAME:
+# - description: ...
+# - type: ...
+# - ...
+
+
+# Ibex MISA CSR
+- csr: misa
+ description: >
+ Machine ISA Register
+ address: 0x301
+ privilege_mode: M
+ rv32:
+ - field_name: MXL
+ description: >
+ Encodes native base ISA width
+ type: R
+ reset_val: 1
+ msb: 31
+ lsb: 30
+ - field_name: Extensions
+ description: >
+ Encodes all supported ISA extensions
+ type: R
+ reset_val: 0x1104
+ msb: 25
+ lsb: 0
+
+# TODO(udij) - clarify expected write behavior
+# MHARTID
+#- csr: mhartid
+# description: >
+# Contains integer ID of hardware thread running code
+# address: 0xF14
+# privilege_mode: M
+# rv32:
+# - field_name: cluster_id
+# description: >
+# ID of the cluster
+# type: R
+# reset_val: 0
+# msb: 10
+# lsb: 5
+# - field_name: core_id
+# description: >
+# ID of the core within cluster
+# type: R
+# reset_val: 0
+# msb: 3
+# lsb: 0
+
+# MSTATUS
+- csr: mstatus
+ descriptipn: >
+ Controls hart's current operating state
+ address: 0x300
+ privilege_mode: M
+ rv32:
+ - field_name: mpp
+ description: >
+ Previous privilege mode
+ type: R
+ reset_val: 0x3
+ msb: 12
+ lsb: 11
+ - field_name: mpie
+ description: >
+ Previous value of interrupt-enable bit
+ type: WARL
+ reset_val: 0
+ msb: 7
+ lsb: 7
+ - field_name: mie
+ description: >
+ M-mode interrupt enable
+ type: WARL
+ reset_val: 0
+ msb: 3
+ lsb: 3
+
+# MIP
+- csr: mip
+ description: >
+ Contains pending interrupt information
+ address: 0x344
+ privilege_mode: M
+ rv32:
+ - field_name: fast
+ description: >
+ platform-specific interrupts
+ type: R
+ reset_val: 0
+ msb: 30
+ lsb: 16
+ - field_name: meip
+ description: >
+ M-mode external interrupts
+ type: R
+ reset_val: 0
+ msb: 11
+ lsb: 11
+ - field_name: mtip
+ description: >
+ M-mode timer interrupts
+ type: R
+ reset_val: 0
+ msb: 7
+ lsb: 7
+ - field_name: msip
+ description: >
+ M-mode software interrupts
+ type: R
+ reset_val: 0
+ msb: 3
+ lsb: 3
+
+# MIE
+- csr: mie
+ description: >
+ Contains interrupt information
+ address: 0x304
+ privilege_mode: M
+ rv32:
+ - field_name: fast
+ description: >
+ platform-specific interrupts
+ type: WARL
+ reset_val: 0
+ msb: 30
+ lsb: 16
+ - field_name: meip
+ description: >
+ M-mode external interrupts
+ type: WARL
+ reset_val: 0
+ msb: 11
+ lsb: 11
+ - field_name: mtip
+ description: >
+ M-mode timer interrupts
+ type: WARL
+ reset_val: 0
+ msb: 7
+ lsb: 7
+ - field_name: msip
+ description: >
+ M-mode software interrupts
+ type: WARL
+ reset_val: 0
+ msb: 3
+ lsb: 3
+
+# MSCRATCH
+- csr: mscratch
+ description: >
+ M-mode scratch register
+ address: 0x340
+ privilege_mode: M
+ rv32:
+ - field_name: mscratch
+ description: >
+ scratch register
+ type: WARL
+ reset_val: 0
+ msb: 31
+ lsb: 0
+
+# MEPC
+- csr: mepc
+ description: >
+ Stores the address of the instruction that was interrupted or caused exception
+ address: 0x341
+ privilege_mode: M
+ rv32:
+ - field_name: mepc
+ description: >
+ M-mode exception PC register
+ type: WARL
+ reset_val: 0
+ msb: 31
+ lsb: 1
+
+# MCAUSE
+- csr: mcause
+ description: >
+ Indicates trap cause
+ address: 0x342
+ privilege_mode: M
+ rv32:
+ - field_name: Interrupt
+ description: >
+ Indicates if trap caused by interrupt
+ type: WARL
+ reset_val: 0
+ msb: 31
+ lsb: 31
+ - field_name: Exception Code
+ type: WLRL
+ reset_val: 0
+ msb: 4
+ lsb: 0
+
+# MTVAL
+- csr: mtval
+ description: >
+ Machine Trap Value register
+ address: 0x343
+ privilege_mode: M
+ rv32:
+ - field_name: mtval
+ description: >
+ Address of faulting instruction
+ type: WARL
+ reset_val: 0
+ msb: 31
+ lsb: 0
+
+# MTVEC
+- csr: mtvec
+ description: >
+ Machine trap vector base address
+ address: 0x305
+ privilege_mode: M
+ rv32:
+ - field_name: base
+ description: >
+ trap vector base address (256 byte aligned)
+ type: WARL
+ reset_val: 0x800000
+ msb: 31
+ lsb: 8
+ - field_name: base_zero_end
+ description: >
+ bottom six bits of base always set to zero
+ type: R
+ reset_val: 0
+ msb: 7
+ lsb: 2
+ - field_name: mode
+ description: >
+ trap handling mode
+ type: R
+ reset_val: 0x1
+ msb: 1
+ lsb: 0
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_asm_program_gen.sv b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_asm_program_gen.sv
index a3c9da7..1abe405 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_asm_program_gen.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_asm_program_gen.sv
@@ -21,35 +21,19 @@
// with ibex.
cfg.check_misa_init_val = 1'b0;
cfg.check_xstatus = 1'b0;
- // The ibex core load the program from 0x80
- // Some address is reserved for hardware interrupt handling, need to decide if we need to copy
- // the init program from crt0.S later.
instr_stream.push_back(".macro init");
instr_stream.push_back(".endm");
instr_stream.push_back(".section .text.init");
instr_stream.push_back(".globl _start");
instr_stream.push_back(".option norvc");
- // 0x0 - 0x4F is reserved for trap/interrupt handling
- repeat (20) begin
- instr_stream.push_back("j mtvec_handler");
- end
- // 0x50 debug mode entry
+ // 0x0 debug mode entry
instr_stream.push_back("j debug_rom");
- // 0x54 debug mode exception handler
+ // 0x4 debug mode exception handler
instr_stream.push_back("j debug_exception");
// Align the start section to 0x80
instr_stream.push_back(".align 7");
- instr_stream.push_back("_start: j _reset_entry");
- // ibex reserves 0x84-0x8C for trap handling, redirect everything mtvec_handler
- // 0x84 illegal instruction
- instr_stream.push_back("j mtvec_handler");
- // 0x88 ECALL instruction handler
- instr_stream.push_back("j mtvec_handler");
- // 0x8C LSU error
- instr_stream.push_back("j mtvec_handler");
instr_stream.push_back(".option rvc");
- // Starting point of the reset entry
- instr_stream.push_back("_reset_entry:");
+ instr_stream.push_back("_start:");
endfunction
endclass
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_core_setting.sv b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_core_setting.sv
index 38b8412..4f4c598 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_core_setting.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_core_setting.sv
@@ -34,6 +34,9 @@
// ISA supported by the processor
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C};
+// Interrupt mode support
+mtvec_mode_t supported_interrupt_mode[$] = {VECTORED};
+
// Debug mode support
bit support_debug_mode = 1;
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py
index ac6ced0..5377300 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py
@@ -27,6 +27,8 @@
trace_csv = RiscvInstructiontTraceCsv(csv_fd)
trace_csv.start_new_trace()
for line in f:
+ if re.search("ecall", line):
+ break
# Extract instruction infromation
m = re.search(r"^\s*(?P<time>\d+)\s+(?P<cycle>\d+) " \
"(?P<pc>[0-9a-f]+) (?P<bin>[0-9a-f]+) (?P<instr>.*)" \
@@ -45,6 +47,49 @@
print("Processed instruction count : %d" % instr_cnt)
+def check_ibex_uvm_log(uvm_log, core_name, test_name, report, write=True):
+ """Process Ibex UVM simulation log.
+
+ This function will be used when a test disables the normal post_compare step.
+ Process the UVM simulation log produced by the test to check for correctness
+
+ Args:
+ uvm_log: the uvm simulation log
+ core_name: the name of the core
+ test_name: name of the test being checked
+ report: the output report file
+ write: enables writing to the log file
+
+ Returns:
+ A boolean indicating whether the test passed or failed based on the signature
+ """
+ pass_cnt = 0
+ fail_cnt = 0
+ with open(uvm_log, "r") as log:
+ for line in log:
+ if 'RISC-V UVM TEST PASSED' in line:
+ pass_cnt += 1
+ break
+ elif 'RISC-V UVM TEST FAILED' in line:
+ fail_cnt += 1
+ break
+
+ if write:
+ if report:
+ fd = open(report, "a+")
+ else:
+ fd = sys.stdout
+ fd.write("%s uvm log : %s\n" % (core_name, uvm_log))
+ if pass_cnt == 1:
+ fd.write("%s : PASSED\n" % test_name)
+ elif fail_cnt == 1:
+ fd.write("%s : FAILED\n" % test_name)
+ if report:
+ fd.close()
+
+ return pass_cnt == 1
+
+
def main():
instr_trace = []
# Parse input arguments
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist
deleted file mode 100644
index e8423a4..0000000
--- a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist
+++ /dev/null
@@ -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
-
-//====================================================================
-// Test name : iterations : options
-//--------------------------------------------------------------------
-riscv_arithmetic_basic_test : 20 :
-riscv_machine_mode_rand_test : 20 :
-riscv_privileged_mode_rand_test : 0 :
-riscv_rand_instr_test : 20 :
-riscv_rand_jump_test : 20 :
-riscv_mmu_stress_test : 20 :
-riscv_page_table_exception_test : 0 :
-riscv_no_fence_test : 10 :
-riscv_sfence_exception_test : 0 :
-riscv_illegal_instr_test : 10 :
-riscv_hint_instr_test : 10 :
-riscv_ebreak_test : 20 :
-riscv_wfi_test : 5 : +enable_interrupt=1
-//--------------------------------------------------------------------
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml
index 80f1e35..7d9c2a1 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml
@@ -1,16 +1,6 @@
-# Copyright Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http:#www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
- test: riscv_arithmetic_basic_test
description: >
@@ -40,7 +30,7 @@
- test: riscv_rand_instr_test
description: >
Random instruction stress test
- iterations: 20
+ iterations: 10
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
@@ -68,7 +58,7 @@
description: >
Test with different patterns of load/store instructions, stress test MMU
operations.
- iterations: 20
+ iterations: 10
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
@@ -85,7 +75,7 @@
instruction and handle corresponding exception properly. An exception
handling routine is designed to resume execution after illegal
instruction exception.
- iterations: 20
+ iterations: 10
gen_test: riscv_rand_instr_test
gen_opts: >
+enable_illegal_instruction=1
@@ -112,43 +102,126 @@
+no_ebreak=0
rtl_test: core_ibex_base_test
-- test: riscv_ebreak_debug_mode_test
+- test: riscv_debug_basic_test
description: >
- Ebreak instruction test with debug mode enabled.
- iterations: 10
- gen_test: riscv_rand_instr_test
+ Randomly assert debug_req_i, random instruction sequence in debug_rom section
+ iterations: 5
+ gen_test: riscv_instr_base_test
gen_opts: >
+ +require_signature_addr=1
+ +gen_debug_section=1
+ +no_ebreak=1
+ +no_branch_jump=1
+instr_cnt=6000
- +no_ebreak=0
- rtl_test: core_ibex_base_test
+ +no_csr_instr=1
+ +no_fence=1
+ +num_of_sub_program=0
+ rtl_test: core_ibex_debug_intr_test
sim_opts: >
- +enable_debug_seq=1
- compare_opts: >
- +compare_final_value_only=1
+ +require_signature_addr=1
+ +max_interval=1000
+ +enable_debug_stress_seq=1
+ compare_opts:
+ compare_final_value_only: 1
+ verbose: 1
-- test: riscv_fast_interrupt_test
+- test: riscv_debug_stress_test
description: >
- WFI(wait for interrupt) instruction test. If WFI is supported, processor
- should halt execution upon decoding WFI instruction and resume execution
- by interrupt. Otherwise WFI should be executed as NOP instruction.
- Interrupt handling routine is skipped to allow instruction strace comparison
- with ISS which is not interrupted during execution.
- iterations: 2
+ Randomly assert debug_req_i more often, debug_rom is empty, with only a dret instruction
gen_test: riscv_rand_instr_test
gen_opts: >
- +skip_trap_handling=1
- +no_wfi=0
- rtl_test: core_ibex_base_test
+ +require_signature_addr=1
+ +no_ebreak=1
+ +instr_cnt=6000
+ +no_csr_instr=1
+ +no_fence=1
+ rtl_test: core_ibex_debug_intr_test
+ iterations: 5
sim_opts: >
- +enable_irq_seq=1
+ +max_interval=250
+ +enable_debug_stress_seq=1
+ +require_signature_addr=1
+ compare_opts:
+ compare_final_value_only: 1
+ verbose: 1
-- test: riscv_full_interrupt_test
+- test: riscv_debug_branch_jump_test
+ description: >
+ Randomly assert debug_req_i, insert branch instructions and subprograms into debug_rom to make core
+ jump around within the debug_rom
+ iterations: 5
+ gen_test: riscv_rand_instr_test
+ gen_opts: >
+ +require_signature_addr=1
+ +gen_debug_section=1
+ +no_ebreak=1
+ +instr_cnt=6000
+ +no_csr_instr=1
+ +no_fence=1
+ +num_of_sub_program=5
+ +num_debug_sub_program=5
+ rtl_test: core_ibex_debug_intr_test
+ sim_opts: >
+ +require_signature_addr=1
+ +enable_debug_stress_seq=1
+ compare_opts:
+ compare_final_value_only: 1
+ verbose: 1
+
+- test: riscv_debug_wfi_test
+ description: >
+ Assert debug_req while core is in WFI sleep state, should jump to debug mode
+ iterations: 5
+ gen_test: riscv_rand_instr_test
+ gen_opts: >
+ +require_signature_addr=1
+ +gen_debug_section=1
+ +no_ebreak=1
+ +instr_cnt=3000
+ +no_csr_instr=1
+ +no_fence=1
+ +no_wfi=0
+ rtl_test: core_ibex_debug_wfi_test
+ sim_opts: >
+ +require_signature_addr=1
+ +enable_debug_single_seq=1
+ compare_opts:
+ compare_final_value_only: 1
+ verbose: 1
+
+- test: riscv_interrupt_test
description: >
Random instruction test with complete interrupt handling
iterations: 0
gen_test: riscv_rand_instr_test
- rtl_test: core_ibex_base_test
+ gen_opts: >
+ +require_signature_addr=1
+ rtl_test: core_ibex_debug_intr_test
sim_opts: >
- +enable_irq_seq=1
- compare_opts: >
- +compare_final_value_only=1
+ +require_signature_addr=1
+ +enable_irq_stress_seq=1
+ compare_opts:
+ compare_final_value_only: 1
+
+- test: riscv_csr_test
+ description: >
+ Test all CSR instructions on all implemented CSR registers
+ iterations: 5
+ no_iss: 1
+ rtl_test: core_ibex_csr_test
+ no_post_compare: 1
+
+- test: riscv_unaligned_load_store_test
+ description: >
+ Unaligned load/store test, ibex should handle it correctly without raising any exception
+ iterations: 5
+ gen_test: riscv_instr_base_test
+ gen_opts: >
+ +instr_cnt=10000
+ +num_of_sub_program=5
+ +directed_instr_0=riscv_load_store_rand_instr_stream,20
+ +directed_instr_1=riscv_load_store_hazard_instr_stream,20
+ +directed_instr_2=riscv_cache_line_stress_instr_stream,20
+ +directed_instr_3=riscv_multi_page_load_store_instr_stream,20
+ +enable_unaligned_load_store=1
+ rtl_test: core_ibex_base_test
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/sim b/hw/vendor/lowrisc_ibex/dv/uvm/sim
deleted file mode 100755
index 6d6eee8..0000000
--- a/hw/vendor/lowrisc_ibex/dv/uvm/sim
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env bash
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-
-# Script to run the assembly tests generated by the riscv-dv instruction generator.
-
-# Test directory
-RUN_DIR="./"
-
-# Assembly test file name
-TEST=""
-
-# Seed
-RAND_SEED=1
-SEED=""
-
-# Wavform dump options
-WAVES=0
-WAVES_OPTS=""
-
-# Coveragedump options
-COV=0
-COV_OPTS=""
-
-# Process command line options
-while [[ $# -gt 0 ]]
-do
-key="$1"
-case $key in
- -dir)
- RUN_DIR="$2"
- shift
- ;;
- -test)
- TEST="$2"
- shift
- ;;
- -waves)
- WAVES="$2"
- shift
- ;;
- -cov)
- COV="$2"
- shift
- ;;
- -seed)
- SEED="$2"
- RAND_SEED=0
- shift
- ;;
- *)
- echo "unknown option $1"
- exit 1
- ;;
-esac
-shift
-done
-
-
-# If the test is specified through "-test" option, run a single test rather
-# than all tests under RUN_DIR.
-if [[ $TEST == "" ]]; then
- find "$RUN_DIR" -name "*.S" > "$RUN_DIR/asm_test_list"
-else
- echo "$TEST" > "$RUN_DIR/asm_test_list"
-fi
-
-OUT="$RUN_DIR/rtl_sim"
-CWD=`pwd`
-
-# Run each test
-while read asm_test; do
- OPTS=""
- SRC=$(echo "$asm_test" | sed 's/^.*\///g' | sed 's/\.S>*$//g')
- BINFILE="$asm_test.bin"
- mkdir -p $OUT/$SRC
- cd $OUT/$SRC
- if [[ $RAND_SEED == 1 ]]; then
- SEED=$RANDOM
- fi
- if [[ $WAVES == 1 ]]; then
- WAVES_OPTS="-ucli -do $CWD/vcs.tcl"
- fi
- if [[ $COV == 1 ]]; then
- COV_OPTS="-cm line+tgl+assert+fsm+branch \
- -cm_dir ${RUN_DIR}/rtl_sim/test.vdb \
- -cm_log /dev/null \
- -assert nopostproc \
- -cm_name test_${SEED}"
- fi
- if [[ "$BINFILE" =~ "ebreak" ]]; then
- OPTS="+enable_debug_seq=1"
- fi
- if [[ "$BINFILE" =~ "wfi" ]]; then
- OPTS="+enable_irq_seq=1"
- fi
- CMD="$OUT/vcs_simv +UVM_TESTNAME=core_ibex_base_test \
- ${WAVES_OPTS} +ntb_random_seed=${SEED} +vcs+lic+wait ${COV_OPTS}\
- +UVM_MAX_QUIT_COUNT=5 +bin=$BINFILE -l sim.log ${OPTS}"
- echo "Running simulation for : $CMD"
- $CMD
-done <"$RUN_DIR/asm_test_list"
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/sim.py b/hw/vendor/lowrisc_ibex/dv/uvm/sim.py
index 67452d5..44558c5 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/sim.py
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/sim.py
@@ -45,7 +45,7 @@
Processed command
"""
if enable == "1":
- return re.sub(keyword, opts, cmd)
+ return re.sub(keyword, opts.rstrip(), cmd)
else:
return re.sub(keyword, "", cmd)
@@ -83,43 +83,6 @@
sys.exit(1)
-def run_cmd(cmd):
- """Run a command and return output
-
- Args:
- cmd : shell command to run
-
- Returns:
- command output
- """
- try:
- ps = subprocess.Popen(cmd,
- shell=True,
- universal_newlines=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- executable='/bin/bash')
- except subprocess.CalledProcessError as exc:
- print(ps.communicate()[0])
- sys.exit(1)
- return ps.communicate()[0]
-
-
-def get_seed(seed):
- """Get the seed to run the generator
-
- Args:
- seed : input seed
-
- Returns:
- seed to run instruction generator
- """
- if seed >= 0:
- return seed
- else:
- return random.getrandbits(32)
-
-
def rtl_compile(compile_cmd, test_list, output_dir, lsf_cmd, opts, verbose):
"""Run the instruction generator
@@ -165,27 +128,24 @@
for test in test_list:
for i in range(test['iterations']):
rand_seed = get_seed(seed)
+ test_sim_cmd = re.sub("<seed>", str(rand_seed), sim_cmd)
+ if "sim_opts" in test:
+ test_sim_cmd += test['sim_opts']
+ print(test_sim_cmd)
sim_dir = output_dir + ("/%s.%d" %(test['test'], i))
run_cmd(("mkdir -p %s" % sim_dir))
os.chdir(sim_dir)
if verbose:
print("Run dir: %s" % sim_dir)
binary = ("%s/%s.%d.bin" % (bin_dir, test['test'], i))
- cmd = lsf_cmd + " " + sim_cmd.rstrip() + \
+ cmd = lsf_cmd + " " + test_sim_cmd.rstrip() + \
(" +UVM_TESTNAME=%s " % test['rtl_test']) + \
(" +bin=%s " % binary) + \
- (" +ntb_random_seed=%d " % rand_seed) + \
(" -l sim.log ")
print("Running %s with %s" % (test['rtl_test'], binary))
if verbose:
print(cmd)
- try:
- output = subprocess.check_output(cmd.split(),
- timeout=1000,
- universal_newlines=True)
- except subprocess.CalledProcessError as exc:
- print(output)
- sys.exit(1)
+ output = run_cmd(' '.join(cmd.split()))
if verbose:
print(output)
@@ -205,19 +165,39 @@
elf = ("%s/asm_tests/%s.%d.o" % (output_dir, test['test'], i))
print("Comparing %s/DUT sim result : %s" % (iss, elf))
run_cmd(("echo 'Test binary: %s' >> %s" % (elf, report)))
+ uvm_log = ("%s/rtl_sim/%s.%d/sim.log" % (output_dir, test['test'], i))
rtl_log = ("%s/rtl_sim/%s.%d/trace_core_00_0.log" % (output_dir, test['test'], i))
rtl_csv = ("%s/rtl_sim/%s.%d/trace_core_00_0.csv" % (output_dir, test['test'], i))
- process_ibex_sim_log(rtl_log, rtl_csv)
- iss_log = ("%s/instr_gen/%s_sim/%s.%d.log" % (output_dir, iss, test['test'], i))
- iss_csv = ("%s/instr_gen/%s_sim/%s.%d.csv" % (output_dir, iss, test['test'], i))
- if iss == "spike":
- process_spike_sim_log(iss_log, iss_csv)
- elif iss == "ovpsim":
- process_ovpsim_sim_log(iss_log, iss_csv)
+ test_name = "%s.%d" % (test['test'], i)
+ if 'no_post_compare' in test and test['no_post_compare'] == 1:
+ check_ibex_uvm_log(uvm_log, "ibex", test_name, report)
else:
- print("Unsupported ISS" % iss)
- sys.exit(1)
- compare_trace_csv(rtl_csv, iss_csv, "ibex", iss, report)
+ process_ibex_sim_log(rtl_log, rtl_csv)
+ iss_log = ("%s/instr_gen/%s_sim/%s.%d.log" % (output_dir, iss, test['test'], i))
+ iss_csv = ("%s/instr_gen/%s_sim/%s.%d.csv" % (output_dir, iss, test['test'], i))
+ if iss == "spike":
+ process_spike_sim_log(iss_log, iss_csv)
+ elif iss == "ovpsim":
+ process_ovpsim_sim_log(iss_log, iss_csv)
+ else:
+ print("Unsupported ISS" % iss)
+ sys.exit(1)
+ uvm_result = check_ibex_uvm_log(uvm_log, "ibex", test_name, report, False)
+ if not uvm_result:
+ check_ibex_uvm_log(uvm_log, "ibex", test_name, report)
+ else:
+ if 'compare_opts' in test:
+ compare_opts = test.get('compare_opts')
+ in_order_mode = compare_opts.get('in_order_mode', 1)
+ coalescing_limit = compare_opts.get('coalescing_limit', 0)
+ verbose = compare_opts.get('verbose', 0)
+ mismatch = compare_opts.get('mismatch_print_limit', 5)
+ compare_final = compare_opts.get('compare_final_value_only', 0)
+ compare_trace_csv(rtl_csv, iss_csv, "ibex", iss, report,
+ in_order_mode, coalescing_limit, verbose,
+ mismatch, compare_final)
+ else:
+ compare_trace_csv(rtl_csv, iss_csv, "ibex", iss, report)
passed_cnt = run_cmd("grep PASSED %s | wc -l" % report).strip()
failed_cnt = run_cmd("grep FAILED %s | wc -l" % report).strip()
summary = ("%s PASSED, %s FAILED" % (passed_cnt, failed_cnt))
@@ -245,7 +225,7 @@
help="RTL simulator setting YAML")
parser.add_argument("--iss", type=str, default="spike",
help="Instruction set simulator")
-parser.add_argument("--verbose", type=int, default=0,
+parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
help="Verbose logging")
parser.add_argument("--cmp_opts", type=str, default="",
help="Compile options for the generator")
@@ -262,6 +242,7 @@
command is not specified")
args = parser.parse_args()
+parser.set_defaults(verbose=False)
cwd = os.path.dirname(os.path.realpath(__file__))
# Create the output directory
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tb/core_ibex_tb_top.sv b/hw/vendor/lowrisc_ibex/dv/uvm/tb/core_ibex_tb_top.sv
index 1eaab87..251ea86 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/tb/core_ibex_tb_top.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/tb/core_ibex_tb_top.sv
@@ -18,14 +18,12 @@
core_ibex_dut_probe_if dut_if(.clk(clk));
// TODO(taliu) Resolve the tied-off ports
- ibex_core_tracing #(.DmHaltAddr(`BOOT_ADDR + 'h50),
- .DmExceptionAddr(`BOOT_ADDR + 'h54)
- ) dut (
+ ibex_core_tracing #(.DmHaltAddr(`BOOT_ADDR + 'h0),
+ .DmExceptionAddr(`BOOT_ADDR + 'h4)) dut (
.clk_i(clk),
.rst_ni(rst_n),
.test_en_i(1'b1),
- .core_id_i('0),
- .cluster_id_i('0),
+ .hart_id_i(32'b0),
.boot_addr_i(`BOOT_ADDR), // align with spike boot address
.debug_req_i(debug_req),
.irq_software_i(irq_if.irq_software),
@@ -64,12 +62,17 @@
force dut.instr_rvalid_i = instr_mem_vif.rvalid;
force instr_mem_vif.addr = dut.instr_addr_o;
force dut.instr_rdata_i = instr_mem_vif.rdata;
+ force dut.instr_err_i = 0; // TODO(taliu) Support interface error
// IRQ interface
force irq_vif.clock = clk;
force irq_vif.reset = ~rst_n;
end
- assign dut_if.ecall = dut.u_ibex_core.id_stage_i.ecall_insn_dec;
+ assign dut_if.ecall = dut.u_ibex_core.id_stage_i.ecall_insn_dec;
+ assign dut_if.wfi = dut.u_ibex_core.id_stage_i.wfi_insn_dec;
+ assign dut_if.ebreak = dut.u_ibex_core.id_stage_i.ebrk_insn;
+ assign dut_if.dret = dut.u_ibex_core.id_stage_i.dret_insn_dec;
+ assign dut_if.mret = dut.u_ibex_core.id_stage_i.mret_insn_dec;
initial begin
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_base_test.sv b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_base_test.sv
index 8e41f25..75d5d58 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_base_test.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_base_test.sv
@@ -4,21 +4,30 @@
class core_ibex_base_test extends uvm_test;
- core_ibex_env env;
- core_ibex_env_cfg cfg;
- virtual clk_if clk_vif;
- virtual core_ibex_dut_probe_if dut_vif;
- mem_model_pkg::mem_model mem;
- core_ibex_vseq vseq;
- bit enable_irq_seq;
- bit enable_debug_seq;
- irq_seq irq_seq_h;
- int unsigned timeout_in_cycles = 2000000;
+ core_ibex_env env;
+ core_ibex_env_cfg cfg;
+ virtual clk_if clk_vif;
+ virtual core_ibex_dut_probe_if dut_vif;
+ mem_model_pkg::mem_model mem;
+ core_ibex_vseq vseq;
+ irq_seq irq_seq_h;
+ int unsigned timeout_in_cycles = 3000000;
+ // If no signature_addr handshake functionality is desired between the
+ // testbench and the generated code, the test will wait for the specified
+ // number of cycles before starting stimulus sequences (irq and debug)
+ int unsigned stimulus_delay = 800;
+ bit[ibex_mem_intf_agent_pkg::DATA_WIDTH] signature_data_q[$];
+ bit[ibex_mem_intf_agent_pkg::DATA_WIDTH] signature_data;
+ uvm_tlm_analysis_fifo #(ibex_mem_intf_seq_item) item_collected_port;
`uvm_component_utils(core_ibex_base_test)
function new(string name="", uvm_component parent=null);
+ core_ibex_report_server ibex_report_server;
super.new(name, parent);
+ ibex_report_server = new();
+ uvm_report_server::set_server(ibex_report_server);
+ item_collected_port = new("item_collected_port_test", this);
endfunction
virtual function void build_phase(uvm_phase phase);
@@ -40,18 +49,30 @@
vseq.cfg = cfg;
endfunction
+ virtual function void connect_phase(uvm_phase phase);
+ super.connect_phase(phase);
+ env.data_if_slave_agent.monitor.item_collected_port.connect(this.item_collected_port.analysis_export);
+ endfunction
+
virtual task run_phase(uvm_phase phase);
phase.raise_objection(this);
dut_vif.fetch_enable = 1'b0;
clk_vif.wait_clks(100);
load_binary_to_mem();
dut_vif.fetch_enable = 1'b1;
- vseq.start(env.vseqr);
+ send_stimulus();
wait_for_test_done();
- vseq.stop();
phase.drop_objection(this);
endtask
+ virtual function void report_phase(uvm_phase phase);
+ super.report_phase(phase);
+ endfunction
+
+ virtual task send_stimulus();
+ vseq.start(env.vseqr);
+ endtask
+
function void load_binary_to_mem();
string bin;
bit [7:0] r8;
@@ -80,6 +101,7 @@
fork
begin
wait (dut_vif.ecall === 1'b1);
+ vseq.stop();
`uvm_info(`gfn, "ECALL instruction is detected, test done", UVM_LOW)
// De-assert fetch enable to finish the test
dut_vif.fetch_enable = 1'b0;
@@ -93,4 +115,71 @@
join_any
endtask
+
+ virtual task wait_for_mem_txn(input bit[ibex_mem_intf_agent_pkg::ADDR_WIDTH-1:0] ref_addr,
+ input signature_type_t ref_type);
+ ibex_mem_intf_seq_item mem_txn;
+ forever begin
+ // The first write to this address is guaranteed to contain the
+ // signature type in bits [7:0]
+ item_collected_port.get(mem_txn);
+ if (mem_txn.addr == ref_addr && mem_txn.data[7:0] === ref_type && mem_txn.read_write == WRITE) begin
+ signature_data = mem_txn.data;
+ case (ref_type)
+ // The very first write to the signature address in every test is
+ // guaranteed to be a write of CORE_STATUS, indicating the
+ // INITIALIZED state
+ CORE_STATUS: begin
+ signature_data_q.push_back(signature_data >> 8);
+ end
+ TEST_RESULT: begin
+ signature_data_q.push_back(signature_data >> 8);
+ end
+ // The next 32 writes to the address are guaranteed to be a dump of
+ // all GPRs
+ WRITE_GPR: begin
+ for(int i = 0; i < 32; i++) begin
+ do begin
+ item_collected_port.get(mem_txn);
+ end while(!(mem_txn.addr == ref_addr && mem_txn.read_write == WRITE));
+ signature_data_q.push_back(mem_txn.data);
+ end
+ end
+ // The next write to this address is guaranteed to be the data held
+ // in the CSR
+ WRITE_CSR: begin
+ signature_data_q.push_back(signature_data >> 8);
+ do begin
+ item_collected_port.get(mem_txn);
+ end while (!(mem_txn.addr == ref_addr && mem_txn.read_write == WRITE));
+ signature_data_q.push_back(mem_txn.data);
+ end
+ default: begin
+ `uvm_fatal(`gfn, $sformatf("The data 0x%0h written to the signature address is formatted incorrectly.", signature_data))
+ end
+ endcase
+ return;
+ end
+ end
+ endtask
+
+ // API of various tasks wrapping wait_for_mem_txn, for various common
+ // functionalities that might be needed for verification purposes.
+ // Will be expanded as needed.
+
+ virtual task check_next_core_status(core_status_t core_status, error_msg="");
+ wait_for_mem_txn(cfg.signature_addr, CORE_STATUS);
+ signature_data = signature_data_q.pop_front();
+ if (signature_data != core_status) begin
+ `uvm_error(`gfn, error_msg)
+ end
+ endtask
+
+ virtual task wait_for_core_status(core_status_t core_status);
+ do begin
+ wait_for_mem_txn(cfg.signature_addr, CORE_STATUS);
+ signature_data = signature_data_q.pop_front();
+ end while (signature_data != core_status);
+ endtask
+
endclass
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_report_server.sv b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_report_server.sv
new file mode 100644
index 0000000..a8db720
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_report_server.sv
@@ -0,0 +1,25 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class core_ibex_report_server extends uvm_default_report_server;
+
+ function new(string name = "");
+ super.new(name);
+ endfunction
+
+ function void report_summarize(UVM_FILE file = 0);
+ int error_count;
+ error_count = get_severity_count(UVM_WARNING);
+ error_count = get_severity_count(UVM_ERROR) + error_count;
+ error_count = get_severity_count(UVM_FATAL) + error_count;
+
+ if (error_count == 0) begin
+ $display("\n--- RISC-V UVM TEST PASSED ---\n");
+ end else begin
+ $display("\n--- RISC-V UVM TEST FAILED ---\n");
+ end
+ super.report_summarize(file);
+ endfunction
+
+endclass
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_seq_lib.sv b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_seq_lib.sv
index 2035a43..0170a47 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_seq_lib.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_seq_lib.sv
@@ -9,7 +9,7 @@
rand int unsigned delay;
int unsigned num_of_iterations; // 0: infinite until stopped
int unsigned iteration_cnt;
- int unsigned max_interval = 1000;
+ int unsigned max_interval;
int unsigned max_delay = 500;
virtual clk_if clk_vif;
bit stop_seq;
@@ -98,7 +98,7 @@
virtual task send_req();
`uvm_info(get_full_name(), "Sending debug request", UVM_HIGH)
dut_vif.debug_req <= 1'b1;
- clk_vif.wait_clks($urandom_range(1, 20));
+ clk_vif.wait_clks($urandom_range(10, 30));
dut_vif.debug_req <= 1'b0;
endtask
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_lib.sv b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_lib.sv
new file mode 100644
index 0000000..34bd049
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_lib.sv
@@ -0,0 +1,124 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// CSR test class
+class core_ibex_csr_test extends core_ibex_base_test;
+
+ `uvm_component_utils(core_ibex_csr_test)
+ `uvm_component_new
+
+ virtual task wait_for_test_done();
+ bit result;
+ fork
+ begin
+ wait_for_mem_txn(cfg.signature_addr, TEST_RESULT);
+ result = signature_data_q.pop_front();
+ if (result == TEST_PASS) begin
+ `uvm_info(`gfn, "CSR test completed successfully!", UVM_LOW)
+ end else if (result == TEST_FAIL) begin
+ `uvm_error(`gfn, "CSR TEST_FAILED!")
+ end else begin
+ `uvm_fatal(`gfn, "CSR test values are not configured properly")
+ end
+ end
+ begin
+ clk_vif.wait_clks(timeout_in_cycles);
+ `uvm_fatal(`gfn, "TEST TIMEOUT!!")
+ end
+ join_any
+ endtask
+
+endclass
+
+// Debug test class
+class core_ibex_debug_intr_test extends core_ibex_base_test;
+
+ `uvm_component_utils(core_ibex_debug_intr_test)
+ `uvm_component_new
+
+ virtual task send_stimulus();
+ fork
+ begin
+ vseq.start(env.vseqr);
+ end
+ begin
+ if (cfg.require_signature_addr) begin
+ wait_for_core_status(INITIALIZED);
+ end else begin
+ // If no signature_addr functionality is desired, then the test will
+ // simply wait for an adequate number of cycles
+ clk_vif.wait_clks(stimulus_delay);
+ end
+ fork
+ begin
+ if (cfg.enable_irq_stress_seq) begin
+ vseq.start_irq_stress_seq();
+ end
+ end
+ begin
+ if (cfg.enable_debug_stress_seq) begin
+ vseq.start_debug_stress_seq();
+ end
+ end
+ join_none
+ end
+ join_none
+ endtask
+
+endclass
+
+// Debug WFI test class
+class core_ibex_debug_wfi_test extends core_ibex_base_test;
+
+ `uvm_component_utils(core_ibex_debug_wfi_test)
+ `uvm_component_new
+
+ virtual task send_stimulus();
+ fork
+ begin
+ vseq.start(env.vseqr);
+ end
+ begin
+ if (!cfg.require_signature_addr) begin
+ clk_vif.wait_clks(stimulus_delay);
+ fork
+ begin
+ if (cfg.enable_irq_stress_seq) begin
+ vseq.start_irq_stress_seq();
+ end
+ end
+ begin
+ if (cfg.enable_debug_stress_seq) begin
+ vseq.start_debug_stress_seq();
+ end
+ end
+ join_none
+ end else begin
+ // Wait for core initialization before starting the wfi stimulus
+ // loop - first write to signature address is guaranteed to be core
+ // initialization info
+ check_next_core_status(INITIALIZED, "Core initialization handshake failure");
+ // TODO(udi) - need to check that no other instruction fetches occur
+ // after the WFI is detected, and before any stimulus is sent to the
+ // core
+ forever begin
+ wait (dut_vif.wfi === 1'b1);
+ clk_vif.wait_clks($urandom_range(100));
+ vseq.start_debug_single_seq();
+ // After assserting this signal, core should wake up and jump into
+ // debug mode from WFI state - next handshake should
+ // be a notification that the core is now in debug mode
+ check_next_core_status(IN_DEBUG_MODE, "Core did not jump into debug mode from WFI state");
+ // We don't want to trigger debug stimulus for any WFI
+ // instructions encountered inside the debug rom - those should
+ // act as NOP instructions - so we wait until hitting the end of
+ // the debug rom
+ wait (dut_vif.dret === 1'b1);
+ end
+ end
+ end
+ join_none
+ endtask
+
+endclass
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_pkg.sv b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_pkg.sv
index c1a83a6..b6a8d4f 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_pkg.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_pkg.sv
@@ -11,9 +11,12 @@
import core_ibex_env_pkg::*;
import ibex_mem_intf_agent_pkg::*;
import irq_agent_pkg::*;
+ import riscv_signature_pkg::*;
+ `include "core_ibex_report_server.sv"
`include "core_ibex_seq_lib.sv"
`include "core_ibex_vseq.sv"
`include "core_ibex_base_test.sv"
+ `include "core_ibex_test_lib.sv"
endpackage
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_vseq.sv b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_vseq.sv
index 440a918..9d22c70 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_vseq.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_vseq.sv
@@ -8,12 +8,15 @@
class core_ibex_vseq extends uvm_sequence;
- ibex_mem_intf_slave_seq instr_intf_seq;
- ibex_mem_intf_slave_seq data_intf_seq;
- mem_model_pkg::mem_model mem;
- irq_seq irq_seq_h;
- debug_seq debug_seq_h;
- core_ibex_env_cfg cfg;
+ ibex_mem_intf_slave_seq instr_intf_seq;
+ ibex_mem_intf_slave_seq data_intf_seq;
+ mem_model_pkg::mem_model mem;
+ irq_seq irq_seq_stress_h;
+ irq_seq irq_seq_single_h;
+ debug_seq debug_seq_stress_h;
+ debug_seq debug_seq_single_h;
+ core_ibex_env_cfg cfg;
+ bit[ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] data;
`uvm_object_utils(core_ibex_vseq)
`uvm_declare_p_sequencer(core_ibex_vseqr)
@@ -22,30 +25,69 @@
virtual task body();
instr_intf_seq = ibex_mem_intf_slave_seq::type_id::create("instr_intf_seq");
data_intf_seq = ibex_mem_intf_slave_seq::type_id::create("data_intf_seq");
+ if (cfg.enable_irq_stress_seq) begin
+ irq_seq_stress_h = irq_seq::type_id::create("irq_seq_stress_h");
+ irq_seq_stress_h.max_interval = cfg.max_interval;
+ end
+ if (cfg.enable_irq_single_seq) begin
+ irq_seq_single_h = irq_seq::type_id::create("irq_seq_single_h");
+ irq_seq_single_h.num_of_iterations = 1;
+ irq_seq_single_h.max_interval = 1;
+ irq_seq_single_h.max_delay = 1;
+ irq_seq_single_h.interval.rand_mode(0);
+ irq_seq_single_h.interval = 0;
+ end
+ if (cfg.enable_debug_stress_seq) begin
+ debug_seq_stress_h = debug_seq::type_id::create("debug_seq_stress_h");
+ debug_seq_stress_h.max_interval = cfg.max_interval;
+ end
+ if (cfg.enable_debug_single_seq) begin
+ debug_seq_single_h = debug_seq::type_id::create("debug_seq_single_h");
+ debug_seq_single_h.num_of_iterations = 1;
+ debug_seq_single_h.max_interval = 1;
+ debug_seq_single_h.max_delay = 1;
+ debug_seq_single_h.interval.rand_mode(0);
+ debug_seq_single_h.interval = 0;
+ end
instr_intf_seq.m_mem = mem;
data_intf_seq.m_mem = mem;
-
fork
instr_intf_seq.start(p_sequencer.instr_if_seqr);
data_intf_seq.start(p_sequencer.data_if_seqr);
- if (cfg.enable_irq_seq) begin
- irq_seq_h = irq_seq::type_id::create("irq_seq_h");
- irq_seq_h.start(p_sequencer.irq_seqr);
- end
- if (cfg.enable_debug_seq) begin
- debug_seq_h = debug_seq::type_id::create("debug_seq_h");
- debug_seq_h.start(null);
- end
join_none
endtask
virtual task stop();
- if (cfg.enable_irq_seq) begin
- irq_seq_h.stop();
+ if (cfg.enable_irq_stress_seq) begin
+ irq_seq_stress_h.stop();
end
- if (cfg.enable_debug_seq) begin
- debug_seq_h.stop();
+ if (cfg.enable_irq_single_seq) begin
+ irq_seq_single_h.stop();
end
+ if (cfg.enable_debug_stress_seq) begin
+ debug_seq_stress_h.stop();
+ end
+ if (cfg.enable_debug_single_seq) begin
+ debug_seq_single_h.stop();
+ end
+ endtask
+
+ // Helper tasks to allow the test fine grained control to start sequences
+ // through the vseq - necessary for testing directed stimulus scenarios
+ virtual task start_debug_stress_seq();
+ debug_seq_stress_h.start(null);
+ endtask
+
+ virtual task start_debug_single_seq();
+ debug_seq_single_h.start(null);
+ endtask
+
+ virtual task start_irq_stress_seq();
+ irq_seq_stress_h.start(p_sequencer.irq_seqr);
+ endtask
+
+ virtual task start_irq_single_seq();
+ irq_seq_single_h.start(p_sequencer.irq_seqr);
endtask
endclass
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml b/hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml
index be7f0e5..ea7037f 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml
@@ -36,6 +36,7 @@
sim:
cmd: >
<out>/vcs_simv +vcs+lic+wait <sim_opts> <wave_opts> <cov_opts>
+ +ntb_random_seed=<seed>
cov_opts: >
-cm line+tgl+assert+fsm+branch
-cm_dir <out>/test.vdb
diff --git a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/ram_1p.sv b/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/ram_1p.sv
index 98b56c1..eaf131c 100644
--- a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/ram_1p.sv
+++ b/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/ram_1p.sv
@@ -42,7 +42,7 @@
if (!rst_ni) begin
rvalid_o <= '0;
end else begin
- rvalid_o <= req_i && ~write_i;
+ rvalid_o <= req_i;
end
end
diff --git a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/top_artya7_100.sv b/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/top_artya7_100.sv
index e212bf7..8391f68 100644
--- a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/top_artya7_100.sv
+++ b/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/top_artya7_100.sv
@@ -48,8 +48,7 @@
.test_en_i ('b0),
- .core_id_i (4'b0),
- .cluster_id_i (6'b0),
+ .hart_id_i (32'b0),
// First instruction executed is at 0x0 + 0x80
.boot_addr_i (32'h00000000),
@@ -58,6 +57,7 @@
.instr_rvalid_i (instr_rvalid),
.instr_addr_o (instr_addr),
.instr_rdata_i (instr_rdata),
+ .instr_err_i ('b0),
.data_req_o (data_req),
.data_gnt_i (data_gnt),
diff --git a/hw/vendor/lowrisc_ibex/examples/sim/tb/ibex_tracing_tb.sv b/hw/vendor/lowrisc_ibex/examples/sim/tb/ibex_tracing_tb.sv
index 48345a0..42b2b7b 100644
--- a/hw/vendor/lowrisc_ibex/examples/sim/tb/ibex_tracing_tb.sv
+++ b/hw/vendor/lowrisc_ibex/examples/sim/tb/ibex_tracing_tb.sv
@@ -77,8 +77,7 @@
.test_en_i (1'b0),
// Core ID, Cluster ID and boot address are considered more or less static
- .core_id_i (4'b0),
- .cluster_id_i (6'b0),
+ .hart_id_i (32'b0),
.boot_addr_i (32'b0),
// Instruction memory interface
@@ -87,6 +86,7 @@
.instr_rvalid_i (instr_rvalid),
.instr_addr_o (),
.instr_rdata_i (instr_rdata),
+ .instr_err_i (1'b0),
// Data memory interface
.data_req_o (),
diff --git a/hw/vendor/lowrisc_ibex/ibex_core.core b/hw/vendor/lowrisc_ibex/ibex_core.core
index 016a118..48c0e9a 100644
--- a/hw/vendor/lowrisc_ibex/ibex_core.core
+++ b/hw/vendor/lowrisc_ibex/ibex_core.core
@@ -21,6 +21,7 @@
- rtl/ibex_multdiv_fast.sv
- rtl/ibex_multdiv_slow.sv
- rtl/ibex_prefetch_buffer.sv
+ - rtl/ibex_pmp.sv
# XXX: Figure out the best way to switch these two implementations
# dynamically on the target.
# - rtl/ibex_register_file_latch.sv # ASIC
diff --git a/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt b/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
index 286fd2d..4df10e5 100644
--- a/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
+++ b/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
@@ -24,34 +24,54 @@
// Bits of signal are not used: fetch_addr_n[0]
// cleaner to write all bits even if not all are used
-lint_off -msg UNUSED -file "*/rtl/ibex_if_stage.sv" -lines 94
+lint_off -msg UNUSED -file "*/rtl/ibex_if_stage.sv" -lines 80
// Bits of signal are not used: shift_right_result_ext[32]
// cleaner to write all bits even if not all are used
-lint_off -msg UNUSED -file "*/rtl/ibex_alu.sv" -lines 122
+lint_off -msg UNUSED -file "*/rtl/ibex_alu.sv" -lines 107
// Bits of signal are not used: alu_adder_ext_i[0]
// Bottom bit is round, not needed
-lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 35
+lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 23
// Bits of signal are not used: mac_res_ext[34]
// cleaner to write all bits even if not all are used
-lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 60
+lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 48
// Bits of signal are not used: res_adder_h[32]
// cleaner to write all bits even if not all are used
-lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 80
+lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 68
// Signal is not used: test_en_i
// testability signal
-lint_off -msg UNUSED -file "*/rtl/ibex_register_file_ff.sv" -lines 38
+lint_off -msg UNUSED -file "*/rtl/ibex_register_file_ff.sv" -lines 21
+
+// Signal is not used: clk_i
+// leaving clk and reset connected in-case we want to add assertions
+lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 15
+
+// Signal is not used: rst_ni
+// leaving clk and reset connected in-case we want to add assertions
+lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 16
+
+// Signal is not used: csr_pmp_addr
+// Signal not connected when PMP is not configured
+lint_off -msg UNUSED -file "*/rtl/ibex_core.sv" -lines 186
+
+// Signal is not used: csr_pmp_cfg
+// Signal not connected when PMP is not configured
+lint_off -msg UNUSED -file "*/rtl/ibex_core.sv" -lines 187
+
+// Signal is not used: priv_mode
+// Signal not connected when PMP is not configured
+lint_off -msg UNUSED -file "*/rtl/ibex_core.sv" -lines 199
// Signal unoptimizable: Feedback to clock or circular logic:
// ibex_core.id_stage_i.controller_i.ctrl_fsm_cs
// Issue lowrisc/ibex#211
-lint_off -msg UNOPTFLAT -file "*/rtl/ibex_controller.sv" -lines 112
+lint_off -msg UNOPTFLAT -file "*/rtl/ibex_controller.sv" -lines 98
// Signal unoptimizable: Feedback to clock or circular logic:
// ibex_core.cs_registers_i.mie_q
// Issue lowrisc/ibex#212
-lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 157
+lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 149
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_alu.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_alu.sv
index ebab401..83268db 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_alu.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_alu.sv
@@ -1,23 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// //
-// Engineer: Markus Wegmann - markus.wegmann@technokrat.ch //
-// //
-// Additional contributions by: //
-// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// //
-// Design Name: ALU //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Arithmetic logic unit of the pipelined processor. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* Arithmetic logic unit
*/
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv
index 31c31d5..feb5a65 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv
@@ -1,21 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// //
-// Engineer: Sven Stucki - svstucki@student.ethz.ch //
-// //
-// Design Name: Compressed instruction decoder //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Decodes RISC-V compressed instructions into their RV32 //
-// equivalent. This module is fully combinatorial. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* Compressed instruction decoder
*
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
index 464d6a1..d61c3fd 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
@@ -1,25 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Matthias Baer - baermatt@student.ethz.ch //
-// //
-// Additional contributions by: //
-// Igor Loi - igor.loi@unibo.it //
-// Andreas Traber - atraber@student.ethz.ch //
-// Sven Stucki - svstucki@student.ethz.ch //
-// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// //
-// Design Name: Main controller //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Main controller of the processor //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* Main controller of the processor
*/
@@ -38,13 +21,15 @@
input logic dret_insn_i, // decoder has DRET instr
input logic wfi_insn_i, // decoder has WFI instr
input logic ebrk_insn_i, // decoder has EBREAK instr
- input logic csr_status_i, // decoder has CSR status instr
+ input logic csr_pipe_flush_i, // do CSR-related pipeline flush
// from IF-ID pipeline stage
input logic instr_valid_i, // instr from IF-ID reg is valid
input logic [31:0] instr_i, // instr from IF-ID reg, for mtval
input logic [15:0] instr_compressed_i, // instr from IF-ID reg, for mtval
input logic instr_is_compressed_i, // instr from IF-ID reg is compressed
+ input logic instr_fetch_err_i, // instr from IF-ID reg has error
+ input logic [31:0] pc_id_i, // instr from IF-ID reg address
// to IF-ID pipeline stage
output logic instr_valid_clear_o, // kill instr in IF-ID reg
@@ -80,6 +65,7 @@
input logic debug_req_i,
output ibex_pkg::dbg_cause_e debug_cause_o,
output logic debug_csr_save_o,
+ output logic debug_mode_o,
input logic debug_single_step_i,
input logic debug_ebreakm_i,
@@ -119,6 +105,8 @@
logic stall;
logic halt_if;
logic halt_id;
+ logic illegal_dret;
+ logic illegal_insn;
logic exc_req;
logic exc_req_lsu;
logic special_req;
@@ -134,8 +122,8 @@
// glitches
always_ff @(negedge clk_i) begin
// print warning in case of decoding errors
- if ((ctrl_fsm_cs == DECODE) && instr_valid_i && illegal_insn_i) begin
- $display("%t: Illegal instruction (core %0d) at PC 0x%h: 0x%h", $time, ibex_core.core_id_i,
+ if ((ctrl_fsm_cs == DECODE) && instr_valid_i && illegal_insn) begin
+ $display("%t: Illegal instruction (hart %0x) at PC 0x%h: 0x%h", $time, ibex_core.hart_id_i,
ibex_id_stage.pc_id_i, ibex_id_stage.instr_rdata_i);
end
end
@@ -149,14 +137,19 @@
assign load_err_d = load_err_i;
assign store_err_d = store_err_i;
+ // "Executing DRET outside of Debug Mode causes an illegal instruction exception."
+ // [Debug Spec v0.13.2, p.41]
+ assign illegal_dret = dret_insn_i & ~debug_mode_q;
+ assign illegal_insn = illegal_insn_i | illegal_dret;
+
// exception requests
- assign exc_req = ecall_insn_i | ebrk_insn_i | illegal_insn_i;
+ assign exc_req = ecall_insn_i | ebrk_insn_i | illegal_insn | instr_fetch_err_i;
// LSU exception requests
assign exc_req_lsu = store_err_i | load_err_i;
// special requests: special instructions, pipeline flushes, exceptions...
- assign special_req = mret_insn_i | dret_insn_i | wfi_insn_i | csr_status_i |
+ assign special_req = mret_insn_i | dret_insn_i | wfi_insn_i | csr_pipe_flush_i |
exc_req | exc_req_lsu;
////////////////
@@ -453,7 +446,11 @@
csr_save_cause_o = 1'b1;
// set exception registers, priorities according to Table 3.7 of Privileged Spec v1.11
- if (illegal_insn_i) begin
+ if (instr_fetch_err_i) begin
+ exc_cause_o = EXC_CAUSE_INSTR_ACCESS_FAULT;
+ csr_mtval_o = pc_id_i;
+
+ end else if (illegal_insn) begin
exc_cause_o = EXC_CAUSE_ILLEGAL_INSN;
csr_mtval_o = instr_is_compressed_i ? {16'b0, instr_compressed_i} : instr_i;
@@ -506,7 +503,7 @@
end
end else begin
- // special instructions
+ // special instructions and pipeline flushes
if (mret_insn_i) begin
pc_mux_o = PC_ERET;
pc_set_o = 1'b1;
@@ -520,6 +517,9 @@
debug_mode_d = 1'b0;
end else if (wfi_insn_i) begin
ctrl_fsm_ns = WAIT_SLEEP;
+ end else if (csr_pipe_flush_i && handle_irq) begin
+ // start handling IRQs when doing CSR-related pipeline flushes
+ ctrl_fsm_ns = IRQ_TAKEN;
end
end // exc_req
@@ -538,6 +538,9 @@
endcase
end
+ // signal to CSR when in debug mode
+ assign debug_mode_o = debug_mode_q;
+
///////////////////
// Stall control //
///////////////////
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
index 98da120..be613b9 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
@@ -1,26 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Matthias Baer - baermatt@student.ethz.ch //
-// //
-// Additional contributions by: //
-// Igor Loi - igor.loi@unibo.it //
-// Andreas Traber - atraber@student.ethz.ch //
-// Sven Stucki - svstucki@student.ethz.ch //
-// Markus Wegmann - markus.wegmann@technokrat.ch //
-// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// //
-// Design Name: Top level module //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Top level module of the RISC-V core. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
`ifdef RISCV_FORMAL
`define RVFI
`endif
@@ -29,6 +11,9 @@
* Top level module of the ibex RISC-V core
*/
module ibex_core #(
+ parameter bit PMPEnable = 0,
+ parameter int unsigned PMPGranularity = 0,
+ parameter int unsigned PMPNumRegions = 4,
parameter int unsigned MHPMCounterNum = 0,
parameter int unsigned MHPMCounterWidth = 40,
parameter bit RV32E = 0,
@@ -42,9 +27,7 @@
input logic test_en_i, // enable all clock gates for testing
- // Core ID, Cluster ID and boot address are considered more or less static
- input logic [ 3:0] core_id_i,
- input logic [ 5:0] cluster_id_i,
+ input logic [31:0] hart_id_i,
input logic [31:0] boot_addr_i,
// Instruction memory interface
@@ -53,6 +36,7 @@
input logic instr_rvalid_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
+ input logic instr_err_i,
// Data memory interface
output logic data_req_o,
@@ -109,12 +93,15 @@
import ibex_pkg::*;
+ localparam int unsigned PMP_NUM_CHAN = 2;
+
// IF/ID signals
logic instr_valid_id;
logic instr_new_id;
logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage
logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage
logic instr_is_compressed_id;
+ logic instr_fetch_err; // Bus error on instr fetch
logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage
logic [31:0] pc_if; // Program counter in IF stage
logic [31:0] pc_id; // Program counter in ID stage
@@ -173,7 +160,6 @@
logic data_we_ex;
logic [1:0] data_type_ex;
logic data_sign_ext_ex;
- logic [1:0] data_reg_offset_ex;
logic data_req_ex;
logic [31:0] data_wdata_ex;
logic [31:0] regfile_wdata_lsu;
@@ -196,6 +182,13 @@
logic csr_mstatus_mie;
logic [31:0] csr_mepc, csr_depc;
+ // PMP signals
+ logic [33:0] csr_pmp_addr [PMPNumRegions];
+ pmp_cfg_t csr_pmp_cfg [PMPNumRegions];
+ logic pmp_req_err [PMP_NUM_CHAN];
+ logic instr_req_out;
+ logic data_req_out;
+
logic csr_save_if;
logic csr_save_id;
logic csr_restore_mret_id;
@@ -203,8 +196,10 @@
logic csr_mtvec_init;
logic [31:0] csr_mtvec;
logic [31:0] csr_mtval;
+ priv_lvl_e priv_mode;
// debug mode and dcsr configuration
+ logic debug_mode;
dbg_cause_e debug_cause;
logic debug_csr_save;
logic debug_single_step;
@@ -304,11 +299,13 @@
.req_i ( instr_req_int ), // instruction request control
// instruction cache interface
- .instr_req_o ( instr_req_o ),
+ .instr_req_o ( instr_req_out ),
.instr_addr_o ( instr_addr_o ),
.instr_gnt_i ( instr_gnt_i ),
.instr_rvalid_i ( instr_rvalid_i ),
.instr_rdata_i ( instr_rdata_i ),
+ .instr_err_i ( instr_err_i ),
+ .instr_pmp_err_i ( pmp_req_err[PMP_I] ),
// outputs to ID stage
.instr_valid_id_o ( instr_valid_id ),
@@ -316,6 +313,7 @@
.instr_rdata_id_o ( instr_rdata_id ),
.instr_rdata_c_id_o ( instr_rdata_c_id ),
.instr_is_compressed_id_o ( instr_is_compressed_id ),
+ .instr_fetch_err_o ( instr_fetch_err ),
.illegal_c_insn_id_o ( illegal_c_insn_id ),
.pc_if_o ( pc_if ),
.pc_id_o ( pc_id ),
@@ -343,6 +341,8 @@
.perf_imiss_o ( perf_imiss )
);
+ // Qualify the instruction request with PMP error
+ assign instr_req_o = instr_req_out & ~pmp_req_err[PMP_I];
//////////////
// ID stage //
@@ -382,6 +382,7 @@
.exc_pc_mux_o ( exc_pc_mux_id ),
.exc_cause_o ( exc_cause ),
+ .instr_fetch_err_i ( instr_fetch_err ),
.illegal_c_insn_i ( illegal_c_insn_id ),
.pc_id_i ( pc_id ),
@@ -416,7 +417,6 @@
.data_we_ex_o ( data_we_ex ), // to load store unit
.data_type_ex_o ( data_type_ex ), // to load store unit
.data_sign_ext_ex_o ( data_sign_ext_ex ), // to load store unit
- .data_reg_offset_ex_o ( data_reg_offset_ex ), // to load store unit
.data_wdata_ex_o ( data_wdata_ex ), // to load store unit
.lsu_addr_incr_req_i ( lsu_addr_incr_req ),
@@ -435,6 +435,7 @@
.irq_nm_i ( irq_nm_i ),
// Debug Signal
+ .debug_mode_o ( debug_mode ),
.debug_cause_o ( debug_cause ),
.debug_csr_save_o ( debug_csr_save ),
.debug_req_i ( debug_req_i ),
@@ -500,15 +501,18 @@
// Load/store unit //
/////////////////////
+ assign data_req_o = data_req_out & ~pmp_req_err[PMP_D];
+
ibex_load_store_unit load_store_unit_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
// data interface
- .data_req_o ( data_req_o ),
+ .data_req_o ( data_req_out ),
.data_gnt_i ( data_gnt_i ),
.data_rvalid_i ( data_rvalid_i ),
.data_err_i ( data_err_i ),
+ .data_pmp_err_i ( pmp_req_err[PMP_D] ),
.data_addr_o ( data_addr_o ),
.data_we_o ( data_we_o ),
@@ -520,7 +524,6 @@
.data_we_ex_i ( data_we_ex ),
.data_type_ex_i ( data_type_ex ),
.data_wdata_ex_i ( data_wdata_ex ),
- .data_reg_offset_ex_i ( data_reg_offset_ex ),
.data_sign_ext_ex_i ( data_sign_ext_ex ),
.data_rdata_ex_o ( regfile_wdata_lsu ),
@@ -553,15 +556,17 @@
ibex_cs_registers #(
.MHPMCounterNum ( MHPMCounterNum ),
.MHPMCounterWidth ( MHPMCounterWidth ),
+ .PMPGranularity ( PMPGranularity ),
+ .PMPNumRegions ( PMPNumRegions ),
.RV32E ( RV32E ),
.RV32M ( RV32M )
) cs_registers_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
- // Core and Cluster ID from outside
- .core_id_i ( core_id_i ),
- .cluster_id_i ( cluster_id_i ),
+ // Hart ID from outside
+ .hart_id_i ( hart_id_i ),
+ .priv_mode_o ( priv_mode ),
// mtvec
.csr_mtvec_o ( csr_mtvec ),
@@ -588,8 +593,13 @@
.csr_mstatus_mie_o ( csr_mstatus_mie ),
.csr_mepc_o ( csr_mepc ),
+ // PMP
+ .csr_pmp_cfg_o ( csr_pmp_cfg ),
+ .csr_pmp_addr_o ( csr_pmp_addr ),
+
// debug
.csr_depc_o ( csr_depc ),
+ .debug_mode_i ( debug_mode ),
.debug_cause_i ( debug_cause ),
.debug_csr_save_i ( debug_csr_save ),
.debug_single_step_o ( debug_single_step ),
@@ -621,6 +631,36 @@
.lsu_busy_i ( lsu_busy )
);
+ if (PMPEnable) begin : g_pmp
+ logic [33:0] pmp_req_addr [PMP_NUM_CHAN];
+ pmp_req_e pmp_req_type [PMP_NUM_CHAN];
+
+ assign pmp_req_addr[PMP_I] = {2'b00,instr_addr_o[31:0]};
+ assign pmp_req_type[PMP_I] = PMP_ACC_EXEC;
+ assign pmp_req_addr[PMP_D] = {2'b00,data_addr_o[31:0]};
+ assign pmp_req_type[PMP_D] = data_we_o ? PMP_ACC_WRITE : PMP_ACC_READ;
+
+ ibex_pmp #(
+ .PMPGranularity ( PMPGranularity ),
+ .PMPNumChan ( PMP_NUM_CHAN ),
+ .PMPNumRegions ( PMPNumRegions )
+ ) pmp_i (
+ .clk_i ( clk ),
+ .rst_ni ( rst_ni ),
+ // Interface to CSRs
+ .csr_pmp_cfg_i ( csr_pmp_cfg ),
+ .csr_pmp_addr_i ( csr_pmp_addr ),
+ .priv_mode_i ( priv_mode ),
+ // Access checking channels
+ .pmp_req_addr_i ( pmp_req_addr ),
+ .pmp_req_type_i ( pmp_req_type ),
+ .pmp_req_err_o ( pmp_req_err )
+ );
+ end else begin : g_no_pmp
+ assign pmp_req_err[PMP_I] = 1'b0;
+ assign pmp_req_err[PMP_D] = 1'b0;
+ end
+
`ifdef RVFI
always_ff @(posedge clk or negedge rst_ni) begin
if (!rst_ni) begin
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv
index 48f3d3b..63c100f 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv
@@ -20,9 +20,7 @@
input logic test_en_i, // enable all clock gates for testing
- // Core ID, Cluster ID and boot address are considered more or less static
- input logic [ 3:0] core_id_i,
- input logic [ 5:0] cluster_id_i,
+ input logic [31:0] hart_id_i,
input logic [31:0] boot_addr_i,
// Instruction memory interface
@@ -31,6 +29,7 @@
input logic instr_rvalid_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
+ input logic instr_err_i,
// Data memory interface
output logic data_req_o,
@@ -100,8 +99,7 @@
.test_en_i,
- .core_id_i,
- .cluster_id_i,
+ .hart_id_i,
.boot_addr_i,
.instr_req_o,
@@ -109,6 +107,7 @@
.instr_rvalid_i,
.instr_addr_o,
.instr_rdata_i,
+ .instr_err_i,
.data_req_o,
.data_gnt_i,
@@ -160,8 +159,7 @@
.rst_ni ( rst_ni ),
.fetch_enable_i ( fetch_enable_i ),
- .core_id_i ( core_id_i ),
- .cluster_id_i ( cluster_id_i ),
+ .hart_id_i ( hart_id_i ),
.valid_i ( rvfi_valid ),
.pc_i ( rvfi_pc_rdata ),
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
index a7adcaf..f65ab51 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
@@ -1,24 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Sven Stucki - svstucki@student.ethz.ch //
-// //
-// Additional contributions by: //
-// Andreas Traber - atraber@iis.ee.ethz.ch //
-// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// //
-// Design Name: Control and Status Registers //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Control and Status Registers (CSRs) following the RISC-V //
-// Privileged Specification, draft version 1.11 //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* Control and Status Registers
*
@@ -28,6 +12,9 @@
module ibex_cs_registers #(
parameter int unsigned MHPMCounterNum = 8,
parameter int unsigned MHPMCounterWidth = 40,
+ parameter bit PMPEnable = 0,
+ parameter int unsigned PMPGranularity = 0,
+ parameter int unsigned PMPNumRegions = 4,
parameter bit RV32E = 0,
parameter bit RV32M = 0
) (
@@ -35,9 +22,9 @@
input logic clk_i,
input logic rst_ni,
- // Core and Cluster ID
- input logic [3:0] core_id_i,
- input logic [5:0] cluster_id_i,
+ // Hart ID
+ input logic [31:0] hart_id_i,
+ output ibex_pkg::priv_lvl_e priv_mode_o,
// mtvec
output logic [31:0] csr_mtvec_o,
@@ -64,7 +51,12 @@
output logic csr_mstatus_mie_o,
output logic [31:0] csr_mepc_o,
+ // PMP
+ output ibex_pkg::pmp_cfg_t csr_pmp_cfg_o [PMPNumRegions],
+ output logic [33:0] csr_pmp_addr_o [PMPNumRegions],
+
// debug
+ input logic debug_mode_i,
input ibex_pkg::dbg_cause_e debug_cause_i,
input logic debug_csr_save_i,
output logic [31:0] csr_depc_o,
@@ -172,6 +164,10 @@
logic [31:0] mstack_epc_q, mstack_epc_d;
logic [5:0] mstack_cause_q, mstack_cause_d;
+ // PMP Signals
+ logic [31:0] pmp_addr_rdata [PMP_MAX_REGIONS];
+ logic [PMP_CFG_W-1:0] pmp_cfg_rdata [PMP_MAX_REGIONS];
+
// Hardware performance monitor signals
logic [31:0] mcountinhibit_d, mcountinhibit_q, mcountinhibit;
logic [31:0] mcountinhibit_force;
@@ -225,7 +221,7 @@
unique case (csr_addr_i)
// mhartid: unique hardware thread id
- CSR_MHARTID: csr_rdata_int = {21'b0, cluster_id_i[5:0], 1'b0, core_id_i[3:0]};
+ CSR_MHARTID: csr_rdata_int = hart_id_i;
// mstatus: always M-mode, contains IE bit
CSR_MSTATUS: begin
@@ -270,10 +266,48 @@
csr_rdata_int[CSR_MFIX_BIT_HIGH:CSR_MFIX_BIT_LOW] = mip.irq_fast;
end
- CSR_DCSR: csr_rdata_int = dcsr_q;
- CSR_DPC: csr_rdata_int = depc_q;
- CSR_DSCRATCH0: csr_rdata_int = dscratch0_q;
- CSR_DSCRATCH1: csr_rdata_int = dscratch1_q;
+ // PMP registers
+ CSR_PMPCFG0: csr_rdata_int = {pmp_cfg_rdata[3], pmp_cfg_rdata[2],
+ pmp_cfg_rdata[1], pmp_cfg_rdata[0]};
+ CSR_PMPCFG1: csr_rdata_int = {pmp_cfg_rdata[7], pmp_cfg_rdata[6],
+ pmp_cfg_rdata[5], pmp_cfg_rdata[4]};
+ CSR_PMPCFG2: csr_rdata_int = {pmp_cfg_rdata[11], pmp_cfg_rdata[10],
+ pmp_cfg_rdata[9], pmp_cfg_rdata[8]};
+ CSR_PMPCFG3: csr_rdata_int = {pmp_cfg_rdata[15], pmp_cfg_rdata[14],
+ pmp_cfg_rdata[13], pmp_cfg_rdata[12]};
+ CSR_PMPADDR0: csr_rdata_int = pmp_addr_rdata[0];
+ CSR_PMPADDR1: csr_rdata_int = pmp_addr_rdata[1];
+ CSR_PMPADDR2: csr_rdata_int = pmp_addr_rdata[2];
+ CSR_PMPADDR3: csr_rdata_int = pmp_addr_rdata[3];
+ CSR_PMPADDR4: csr_rdata_int = pmp_addr_rdata[4];
+ CSR_PMPADDR5: csr_rdata_int = pmp_addr_rdata[5];
+ CSR_PMPADDR6: csr_rdata_int = pmp_addr_rdata[6];
+ CSR_PMPADDR7: csr_rdata_int = pmp_addr_rdata[7];
+ CSR_PMPADDR8: csr_rdata_int = pmp_addr_rdata[8];
+ CSR_PMPADDR9: csr_rdata_int = pmp_addr_rdata[9];
+ CSR_PMPADDR10: csr_rdata_int = pmp_addr_rdata[10];
+ CSR_PMPADDR11: csr_rdata_int = pmp_addr_rdata[11];
+ CSR_PMPADDR12: csr_rdata_int = pmp_addr_rdata[12];
+ CSR_PMPADDR13: csr_rdata_int = pmp_addr_rdata[13];
+ CSR_PMPADDR14: csr_rdata_int = pmp_addr_rdata[14];
+ CSR_PMPADDR15: csr_rdata_int = pmp_addr_rdata[15];
+
+ CSR_DCSR: begin
+ csr_rdata_int = dcsr_q;
+ illegal_csr = ~debug_mode_i;
+ end
+ CSR_DPC: begin
+ csr_rdata_int = depc_q;
+ illegal_csr = ~debug_mode_i;
+ end
+ CSR_DSCRATCH0: begin
+ csr_rdata_int = dscratch0_q;
+ illegal_csr = ~debug_mode_i;
+ end
+ CSR_DSCRATCH1: begin
+ csr_rdata_int = dscratch1_q;
+ illegal_csr = ~debug_mode_i;
+ end
// machine counter/timers
CSR_MCOUNTINHIBIT: csr_rdata_int = mcountinhibit;
@@ -527,7 +561,7 @@
end
// only write CSRs during one clock cycle
- assign csr_we_int = csr_wreq & instr_new_id_i;
+ assign csr_we_int = csr_wreq & ~illegal_csr_priv & instr_new_id_i;
assign csr_rdata_o = csr_rdata_int;
@@ -600,6 +634,131 @@
end
end
+ assign priv_mode_o = mstatus_q.mpp;
+
+ // -----------------
+ // PMP registers
+ // -----------------
+
+ if (PMPEnable) begin : g_pmp_registers
+ pmp_cfg_t pmp_cfg [PMPNumRegions];
+ pmp_cfg_t pmp_cfg_wdata [PMPNumRegions];
+ logic [31:0] pmp_addr [PMPNumRegions];
+ logic [PMPNumRegions-1:0] pmp_cfg_we;
+ logic [PMPNumRegions-1:0] pmp_addr_we;
+
+ // Expanded / qualified register read data
+ for (genvar i = 0; i < PMP_MAX_REGIONS; i++) begin : g_exp_rd_data
+ if (i < PMPNumRegions) begin : g_implemented_regions
+ // Add in zero padding for reserved fields
+ assign pmp_cfg_rdata[i] = {pmp_cfg[i].lock, 2'b00, pmp_cfg[i].mode,
+ pmp_cfg[i].exec, pmp_cfg[i].write, pmp_cfg[i].read};
+
+ // Address field read data depends on the current programmed mode and the granularity
+ // See RISC-V Privileged Specification, version 1.11, Section 3.6.1
+ if (PMPGranularity == 0) begin : g_pmp_g0
+ // If G == 0, read data is unmodified
+ assign pmp_addr_rdata[i] = pmp_addr[i];
+
+ end else if (PMPGranularity == 1) begin : g_pmp_g1
+ // If G == 1, bit [G-1] reads as zero in TOR or OFF mode
+ always_comb begin
+ pmp_addr_rdata[i] = pmp_addr[i];
+ if ((pmp_cfg[i].mode == PMP_MODE_OFF) || (pmp_cfg[i].mode == PMP_MODE_TOR)) begin
+ pmp_addr_rdata[i][PMPGranularity-1:0] = '0;
+ end
+ end
+
+ end else begin
+ // For G >= 2, bits are masked to one or zero depending on the mode
+ always_comb begin
+ pmp_addr_rdata[i] = pmp_addr[i];
+ if ((pmp_cfg[i].mode == PMP_MODE_OFF) || (pmp_cfg[i].mode == PMP_MODE_TOR)) begin
+ // In TOR or OFF mode, bits [G-1:0] must read as zero
+ pmp_addr_rdata[i][PMPGranularity-1:0] = '0;
+ end else if (pmp_cfg[i].mode == PMP_MODE_NAPOT) begin
+ // In NAPOT mode, bits [G-2:0] must read as one
+ pmp_addr_rdata[i][PMPGranularity-2:0] = '1;
+ end
+ end
+ end
+
+ end else begin : g_other_regions
+ // Non-implemented regions read as zero
+ assign pmp_cfg_rdata[i] = '0;
+ assign pmp_addr_rdata[i] = '0;
+ end
+ end
+
+ // Write data calculation
+ for (genvar i = 0; i < PMPNumRegions; i++) begin : g_pmp_csrs
+ // -------------------------
+ // Instantiate cfg registers
+ // -------------------------
+ assign pmp_cfg_we[i] = csr_we_int & ~pmp_cfg[i].lock &
+ (csr_addr == (CSR_OFF_PMP_CFG + (i[11:0] >> 2)));
+
+ // Select the correct WDATA (each CSR contains 4 CFG fields, each with 2 RES bits)
+ assign pmp_cfg_wdata[i].lock = csr_wdata_int[(i%4)*PMP_CFG_W+7];
+ // NA4 mode is not selectable when G > 0, mode is treated as OFF
+ always_comb begin
+ unique case (csr_wdata_int[(i%4)*PMP_CFG_W+3+:2])
+ 2'b00 : pmp_cfg_wdata[i].mode = PMP_MODE_OFF;
+ 2'b01 : pmp_cfg_wdata[i].mode = PMP_MODE_TOR;
+ 2'b10 : pmp_cfg_wdata[i].mode = (PMPGranularity == 0) ? PMP_MODE_NA4:
+ PMP_MODE_OFF;
+ 2'b11 : pmp_cfg_wdata[i].mode = PMP_MODE_NAPOT;
+ default : pmp_cfg_wdata[i].mode = pmp_cfg_mode_e'('X);
+ endcase
+ end
+ assign pmp_cfg_wdata[i].exec = csr_wdata_int[(i%4)*PMP_CFG_W+2];
+ // W = 1, R = 0 is a reserved combination. For now, we force W to 0 if R == 0
+ assign pmp_cfg_wdata[i].write = &csr_wdata_int[(i%4)*PMP_CFG_W+:2];
+ assign pmp_cfg_wdata[i].read = csr_wdata_int[(i%4)*PMP_CFG_W];
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ pmp_cfg[i] <= pmp_cfg_t'('b0);
+ end else if (pmp_cfg_we[i]) begin
+ pmp_cfg[i] <= pmp_cfg_wdata[i];
+ end
+ end
+
+ // --------------------------
+ // Instantiate addr registers
+ // --------------------------
+ if (i < PMPNumRegions - 1) begin : g_lower
+ assign pmp_addr_we[i] = csr_we_int & ~pmp_cfg[i].lock &
+ (pmp_cfg[i+1].mode != PMP_MODE_TOR) &
+ (csr_addr == (CSR_OFF_PMP_ADDR + i[11:0]));
+ end else begin : g_upper
+ assign pmp_addr_we[i] = csr_we_int & ~pmp_cfg[i].lock &
+ (csr_addr == (CSR_OFF_PMP_ADDR + i[11:0]));
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ pmp_addr[i] <= 'b0;
+ end else if (pmp_addr_we[i]) begin
+ pmp_addr[i] <= csr_wdata_int;
+ end
+ end
+ assign csr_pmp_cfg_o[i] = pmp_cfg[i];
+ assign csr_pmp_addr_o[i] = {pmp_addr[i],2'b00};
+ end
+
+ end else begin : g_no_pmp_tieoffs
+ // Generate tieoffs when PMP is not configured
+ for (genvar i = 0; i < PMP_MAX_REGIONS; i++) begin : g_rdata
+ assign pmp_addr_rdata[i] = '0;
+ assign pmp_cfg_rdata[i] = '0;
+ end
+ for (genvar i = 0; i < PMPNumRegions; i++) begin : g_outputs
+ assign csr_pmp_cfg_o[i] = pmp_cfg_t'('0);
+ assign csr_pmp_addr_o[i] = '0;
+ end
+ end
+
//////////////////////////
// Performance monitor //
//////////////////////////
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
index d472c50..72f483d 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
@@ -1,26 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer Andreas Traber - atraber@iis.ee.ethz.ch //
-// //
-// Additional contributions by: //
-// Matthias Baer - baermatt@student.ethz.ch //
-// Igor Loi - igor.loi@unibo.it //
-// Sven Stucki - svstucki@student.ethz.ch //
-// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// Markus Wegmann - markus.wegmann@technokrat.ch //
-// //
-// Design Name: Decoder //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Decoder //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
// Source/Destination register instruction index
`define REG_S1 19:15
`define REG_S2 24:20
@@ -82,7 +64,7 @@
// CSRs
output logic csr_access_o, // access to CSR
output ibex_pkg::csr_op_e csr_op_o, // operation to perform on CSR
- output logic csr_status_o, // access to xstatus CSR
+ output logic csr_pipe_flush_o, // CSR-related pipeline flush
// LSU
output logic data_req_o, // start transaction to data memory
@@ -91,7 +73,6 @@
// word or word
output logic data_sign_extension_o, // sign extension for data read from
// memory
- output logic [1:0] data_reg_offset_o, // register byte offset for stores
// jump/branches
output logic jump_in_dec_o, // jump is being calculated in ALU
@@ -159,6 +140,32 @@
end
end
+ /////////////////////////////////
+ // CSR-related pipline flushes //
+ /////////////////////////////////
+ always_comb begin : csr_pipeline_flushes
+ csr_pipe_flush_o = 1'b0;
+
+ // A pipeline flush is needed to let the controller react after modifying certain CSRs:
+ // - When enabling interrupts, pending IRQs become visible to the controller only during
+ // the next cycle. If during that cycle the core disables interrupts again, it does not
+ // see any pending IRQs and consequently does not start to handle interrupts.
+ // - When modifying debug CSRs - TODO: Check if this is really needed
+ if (csr_access_o == 1'b1 && (csr_op_o == CSR_OP_WRITE || csr_op_o == CSR_OP_SET)) begin
+ if (csr_num_e'(instr[31:20]) == CSR_MSTATUS ||
+ csr_num_e'(instr[31:20]) == CSR_MIE) begin
+ csr_pipe_flush_o = 1'b1;
+ end
+ end else if (csr_access_o == 1'b1 && csr_op_o != CSR_OP_READ) begin
+ if (csr_num_e'(instr[31:20]) == CSR_DCSR ||
+ csr_num_e'(instr[31:20]) == CSR_DPC ||
+ csr_num_e'(instr[31:20]) == CSR_DSCRATCH0 ||
+ csr_num_e'(instr[31:20]) == CSR_DSCRATCH1) begin
+ csr_pipe_flush_o = 1'b1;
+ end
+ end
+ end
+
/////////////
// Decoder //
/////////////
@@ -183,14 +190,12 @@
regfile_we = 1'b0;
csr_access_o = 1'b0;
- csr_status_o = 1'b0;
csr_illegal = 1'b0;
csr_op = CSR_OP_READ;
data_we_o = 1'b0;
data_type_o = 2'b00;
data_sign_extension_o = 1'b0;
- data_reg_offset_o = 2'b00;
data_req_o = 1'b0;
illegal_insn = 1'b0;
@@ -555,17 +560,6 @@
default: csr_illegal = 1'b1;
endcase
- if (!csr_illegal) begin
- // flush pipeline on access to mstatus or debug CSRs
- if (csr_num_e'(instr[31:20]) == CSR_MSTATUS ||
- csr_num_e'(instr[31:20]) == CSR_DCSR ||
- csr_num_e'(instr[31:20]) == CSR_DPC ||
- csr_num_e'(instr[31:20]) == CSR_DSCRATCH0 ||
- csr_num_e'(instr[31:20]) == CSR_DSCRATCH1) begin
- csr_status_o = 1'b1;
- end
- end
-
illegal_insn = csr_illegal;
end
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
index f12a75f..54041a3 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
@@ -1,26 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Renzo Andri - andrire@student.ethz.ch //
-// //
-// Additional contributions by: //
-// Igor Loi - igor.loi@unibo.it //
-// Sven Stucki - svstucki@student.ethz.ch //
-// Andreas Traber - atraber@iis.ee.ethz.ch //
-// Markus Wegmann - markus.wegmann@technokrat.ch //
-// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// //
-// Design Name: Execute stage //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Execution block: Hosts ALU and MUL/DIV unit //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* Execution stage
*
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
index ba32767..1a2d5d1 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
@@ -1,18 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Andreas Traber - atraber@iis.ee.ethz.ch //
-// //
-// Design Name: Fetch Fifo for 32 bit memory interface //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Fetch fifo //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* Fetch Fifo for 32 bit memory interface
*
@@ -30,6 +20,7 @@
// input port
input logic [31:0] in_addr_i,
input logic [31:0] in_rdata_i,
+ input logic in_err_i,
input logic in_valid_i,
output logic in_ready_o,
@@ -39,6 +30,7 @@
input logic out_ready_i,
output logic [31:0] out_rdata_o,
output logic [31:0] out_addr_o,
+ output logic out_err_o,
output logic out_valid_stored_o // same as out_valid_o, except that if something is
// incoming now it is not included. This signal is
@@ -50,10 +42,12 @@
// index 0 is used for output
logic [DEPTH-1:0] [31:0] addr_n, addr_int, addr_q;
logic [DEPTH-1:0] [31:0] rdata_n, rdata_int, rdata_q;
+ logic [DEPTH-1:0] err_n, err_int, err_q;
logic [DEPTH-1:0] valid_n, valid_int, valid_q;
logic [31:2] addr_next;
logic [31:0] rdata, rdata_unaligned;
+ logic err, err_unaligned;
logic valid, valid_unaligned;
logic aligned_is_compressed, unaligned_is_compressed;
@@ -65,12 +59,22 @@
assign rdata = valid_q[0] ? rdata_q[0] : in_rdata_i;
+ assign err = valid_q[0] ? err_q[0] : in_err_i;
assign valid = valid_q[0] | in_valid_i;
assign rdata_unaligned = valid_q[1] ? {rdata_q[1][15:0], rdata[31:16]} :
{in_rdata_i[15:0], rdata[31:16]};
- // it is implied that rdata_valid_q[0] is set
- assign valid_unaligned = valid_q[1] | (valid_q[0] & in_valid_i);
+ // If entry[1] is valid, an error can come from entry[0] or entry[1], unless the
+ // instruction in entry[0] is compressed (entry[1] is a new instruction)
+ // If entry[1] is not valid, and entry[0] is, an error can come from entry[0] or the incoming
+ // data, unless the instruction in entry[0] is compressed
+ // If entry[0] is not valid, the error must come from the incoming data
+ assign err_unaligned = valid_q[1] ? ((err_q[1] & ~unaligned_is_compressed) | err_q[0]) :
+ ((valid_q[0] & err_q[0]) |
+ (in_err_i & (~valid_q[0] | ~unaligned_is_compressed)));
+ // An uncompressed unaligned instruction is only valid if both parts are available
+ assign valid_unaligned = valid_q[1] ? 1'b1 :
+ (valid_q[0] & in_valid_i);
assign unaligned_is_compressed = rdata[17:16] != 2'b11;
assign aligned_is_compressed = rdata[ 1: 0] != 2'b11;
@@ -87,6 +91,7 @@
if (out_addr_o[1]) begin
// unaligned case
out_rdata_o = rdata_unaligned;
+ out_err_o = err_unaligned;
if (unaligned_is_compressed) begin
out_valid_o = valid;
@@ -96,6 +101,7 @@
end else begin
// aligned case
out_rdata_o = rdata;
+ out_err_o = err;
out_valid_o = valid;
end
end
@@ -134,12 +140,14 @@
always_comb begin
addr_int = addr_q;
rdata_int = rdata_q;
+ err_int = err_q;
valid_int = valid_q;
if (in_valid_i) begin
for (int j = 0; j < DEPTH; j++) begin
if (!valid_q[j]) begin
addr_int[j] = in_addr_i;
rdata_int[j] = in_rdata_i;
+ err_int[j] = in_err_i;
valid_int[j] = 1'b1;
break;
end
@@ -153,6 +161,7 @@
always_comb begin
addr_n = addr_int;
rdata_n = rdata_int;
+ err_n = err_int;
valid_n = valid_int;
if (out_ready_i && out_valid_o) begin
@@ -165,6 +174,7 @@
end
rdata_n = {32'b0, rdata_int[DEPTH-1:1]};
+ err_n = {1'b0, err_int[DEPTH-1:1]};
valid_n = {1'b0, valid_int[DEPTH-1:1]};
end else if (aligned_is_compressed) begin
// just increase address, do not move to next entry in FIFO
@@ -173,6 +183,7 @@
// move to next entry in FIFO
addr_n[0] = {addr_next[31:2], 2'b00};
rdata_n = {32'b0, rdata_int[DEPTH-1:1]};
+ err_n = {1'b0, err_int[DEPTH-1:1]};
valid_n = {1'b0, valid_int[DEPTH-1:1]};
end
end
@@ -186,6 +197,7 @@
if (!rst_ni) begin
addr_q <= '{default: '0};
rdata_q <= '{default: '0};
+ err_q <= '0;
valid_q <= '0;
end else begin
// on a clear signal from outside we invalidate the content of the FIFO
@@ -195,6 +207,7 @@
end else begin
addr_q <= addr_n;
rdata_q <= rdata_n;
+ err_q <= err_n;
valid_q <= valid_n;
end
end
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
index e6e36c4..45f2446 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
@@ -1,26 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Renzo Andri - andrire@student.ethz.ch //
-// //
-// Additional contributions by: //
-// Igor Loi - igor.loi@unibo.it //
-// Andreas Traber - atraber@student.ethz.ch //
-// Sven Stucki - svstucki@student.ethz.ch //
-// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// //
-// Design Name: Instruction Decode Stage //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Decode stage of the core. It decodes the instructions //
-// and hosts the register file. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
`ifdef RISCV_FORMAL
`define RVFI
`endif
@@ -65,6 +47,7 @@
output ibex_pkg::exc_cause_e exc_cause_o,
input logic illegal_c_insn_i,
+ input logic instr_fetch_err_i,
input logic [31:0] pc_id_i,
@@ -99,7 +82,6 @@
output logic data_we_ex_o,
output logic [1:0] data_type_ex_o,
output logic data_sign_ext_ex_o,
- output logic [1:0] data_reg_offset_ex_o,
output logic [31:0] data_wdata_ex_o,
input logic lsu_addr_incr_req_i,
@@ -118,6 +100,7 @@
input logic lsu_store_err_i,
// Debug Signal
+ output logic debug_mode_o,
output ibex_pkg::dbg_cause_e debug_cause_o,
output logic debug_csr_save_o,
input logic debug_req_i,
@@ -214,11 +197,10 @@
logic data_we_id;
logic [1:0] data_type_id;
logic data_sign_ext_id;
- logic [1:0] data_reg_offset_id;
logic data_req_id, data_req_dec;
// CSR control
- logic csr_status;
+ logic csr_pipe_flush;
logic [31:0] alu_operand_a;
logic [31:0] alu_operand_b;
@@ -377,14 +359,13 @@
// CSRs
.csr_access_o ( csr_access_o ),
.csr_op_o ( csr_op_o ),
- .csr_status_o ( csr_status ),
+ .csr_pipe_flush_o ( csr_pipe_flush ),
// LSU
.data_req_o ( data_req_dec ),
.data_we_o ( data_we_id ),
.data_type_o ( data_type_id ),
.data_sign_extension_o ( data_sign_ext_id ),
- .data_reg_offset_o ( data_reg_offset_id ),
// jump/branches
.jump_in_dec_o ( jump_in_dec ),
@@ -412,13 +393,15 @@
.dret_insn_i ( dret_insn_dec ),
.wfi_insn_i ( wfi_insn_dec ),
.ebrk_insn_i ( ebrk_insn ),
- .csr_status_i ( csr_status ),
+ .csr_pipe_flush_i ( csr_pipe_flush ),
// from IF-ID pipeline
.instr_valid_i ( instr_valid_i ),
.instr_i ( instr_rdata_i ),
.instr_compressed_i ( instr_rdata_c_i ),
.instr_is_compressed_i ( instr_is_compressed_i ),
+ .instr_fetch_err_i ( instr_fetch_err_i ),
+ .pc_id_i ( pc_id_i ),
// to IF-ID pipeline
.instr_valid_clear_o ( instr_valid_clear_o ),
@@ -457,6 +440,7 @@
.csr_mtval_o ( csr_mtval_o ),
// Debug Signal
+ .debug_mode_o ( debug_mode_o ),
.debug_cause_o ( debug_cause_o ),
.debug_csr_save_o ( debug_csr_save_o ),
.debug_req_i ( debug_req_i ),
@@ -499,7 +483,6 @@
assign data_type_ex_o = data_type_id;
assign data_sign_ext_ex_o = data_sign_ext_id;
assign data_wdata_ex_o = regfile_rdata_b;
- assign data_reg_offset_ex_o = data_reg_offset_id;
assign alu_operator_ex_o = alu_operator;
assign alu_operand_a_ex_o = alu_operand_a;
@@ -630,7 +613,8 @@
// the instruction delivered to the ID stage should always be valid
assert property (
- @(posedge clk_i) (instr_valid_i & (~illegal_c_insn_i)) |-> (!$isunknown(instr_rdata_i)) ) else
+ @(posedge clk_i) (instr_valid_i & ~(illegal_c_insn_i | instr_fetch_err_i)) |->
+ (!$isunknown(instr_rdata_i)) ) else
$display("Instruction is valid, but has at least one X");
// make sure multicycles enable signals are unique
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
index 62cf845..a1fa6d4 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
@@ -1,25 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Renzo Andri - andrire@student.ethz.ch //
-// //
-// Additional contributions by: //
-// Igor Loi - igor.loi@unibo.it //
-// Andreas Traber - atraber@student.ethz.ch //
-// Sven Stucki - svstucki@student.ethz.ch //
-// //
-// Design Name: Instruction Fetch Stage //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Instruction fetch unit: Selection of the next PC, and //
-// buffering (sampling) of the read instruction //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* Instruction Fetch Stage
*
@@ -42,6 +25,8 @@
input logic instr_gnt_i,
input logic instr_rvalid_i,
input logic [31:0] instr_rdata_i,
+ input logic instr_err_i,
+ input logic instr_pmp_err_i,
// output of ID stage
output logic instr_valid_id_o, // instr in IF-ID is valid
@@ -52,6 +37,7 @@
// instr_is_compressed_id_o = 1'b1
output logic instr_is_compressed_id_o, // compressed decoder thinks this
// is a compressed instr
+ output logic instr_fetch_err_o, // bus error on fetch
output logic illegal_c_insn_id_o, // compressed decoder thinks this
// is an invalid instr
output logic [31:0] pc_if_o,
@@ -97,6 +83,7 @@
logic fetch_ready;
logic [31:0] fetch_rdata;
logic [31:0] fetch_addr;
+ logic fetch_err;
logic [31:0] exc_pc;
@@ -155,6 +142,7 @@
.valid_o ( fetch_valid ),
.rdata_o ( fetch_rdata ),
.addr_o ( fetch_addr ),
+ .err_o ( fetch_err ),
// goes to instruction memory / instruction cache
.instr_req_o ( instr_req_o ),
@@ -162,6 +150,8 @@
.instr_gnt_i ( instr_gnt_i ),
.instr_rvalid_i ( instr_rvalid_i ),
.instr_rdata_i ( instr_rdata_i ),
+ .instr_err_i ( instr_err_i ),
+ .instr_pmp_err_i ( instr_pmp_err_i ),
// Prefetch Buffer Status
.busy_o ( prefetch_busy )
@@ -241,6 +231,7 @@
instr_new_id_o <= 1'b0;
instr_valid_id_o <= 1'b0;
instr_rdata_id_o <= '0;
+ instr_fetch_err_o <= '0;
instr_rdata_c_id_o <= '0;
instr_is_compressed_id_o <= 1'b0;
illegal_c_insn_id_o <= 1'b0;
@@ -250,6 +241,7 @@
if (if_id_pipe_reg_we) begin
instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed;
+ instr_fetch_err_o <= fetch_err;
instr_rdata_c_id_o <= fetch_rdata[15:0];
instr_is_compressed_id_o <= instr_is_compressed_int;
illegal_c_insn_id_o <= illegal_c_insn;
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv
index 2741a85..8abcd95 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv
@@ -1,25 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Igor Loi - igor.loi@unibo.it //
-// //
-// Additional contributions by: //
-// Andreas Traber - atraber@iis.ee.ethz.ch //
-// Markus Wegmann - markus.wegmann@technokrat.ch //
-// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// //
-// Design Name: Load Store Unit //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Load Store Unit, used to eliminate multiple access during //
-// processor stalls, and to align bytes and halfwords //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* Load Store Unit
*
@@ -35,6 +18,7 @@
input logic data_gnt_i,
input logic data_rvalid_i,
input logic data_err_i,
+ input logic data_pmp_err_i,
output logic [31:0] data_addr_o,
output logic data_we_o,
@@ -46,7 +30,6 @@
input logic data_we_ex_i, // write enable -> from ID/EX
input logic [1:0] data_type_ex_i, // data type: word, half word, byte -> from ID/EX
input logic [31:0] data_wdata_ex_i, // data to write to memory -> from ID/EX
- input logic [1:0] data_reg_offset_ex_i, // register byte offset for stores -> from ID/EX
input logic data_sign_ext_ex_i, // sign extension -> from ID/EX
output logic [31:0] data_rdata_ex_o, // requested data -> to ID/EX
@@ -59,7 +42,7 @@
output logic [31:0] addr_last_o, // address of last transaction -> to controller
// -> mtval
// -> AGU for misaligned accesses
- output logic data_valid_o, // LSU has completed transaction -> to
+ output logic data_valid_o, // LSU has completed transaction -> to
// exception signals
output logic load_err_o,
@@ -72,6 +55,7 @@
logic [31:0] data_addr_w_aligned;
logic [31:0] addr_last_q, addr_last_d;
+ logic data_update;
logic [31:0] rdata_q, rdata_d;
logic [1:0] rdata_offset_q, rdata_offset_d;
logic [1:0] data_type_q, data_type_d;
@@ -92,6 +76,8 @@
logic split_misaligned_access;
logic handle_misaligned_q, handle_misaligned_d; // high after receiving grant for first
// part of a misaligned access
+ logic pmp_err_q;
+ logic data_or_pmp_err;
typedef enum logic [2:0] {
IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID
@@ -161,9 +147,8 @@
/////////////////////
// prepare data to be written to the memory
- // we handle misaligned accesses, half word and byte accesses and
- // register offsets here
- assign wdata_offset = data_addr[1:0] - data_reg_offset_ex_i[1:0];
+ // we handle misaligned accesses, half word and byte accesses here
+ assign wdata_offset = data_addr[1:0];
always_comb begin
unique case (wdata_offset)
2'b00: data_wdata = data_wdata_ex_i[31:0];
@@ -187,10 +172,16 @@
end
// update control signals for next read data upon receiving grant
- assign rdata_offset_d = data_gnt_i ? data_addr[1:0] : rdata_offset_q;
- assign data_type_d = data_gnt_i ? data_type_ex_i : data_type_q;
- assign data_sign_ext_d = data_gnt_i ? data_sign_ext_ex_i : data_sign_ext_q;
- assign data_we_d = data_gnt_i ? data_we_ex_i : data_we_q;
+ // This must also be set for a pmp error (which might not actually be granted) to force
+ // data_we_q to update in order to signal the correct exception type (load or store)
+ // Note that we can use the registered pmp_err_q here since we will always take an
+ // extra cycle to progress to the RVALID state
+ assign data_update = data_gnt_i | pmp_err_q;
+
+ assign rdata_offset_d = data_update ? data_addr[1:0] : rdata_offset_q;
+ assign data_type_d = data_update ? data_type_ex_i : data_type_q;
+ assign data_sign_ext_d = data_update ? data_sign_ext_ex_i : data_sign_ext_q;
+ assign data_we_d = data_update ? data_we_ex_i : data_we_q;
// registers for rdata alignment and sign-extension
always_ff @(posedge clk_i or negedge rst_ni) begin
@@ -329,6 +320,7 @@
data_valid_o = 1'b0;
addr_incr_req_o = 1'b0;
handle_misaligned_d = handle_misaligned_q;
+ data_or_pmp_err = 1'b0;
unique case (ls_fsm_cs)
@@ -346,7 +338,7 @@
WAIT_GNT_MIS: begin
data_req_o = 1'b1;
- if (data_gnt_i) begin
+ if (data_gnt_i || pmp_err_q) begin
handle_misaligned_d = 1'b1;
ls_fsm_ns = WAIT_RVALID_MIS;
end
@@ -355,11 +347,14 @@
WAIT_RVALID_MIS: begin
// tell ID/EX stage to update the address
addr_incr_req_o = 1'b1;
- if (data_rvalid_i) begin
- // first part rvalid is received
- if (data_err_i) begin
+ // first part rvalid is received, or gets a pmp error
+ // pmp_err_i will hold stable until the address is updated, and
+ // therefore pmp_err_q is valid in both WAIT_GNT_MIS and WAIT_RVALID_MIS states
+ if (data_rvalid_i || pmp_err_q) begin
+ if (pmp_err_q || data_err_i) begin
// first part created an error, abort transaction
data_valid_o = 1'b1;
+ data_or_pmp_err = 1'b1;
handle_misaligned_d = 1'b0;
ls_fsm_ns = IDLE;
end else begin
@@ -383,15 +378,18 @@
// tell ID/EX stage to update the address
addr_incr_req_o = handle_misaligned_q;
data_req_o = 1'b1;
- if (data_gnt_i) begin
+ if (data_gnt_i || pmp_err_q) begin
ls_fsm_ns = WAIT_RVALID;
end
end
WAIT_RVALID: begin
data_req_o = 1'b0;
- if (data_rvalid_i) begin
+ // pmp_err_i will hold stable until the address is updated, and
+ // therefore pmp_err_q is valid in both WAIT_GNT and WAIT_RVALID states
+ if (data_rvalid_i || pmp_err_q) begin
data_valid_o = 1'b1;
+ data_or_pmp_err = data_err_i | pmp_err_q;
handle_misaligned_d = 1'b0;
ls_fsm_ns = IDLE;
end else begin
@@ -421,10 +419,12 @@
ls_fsm_cs <= IDLE;
addr_last_q <= '0;
handle_misaligned_q <= '0;
+ pmp_err_q <= '0;
end else begin
ls_fsm_cs <= ls_fsm_ns;
addr_last_q <= addr_last_d;
handle_misaligned_q <= handle_misaligned_d;
+ pmp_err_q <= data_pmp_err_i;
end
end
@@ -447,10 +447,9 @@
// output to ID stage: mtval + AGU for misaligned transactions
assign addr_last_o = addr_last_q;
- // to know what kind of error to signal, we need to know the type of the transaction to which
- // the outsanding rvalid belongs.
- assign load_err_o = data_err_i & data_rvalid_i & ~data_we_q;
- assign store_err_o = data_err_i & data_rvalid_i & data_we_q;
+ // Signal a load or store error depending on the transaction type outstanding
+ assign load_err_o = data_or_pmp_err & ~data_we_q;
+ assign store_err_o = data_or_pmp_err & data_we_q;
assign busy_o = (ls_fsm_cs == WAIT_RVALID) | (data_req_o == 1'b1);
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
index 34074b1..4be3bf2 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
@@ -1,20 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// //
-// //
-// Design Name: Fast Multiplier and Division //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: 16x16 kernel multiplier and Long Division //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
`define OP_L 15:0
`define OP_H 31:16
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv
index dddaa8d..1f58eab 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv
@@ -1,20 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// //
-// //
-// Design Name: Slow Multiplier and Division //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Baugh-Wooley multiplier and Long Division //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* Slow Multiplier and Division
*
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv
index cf92a97..8df2f46 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv
@@ -1,23 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2017 ETH Zurich and University of Bologna.
+// Copyright 2017 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Matthias Baer - baermatt@student.ethz.ch //
-// //
-// Additional contributions by: //
-// Sven Stucki - svstucki@student.ethz.ch //
-// //
-// //
-// Design Name: RISC-V processor core //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Defines for various constants used by the processor core. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* Package with constants used by Ibex
*/
@@ -190,6 +175,7 @@
// EXC_CAUSE_IRQ_FAST_14 = {1'b1, 5'd30},
EXC_CAUSE_IRQ_NM = {1'b1, 5'd31}, // == EXC_CAUSE_IRQ_FAST_15
EXC_CAUSE_INSN_ADDR_MISA = {1'b0, 5'd00},
+ EXC_CAUSE_INSTR_ACCESS_FAULT = {1'b0, 5'd01},
EXC_CAUSE_ILLEGAL_INSN = {1'b0, 5'd02},
EXC_CAUSE_BREAKPOINT = {1'b0, 5'd03},
EXC_CAUSE_LOAD_ACCESS_FAULT = {1'b0, 5'd05},
@@ -206,6 +192,36 @@
DBG_CAUSE_STEP = 3'h4
} dbg_cause_e;
+// PMP constants
+parameter int unsigned PMP_MAX_REGIONS = 16;
+parameter int unsigned PMP_CFG_W = 8;
+
+// PMP acces type
+parameter int unsigned PMP_I = 0;
+parameter int unsigned PMP_D = 1;
+
+typedef enum logic [1:0] {
+ PMP_ACC_EXEC = 2'b00,
+ PMP_ACC_WRITE = 2'b01,
+ PMP_ACC_READ = 2'b10
+} pmp_req_e;
+
+// PMP cfg structures
+typedef enum logic [1:0] {
+ PMP_MODE_OFF = 2'b00,
+ PMP_MODE_TOR = 2'b01,
+ PMP_MODE_NA4 = 2'b10,
+ PMP_MODE_NAPOT = 2'b11
+} pmp_cfg_mode_e;
+
+typedef struct packed {
+ logic lock;
+ pmp_cfg_mode_e mode;
+ logic exec;
+ logic write;
+ logic read;
+} pmp_cfg_t;
+
// CSRs
typedef enum logic[11:0] {
// Machine information
@@ -224,6 +240,28 @@
CSR_MTVAL = 12'h343,
CSR_MIP = 12'h344,
+ // Physical memory protection
+ CSR_PMPCFG0 = 12'h3A0,
+ CSR_PMPCFG1 = 12'h3A1,
+ CSR_PMPCFG2 = 12'h3A2,
+ CSR_PMPCFG3 = 12'h3A3,
+ CSR_PMPADDR0 = 12'h3B0,
+ CSR_PMPADDR1 = 12'h3B1,
+ CSR_PMPADDR2 = 12'h3B2,
+ CSR_PMPADDR3 = 12'h3B3,
+ CSR_PMPADDR4 = 12'h3B4,
+ CSR_PMPADDR5 = 12'h3B5,
+ CSR_PMPADDR6 = 12'h3B6,
+ CSR_PMPADDR7 = 12'h3B7,
+ CSR_PMPADDR8 = 12'h3B8,
+ CSR_PMPADDR9 = 12'h3B9,
+ CSR_PMPADDR10 = 12'h3BA,
+ CSR_PMPADDR11 = 12'h3BB,
+ CSR_PMPADDR12 = 12'h3BC,
+ CSR_PMPADDR13 = 12'h3BD,
+ CSR_PMPADDR14 = 12'h3BE,
+ CSR_PMPADDR15 = 12'h3BF,
+
// Debug/trace
CSR_DCSR = 12'h7b0,
CSR_DPC = 12'h7b1,
@@ -240,6 +278,10 @@
CSR_MINSTRETH = 12'hB82
} csr_num_e;
+// CSR pmp-related offsets
+parameter logic [11:0] CSR_OFF_PMP_CFG = 12'h3A0; // pmp_cfg @ 12'h3a0 - 12'h3a3
+parameter logic [11:0] CSR_OFF_PMP_ADDR = 12'h3B0; // pmp_addr @ 12'h3b0 - 12'h3bf
+
// CSR mhpmcounter-related offsets and mask
parameter logic [11:0] CSR_OFF_MCOUNTER_SETUP = 12'h320; // mcounter_setup @ 12'h323 - 12'h33F
parameter logic [11:0] CSR_OFF_MCOUNTER = 12'hB00; // mcounter @ 12'hB03 - 12'hB1F
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_pmp.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_pmp.sv
new file mode 100644
index 0000000..e54edab
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_pmp.sv
@@ -0,0 +1,113 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+module ibex_pmp #(
+ // Granularity of NAPOT access,
+ // 0 = No restriction, 1 = 8 byte, 2 = 16 byte, 3 = 32 byte, etc.
+ parameter int unsigned PMPGranularity = 0,
+ // Number of access channels (e.g. i-side + d-side)
+ parameter int unsigned PMPNumChan = 2,
+ // Number of implemented regions
+ parameter int unsigned PMPNumRegions = 4
+) (
+ // Clock and Reset
+ input logic clk_i,
+ input logic rst_ni,
+
+ // Interface to CSRs
+ input ibex_pkg::pmp_cfg_t csr_pmp_cfg_i [PMPNumRegions],
+ input logic [33:0] csr_pmp_addr_i [PMPNumRegions],
+
+ input ibex_pkg::priv_lvl_e priv_mode_i, // Current priv mode, assumed to
+ // be the same for all channels
+ // Access checking channels
+ input logic [33:0] pmp_req_addr_i [PMPNumChan],
+ input ibex_pkg::pmp_req_e pmp_req_type_i [PMPNumChan],
+ output logic pmp_req_err_o [PMPNumChan]
+
+);
+
+ import ibex_pkg::*;
+
+ // Access Checking Signals
+ logic [33:0] region_start_addr [PMPNumRegions];
+ logic [33:PMPGranularity+2] region_addr_mask [PMPNumRegions];
+ logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_high;
+ logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_low;
+ logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_both;
+ logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_partial;
+ logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_perm_check;
+ logic [PMPNumChan-1:0][PMPNumRegions-1:0] machine_access_fault;
+ logic [PMPNumChan-1:0][PMPNumRegions-1:0] user_access_allowed;
+ logic [PMPNumChan-1:0] access_fault;
+
+
+ // ---------------
+ // Access checking
+ // ---------------
+
+ for (genvar r = 0; r < PMPNumRegions; r++) begin : g_addr_exp
+ // Start address for TOR matching
+ if (r == 0) begin : g_entry0
+ assign region_start_addr[r] = (csr_pmp_cfg_i[r].mode == PMP_MODE_TOR) ? 34'h000000000 :
+ csr_pmp_addr_i[r];
+ end else begin : g_oth
+ assign region_start_addr[r] = (csr_pmp_cfg_i[r].mode == PMP_MODE_TOR) ? csr_pmp_addr_i[r-1] :
+ csr_pmp_addr_i[r];
+ end
+ // Address mask for NA matching
+ for (genvar b = PMPGranularity+2; b < 34; b++) begin : g_bitmask
+ if (b == PMPGranularity+2) begin : g_bit0
+ // Always mask bit (G+2) for NAPOT
+ assign region_addr_mask[r][b] = (csr_pmp_cfg_i[r].mode != PMP_MODE_NAPOT);
+ end else begin : g_others
+ // We will mask this bit if it is within the programmed granule
+ // i.e. addr = yyyy 0111
+ // ^
+ // | This bit pos is the top of the mask, all lower bits set
+ // thus mask = 1111 0000
+ assign region_addr_mask[r][b] = (csr_pmp_cfg_i[r].mode != PMP_MODE_NAPOT) |
+ ~&csr_pmp_addr_i[r][b-1:PMPGranularity+2];
+ end
+ end
+ end
+
+ for (genvar c = 0; c < PMPNumChan; c++) begin : g_access_check
+ for (genvar r = 0; r < PMPNumRegions; r++) begin : g_regions
+ // TOR Region high/low matching is reused for all match types
+ assign region_match_low[c][r] = (pmp_req_addr_i[c][33:PMPGranularity+2] >=
+ // Comparators are sized according to granularity
+ (region_start_addr[r][33:PMPGranularity+2] &
+ region_addr_mask[r]));
+ assign region_match_high[c][r] = (pmp_req_addr_i[c][33:PMPGranularity+2] <=
+ (csr_pmp_addr_i[r][33:PMPGranularity+2] &
+ region_addr_mask[r]));
+ assign region_match_both[c][r] = region_match_low[c][r] & region_match_high[c][r] &
+ (csr_pmp_cfg_i[r].mode != PMP_MODE_OFF);
+ assign region_match_partial[c][r] = (region_match_low[c][r] ^ region_match_high[c][r]) &
+ (csr_pmp_cfg_i[r].mode != PMP_MODE_OFF);
+ // Check specific required permissions
+ assign region_perm_check[c][r] =
+ ((pmp_req_type_i[c] == PMP_ACC_EXEC) & csr_pmp_cfg_i[r].exec) |
+ ((pmp_req_type_i[c] == PMP_ACC_WRITE) & csr_pmp_cfg_i[r].write) |
+ ((pmp_req_type_i[c] == PMP_ACC_READ) & csr_pmp_cfg_i[r].read);
+ // In machine mode, any match to a locked region without sufficient permissions is a fault
+ assign machine_access_fault[c][r] = region_match_both[c][r] & csr_pmp_cfg_i[r].lock &
+ ~region_perm_check[c][r];
+ if (r == 0) begin : g_region0
+ // In any other mode, any access should fault unless is matches a region
+ assign user_access_allowed[c][r] = region_match_both[c][r] & region_perm_check[c][r];
+ end else begin : g_oth_regions
+ assign user_access_allowed[c][r] = region_match_both[c][r] & region_perm_check[c][r] &
+ // any higher priority (lower region number) partial match should also cause a fault
+ ~|region_match_partial[c][r-1:0];
+ end
+ end
+ assign access_fault[c] = (priv_mode_i == PRIV_LVL_M) ? |machine_access_fault[c] :
+ ~|user_access_allowed[c];
+
+ assign pmp_req_err_o[c] = access_fault[c];
+ end
+
+endmodule
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv
index bef2d17..cda0bb7 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv
@@ -1,19 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Andreas Traber - atraber@iis.ee.ethz.ch //
-// //
-// Design Name: Prefetcher Buffer for 32 bit memory interface //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Prefetch Buffer that caches instructions. This cuts overly //
-// long critical paths to the instruction cache //
-// //
-////////////////////////////////////////////////////////////////////////////////
/**
* Prefetcher Buffer for 32 bit memory interface
*
@@ -34,6 +23,7 @@
output logic valid_o,
output logic [31:0] rdata_o,
output logic [31:0] addr_o,
+ output logic err_o,
// goes to instruction memory / instruction cache
@@ -41,6 +31,8 @@
input logic instr_gnt_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
+ input logic instr_err_i,
+ input logic instr_pmp_err_i,
input logic instr_rvalid_i,
// Prefetch Buffer Status
@@ -56,6 +48,8 @@
logic [31:0] instr_addr_q, fetch_addr;
logic [31:0] instr_addr, instr_addr_w_aligned;
logic addr_valid;
+ logic pmp_err_q;
+ logic instr_or_pmp_err;
logic fifo_valid;
logic fifo_ready;
@@ -71,6 +65,10 @@
// Fetch fifo - consumes addresses and data //
//////////////////////////////////////////////
+ // Instruction fetch errors are valid on the data phase of a request
+ // PMP errors are generated in the address phase, and registered into a fake data phase
+ assign instr_or_pmp_err = instr_err_i | pmp_err_q;
+
ibex_fetch_fifo fifo_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@@ -79,6 +77,7 @@
.in_addr_i ( instr_addr_q ),
.in_rdata_i ( instr_rdata_i ),
+ .in_err_i ( instr_or_pmp_err ),
.in_valid_i ( fifo_valid ),
.in_ready_o ( fifo_ready ),
@@ -87,6 +86,7 @@
.out_ready_i ( ready_i ),
.out_rdata_o ( rdata_o ),
.out_addr_o ( addr_o ),
+ .out_err_o ( err_o ),
.out_valid_stored_o ( )
);
@@ -141,7 +141,10 @@
end
//~> granted request or not
- pf_fsm_ns = instr_gnt_i ? WAIT_RVALID : WAIT_GNT;
+ // If the instruction generated a PMP error, we may or may not
+ // get granted (the external valid is suppressed by the error)
+ // but we proceed to WAIT_RVALID to push the error to the fifo
+ pf_fsm_ns = (instr_gnt_i || pmp_err_q) ? WAIT_RVALID : WAIT_GNT;
end // case: WAIT_GNT
// we wait for rvalid, after that we are ready to serve a new request
@@ -155,7 +158,8 @@
if (req_i && (fifo_ready || branch_i)) begin
// prepare for next request
- if (instr_rvalid_i) begin
+ // Fake the rvalid for PMP errors to push the error to the fifo
+ if (instr_rvalid_i || pmp_err_q) begin
instr_req_o = 1'b1;
fifo_valid = 1'b1;
addr_valid = 1'b1;
@@ -173,7 +177,8 @@
end else begin
// just wait for rvalid and go back to IDLE, no new request
- if (instr_rvalid_i) begin
+ // Fake the rvalid for PMP errors to push the error to the fifo
+ if (instr_rvalid_i || pmp_err_q) begin
fifo_valid = 1'b1;
pf_fsm_ns = IDLE;
end
@@ -214,11 +219,13 @@
if (!rst_ni) begin
pf_fsm_cs <= IDLE;
instr_addr_q <= '0;
+ pmp_err_q <= '0;
end else begin
pf_fsm_cs <= pf_fsm_ns;
if (addr_valid) begin
instr_addr_q <= instr_addr;
+ pmp_err_q <= instr_pmp_err_i;
end
end
end
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_ff.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_ff.sv
index 07907ec..4dcfaeb 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_ff.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_ff.sv
@@ -1,25 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Francesco Conti - f.conti@unibo.it //
-// //
-// Additional contributions by: //
-// Markus Wegmann - markus.wegmann@technokrat.ch //
-// //
-// Design Name: RISC-V register file //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Register file with 31 or 15x 32 bit wide registers. //
-// Register 0 is fixed to 0. This register file is based on //
-// flip flops. Use this register file when targeting FPGA //
-// synthesis or Verilator simulation. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* RISC-V register file
*
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_latch.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_latch.sv
index 06d6aec..a5ec550 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_latch.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_latch.sv
@@ -1,28 +1,8 @@
// Copyright lowRISC contributors.
-// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Antonio Pullini - pullinia@iis.ee.ethz.ch //
-// //
-// Additional contributions by: //
-// Sven Stucki - svstucki@student.ethz.ch //
-// Markus Wegmann - markus.wegmann@technokrat.ch //
-// //
-// Design Name: RISC-V register file //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Register file with 31 or 15x 32 bit wide registers. //
-// Register 0 is fixed to 0. This register file is based on //
-// latches and is thus smaller than the flip-flop based RF. //
-// It requires a target technology-specific clock gating //
-// cell. Use this register file when targeting ASIC //
-// synthesis or event-based simulators. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
/**
* RISC-V register file
*
@@ -66,7 +46,7 @@
logic [NUM_WORDS-1:1] mem_clocks;
logic [DataWidth-1:0] wdata_a_q;
- // Write port W1
+ // internal addresses
logic [ADDR_WIDTH-1:0] raddr_a_int, raddr_b_int, waddr_a_int;
assign raddr_a_int = raddr_a_i[ADDR_WIDTH-1:0];
@@ -75,24 +55,25 @@
logic clk_int;
- //////////////////////////////////////
- // READ: Read address decoder (RAD) //
- //////////////////////////////////////
+ //////////
+ // READ //
+ //////////
assign rdata_a_o = mem[raddr_a_int];
assign rdata_b_o = mem[raddr_b_int];
- ///////////////////////////////
- // WRITE: SAMPLE INPUT DATA //
- ///////////////////////////////
-
+ ///////////
+ // WRITE //
+ ///////////
+ // Global clock gating
prim_clock_gating cg_we_global (
- .clk_i ( clk_i ),
- .en_i ( we_a_i ),
- .test_en_i ( test_en_i ),
- .clk_o ( clk_int )
+ .clk_i ( clk_i ),
+ .en_i ( we_a_i ),
+ .test_en_i ( test_en_i ),
+ .clk_o ( clk_int )
);
- // use clk_int here, since otherwise we don't want to write anything anyway
+ // Sample input data
+ // Use clk_int here, since otherwise we don't want to write anything anyway.
always_ff @(posedge clk_int or negedge rst_ni) begin : sample_wdata
if (!rst_ni) begin
wdata_a_q <= '0;
@@ -103,9 +84,7 @@
end
end
- ///////////////////////////////////////////////////////////////
- // WRITE: Write Address Decoder (WAD), combinatorial process //
- ///////////////////////////////////////////////////////////////
+ // Write address decoding
always_comb begin : wad
for (int i = 1; i < NUM_WORDS; i++) begin : wad_word_iter
if (we_a_i && (waddr_a_int == i)) begin
@@ -116,9 +95,7 @@
end
end
- //////////////////////////////////////////////////////////////////////////
- // WRITE: Clock gating (if integrated clock-gating cells are available) //
- //////////////////////////////////////////////////////////////////////////
+ // Individual clock gating (if integrated clock-gating cells are available)
for (genvar x = 1; x < NUM_WORDS; x++) begin : gen_cg_word_iter
prim_clock_gating cg_i (
.clk_i ( clk_int ),
@@ -128,19 +105,11 @@
);
end
- ////////////////////////////
- // WRITE: Write operation //
- ////////////////////////////
- // Generate M = WORDS sequential processes, each of which describes one
- // word of the memory. The processes are synchronized with the clocks
- // ClocksxC(i), i = 0, 1, ..., M-1
- // Use active low, i.e. transparent on low latches as storage elements
- // Data is sampled on rising clock edge
-
+ // Actual write operation:
+ // Generate the sequential process for the NUM_WORDS words of the memory.
+ // The process is synchronized with the clocks mem_clocks[k], k = 1, ..., NUM_WORDS-1.
always_latch begin : latch_wdata
- // Note: The assignment has to be done inside this process or Modelsim complains about it
mem[0] = '0;
-
for (int k = 1; k < NUM_WORDS; k++) begin : latch_wdata_word_iter
if (mem_clocks[k]) begin
mem[k] = wdata_a_q;
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_tracer.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_tracer.sv
index 7bc2b88..2048d46 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_tracer.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_tracer.sv
@@ -3,20 +3,6 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-////////////////////////////////////////////////////////////////////////////////
-// Engineer: Andreas Traber - atraber@iis.ee.ethz.ch //
-// //
-// Additional contributions by: //
-// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
-// //
-// Design Name: RISC-V Tracer //
-// Project Name: ibex //
-// Language: SystemVerilog //
-// //
-// Description: Traces the executed instructions //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
// Source/Destination register instruction index
`define REG_S1 19:15
`define REG_S2 24:20
@@ -37,8 +23,7 @@
input logic rst_ni,
input logic fetch_enable_i,
- input logic [3:0] core_id_i,
- input logic [5:0] cluster_id_i,
+ input logic [31:0] hart_id_i,
input logic valid_i,
input logic [31:0] pc_i,
@@ -304,7 +289,7 @@
initial begin
wait(rst_ni == 1'b1);
wait(fetch_enable_i == 1'b1);
- $sformat(fn, "trace_core_%h_%h.log", cluster_id_i, core_id_i);
+ $sformat(fn, "trace_core_%h.log", hart_id_i);
$display("[TRACER] Output filename is: %s", fn);
f = $fopen(fn, "w");
$fwrite(f, " Time Cycles PC Instr Mnemonic\n");
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv
index d0c1f25..88a159d 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv
@@ -1,5 +1,5 @@
// Copyright lowRISC contributors.
-// Copyright 2017 ETH Zurich and University of Bologna.
+// Copyright 2017 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
diff --git a/hw/vendor/lowrisc_ibex/src_files.yml b/hw/vendor/lowrisc_ibex/src_files.yml
index 4edd591..67513ea 100644
--- a/hw/vendor/lowrisc_ibex/src_files.yml
+++ b/hw/vendor/lowrisc_ibex/src_files.yml
@@ -17,6 +17,7 @@
rtl/ibex_multdiv_fast.sv,
rtl/ibex_prefetch_buffer.sv,
rtl/ibex_fetch_fifo.sv,
+ rtl/ibex_pmp.sv,
rtl/ibex_core.sv,
]
ibex_vip_rtl:
@@ -29,6 +30,7 @@
rtl/ibex_pkg.sv,
rtl/ibex_tracer_pkg.sv,
rtl/ibex_tracer.sv,
+ rtl/ibex_core_tracing.sv,
]
ibex_regfile_rtl:
targets: [
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv.lock.hjson b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv.lock.hjson
index fccdd5f..b4e5d34 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv.lock.hjson
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv.lock.hjson
@@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
- rev: a07e0a726edf0230314c08d31546eecbed23054b
+ rev: 102791dbb7eb992d3bc22336d2e4e5f0d688e761
}
}
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/.gitignore b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/.gitignore
index b770311..4075aac 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/.gitignore
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/.gitignore
@@ -2,3 +2,4 @@
*.bin
out_*/
work/
+*.pyc
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/README.md b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/README.md
index 44fd621..58d642f 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/README.md
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/README.md
@@ -3,7 +3,7 @@
RISCV-DV is a SV/UVM based open-source instruction generator for RISC-V
processor verification. It currently supports the following features:
-- Supported instruction set: RV32IMC, RV64IMC
+- Supported instruction set: RV32IMAC, RV64IMAC
- Supported privileged mode: machine mode, supervisor mode, user mode
- Page table randomization and exception
- Privileged CSR setup randomization
@@ -15,6 +15,10 @@
- Supports mixing directed instructions with random instruction stream
- Supports co-simulation with multiple ISS : spike, riscv-ovpsim
+A CSR test generation script written in Python is also provided, to generate a
+directed test suite that stresses all CSR instructions on all of the CSRs that
+the core implements.
+
## Getting Started
### Prerequisites
@@ -24,9 +28,26 @@
Synopsys VCS, Cadence Incisive/Xcelium, and Mentor Questa simulators. Please
make sure the EDA tool environment is properly setup before running the generator.
+To be able to run the CSR generation script, the open-source `bitstring`
+Python library is required ([bitstring](https://github.com/scott-griffiths/bitstring)).
+To install this library, either clone the repository and run the `setup.py`
+setup script, or run only one of the below commands:
+```
+1) sudo apt-get install python3-bitstring (or your OS-specific package manager)
+2) pip install bitstring
+```
+
### Running the generator
-A simple script "run" is provided for you to run a single test or a regression.
+
+A simple script "run.py" is provided for you to run a single test or a regression.
+
+You can use --help to get the complete command reference:
+
+```
+python3 run.py --help
+```
+
Here is the command to run a single test:
```
@@ -35,9 +56,9 @@
You can specify the simulator by "-simulator" option
```
-python3 run.py --test=riscv_arithmetic_basic_test --simulator=irun
-python3 run.py --test=riscv_arithmetic_basic_test --simulator=vcs
-python3 run.py --test=riscv_arithmetic_basic_test --simulator=questa
+python3 run.py --test riscv_arithmetic_basic_test --simulator ius
+python3 run.py --test riscv_arithmetic_basic_test --simulator vcs
+python3 run.py --test riscv_arithmetic_basic_test --simulator questa
```
The complete test list can be found in [yaml/testlist.yaml](https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml). To run a full
regression, simply use below command
@@ -55,20 +76,45 @@
Here's a few more examples of the run command:
```
-// Get the complete command reference info
-python3 run.py --help
-
// Run a single test 10 times
-python3 run.py --test=riscv_page_table_exception_test --iterations=10
+python3 run.py --test riscv_page_table_exception_test --iterations 10
+
+// Run a test with verbose logging
+python3 run.py --test riscv_page_table_exception_test --verbose
// Run a test with a specified seed
-python3 run.py --test=riscv_page_table_exception_test --seed=123
+python3 run.py --test riscv_page_table_exception_test --seed 123
// Skip the generation, run ISS simulation with previously generated program
-python3 run.py --test=riscv_page_table_exception_test --steps=iss_sim
+python3 run.py --test riscv_page_table_exception_test --steps iss_sim
+
+// Run the generator only, do not compile and simluation with ISS
+python3 run.py --test riscv_page_table_exception_test --steps gen
+
+// Compile the generator only, do not simulate
+python3 run.py --test riscv_page_table_exception_test --co
+
....
```
+### Privileged CSR Test Generation
+
+
+The CSR generation script is located at
+[scripts/gen_csr_test.py](https://github.com/google/riscv-dv/blob/master/scripts/gen_csr_test.py).
+The CSR test code that this script generates will execute every CSR instruction
+on every processor implemented CSR, writing values to the CSR and then using a
+prediction function to calculate a reference value that will be written into
+another GPR. The reference value will then be compared to the value actually
+stored in the CSR to determine whether to jump to the failure condition or
+continue executing, allowing it to be completely self checking. This script has
+been integrated with run.py. If you want to run it separately, you can get the
+command reference with --help:
+
+```
+python3 scripts/gen_csr_test.py --help
+```
+
## Configuration
### Setup regression test list
@@ -76,15 +122,17 @@
[Test list in YAML format](https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml)
```
-# test : Assembly test name
-# description : Description of this test
-# gen_opts : Instruction generator options
-# iterations : Number of iterations of this test
-# gen_test : Test name used by the instruction generator
-# rtl_test : RTL simulation test name
-# cmp_opts : Compile options passed to the instruction generator
-# sim_opts : Simulation options passed to the instruction generator
-# compare_opts : Options for the RTL & ISS trace comparison
+# test : Assembly test name
+# description : Description of this test
+# gen_opts : Instruction generator options
+# iterations : Number of iterations of this test
+# no_iss : Enable/disable ISS simulation (Optional)
+# gen_test : Test name used by the instruction generator
+# rtl_test : RTL simulation test name
+# cmp_opts : Compile options passed to the instruction generator
+# sim_opts : Simulation options passed to the instruction generator
+# no_post_compare : Enable/disable log comparison (Optional)
+# compare_opts : Options for the RTL & ISS trace comparison
- test: riscv_arithmetic_basic_test
description: >
@@ -102,6 +150,11 @@
```
+Note: To automatically generate CSR tests without having to explicitly run the
+script, include `riscv_csr_test` in the testlist as shown in the example YAML
+file above.
+
+
### Configure the generator to match your processor features
The default configuration of the instruction generator is for RV64IMC RISC-V
@@ -133,23 +186,76 @@
### Runtime options of the generator
-| Option | Description | default |
-|----------|:-------------:|:------:|
-| num_of_tests | Number of assembly tests to be generated | 1 |
-| num_of_sub_program | Number of sub-program in one test | 5 |
-| instr_cnt | Instruction count per test | 200 |
-| enable_page_table_exception | Enable page table exception | 0 |
-| no_ebreak | Disable ebreak instruction | 1 |
-| no_wfi | Disable WFI instruction | 1 |
-| no_branch_jump | Disable branch/jump instruction | 0 |
-| no_load_store | Disable load/store instruction | 0 |
-| no_csr_instr | Disable CSR instruction | 0 |
-| no_fence | Disable fence instruction | 0 |
-| enable_illegal_instruction | Enable illegal instructions | 0 |
-| enable_hint_instruction | Enable HINT instruction | 0 |
-| boot_mode | m:Machine mode, s:Supervisor mode, u:User mode | m |
-| no_directed_instr | Disable directed instruction stream | 0 |
-| enable_interrupt | Enable MStatus.MIE, used in interrupt test | 0 |
+| Option | Description | Default |
+|:---------------------------:|:-------------------------------------------------:|:-------:|
+| num_of_tests | Number of assembly tests to be generated | 1 |
+| num_of_sub_program | Number of sub-program in one test | 5 |
+| instr_cnt | Instruction count per test | 200 |
+| enable_page_table_exception | Enable page table exception | 0 |
+| no_ebreak | Disable ebreak instruction | 1 |
+| no_wfi | Disable WFI instruction | 1 |
+| no_branch_jump | Disable branch/jump instruction | 0 |
+| no_load_store | Disable load/store instruction | 0 |
+| no_csr_instr | Disable CSR instruction | 0 |
+| no_fence | Disable fence instruction | 0 |
+| enable_illegal_instruction | Enable illegal instructions | 0 |
+| enable_hint_instruction | Enable HINT instruction | 0 |
+| boot_mode | m:Machine mode, s:Supervisor mode, u:User mode | m |
+| no_directed_instr | Disable directed instruction stream | 0 |
+| require_signature_addr | Set to 1 if test needs to talk to testbench | 0 |
+| signature_addr | Write to this addr to send data to testbench | 0 |
+| enable_interrupt | Enable MStatus.MIE, used in interrupt test | 0 |
+| gen_debug_section | Disables randomized debug_rom section | 0 |
+| num_debug_sub_program | Number of debug sub-programs in test | 0 |
+
+
+### Setup Privileged CSR description
+
+This YAML description file of all CSRs is only required for the privileged CSR
+test. All other standard tests do not use this description.
+
+[CSR descriptions in YAML
+format](https://github.com/google/riscv-dv/blob/master/yaml/csr_template.yaml)
+
+```
+- csr: CSR_NAME
+ description: >
+ BRIEF_DESCRIPTION
+ address: 0x###
+ privilege_mode: MODE (D/M/S/H/U)
+ rv32:
+ - MSB_FIELD_NAME:
+ - description: >
+ BRIEF_DESCRIPTION
+ - type: TYPE (WPRI/WLRL/WARL/R)
+ - reset_val: RESET_VAL
+ - msb: MSB_POS
+ - lsb: LSB_POS
+ - ...
+ - ...
+ - LSB_FIELD_NAME:
+ - description: ...
+ - type: ...
+ - ...
+ rv64:
+ - MSB_FIELD_NAME:
+ - description: >
+ BRIEF_DESCRIPTION
+ - type: TYPE (WPRI/WLRL/WARL/R)
+ - reset_val: RESET_VAL
+ - msb: MSB_POS
+ - lsb: LSB_POS
+ - ...
+ - ...
+ - LSB_FIELD_NAME:
+ - description: ...
+ - type: ...
+ - ...
+```
+
+To specify what ISA width should be generated in the test, simply include the
+matching rv32/rv64/rv128 entry and fill in the appropriate CSR field entries.
+
### Adding new instruction stream and test
@@ -163,28 +269,39 @@
+directed_instr_5=riscv_multi_page_load_store_instr_stream,4
```
-## Run ISS(Instruction Set Simulator) simulation
+## Compile generated programs with GCC
-The default ISS is spike. Thanks for the great support from Imperas Software Ltd.,
-we have added the support for [riscv-ovpsim](https://github.com/riscv/riscv-ovpsim).
+- Install [riscv-gcc](https://github.com/riscv/riscv-gcc) toolchain
+- Set environment variable RISCV_GCC to the directory of the RISC-V gcc
+ executable. (example: <install_dir>/bin/riscv32-unknown-elf-gcc)
-- spike setup
+## Run ISS (Instruction Set Simulator) simulation
+
+Currently three ISS are supported, the default ISS is spike. You can install any
+one of below to run ISS simulation.
+
+- [spike](https://github.com/riscv/riscv-isa-sim#) setup
- Follow the [steps](https://github.com/riscv/riscv-isa-sim#build-steps) to build spike
- Make sure RISCV_ENABLE_COMMITLOG is defined in [config.h.in](https://github.com/riscv/riscv-isa-sim/blob/master/config.h.in)
- Set environment variable SPIKE_PATH to the directory of the spike binary
- [riscv-ovpsim](https://github.com/riscv/riscv-ovpsim) setup
- Download the riscv-ovpsim binary
- Set environment variable OVPSIM_PATH to the directory of the ovpsim binary
-
+- [sail-riscv](https://github.com/rems-project/sail-riscv) setup
+ - Follow the [steps](https://github.com/rems-project/sail-riscv/blob/master/README.md) to install sail-riscv
+ - Set environment variable SAIL_RISCV to the sail-riscv binary
You can use -iss to run with different ISS.
```
// Run ISS with spike
-python3 run.py --test=riscv_page_table_exception_test --iss=spike
+python3 run.py --test riscv_page_table_exception_test --iss spike
// Run ISS with riscv-ovpsim
-python3 run.py --test=riscv_rand_instr_test --iss=ovpsim
+python3 run.py --test riscv_rand_instr_test --iss ovpsim
+
+// Run ISS with sail-riscv
+python3 run.py --test riscv_rand_instr_test --iss sail
```
To run with ISS simulation for RV32IMC, you can specify ISA and ABI from command
@@ -192,7 +309,7 @@
```
// Run a full regression with RV32IMC
-python3 run.py --isa=rv32imc --mabi=ilp32
+python3 run.py --isa rv32imc --mabi ilp32
```
We have added a flow to run ISS simulation with both spike and riscv-ovpsim,
@@ -202,6 +319,7 @@
```
python3 run.py --test=riscv_rand_instr_test --iss=spike,ovpsim
+python3 run.py --test=riscv_rand_instr_test --iss=spike,sail
```
### Integrate a new ISS
@@ -218,13 +336,13 @@
Simulate with the new ISS
```
-python3 run.py --test=riscv_page_table_exception_test --iss=new_iss_name
+python3 run.py --test riscv_page_table_exception_test --iss new_iss_name
```
## End-to-end RTL and ISS co-simulation flow
We have collaborated with LowRISC to apply this flow for [IBEX RISC-V core
-verification](https://github.com/lowRISC/ibex/tree/master/dv/uvm). You can use
+verification](https://github.com/lowRISC/ibex/blob/master/doc/verification.rst). You can use
it as a reference to setup end-to-end co-simulation flow. It's also a good
reference for [customizing the generator](https://github.com/lowRISC/ibex/tree/master/dv/uvm/riscv_dv_extension) without getting impacted by upstream
changes.
@@ -252,73 +370,6 @@
- Coverage model.
- Debug mode support
-### DEPRECATED simulation flow
-
-Note: The flow mentioned below will soon be deprecated. Please switch to new
-flow.
-
-A simple script "run" is provided for you to run a single test or a regression.
-Here is the command to run a single test:
-
-```
-./run -test riscv_instr_base_test
-```
-You can specify the simulator by "-tool" option
-
-```
-./run -test riscv_instr_base_test -tool irun
-./run -test riscv_instr_base_test -tool vcs
-./run -test riscv_instr_base_test -tool questa
-```
-The complete test list can be found in testlist. To run a full regression, you
-can just specify the test name to "all".
-
-```
-./run -test all
-```
-The script will run each test in the test list sequentially with the iteration
-count specified in the "testlist". All the generated RISC-V assembly will be
-listed when the regression is done. If it is successful, you should see the
-following output:
-
-```
-===========================================================
- Generated RISC-V assembly tests
- ----------------------------------------------------------
-./out_2018-11-20/asm_tests/riscv_arithmetic_basic_test.0.S
-./out_2018-11-20/asm_tests/riscv_machine_mode_rand_test.0.S
-./out_2018-11-20/asm_tests/riscv_mmu_stress_test.0.S
-./out_2018-11-20/asm_tests/riscv_mmu_stress_test.1.S
-./out_2018-11-20/asm_tests/riscv_no_fence_test.0.S
-./out_2018-11-20/asm_tests/riscv_page_table_exception_test.0.S
-./out_2018-11-20/asm_tests/riscv_page_table_exception_test.1.S
-./out_2018-11-20/asm_tests/riscv_privileged_mode_rand_test.0.S
-./out_2018-11-20/asm_tests/riscv_privileged_mode_rand_test.1.S
-./out_2018-11-20/asm_tests/riscv_rand_instr_test.0.S
-./out_2018-11-20/asm_tests/riscv_rand_instr_test.1.S
-./out_2018-11-20/asm_tests/riscv_rand_jump_test.0.S
-./out_2018-11-20/asm_tests/riscv_sfence_exception_test.0.S
-```
-
-Here's a few more examples of the run command:
-
-```
-// Run a single test 10 times
-./run -test riscv_page_table_exception_test -n 10
-
-// Run a test with a specified seed
-./run -test riscv_page_table_exception_test -seed 123
-
-// Run a test with addtional runtime options, separated with comma
-./run -test riscv_rand_instr_test -runo +instr_cnt=10000,+no_fence=1
-
-// Two steps compile and simulation (Avoid multiple compilation)
-./run -co # compile only
-# Generate multiple tests
-./run -so -test riscv_rand_instr_test -n 10
-./run -so -test riscv_mmu_stress_test -n 20
-....
-```
## Disclaimer
This is not an officially supported Google product.
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/files.f b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/files.f
index bfd9b7a..8722407 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/files.f
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/files.f
@@ -17,6 +17,7 @@
+incdir+./test
// SOURCES
+./src/riscv_signature_pkg.sv
./src/riscv_instr_pkg.sv
./test/riscv_instr_test_pkg.sv
./test/riscv_instr_gen_tb_top.sv
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/iss_cmp b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/iss_cmp
deleted file mode 100755
index 18f915e..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/iss_cmp
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-# Copyright 2018 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-spike_log="$1"
-ovpsim_log="$2"
-report_file="$3"
-
-# -----------------------------------------------------------------------------
-# Convert spike log to standard instruction trace csv
-# -----------------------------------------------------------------------------
-# Convert the spike log to riscv_instr_trace.proto format
-spike_csv=$(echo "$spike_log" | sed 's/\.log/.csv/g')
-python scripts/spike_log_to_trace_csv.py --log $spike_log \
- --csv $spike_csv --xlen 64
-
-# -----------------------------------------------------------------------------
-# Convert ovpsim log to standard instruction trace csv
-# -----------------------------------------------------------------------------
-# Convert the spike log to riscv_instr_trace.proto format
-ovpsim_csv=$(echo "$ovpsim_log" | sed 's/\.log/.csv/g')
-python scripts/ovpsim_log_to_trace_csv.py --log $ovpsim_log --csv $ovpsim_csv
-
-# -----------------------------------------------------------------------------
-# Compare the trace log
-# -----------------------------------------------------------------------------
-python scripts/instr_trace_compare.py $spike_csv $ovpsim_csv \
- spike ovpsim >> $report_file
-echo >> $report_file
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/iss_sim b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/iss_sim
deleted file mode 100755
index 22baa05..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/iss_sim
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/bin/bash
-# Copyright 2018 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Environment variable for the path of RISC-V GCC toolchain
-# You can install the toolchain from https://github.com/riscv/riscv-gcc
-# RISCV_TOOLCHAIN="XXX"
-
-# GCC compile options
-ABI="lp64"
-ISA="rv64imc"
-
-DATE=`date +%Y-%m-%d`
-
-# Instruction set simulator
-ISS="spike" # other options: ovpsim, all
-
-# riscv-ovpsim options
-OVPSIM_VARIANT="RV64GC"
-
-# Binary of RISC-V ovpsim ISS
-# https://github.com/riscv/riscv-ovpsim
-RISCV_OVPSIM="${OVPSIM_PATH}/riscvOVPsim.exe"
-
-# Directory of assemble tests
-SRC_DIR="./out_${DATE}/asm_tests"
-
-# Assembly test file name
-TEST=""
-
-# Regression report file name
-REPORT="$SRC_DIR/regression_report.log"
-
-# Clean the result of the previous runs
-CLEAN=1
-
-if [[ -z $RISCV_TOOLCHAIN ]]; then
- echo "ERROR: Please define RISCV_TOOLCHAIN environment variable first"
- exit 1
-fi
-
-# Process command line options
-while [[ $# -gt 0 ]]
-do
-key="$1"
- case $key in
- -iss)
- ISS="$2"
- shift
- ;;
- -dir)
- SRC_DIR="$2"
- shift
- ;;
- -toolchain)
- RISCV_TOOLCHAIN="$2"
- shift
- ;;
- -isa)
- ISA="$2"
- shift
- ;;
- -abi)
- ABI="$2"
- shift
- ;;
- -test)
- TEST="$2"
- shift
- ;;
- -report)
- REPORT="$2"
- shift
- ;;
- -noclean)
- CLEAN=0
- shift
- ;;
- *)
- echo "unknown option $1"
- return
- ;;
-esac
-shift
-done
-
-RISCV_GCC="$RISCV_TOOLCHAIN/bin/riscv64-unknown-elf-gcc"
-RISCV_OBJCOPY="$RISCV_TOOLCHAIN/bin/riscv64-unknown-elf-objcopy"
-RISCV_SPIKE="$RISCV_TOOLCHAIN/bin/spike"
-
-mkdir -p "$SRC_DIR"
-
-# If the test is specified through "-test" option, run a single test rather
-# than all tests under SRC_DIR.
-if [[ $TEST == "" ]]; then
- find "$SRC_DIR" -name "*.S" > "$SRC_DIR/asm_test_list"
-else
- echo "$TEST" > "$SRC_DIR/asm_test_list"
-fi
-
-if [[ $ISA =~ 32 ]]; then
- OVPSIM_VARIANT="RV32GC"
-fi
-
-# Clean up previous running result
-if [[ $CLEAN == 1 ]]; then
- rm -rf "$REPORT"
- if [[ "$ISS" == "spike" ]] || [[ "$ISS" == "all" ]]; then
- rm -rf "$SRC_DIR/spike_sim"
- fi
- if [[ "$ISS" == "ovpsim" ]] || [[ "$ISS" == "all" ]]; then
- rm -rf "$SRC_DIR/riscv_ovpsim"
- fi
-fi
-
-# GCC compile
-while read asm_test; do
- # Generate binary for RTL simulation
- SRC="$asm_test"
- OBJFILE="$asm_test.o"
- BINFILE="$asm_test.bin"
- GCC_CMD="$RISCV_GCC -march=$ISA -mabi=$ABI -static -mcmodel=medany \
- -fvisibility=hidden -nostdlib \
- -nostartfiles -I$RISCV_TESTS/env/p \
- -Tscripts/link.ld $SRC -o $OBJFILE"
- echo "riscv_gcc compiling : $SRC"
- $($GCC_CMD)
- echo "Convert $OBJFILE to $BINFILE"
- # Convert the ELF to plain binary
- # You can load this binary to your RTL simulation
- "$RISCV_OBJCOPY" -O binary "$OBJFILE" "$BINFILE"
-done <"$SRC_DIR/asm_test_list"
-
-if [[ "$ISS" == "ovpsim" ]] || [[ "$ISS" == "all" ]]; then
- mkdir -p "$SRC_DIR/riscv_ovpsim"
-fi
-if [[ "$ISS" == "spike" ]] || [[ "$ISS" == "all" ]]; then
- mkdir -p "$SRC_DIR/spike_sim"
-fi
-
-# Run ISS simulation
-while read asm_test; do
- ELF="${asm_test}.o"
- TEST_NAME=$(echo "$ELF" | sed 's/^.*\///g')
- # Spike sim
- if [[ "$ISS" == "spike" ]] || [[ "$ISS" == "all" ]]; then
- echo "Running spike: $TEST_NAME"
- SPIKE_LOG="$SRC_DIR/spike_sim/$TEST_NAME.log"
- SPIKE_CMD="timeout 60s $RISCV_SPIKE --isa=$ISA -l $ELF &> $SPIKE_LOG"
- $($SPIKE_CMD &> $SPIKE_LOG)
- fi
- # riscv_ovpsim sim
- if [[ "$ISS" == "ovpsim" ]] || [[ "$ISS" == "all" ]]; then
- if [[ -z $OVPSIM_PATH ]]; then
- echo "ERROR: Please define OVPSIM_PATH environment variable first"
- exit 1
- fi
- OVPSIM_LOG="$SRC_DIR/riscv_ovpsim/$TEST_NAME.log"
- echo "Running ovpsim: $TEST_NAME"
- RISCV_OVPSIM_CMD="$RISCV_OVPSIM --variant $OVPSIM_VARIANT \
- --override riscvOVPsim/cpu/PMP_registers=0 \
- --override riscvOVPsim/cpu/simulateexceptions=T \
- --trace --tracechange --traceshowicount --program $ELF \
- --finishafter 500000"
- $($RISCV_OVPSIM_CMD &> $OVPSIM_LOG)
- fi
- if [[ "$ISS" == "all" ]]; then
- echo "Rerun command: ./iss_sim -test $asm_test -iss all" >> "$REPORT"
- echo "spike : $SPIKE_LOG" >> "$REPORT"
- echo "ovpsim : $OVPSIM_LOG" >> "$REPORT"
- ./iss_cmp "$SPIKE_LOG" "$OVPSIM_LOG" "$REPORT"
- tail -1 "$REPORT"
- echo "" >> "$REPORT"
- fi
-done <"$SRC_DIR/asm_test_list"
-
-if [[ "$ISS" == "all" ]]; then
- echo "Full regression report is saved to $REPORT"
- cat "$REPORT"
-fi
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run
deleted file mode 100755
index 23980f2..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run
+++ /dev/null
@@ -1,308 +0,0 @@
-#!/bin/bash
-# Copyright 2018 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-# This is simple run script to run a dedicated test or a regression
-#
-# Usage:
-# Run a single test with irun
-# ./run -tool irun -test riscv_instr_base_test
-#
-# Run regression with vcs
-# ./run -test all
-#
-# Change output directory
-# ./run -out my_output_dir
-
-DATE=`date +%Y-%m-%d`
-
-# RTL simulator, supports vcs, irun, and questa
-SIMULATOR="vcs"
-
-# random seed
-SEED=`date +%s`
-
-# Test name, "all" means run all tests in the testlist
-TEST="riscv_instr_base_test"
-
-# Number of assembly programs to be generated for this test
-# This option only apply to single test mode. For the regression mode, the number is specified in
-# the testlist
-NUM_TESTS=1
-
-# Simulation output directory
-OUT="./out_${DATE}"
-
-# Simulation only
-SIM_ONLY=0
-
-# Compile only
-CMP_ONLY=0
-
-# Compile/run time options
-SIM_OPTS=""
-CMP_OPTS=""
-
-# Verbose logging, by default disable detail logging
-VERBOSE=0
-
-# Submit to LSF
-LSF_CMD="bsub"
-LSF_OPTS=""
-LSF=0
-LSF_TIMEOUT=100
-
-# Testlist for regression
-TEST_LIST=testlist
-
-# Process command line options
-while [[ $# -gt 0 ]]
-do
-key="$1"
-case $key in
- -tool)
- SIMULATOR="$2"
- shift
- ;;
- -test)
- TEST="$2"
- shift
- ;;
- -n)
- NUM_TESTS="$2"
- shift
- ;;
- -seed)
- SEED="$2"
- shift
- ;;
- -sim_opts)
- SIM_OPTS="$2"
- shift
- ;;
- -cmp_opts)
- CMP_OPTS="$2"
- shift
- ;;
- -testlist)
- TEST_LIST="$2"
- shift
- ;;
- -timeout)
- LSF_TIMEOUT="$2"
- shift
- ;;
- -so)
- SIM_ONLY=1
- ;;
- -verbose)
- VERBOSE=1
- ;;
- -co)
- CMP_ONLY=1
- ;;
- -lsf)
- LSF=1
- ;;
- -lsf_opts)
- LSF_OPTS="$2"
- shift
- ;;
- -o)
- OUT="$2"
- shift
- ;;
- *)
- echo "unknown option $1"
- exit 1
- ;;
-esac
-shift
-done
-
-if [[ $LSF == 0 ]]; then
- LSF_CMD=""
-fi
-
-OUT=`realpath ${OUT}`
-
-# Generate compile and simulation commands
-if [[ "$SIMULATOR" == "vcs" ]]; then
-
- function run_compile {
- vcs -file ./vcs.compile.option.f \
- -f ./files.f -full64 \
- -l $OUT/compile.log \
- -Mdir=$OUT/vcs_simv.csrc \
- -o $OUT/vcs_simv ${CMP_OPTS}
- }
-
- SIM_CMD="$OUT/vcs_simv +vcs+lic+wait +UVM_TESTNAME="
- SIM_SEED="+ntb_random_seed="
-
-elif [[ "$SIMULATOR" == "irun" ]]; then
-
- function run_compile {
- irun -64bit \
- -access +rwc \
- -f ./files.f \
- -q -sv -uvm \
- -vlog_ext +.vh -I. \
- -uvmhome CDNS-1.2 \
- -elaborate \
- -l ${OUT}/compile.log ${CMP_OPTS}
- }
-
- SIM_CMD="irun -R +UVM_TESTNAME="
- SIM_SEED="-svseed "
-
-elif [[ "$SIMULATOR" == "questa" ]]; then
-#Questa requires mapping libraries to compile correctly
- function run_compile {
- vmap mtiUvm $QUESTA_HOME/questasim/uvm-1.2
- vlog -64 \
- -access=rwc \
- -f ./files.f \
- -sv \
- -mfcu -cuname design_cuname \
- +define+UVM_REGEX_NO_DPI \
- -writetoplevels ${OUT}/top.list \
- -l ${OUT}/compile.log ${CMP_OPTS}
- vopt -64 -debug \
- +designfile -f ${OUT}/top.list \
- -l ${OUT}/optimize.log ${CMP_OPTS} \
- -o design_opt
- }
-
- SIM_CMD="vsim -64 -c -do questa_sim.tcl design_opt +UVM_TESTNAME="
- SIM_SEED="-sv_seed "
-
-else
- echo "unsupported simulator $SIMULATOR"
- exit 1
-fi
-
-# Clean up previous runs
-if [[ $SIM_ONLY == 0 ]]; then
- rm -rf ${OUT}
-else
- rm -rf ${OUT}/asm_tests
-fi
-
-mkdir -p ${OUT}
-mkdir -p ${OUT}/asm_tests
-
-# Compilation
-if [[ $SIM_ONLY == 0 ]]; then
- echo "Building RISC-V instruction generator..."
- if [[ $VERBOSE == 1 ]]; then
- run_compile
- else
- run_compile > /dev/null
- fi
- echo "Building RISC-V instruction generator...done"
-fi
-
-# Skip simulation if compilation only flag is set
-if [[ $CMP_ONLY == 1 ]]; then
- exit 0
-fi
-
-# Run sim
-if [[ ${TEST} == "all" ]]; then
- echo "Running regression with testlist: $TEST_LIST"
- LOG_LIST="${OUT}/sim_log.list"
- PROGRAM_CNT=0
- cat "$TEST_LIST"
- rm -rf "$LOG_LIST"
- while read line; do
- if ! [[ $line =~ ^\/\/ ]]; then
- if [[ $line =~([a-z0-9_-]*)([[:space:]]*)\:([[:space:]]*)([0-9]*)([[:space:]]*)\:(.*$) ]]; then
- SEED=`date +%s`
- TEST=${BASH_REMATCH[1]}
- ITERATION=${BASH_REMATCH[4]}
- TEST_OPTS=${BASH_REMATCH[6]}
- if [[ ${ITERATION} != "0" ]]; then
- echo "Running ${TEST} to generate ${ITERATION} tests"
- CMD="${SIM_CMD}${TEST} +asm_file_name=${OUT}/asm_tests/${TEST} \
- ${SIM_SEED}${SEED} ${TEST_OPTS} ${SIM_OPTS} \
- -l ${OUT}/sim_${TEST}.log +num_of_tests=${ITERATION}"
- ((PROGRAM_CNT+=$ITERATION))
- echo "${OUT}/sim_${TEST}.log" >> ${LOG_LIST}
- if [[ $VERBOSE == 1 ]]; then
- ${LSF_CMD} ${LSF_OPTS} ${CMD}
- else
- ${LSF_CMD} ${LSF_OPTS} ${CMD} > /dev/null
- fi
- fi
- fi
- fi
- done < $TEST_LIST
- # Wait util all tests are generated
- if [[ $LSF == 1 ]]; then
- TIMEOUT_CNT=0
- TOTAL_CNT=`wc -l < ${LOG_LIST}`
- echo "Waiting for ${TOTAL_CNT} tests to complete, ${PROGRAM_CNT} programs to generate."
- while [[ 1 ]]; do
- COMPLETED_CNT=0
- while read log; do
- if [[ -f "$log" ]]; then
- if grep -q "TEST GENERATION DONE" $log; then
- ((COMPLETED_CNT+=1))
- else
- if [[ $VERBOSE == 1 ]]; then
- echo "$log is not completed"
- fi
- fi
- else
- if [[ $VERBOSE == 1 ]]; then
- echo "$log is not completed"
- fi
- fi
- done < ${LOG_LIST}
- GENERATED_CNT=`find ${OUT}/asm_tests/ -name "*.S" | wc -l`
- echo "[$TIMEOUT_CNT] Progress > Test:${COMPLETED_CNT}/${TOTAL_CNT} Program:${GENERATED_CNT}/${PROGRAM_CNT}"
- if [[ "$COMPLETED_CNT" == "$TOTAL_CNT" ]]; then
- break
- else
- if [[ "$TIMEOUT_CNT" == "$LSF_TIMEOUT" ]]; then
- echo "Generator timeout after $LSF_TIMEOUT * 10 seconds"
- break
- else
- sleep 10
- fi
- fi
- ((TIMEOUT_CNT+=1))
- done
- fi
-else
- echo "Running test ${TEST} to generate ${NUM_TESTS} tests"
- CMD="${SIM_CMD}${TEST} +asm_file_name=${OUT}/asm_tests/${TEST} \
- ${SIM_SEED}${SEED} \
- -l ${OUT}/sim_${TEST}.log \
- +num_of_tests=${NUM_TESTS} ${SIM_OPTS}"
- if [[ $VERBOSE == 1 ]]; then
- ${CMD}
- else
- ${CMD} > /dev/null
- fi
-fi
-
-
-# List all generated assembly tests
-echo "==========================================================="
-echo " Generated RISC-V assembly tests"
-echo " ----------------------------------------------------------"
-find $OUT/asm_tests -name "*.S" | sort -k11
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run.py
index fe32c7f..0da97d8 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run.py
@@ -21,12 +21,17 @@
import subprocess
import re
import sys
+import logging
+from datetime import date
from scripts.lib import *
from scripts.spike_log_to_trace_csv import *
from scripts.ovpsim_log_to_trace_csv import *
+from scripts.sail_log_to_trace_csv import *
from scripts.instr_trace_compare import *
+LOGGER = logging.getLogger()
+
def get_generator_cmd(simulator, simulator_yaml):
""" Setup the compile and simulation command for the generator
@@ -38,16 +43,16 @@
compile_cmd : RTL simulator command to compile the instruction generator
sim_cmd : RTL simulator command to run the instruction generator
"""
- print("Processing simulator setup file : %s" % simulator_yaml)
+ logging.info("Processing simulator setup file : %s" % simulator_yaml)
yaml_data = read_yaml(simulator_yaml)
# Search for matched simulator
for entry in yaml_data:
if entry['tool'] == simulator:
- print ("Found matching simulator: %s" % entry['tool'])
+ logging.info("Found matching simulator: %s" % entry['tool'])
compile_cmd = entry['compile_cmd']
sim_cmd = entry['sim_cmd']
return compile_cmd, sim_cmd
- print ("Cannot find RTL simulator %0s" % simulator)
+ logging.error("Cannot find RTL simulator %0s" % simulator)
sys.exit(1)
@@ -62,12 +67,12 @@
Returns:
cmd : ISS run command
"""
- print("Processing ISS setup file : %s" % iss_yaml)
+ logging.info("Processing ISS setup file : %s" % iss_yaml)
yaml_data = read_yaml(iss_yaml)
# Search for matched ISS
for entry in yaml_data:
if entry['iss'] == iss:
- print ("Found matching ISS: %s" % entry['iss'])
+ logging.info("Found matching ISS: %s" % entry['iss'])
cmd = entry['cmd'].rstrip()
cmd = re.sub("\<path_var\>", get_env_var(entry['path_var']), cmd)
if iss == "ovpsim":
@@ -75,7 +80,7 @@
else:
cmd = re.sub("\<variant\>", isa, cmd)
return cmd
- print ("Cannot find ISS %0s" % iss)
+ logging.error("Cannot find ISS %0s" % iss)
sys.exit(1)
@@ -95,68 +100,89 @@
return cmd
-def gen(test_list, simulator, simulator_yaml, output_dir, sim_only,
- compile_only, lsf_cmd, seed, cwd, cmp_opts, sim_opts, timeout_s, verbose):
+def gen(test_list, csr_file, end_signature_addr, isa, simulator,
+ simulator_yaml, output_dir, sim_only, compile_only, lsf_cmd, seed,
+ cwd, cmp_opts, sim_opts, timeout_s):
"""Run the instruction generator
Args:
- test_list : List of assembly programs to be compiled
- simulator : RTL simulator used to run instruction generator
- simulator_yaml : RTL simulator configuration file in YAML format
- output_dir : Output directory of the ELF files
- sim_only : Simulation only
- compile_only : Compile the generator only
- lsf_cmd : LSF command used to run the instruction generator
- seed : Seed to the instruction generator
- cmp_opts : Compile options for the generator
- sim_opts : Simulation options for the generator
- timeout_s : Timeout limit in seconds
- verbose : Verbose logging
+ test_list : List of assembly programs to be compiled
+ csr_file : YAML file containing description of all CSRs
+ end_signature_addr : Address that tests will write pass/fail signature to at end of test
+ isa : Processor supported ISA subset
+ simulator : RTL simulator used to run instruction generator
+ simulator_yaml : RTL simulator configuration file in YAML format
+ output_dir : Output directory of the ELF files
+ sim_only : Simulation only
+ compile_only : Compile the generator only
+ lsf_cmd : LSF command used to run the instruction generator
+ seed : Seed to the instruction generator
+ cmp_opts : Compile options for the generator
+ sim_opts : Simulation options for the generator
+ timeout_s : Timeout limit in seconds
"""
+ # Mutually exclusive options between compile_only and sim_only
+ if compile_only and sim_only:
+ logging.error("argument -co is not allowed with argument -so")
# Setup the compile and simulation command for the generator
compile_cmd = []
sim_cmd = ""
compile_cmd, sim_cmd = get_generator_cmd(simulator, simulator_yaml);
+ if len(test_list) == 0:
+ return
# Compile the instruction generator
if not sim_only:
- print ("Building RISC-V instruction generator")
- for cmd in compile_cmd:
- cmd = re.sub("<out>", os.path.abspath(output_dir), cmd)
- cmd = re.sub("<cwd>", cwd, cmd)
- cmd = re.sub("<cmp_opts>", cmp_opts, cmd)
- if verbose:
- print("Compile command: %s" % cmd)
- output = run_cmd(cmd)
- if verbose:
- print(output)
+ if (not((len(test_list) == 1) and (test_list[0]['test'] == 'riscv_csr_test'))):
+ logging.info("Building RISC-V instruction generator")
+ for cmd in compile_cmd:
+ cmd = re.sub("<out>", os.path.abspath(output_dir), cmd)
+ cmd = re.sub("<cwd>", cwd, cmd)
+ cmd = re.sub("<cmp_opts>", cmp_opts, cmd)
+ logging.debug("Compile command: %s" % cmd)
+ logging.debug(run_cmd(cmd))
# Run the instruction generator
if not compile_only:
cmd_list = []
sim_cmd = re.sub("<out>", os.path.abspath(output_dir), sim_cmd)
sim_cmd = re.sub("<cwd>", cwd, sim_cmd)
sim_cmd = re.sub("<sim_opts>", sim_opts, sim_cmd)
- print ("Running RISC-V instruction generator")
+ logging.info("Running RISC-V instruction generator")
for test in test_list:
- if test['iterations'] > 0:
- rand_seed = get_seed(seed)
- cmd = lsf_cmd + " " + sim_cmd.rstrip() + \
- (" +UVM_TESTNAME=%s " % test['gen_test']) + \
- (" +num_of_tests=%d " % test['iterations']) + \
- (" +asm_file_name=%s/asm_tests/%s " % (output_dir, test['test'])) + \
- (" -l %s/sim_%s.log " % (output_dir, test['test']))
- cmd = re.sub("<seed>", str(rand_seed), cmd)
- if "gen_opts" in test:
- cmd += test['gen_opts']
- print("Generating %d %s" % (test['iterations'], test['test']))
+ iterations = test['iterations']
+ if iterations > 0:
+ """
+ If we are running a CSR test, need to call a separate python script
+ to generate directed CSR test code, located at scripts/gen_csr_test.py.
+ """
+ if test['test'] == 'riscv_csr_test':
+ cmd = "python3 scripts/gen_csr_test.py" + \
+ (" --csr_file %s" % csr_file) + \
+ (" --xlen %s" % re.search(r"(?P<xlen>[0-9]+)", isa).group("xlen")) + \
+ (" --iterations %i" % iterations) + \
+ (" --out %s/asm_tests" % output_dir) + \
+ (" --end_signature_addr %s" % end_signature_addr)
+ else:
+ rand_seed = get_seed(seed)
+ cmd = lsf_cmd + " " + sim_cmd.rstrip() + \
+ (" +UVM_TESTNAME=%s " % test['gen_test']) + \
+ (" +num_of_tests=%i " % iterations) + \
+ (" +asm_file_name=%s/asm_tests/%s " % (output_dir, test['test'])) + \
+ (" -l %s/sim_%s.log " % (output_dir, test['test']))
+ cmd = re.sub("<seed>", str(rand_seed), cmd)
+ if "gen_opts" in test:
+ cmd += test['gen_opts']
+ if not re.search("c", isa):
+ cmd += "+disable_comparessed_instr=1";
+ logging.info("Generating %d %s" % (iterations, test['test']))
if lsf_cmd:
cmd_list.append(cmd)
else:
- run_cmd(cmd, verbose, timeout_s)
+ run_cmd(cmd, timeout_s)
if lsf_cmd:
- run_parallel_cmd(cmd_list, verbose, timeout_s)
+ run_parallel_cmd(cmd_list, timeout_s)
-def gcc_compile(test_list, output_dir, isa, mabi, verbose):
+def gcc_compile(test_list, output_dir, isa, mabi, opts):
"""Use riscv gcc toolchain to compile the assembly program
Args:
@@ -164,7 +190,6 @@
output_dir : Output directory of the ELF files
isa : ISA variant passed to GCC
mabi : MABI variant passed to GCC
- verbose : Verbose logging
"""
for test in test_list:
for i in range(0, test['iterations']):
@@ -173,26 +198,31 @@
elf = prefix + ".o"
binary = prefix + ".bin"
# gcc comilation
- cmd = ("%s -march=%s -mabi=%s -static -mcmodel=medany \
+ cmd = ("%s -static -mcmodel=medany \
-fvisibility=hidden -nostdlib \
- -nostartfiles \
- -Tscripts/link.ld %s -o %s" % \
- (get_env_var("RISCV_GCC") ,isa, mabi, asm, elf))
- print("Compiling %s" % asm)
- if verbose:
- print(cmd)
+ -nostartfiles %s \
+ -Tscripts/link.ld %s -o %s " % \
+ (get_env_var("RISCV_GCC"), asm, opts, elf))
+ if 'gcc_opts' in test:
+ cmd += test['gcc_opts']
+ # If march/mabi is not defined in the test gcc_opts, use the default
+ # setting from the command line.
+ if not re.search('march', cmd):
+ cmd += (" -march=%s" % isa)
+ if not re.search('mabi', cmd):
+ cmd += (" -mabi=%s" % mabi)
+ logging.info("Compiling %s" % asm)
+ logging.debug(cmd)
output = subprocess.check_output(cmd.split())
- if verbose:
- print(output)
+ logging.debug(output)
# Convert the ELF to plain binary, used in RTL sim
- print ("Converting to %s" % binary)
+ logging.info("Converting to %s" % binary)
cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY"), elf, binary))
output = subprocess.check_output(cmd.split())
- if verbose:
- print(output)
+ logging.debug(output)
-def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s, verbose):
+def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s):
"""Run ISS simulation with the generated test program
Args:
@@ -202,26 +232,27 @@
iss_yaml : ISS configuration file in YAML format
isa : ISA variant passed to the ISS
timeout_s : Timeout limit in seconds
- verbose : Verbose logging
"""
for iss in iss_list.split(","):
log_dir = ("%s/%s_sim" % (output_dir, iss))
base_cmd = parse_iss_yaml(iss, iss_yaml, isa)
- print ("%s sim log dir: %s" % (iss, log_dir))
+ logging.info("%s sim log dir: %s" % (iss, log_dir))
subprocess.run(["mkdir", "-p", log_dir])
for test in test_list:
- for i in range(0, test['iterations']):
- prefix = ("%s/asm_tests/%s.%d" % (output_dir, test['test'], i))
- elf = prefix + ".o"
- log = ("%s/%s.%d.log" % (log_dir, test['test'], i))
- cmd = get_iss_cmd(base_cmd, elf, log)
- print ("Running ISS simulation: %s" % elf)
- run_cmd(cmd, 0, timeout_s)
- if verbose:
- print (cmd)
+ if 'no_iss' in test and test['no_iss'] == 1:
+ continue
+ else:
+ for i in range(0, test['iterations']):
+ prefix = ("%s/asm_tests/%s.%d" % (output_dir, test['test'], i))
+ elf = prefix + ".o"
+ log = ("%s/%s.%d.log" % (log_dir, test['test'], i))
+ cmd = get_iss_cmd(base_cmd, elf, log)
+ logging.info("Running ISS simulation: %s" % elf)
+ run_cmd(cmd, timeout_s)
+ logging.debug(cmd)
-def iss_cmp(test_list, iss, output_dir, isa, verbose):
+def iss_cmp(test_list, iss, output_dir, isa):
"""Compare ISS simulation reult
Args:
@@ -229,7 +260,6 @@
iss : List of instruction set simulators
output_dir : Output directory of the ELF files
isa : ISA
- verbose : Verbose logging
"""
iss_list = iss.split(",")
if len(iss_list) != 2:
@@ -239,8 +269,8 @@
for test in test_list:
for i in range(0, test['iterations']):
elf = ("%s/asm_tests/%s.%d.o" % (output_dir, test['test'], i))
- print("Comparing ISS sim result %s/%s : %s" %
- (iss_list[0], iss_list[1], elf))
+ logging.info("Comparing ISS sim result %s/%s : %s" %
+ (iss_list[0], iss_list[1], elf))
csv_list = []
run_cmd(("echo 'Test binary: %s' >> %s" % (elf, report)))
for iss in iss_list:
@@ -251,100 +281,153 @@
process_spike_sim_log(log, csv)
elif iss == "ovpsim":
process_ovpsim_sim_log(log, csv)
+ elif iss == "sail":
+ process_sail_sim_log(log, csv)
else:
- print("Unsupported ISS" % iss)
+ logging.error("Unsupported ISS" % iss)
sys.exit(1)
compare_trace_csv(csv_list[0], csv_list[1], iss_list[0], iss_list[1], report)
passed_cnt = run_cmd("grep PASSED %s | wc -l" % report).strip()
failed_cnt = run_cmd("grep FAILED %s | wc -l" % report).strip()
summary = ("%s PASSED, %s FAILED" % (passed_cnt, failed_cnt))
- print(summary)
+ logging.info(summary)
run_cmd(("echo %s >> %s" % (summary, report)))
- print("ISS regression report is saved to %s" % report)
+ logging.info("ISS regression report is saved to %s" % report)
-# Parse input arguments
-parser = argparse.ArgumentParser()
+def setup_parser():
+ """Create a command line parser.
-parser.add_argument("--o", type=str, default="./out",
- help="Output directory name")
-parser.add_argument("--testlist", type=str, default="",
- help="Regression testlist")
-parser.add_argument("--isa", type=str, default="rv64imc",
- help="RISC-V ISA subset")
-parser.add_argument("--mabi", type=str, default="lp64",
- help="mabi used for compilation, lp32 or lp64")
-parser.add_argument("--test", type=str, default="all",
- help="Test name, 'all' means all tests in the list")
-parser.add_argument("--seed", type=int, default=-1,
- help="Randomization seed, default -1 means random seed")
-parser.add_argument("--iterations", type=int, default=0,
- help="Override the iteration count in the test list")
-parser.add_argument("--simulator", type=str, default="vcs",
- help="Simulator used to run the generator, default VCS")
-parser.add_argument("--simulator_yaml", type=str, default="",
- help="RTL simulator setting YAML")
-parser.add_argument("--iss", type=str, default="spike",
- help="RISC-V instruction set simulator: spike, ovpsim")
-parser.add_argument("--iss_yaml", type=str, default="",
- help="ISS setting YAML")
-parser.add_argument("--verbose", type=int, default=0,
- help="Verbose logging")
-parser.add_argument("--co", type=int, default=0,
- help="Compile the generator only")
-parser.add_argument("--so", type=int, default=0,
- help="Simulate the generator only")
-parser.add_argument("--cmp_opts", type=str, default="",
- help="Compile options for the generator")
-parser.add_argument("--sim_opts", type=str, default="",
- help="Simulation options for the generator")
-parser.add_argument("--steps", type=str, default="all",
- help="Run steps: gen,gcc_compile,iss_sim,iss_cmp")
-parser.add_argument("--lsf_cmd", type=str, default="",
- help="LSF command. Run in local sequentially if lsf \
- command is not specified")
-parser.add_argument("--gen_timeout", type=int, default=360,
- help="Generator timeout limit in seconds")
-parser.add_argument("--iss_timeout", type=int, default=50,
- help="ISS sim timeout limit in seconds")
+ Returns: The created parser.
+ """
+ # Parse input arguments
+ parser = argparse.ArgumentParser()
-args = parser.parse_args()
-cwd = os.path.dirname(os.path.realpath(__file__))
+ parser.add_argument("-o", "--output", type=str,
+ help="Output directory name", dest="o")
+ parser.add_argument("-tl", "--testlist", type=str, default="",
+ help="Regression testlist", dest="testlist")
+ parser.add_argument("-tn", "--test", type=str, default="all",
+ help="Test name, 'all' means all tests in the list", dest="test")
+ parser.add_argument("--seed", type=int, default=-1,
+ help="Randomization seed, default -1 means random seed")
+ parser.add_argument("-i", "--iterations", type=int, default=0,
+ help="Override the iteration count in the test list", dest="iterations")
+ parser.add_argument("-si", "--simulator", type=str, default="vcs",
+ help="Simulator used to run the generator, default VCS", dest="simulator")
+ parser.add_argument("--iss", type=str, default="spike",
+ help="RISC-V instruction set simulator: spike,ovpsim,sail")
+ parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
+ help="Verbose logging")
+ parser.add_argument("--co", dest="co", action="store_true",
+ help="Compile the generator only")
+ parser.add_argument("--so", dest="so", action="store_true",
+ help="Simulate the generator only")
+ parser.add_argument("--cmp_opts", type=str, default="",
+ help="Compile options for the generator")
+ parser.add_argument("--sim_opts", type=str, default="",
+ help="Simulation options for the generator")
+ parser.add_argument("--gcc_opts", type=str, default="",
+ help="GCC compile options")
+ parser.add_argument("-s", "--steps", type=str, default="all",
+ help="Run steps: gen,gcc_compile,iss_sim,iss_cmp", dest="steps")
+ parser.add_argument("--lsf_cmd", type=str, default="",
+ help="LSF command. Run in local sequentially if lsf \
+ command is not specified")
+ parser.add_argument("--isa", type=str, default="rv64gc",
+ help="RISC-V ISA subset")
+ parser.add_argument("-m", "--mabi", type=str, default="lp64",
+ help="mabi used for compilation, lp32 or lp64", dest="mabi")
+ parser.add_argument("--gen_timeout", type=int, default=360,
+ help="Generator timeout limit in seconds")
+ parser.add_argument("--end_signature_addr", type=str, default="0",
+ help="Address that privileged CSR test writes to at EOT")
+ parser.add_argument("--iss_timeout", type=int, default=50,
+ help="ISS sim timeout limit in seconds")
+ parser.add_argument("--iss_yaml", type=str, default="",
+ help="ISS setting YAML")
+ parser.add_argument("--simulator_yaml", type=str, default="",
+ help="RTL simulator setting YAML")
+ parser.add_argument("--csr_yaml", type=str, default="",
+ help="CSR description file")
-if not args.iss_yaml:
- args.iss_yaml = cwd + "/yaml/iss.yaml"
+ parser.set_defaults(co=False)
+ parser.set_defaults(so=False)
+ parser.set_defaults(verbose=False)
-if not args.simulator_yaml:
- args.simulator_yaml = cwd + "/yaml/simulator.yaml"
+ return parser
-if not args.testlist:
- args.testlist = cwd + "/yaml/testlist.yaml"
-# Create output directory
-subprocess.run(["mkdir", "-p", args.o])
-subprocess.run(["mkdir", "-p", ("%s/asm_tests" % args.o)])
+def setup_logging(verbose):
+ """Setup the root logger.
-# Process regression test list
-matched_list = []
-process_regression_list(args.testlist, args.test, args.iterations, matched_list)
-if len(matched_list) == 0:
- sys.exit("Cannot find %s in %s" % (args.test, args.testlist))
+ Args:
+ verbose: Verbose logging
+ """
+ if verbose:
+ logging.basicConfig(format="%(asctime)s %(filename)s:%(lineno)-5s %(levelname)-8s %(message)s",
+ datefmt='%a, %d %b %Y %H:%M:%S',
+ level=logging.DEBUG)
+ else:
+ logging.basicConfig(format="%(asctime)s %(levelname)-8s %(message)s",
+ datefmt='%a, %d %b %Y %H:%M:%S',
+ level=logging.INFO)
-# Run instruction generator
-if args.steps == "all" or re.match("gen", args.steps):
- gen(matched_list, args.simulator, args.simulator_yaml, args.o,
- args.so, args.co, args.lsf_cmd, args.seed, cwd,
- args.cmp_opts, args.sim_opts, args.gen_timeout, args.verbose)
-# Compile the assembly program to ELF, convert to plain binary
-if args.steps == "all" or re.match("gcc_compile", args.steps):
- gcc_compile(matched_list, args.o, args.isa, args.mabi, args.verbose)
+def main():
+ """This is the main entry point."""
-# Run ISS simulation
-if args.steps == "all" or re.match("iss_sim", args.steps):
- iss_sim(matched_list, args.o, args.iss, args.iss_yaml,
- args.isa, args.iss_timeout, args.verbose)
+ parser = setup_parser()
+ args = parser.parse_args()
+ cwd = os.path.dirname(os.path.realpath(__file__))
+ setup_logging(args.verbose)
-# Compare ISS simulation result
-if args.steps == "all" or re.match("iss_cmp", args.steps):
- iss_cmp(matched_list, args.iss, args.o, args.isa, args.verbose)
+ if not args.csr_yaml:
+ args.csr_yaml = cwd + "/yaml/csr_template.yaml"
+
+ if not args.iss_yaml:
+ args.iss_yaml = cwd + "/yaml/iss.yaml"
+
+ if not args.simulator_yaml:
+ args.simulator_yaml = cwd + "/yaml/simulator.yaml"
+
+ if not args.testlist:
+ args.testlist = cwd + "/yaml/testlist.yaml"
+
+ # Create output directory
+ if args.o is None:
+ output_dir = "out_" + str(date.today())
+ else:
+ output_dir = args.o
+ subprocess.run(["mkdir", "-p", output_dir])
+ subprocess.run(["mkdir", "-p", ("%s/asm_tests" % output_dir)])
+
+ # Process regression test list
+ matched_list = []
+ process_regression_list(args.testlist, args.test, args.iterations, matched_list)
+ if len(matched_list) == 0:
+ sys.exit("Cannot find %s in %s" % (args.test, args.testlist))
+
+ # Run instruction generator
+ if args.steps == "all" or re.match("gen", args.steps):
+ gen(matched_list, args.csr_yaml, args.end_signature_addr, args.isa,
+ args.simulator, args.simulator_yaml, output_dir, args.so,
+ args.co, args.lsf_cmd, args.seed, cwd, args.cmp_opts,
+ args.sim_opts, args.gen_timeout)
+
+ if not args.co:
+ # Compile the assembly program to ELF, convert to plain binary
+ if args.steps == "all" or re.match("gcc_compile", args.steps):
+ gcc_compile(matched_list, output_dir, args.isa, args.mabi, args.gcc_opts)
+
+ # Run ISS simulation
+ if args.steps == "all" or re.match("iss_sim", args.steps):
+ iss_sim(matched_list, output_dir, args.iss, args.iss_yaml,
+ args.isa, args.iss_timeout)
+
+ # Compare ISS simulation result
+ if args.steps == "all" or re.match("iss_cmp", args.steps):
+ iss_cmp(matched_list, args.iss, output_dir, args.isa)
+
+if __name__ == "__main__":
+ main()
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/gen_csr_test.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/gen_csr_test.py
index b2915b9..a1604cf 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/gen_csr_test.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/gen_csr_test.py
@@ -31,8 +31,21 @@
import yaml
import argparse
import random
-from bitstring import BitArray as bitarray
+import copy
+try:
+ from bitstring import BitArray as bitarray
+except ImportError as e:
+ logging.error("Please install bitstring package: sudo apt-get install python3-bitstring")
+ sys.exit(1)
+
+"""
+Defines the test's success/failure values, one of which will be written to
+the chosen signature address to indicate the test's result.
+"""
+TEST_RESULT = 1
+TEST_PASS = 0
+TEST_FAIL = 1
def get_csr_map(csr_file, xlen):
"""
@@ -44,7 +57,7 @@
Returns:
A dictionary contining mappings for each CSR, of the form:
- { csr_name : [csr_val_bitarray, csr_mask_bitarray] }
+ { csr_name : [csr_address, csr_val_bitarray, csr_write_mask_bitarray, csr_read_mask_bitarray] }
"""
rv_string = "rv{}".format(str(xlen))
csrs = {}
@@ -52,23 +65,28 @@
csr_description = yaml.safe_load(c)
for csr_dict in csr_description:
csr_name = csr_dict.get("csr")
+ csr_address = csr_dict.get("address")
assert(rv_string in csr_dict), "The {} CSR must be configured for rv{}".format(csr_name, str(rv))
csr_value = bitarray(uintbe=0, length=xlen)
- csr_mask = bitarray(uintbe=0, length=xlen)
+ csr_write_mask = []
+ csr_read_mask = bitarray(uintbe=0, length=xlen)
csr_field_list = csr_dict.get(rv_string)
for csr_field_detail_dict in csr_field_list:
field_type = csr_field_detail_dict.get("type")
field_val = csr_field_detail_dict.get("reset_val")
field_msb = csr_field_detail_dict.get("msb")
field_lsb = csr_field_detail_dict.get("lsb")
- field_size = field_msb - field_lsb
+ field_size = field_msb - field_lsb + 1
if field_type != "WPRI":
- val_size = field_msb - field_lsb + 1
- val_bitarray = bitarray(uint=field_val, length=val_size)
- mask_bitarray = bitarray(uint=1, length=1) * val_size
+ val_bitarray = bitarray(uint=field_val, length=field_size)
+ mask_bitarray = bitarray(uint=1, length=1) * field_size
+ start_pos = xlen - 1 - field_msb
+ end_pos = xlen - 1 - field_lsb
+ csr_read_mask.overwrite(mask_bitarray, xlen - 1 - field_msb)
csr_value.overwrite(val_bitarray, xlen - 1 - field_msb)
- csr_mask.overwrite(mask_bitarray, xlen - 1 - field_msb)
- csrs.update({csr_name : [csr_value, csr_mask]})
+ access = True if field_type == "R" else False
+ csr_write_mask.append([mask_bitarray, (start_pos, end_pos), access])
+ csrs.update({csr_name : [csr_address, csr_value, csr_write_mask, csr_read_mask]})
return csrs
@@ -102,38 +120,46 @@
return val
-def csr_write(val, csr_val, csr_mask):
+def csr_write(val, csr_val, csr_write_mask):
"""
Performs a CSR write.
Args:
val: A bitarray containing the value to be written.
csr_val: A bitarray containing the current CSR value.
- csr_mask: A bitarray containing the CSR's mask.
+ csr_write_mask: A bitarray containing the CSR's mask.
"""
- if val.len != csr_mask.len:
- csr_val.overwrite(val & csr_mask, 0)
+ for bitslice in csr_write_mask:
+ read_only = bitslice[2]
+ start_index = bitslice[1][0]
+ end_index = bitslice[1][1]
+ length = end_index - start_index + 1
+ mask_val = bitslice[0]
+ # only write if not read only
+ if not read_only:
+ val_slice = val[start_index:end_index+1]
+ csr_val.overwrite(mask_val & val_slice, start_index)
"""
CSR Read:
Reads the given CSR, after applying the bitmask
"""
-def csr_read(csr_val, csr_mask):
+def csr_read(csr_val, csr_read_mask):
"""
Performs a CSR read.
Args:
csr_val: A bitarray containing the current CSR value.
- csr_mask: A bitarray containing the CSR's mask.
+ csr_read_mask: A bitarray containing the CSR's read mask.
Returns:
- A bitarray of the logical AND of csr_val and csr_mask.
+ A bitarray of the logical AND of csr_val and csr_read_mask.
"""
- return csr_val & csr_mask
+ return csr_val & csr_read_mask
-def predict_csr_val(csr_op, rs1_val, csr_val, csr_mask):
+def predict_csr_val(csr_op, rs1_val, csr_val, csr_write_mask, csr_read_mask):
"""
Predicts the CSR reference value, based on the current CSR operation.
@@ -141,7 +167,8 @@
csr_op: A string of the CSR operation being performed.
rs1_val: A bitarray containing the value to be written to the CSR.
csr_val: A bitarray containing the current value of the CSR.
- csr_mask: A bitarray containing the CSR's mask.
+ csr_write_mask: A bitarray containing the CSR's write mask.
+ csr_read_mask: A bitarray containing the CSR's read mask
Returns:
A hexadecimal string of the predicted CSR value.
@@ -150,68 +177,97 @@
# create a zero bitarray to zero extend immediates
zero = bitarray(uint=0, length=csr_val.len - 5)
if csr_op == 'csrrw':
- prediction = csr_read(csr_val, csr_mask)
- csr_write(rs1_val, csr_val, csr_mask)
+ prediction = csr_read(csr_val, csr_read_mask)
+ csr_write(rs1_val, csr_val, csr_write_mask)
elif csr_op == 'csrrs':
- prediction = csr_read(csr_val, csr_mask)
- csr_write(rs1_val | prediction, csr_val, csr_mask)
+ prediction = csr_read(csr_val, csr_read_mask)
+ csr_write(rs1_val | prediction, csr_val, csr_write_mask)
elif csr_op == 'csrrc':
- prediction = csr_read(csr_val, csr_mask)
- csr_write((~rs1_val) & prediction, csr_val, csr_mask)
+ prediction = csr_read(csr_val, csr_read_mask)
+ csr_write((~rs1_val) & prediction, csr_val, csr_write_mask)
elif csr_op == 'csrrwi':
- prediction = csr_read(csr_val, csr_mask)
+ prediction = csr_read(csr_val, csr_read_mask)
zero.append(rs1_val[-5:])
- csr_write(zero, csr_val, csr_mask)
+ csr_write(zero, csr_val, csr_write_mask)
elif csr_op == 'csrrsi':
- prediction = csr_read(csr_val, csr_mask)
+ prediction = csr_read(csr_val, csr_read_mask)
zero.append(rs1_val[-5:])
- csr_write(zero | prediction, csr_val, csr_mask)
+ csr_write(zero | prediction, csr_val, csr_write_mask)
elif csr_op == 'csrrci':
- prediction = csr_read(csr_val, csr_mask)
+ prediction = csr_read(csr_val, csr_read_mask)
zero.append(rs1_val[-5:])
- csr_write((~zero) & prediction, csr_val, csr_mask)
+ csr_write((~zero) & prediction, csr_val, csr_write_mask)
return f"0x{prediction.hex}"
-def gen_csr_test_fail(test_file):
+def gen_setup(test_file):
+ """
+ Generates the setup code for the CSR test.
+
+ Args:
+ test_file: the file containing the generated assembly code.
+ """
+ test_file.write(f".macro init\n")
+ test_file.write(f".endm\n")
+ test_file.write(f".section .text.init\n")
+ test_file.write(f".globl _start\n")
+ test_file.write(f".option norvc\n")
+ for i in range(32):
+ test_file.write(f"j csr_fail\n")
+ test_file.write(f"_start:\n")
+
+
+def gen_csr_test_fail(test_file, end_addr):
"""
Generates code to handle a test failure.
This code consists of writing 1 to the GP register in an infinite loop.
The testbench will poll this register at the end of the test to detect failure.
Args:
- The file containing the generated assembly test code.
+ test_file: the file containing the generated assembly test code.
+ end_addr: address that should be written to at end of test
"""
test_file.write(f"csr_fail:\n")
- test_file.write(f"\tli gp, 1\n")
+ test_file.write(f"\tli x1, {TEST_FAIL}\n")
+ test_file.write(f"\tslli x1, x1, 8\n")
+ test_file.write(f"\taddi x1, x1, {TEST_RESULT}\n")
+ test_file.write(f"\tli x2, {end_addr}\n")
+ test_file.write(f"\tsw x1, 0(x2)\n")
test_file.write(f"\tj csr_fail\n")
-def gen_csr_test_pass(test_file):
+def gen_csr_test_pass(test_file, end_addr):
"""
Generates code to handle test success.
This code consists of writing 2 to the GP register in an infinite loop.
The testbench will poll this register at the end of the test to detect success.
Args:
- The file containing the generated assembly test code.
+ test_file: the file containing the generated assembly test code.
+ end_addr: address that should be written to at end of test
"""
test_file.write(f"csr_pass:\n")
- test_file.write(f"\tli gp, 1\n")
+ test_file.write(f"\tli x1, {TEST_PASS}\n")
+ test_file.write(f"\tslli x1, x1, 8\n")
+ test_file.write(f"\taddi x1, x1, {TEST_RESULT}\n")
+ test_file.write(f"\tli x2, {end_addr}\n")
+ test_file.write(f"\tsw x1, 0(x2)\n")
test_file.write(f"\tj csr_pass\n")
-def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out):
+def gen_csr_instr(original_csr_map, csr_instructions, xlen,
+ iterations, out, end_signature_addr):
"""
Uses the information in the map produced by get_csr_map() to generate
test CSR instructions operating on the generated random values.
Args:
- csr_map: The dictionary containing CSR mappings generated by get_csr_map()
+ original_csr_map: The dictionary containing CSR mappings generated by get_csr_map()
csr_instructions: A list of all supported CSR instructions in string form.
xlen: The RISC-V ISA bit length.
iterations: Indicates how many randomized test files will be generated.
out: A string containing the directory path that the tests will be generated in.
+ end_signature_addr: The address the test should write to upon terminating
Returns:
No explicit return value, but will write the randomized assembly test code
@@ -220,13 +276,14 @@
for i in range(iterations):
# pick two GPRs at random to act as source and destination registers
# for CSR operations
- source_reg, dest_reg = [f"x{i}" for i in random.sample(range(5, 15), 2)]
+ csr_map = copy.deepcopy(original_csr_map)
+ source_reg, dest_reg = [f"x{i}" for i in random.sample(range(1, 16), 2)]
csr_list = list(csr_map.keys())
with open(f"{out}/riscv_csr_test.{i}.S", "w") as csr_test_file:
- csr_test_file.write(f"csr_test:\n")
+ gen_setup(csr_test_file)
for csr in csr_list:
- last_csr = csr
- csr_val, csr_mask = csr_map.get(csr)
+ csr_address, csr_val, csr_write_mask, csr_read_mask = csr_map.get(csr)
+ csr_test_file.write(f"\t# {csr}\n")
for op in csr_instructions:
for i in range(3):
# hex string
@@ -235,11 +292,16 @@
first_li = ""
if op[-1] == "i":
imm = rand_rs1_val[-5:]
- csr_inst = f"\t{op} {dest_reg}, {csr}, 0b{imm.bin}\n"
+ csr_inst = f"\t{op} {dest_reg}, {csr_address}, 0b{imm.bin}\n"
+ imm_val = bitarray(uint=0, length=xlen-5)
+ imm_val.append(imm)
+ predict_li = (f"\tli {source_reg}, "
+ f"{predict_csr_val(op, imm_val, csr_val, csr_write_mask, csr_read_mask)}\n")
else:
first_li = f"\tli {source_reg}, 0x{rand_rs1_val.hex}\n"
- csr_inst = f"\t{op} {dest_reg}, {csr}, {source_reg}\n"
- predict_li = f"\tli {source_reg}, {predict_csr_val(op, rand_rs1_val, csr_val, csr_mask)}\n"
+ csr_inst = f"\t{op} {dest_reg}, {csr_address}, {source_reg}\n"
+ predict_li = (f"\tli {source_reg}, "
+ f"{predict_csr_val(op, rand_rs1_val, csr_val, csr_write_mask, csr_read_mask)}\n")
branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n"
csr_test_file.write(first_li)
csr_test_file.write(csr_inst)
@@ -250,25 +312,32 @@
been written to the CSR has not been tested.
"""
if csr == csr_list[-1] and op == csr_instructions[-1] and i == 2:
- final_csr_read = f"\tcsrr {dest_reg}, {csr_list[-1]}\n"
+ final_csr_read = f"\tcsrr {dest_reg}, {csr_address}\n"
csrrs_read_mask = bitarray(uint=0, length=xlen)
- final_li = f"\tli {source_reg}, {predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_mask)}\n"
+ final_li = (f"\tli {source_reg}, "
+ f"{predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_write_mask, csr_read_mask)}\n")
final_branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n"
csr_test_file.write(final_csr_read)
csr_test_file.write(final_li)
csr_test_file.write(final_branch_check)
- gen_csr_test_pass(csr_test_file)
- gen_csr_test_fail(csr_test_file)
+ gen_csr_test_pass(csr_test_file, end_signature_addr)
+ gen_csr_test_fail(csr_test_file, end_signature_addr)
"""
Define command line arguments.
"""
parser = argparse.ArgumentParser()
-parser.add_argument("--csr_file", type=str, help="The YAML file contating descriptions of all processor supported CSRs")
-parser.add_argument("--xlen", type=int, default=32, help="Specify the ISA width, e.g. 32 or 64 or 128")
-parser.add_argument("--num_test", type=int, default=1, help="Specify how many tests to be generated")
-parser.add_argument("--out", type=str, default="./", help="Specify output directory")
+parser.add_argument("--csr_file", type=str, default="yaml/csr_template.yaml",
+ help="The YAML file contating descriptions of all processor supported CSRs")
+parser.add_argument("--xlen", type=int, default=32,
+ help="Specify the ISA width, e.g. 32 or 64 or 128")
+parser.add_argument("--iterations", type=int, default=1,
+ help="Specify how many tests to be generated")
+parser.add_argument("--out", type=str, default="./",
+ help="Specify output directory")
+parser.add_argument("--end_signature_addr", type=str, default="0",
+ help="Address that should be written to at end of this test")
args = parser.parse_args()
@@ -277,4 +346,6 @@
"""
csr_ops = ['csrrw', 'csrrs', 'csrrc', 'csrrwi', 'csrrsi', 'csrrci']
-gen_csr_instr(get_csr_map(args.csr_file, args.xlen), csr_ops, args.xlen, args.num_test, args.out)
+gen_csr_instr(get_csr_map(args.csr_file, args.xlen),
+ csr_ops, args.xlen, args.iterations, args.out,
+ args.end_signature_addr)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/instr_trace_compare.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/instr_trace_compare.py
index 870c554..ead4f5c 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/instr_trace_compare.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/instr_trace_compare.py
@@ -32,6 +32,10 @@
matched_cnt = 0
mismatch_cnt = 0
+ # ensure that in order mode is disabled if necessary
+ if compare_final_value_only:
+ in_order_mode = 0
+
if log:
fd = open(log, 'a+')
else:
@@ -56,6 +60,8 @@
gpr_val_2 = {}
for trace in instr_trace_1:
trace_1_index += 1
+ if trace.rd == "":
+ continue
# Check if there's a GPR change caused by this instruction
gpr_state_change_1 = check_update_gpr(trace.rd, trace.rd_val, gpr_val_1)
if gpr_state_change_1 == 0:
@@ -63,10 +69,11 @@
# Move forward the other trace until a GPR update happens
gpr_state_change_2 = 0
while (gpr_state_change_2 == 0 and trace_2_index < len(instr_trace_2)):
- gpr_state_change_2 = check_update_gpr(
- instr_trace_2[trace_2_index].rd,
- instr_trace_2[trace_2_index].rd_val,
- gpr_val_2)
+ if instr_trace_2[trace_2_index].rd != "":
+ gpr_state_change_2 = check_update_gpr(
+ instr_trace_2[trace_2_index].rd,
+ instr_trace_2[trace_2_index].rd_val,
+ gpr_val_2)
trace_2_index += 1
# Check if the GPR update is the same between trace 1 and 2
if gpr_state_change_2 == 0:
@@ -131,8 +138,8 @@
for trace_1_index in range(0, len(gpr_trace_1[gpr])-1):
if (trace_2_index == len(gpr_trace_2[gpr])):
break
- if long(gpr_trace_1[gpr][trace_1_index].rd_val, 16) != \
- long(gpr_trace_2[gpr][trace_2_index].rd_val, 16):
+ if int(gpr_trace_1[gpr][trace_1_index].rd_val, 16) != \
+ int(gpr_trace_2[gpr][trace_2_index].rd_val, 16):
if coalesced_updates >= coalescing_limit:
coalesced_updates = 0
mismatch_cnt += 1
@@ -163,8 +170,8 @@
mismatch_cnt += 1
fd.write("Zero GPR[%s] updates observed: %s:%d, %s:%d\n" % (gpr,
name1, len(gpr_trace_1[gpr]), name2, len(gpr_trace_2[gpr])))
- elif long(gpr_trace_1[gpr][-1].rd_val, 16) != \
- long(gpr_trace_2[gpr][-1].rd_val, 16):
+ elif int(gpr_trace_1[gpr][-1].rd_val, 16) != \
+ int(gpr_trace_2[gpr][-1].rd_val, 16):
mismatch_cnt += 1
if mismatch_cnt <= mismatch_print_limit:
fd.write("Mismatch final value:\n")
@@ -183,12 +190,13 @@
def parse_gpr_update_from_trace(trace_csv, gpr_trace):
prev_val = {}
for trace in trace_csv:
- if not (trace.rd in prev_val):
- gpr_trace[trace.rd] = []
- gpr_trace[trace.rd].append(trace)
- elif prev_val[trace.rd] != trace.rd_val:
- gpr_trace[trace.rd].append(trace)
- prev_val[trace.rd] = trace.rd_val
+ if trace.rd != "":
+ if not (trace.rd in prev_val):
+ gpr_trace[trace.rd] = []
+ gpr_trace[trace.rd].append(trace)
+ elif prev_val[trace.rd] != trace.rd_val:
+ gpr_trace[trace.rd].append(trace)
+ prev_val[trace.rd] = trace.rd_val
def check_update_gpr(rd, rd_val, gpr):
@@ -206,10 +214,10 @@
def main():
# Parse input arguments
parser = argparse.ArgumentParser()
- parser.add_argument("csv_file_1", type=str, help="Instruction trace 1 CSV")
- parser.add_argument("csv_file_2", type=str, help="Instruction trace 2 CSV")
- parser.add_argument("csv_name_1", type=str, help="Instruction trace 1 name")
- parser.add_argument("csv_name_2", type=str, help="Instruction trace 2 name")
+ parser.add_argument("--csv_file_1", type=str, help="Instruction trace 1 CSV")
+ parser.add_argument("--csv_file_2", type=str, help="Instruction trace 2 CSV")
+ parser.add_argument("--csv_name_1", type=str, help="Instruction trace 1 name")
+ parser.add_argument("--csv_name_2", type=str, help="Instruction trace 2 name")
# optional arguments
parser.add_argument("--log", type=str, default="",
help="Log file")
@@ -228,9 +236,6 @@
args = parser.parse_args()
- if args.compare_final_value_only:
- args.in_order_mode = 0
-
# Compare trace CSV
compare_trace_csv(args.csv_file_1, args.csv_file_2,
args.csv_name_1, args.csv_name_2, args.log,
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/lib.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/lib.py
index ae7c54b..1037680 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/lib.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/lib.py
@@ -22,6 +22,7 @@
import subprocess
import time
import yaml
+import logging
def read_yaml(yaml_file):
""" Read YAML file to a dictionary
@@ -36,7 +37,7 @@
try:
yaml_data = yaml.safe_load(f)
except yaml.YAMLError as exc:
- print(exc)
+ logging.error(exc)
sys.exit(1)
return yaml_data
@@ -53,7 +54,7 @@
try:
val = os.environ[var]
except KeyError:
- print ("Please set the environment variable %0s" % var)
+ logging.warning("Please set the environment variable %0s" % var)
sys.exit(1)
return val
@@ -73,7 +74,7 @@
return random.getrandbits(32)
-def run_cmd(cmd, verbose = 0, timeout_s = 999):
+def run_cmd(cmd, timeout_s = 999):
"""Run a command and return output
Args:
@@ -89,20 +90,19 @@
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as exc:
- print(ps.communicate()[0])
+ logging.error(ps.communicate()[0])
sys.exit(1)
try:
output = ps.communicate(timeout = timeout_s)[0]
except subprocess.TimeoutExpired:
- print("Timeout[%ds]: %s" % (timeout_s, cmd))
+ logging.error("Timeout[%ds]: %s" % (timeout_s, cmd))
output = ""
ps.kill()
- if verbose:
- print(output)
+ logging.debug(output)
return output
-def run_parallel_cmd(cmd_list, verbose = 0, timeout_s = 999):
+def run_parallel_cmd(cmd_list, timeout_s = 999):
"""Run a list of commands in parallel
Args:
@@ -120,18 +120,16 @@
stderr=subprocess.STDOUT)
children.append(ps)
for i in range(len(children)):
- print("Command progress: %d/%d" % (i, len(children)))
- if verbose:
- print("Waiting for command: %s" % cmd_list[i])
+ logging.info("Command progress: %d/%d" % (i, len(children)))
+ logging.debug("Waiting for command: %s" % cmd_list[i])
try:
output = children[i].communicate(timeout = timeout_s)[0]
except subprocess.TimeoutExpired:
- print("Timeout[%ds]: %s" % (timeout_s, cmd))
+ logging.error("Timeout[%ds]: %s" % (timeout_s, cmd))
children[i].kill()
# Restore stty setting otherwise the terminal may go crazy
os.system("stty sane")
- if verbose:
- print(output)
+ logging.debug(output)
def process_regression_list(testlist, test, iterations, matched_list):
@@ -145,13 +143,13 @@
Returns:
matched_list : A list of matched tests
"""
- print("Processing regression test list : %s, test: %s" % (testlist, test))
+ logging.info("Processing regression test list : %s, test: %s" % (testlist, test))
yaml_data = read_yaml(testlist)
for entry in yaml_data:
if (entry['test'] == test) or (test == "all"):
- if iterations > 0:
+ if (iterations > 0 and entry['iterations'] > 0):
entry['iterations'] = iterations
if entry['iterations'] > 0:
- print ("Found matched tests: %s, iterations:%0d" %
- (entry['test'], entry['iterations']))
+ logging.info("Found matched tests: %s, iterations:%0d" %
+ (entry['test'], entry['iterations']))
matched_list.append(entry)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py
index 1c0874e..3733b14 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py
@@ -18,6 +18,7 @@
import re
import os
import argparse
+import logging
from riscv_trace_csv import *
@@ -27,7 +28,7 @@
Extract instruction and affected register information from ovpsim simulation
log and save to a list.
"""
- print("Processing ovpsim log : %s" % ovpsim_log)
+ logging.info("Processing ovpsim log : %s" % ovpsim_log)
instr_cnt = 0
trace_instr = ""
trace_bin = ""
@@ -66,7 +67,7 @@
rv_instr_trace.binary = trace_bin
rv_instr_trace.addr = trace_addr
trace_csv.write_trace_entry(rv_instr_trace)
- print("Processed instruction count : %d" % instr_cnt)
+ logging.info("Processed instruction count : %d" % instr_cnt)
def main():
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/riscv_trace_csv.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/riscv_trace_csv.py
index 329f642..4dfd104 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/riscv_trace_csv.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/riscv_trace_csv.py
@@ -32,6 +32,7 @@
self.addr = ""
self.binary = ""
self.instr_str = ""
+ self.instr = ""
self.privileged_mode = ""
def get_trace_string(self):
@@ -47,6 +48,7 @@
def __init__(self, csv_fd):
self.csv_fd = csv_fd
+ self.gpr = {}
def start_new_trace(self):
@@ -72,11 +74,19 @@
def write_trace_entry(self, entry):
"""Write a new trace entry to CSV"""
- self.csv_writer.writerow({'str' : entry.instr_str,
- 'rd' : entry.rd,
- 'rd_val' : entry.rd_val,
- 'binary' : entry.binary,
- 'addr' : entry.addr})
+ self.gpr[entry.rd] = entry.rd_val
+ self.csv_writer.writerow({'str' : entry.instr_str,
+ 'rd' : entry.rd,
+ 'rd_val' : entry.rd_val,
+ 'rs1' : entry.rs1,
+ 'rs1_val' : entry.rs1_val,
+ 'rs2' : entry.rs2,
+ 'rs2_val' : entry.rs2_val,
+ 'addr' : entry.addr,
+ 'instr' : entry.instr,
+ 'imm' : entry.imm,
+ 'binary' : entry.binary,
+ 'addr' : entry.addr})
def gpr_to_abi(gpr):
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/sail_log_to_trace_csv.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/sail_log_to_trace_csv.py
new file mode 100644
index 0000000..061da71
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/sail_log_to_trace_csv.py
@@ -0,0 +1,97 @@
+"""
+Copyright 2019 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Convert sail sim log to standard riscv instruction trace format
+"""
+
+import argparse
+import os
+import re
+import sys
+import logging
+
+sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
+
+from riscv_trace_csv import *
+
+START_RE = re.compile(r"\[4\] \[M\]: 0x.*00001010")
+END_RE = re.compile(r"ecall")
+INSTR_RE = re.compile(r"\[[0-9].*\] \[(?P<pri>.)\]: 0x(?P<addr>[A-F0-9]+?)"
+ " \(0x(?P<bin>[A-F0-9]+?)\) (?P<instr>.+?$)")
+RD_RE = re.compile(r"x(?P<reg>[0-9]+?) <- 0x(?P<val>[A-F0-9]*)")
+
+def process_sail_sim_log(sail_log, csv):
+ """Process SAIL RISCV simulation log.
+
+ Extract instruction and affected register information from sail simulation
+ log and save to a list.
+ """
+ logging.info("Processing sail log : %s" % sail_log)
+ instr_cnt = 0
+ sail_instr = ""
+
+ with open(sail_log, "r") as f, open(csv, "w") as csv_fd:
+ search_start = 0
+ instr_start = 0
+ trace_csv = RiscvInstructiontTraceCsv(csv_fd)
+ trace_csv.start_new_trace()
+ instr = None
+ for line in f:
+ # Extract instruction infromation
+ m = START_RE.search(line)
+ if m:
+ search_start = 1
+ continue
+ m = END_RE.search(line)
+ if m:
+ break
+ if search_start:
+ instr = INSTR_RE.search(line)
+ if instr:
+ instr_start = 1
+ pri = instr.group("pri")
+ addr = instr.group("addr").lower()
+ binary = instr.group("bin").lower()
+ instr_str = instr.group("instr")
+ continue
+ if instr_start:
+ m = RD_RE.search(line)
+ if m:
+ # Write the extracted instruction to a csvcol buffer file
+ instr_cnt += 1
+ rv_instr_trace = RiscvInstructiontTraceEntry()
+ rv_instr_trace.rd = gpr_to_abi("x%0s" % m.group("reg"))
+ rv_instr_trace.rd_val = m.group("val").lower()
+ rv_instr_trace.privileged_mode = pri
+ rv_instr_trace.addr = addr
+ rv_instr_trace.binary = binary
+ rv_instr_trace.instr_str = instr_str
+ trace_csv.write_trace_entry(rv_instr_trace)
+ instr_start = 0
+ logging.info("Processed instruction count : %d" % instr_cnt)
+
+
+def main():
+ instr_trace = []
+ # Parse input arguments
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--log", type=str, help="Input sail simulation log")
+ parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
+ args = parser.parse_args()
+ # Process sail log
+ process_sail_sim_log(args.log, args.csv)
+
+if __name__ == "__main__":
+ main()
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py
index f42c43b..45a23f8 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py
@@ -20,6 +20,7 @@
import os
import re
import sys
+import logging
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
@@ -31,10 +32,18 @@
Extract instruction and affected register information from spike simulation
log and save to a list.
"""
- print("Processing spike log : %s" % spike_log)
+ logging.info("Processing spike log : %s" % spike_log)
instr_cnt = 0
spike_instr = ""
+ RD_RE = re.compile(r"(?P<pri>\d) 0x(?P<addr>[a-f0-9]+?) " \
+ "\((?P<bin>.*?)\) x\s*(?P<reg>\d*?) 0x(?P<val>.*)")
+ CORE_RE = re.compile(r"core.*0x(?P<addr>[a-f0-9]+?) \(0x(?P<bin>.*?)\) (?P<instr>.*?)$")
+ INSTR_RE = re.compile(r"(?P<instr>[a-z\.]+?)(\s+?)(?P<operand>.*)")
+ GPR_RE = re.compile(r"^[a-z][0-9a-z]$")
+ CSR_RE = re.compile(r"csr")
+ ILLE_RE = re.compile(r"trap_illegal_instruction")
+
# Remove all the init spike boot instructions
cmd = ("sed -i '/core.*0x0000000000001010/,$!d' %s" % spike_log)
os.system(cmd)
@@ -42,30 +51,65 @@
cmd = ("sed -i '/ecall/q' %s" % spike_log)
os.system(cmd)
+ gpr = {}
+ gpr["zero"] = 0
+
with open(spike_log, "r") as f, open(csv, "w") as csv_fd:
trace_csv = RiscvInstructiontTraceCsv(csv_fd)
trace_csv.start_new_trace()
for line in f:
# Extract instruction infromation
- m = re.search(r"core(.*)\) (.*)", line)
+ m = CORE_RE.search(line)
if m:
- spike_instr = m.group(2)
- else:
- # Extract register value information
- m = re.search(r"(?P<pri>\d) 0x(?P<addr>[a-f0-9]+?) " \
- "\((?P<bin>.*?)\) x\s*(?P<reg>\d*?) 0x(?P<val>.*)", line)
- if m:
- # Write the extracted instruction to a csvcol buffer file
- instr_cnt += 1
- rv_instr_trace = RiscvInstructiontTraceEntry()
- rv_instr_trace.rd = gpr_to_abi("x%0s" % m.group("reg"))
- rv_instr_trace.rd_val = m.group("val")
- rv_instr_trace.privileged_mode = m.group("pri")
- rv_instr_trace.addr = m.group("addr")
- rv_instr_trace.binary = m.group("bin")
- rv_instr_trace.instr_str = spike_instr
+ spike_instr = m.group("instr")
+ rv_instr_trace = RiscvInstructiontTraceEntry()
+ rv_instr_trace.instr_str = spike_instr
+ rv_instr_trace.addr = m.group("addr")
+ rv_instr_trace.binary = m.group("bin")
+ if spike_instr == "wfi":
trace_csv.write_trace_entry(rv_instr_trace)
- print("Processed instruction count : %d" % instr_cnt)
+ continue
+ nextline = f.readline()
+ if nextline != "":
+ if ILLE_RE.search(nextline):
+ continue
+ m = RD_RE.search(nextline)
+ if m:
+ # Extract RD information
+ instr_cnt += 1
+ rv_instr_trace.rd = gpr_to_abi("x%0s" % m.group("reg"))
+ rv_instr_trace.rd_val = m.group("val")
+ rv_instr_trace.privileged_mode = m.group("pri")
+ gpr[rv_instr_trace.rd] = rv_instr_trace.rd_val
+ s = INSTR_RE.search(spike_instr)
+ if s:
+ rv_instr_trace.instr = s.group("instr")
+ operand_str = s.group("operand").replace(" ", "")
+ if operand_str != "" :
+ operands = operand_str.split(",")
+ if CSR_RE.search(s.group("instr")):
+ # CSR instruction
+ operand = operands[-1]
+ if GPR_RE.search(operand) or operand == "zero":
+ rv_instr_trace.rs1 = operand
+ rv_instr_trace.rs1_val = gpr[operand]
+ else:
+ rv_instr_trace.imm = operand
+ else:
+ # Non CSR instruction
+ for i in range(1, len(operands)):
+ operand = operands[i]
+ if GPR_RE.search(operand) or operand == "zero":
+ if i == 1:
+ rv_instr_trace.rs1 = operand
+ rv_instr_trace.rs1_val = gpr[operand]
+ else:
+ rv_instr_trace.rs2 = operands[i]
+ rv_instr_trace.rs2_val = gpr[operand]
+ else:
+ rv_instr_trace.imm = operand
+ trace_csv.write_trace_entry(rv_instr_trace)
+ logging.info("Processed instruction count : %d" % instr_cnt)
def main():
@@ -78,5 +122,6 @@
# Process spike log
process_spike_sim_log(args.log, args.csv)
+
if __name__ == "__main__":
main()
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/setting/riscv_core_setting.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/setting/riscv_core_setting.sv
index a893983..5ca55e0 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/setting/riscv_core_setting.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/setting/riscv_core_setting.sv
@@ -30,7 +30,10 @@
riscv_instr_name_t unsupported_instr[];
// ISA supported by the processor
-riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C};
+riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C, RV32A, RV64A};
+
+// Interrupt mode support
+mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};
// Debug mode support
bit support_debug_mode = 0;
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_amo_instr_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_amo_instr_lib.sv
new file mode 100644
index 0000000..f16fe58
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_amo_instr_lib.sv
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Base class for AMO instruction stream
+class riscv_amo_base_instr_stream extends riscv_directed_instr_stream;
+
+ rand int unsigned num_amo;
+ rand int unsigned num_mixed_instr;
+ rand int base;
+ rand riscv_reg_t rs1_reg;
+ riscv_reg_t reserved_rd[$];
+ rand int unsigned data_page_id;
+
+ // User can specify a small group of available registers to generate various hazard condition
+ rand riscv_reg_t avail_regs[];
+
+ `uvm_object_utils(riscv_amo_base_instr_stream)
+
+ constraint rs1_c {
+ !(rs1_reg inside {cfg.reserved_regs, reserved_rd, ZERO});
+ }
+
+ constraint addr_range_c {
+ data_page_id < max_data_page_id;
+ base inside {[0 : max_load_store_offset-1]};
+ }
+
+ constraint aligned_amo_c {
+ if (XLEN == 32) {
+ base % 4 == 0;
+ } else {
+ base % 8 == 0;
+ }
+ }
+
+ function new(string name = "");
+ super.new(name);
+ instr_list.rand_mode(0);
+ endfunction
+
+ function void post_randomize();
+ gen_amo_instr();
+ // rs1 cannot be modified by other instructions
+ if(!(rs1_reg inside {reserved_rd})) begin
+ reserved_rd.push_back(rs1_reg);
+ end
+ add_mixed_instr();
+ add_rs1_init_la_instr();
+ super.post_randomize();
+ endfunction
+
+ // Use "la" instruction to initialize the base regiseter
+ virtual function void add_rs1_init_la_instr();
+ riscv_pseudo_instr la_instr;
+ la_instr = riscv_pseudo_instr::type_id::create("la_instr");
+ `DV_CHECK_RANDOMIZE_WITH_FATAL(la_instr,
+ pseudo_instr_name == LA;
+ rd == rs1_reg;,
+ "Cannot randomize la_instr")
+ if(access_u_mode_mem) begin
+ la_instr.imm_str = $sformatf("data_page_%0d+%0d", data_page_id, base);
+ end else begin
+ la_instr.imm_str = $sformatf("kernel_data_page_%0d+%0d", data_page_id, base);
+ end
+ instr_list.push_front(la_instr);
+ endfunction
+
+ // AMO instruction generation
+ virtual function void gen_amo_instr();
+ endfunction
+
+ // Insert some other instructions to mix with load/store instruction
+ virtual function void add_mixed_instr();
+ riscv_rand_instr rand_instr;
+ for(int i = 0; i < num_mixed_instr; i ++) begin
+ rand_instr = riscv_rand_instr::type_id::create("rand_instr");
+ rand_instr.cfg = cfg;
+ rand_instr.reserved_rd = reserved_rd;
+ `DV_CHECK_RANDOMIZE_WITH_FATAL(rand_instr,
+ if(avail_regs.size() > 0) {
+ rs1 inside {avail_regs};
+ rd inside {avail_regs};
+ }
+ !(category inside {LOAD, STORE, BRANCH, JUMP});,
+ "Cannot randomize instruction")
+ insert_instr(rand_instr);
+ end
+ endfunction
+
+endclass
+
+// A pair of LR/SC instruction
+class riscv_lr_sc_instr_stream extends riscv_amo_base_instr_stream;
+
+ riscv_rand_instr lr_instr;
+ riscv_rand_instr sc_instr;
+
+ constraint legal_c {
+ num_amo == 1;
+ num_mixed_instr inside {[0:15]};
+ }
+
+ `uvm_object_utils(riscv_lr_sc_instr_stream)
+
+ function new(string name = "");
+ super.new(name);
+ lr_instr = riscv_rand_instr::type_id::create("lr_instr");
+ sc_instr = riscv_rand_instr::type_id::create("sc_instr");
+ endfunction
+
+ virtual function void gen_amo_instr();
+ lr_instr.cfg = cfg;
+ sc_instr.cfg = cfg;
+ lr_instr.disable_a_extension_c.constraint_mode(0);
+ sc_instr.disable_a_extension_c.constraint_mode(0);
+ `DV_CHECK_RANDOMIZE_WITH_FATAL(lr_instr,
+ rs1 == rs1_reg;
+ rd != rs1_reg;
+ instr_name inside {LR_W, LR_D};)
+ `DV_CHECK_RANDOMIZE_WITH_FATAL(sc_instr,
+ rs1 == rs1_reg;
+ rd != rs1_reg;
+ instr_name inside {SC_W, SC_D};)
+ instr_list.push_front(lr_instr);
+ instr_list.push_front(sc_instr);
+ endfunction
+
+endclass
+
+class riscv_amo_instr_stream extends riscv_amo_base_instr_stream;
+
+ riscv_rand_instr amo_instr[];
+
+ constraint reasonable_c {
+ solve num_amo before num_mixed_instr;
+ num_amo inside {[1:10]};
+ num_mixed_instr inside {[0:2*num_amo]};
+ }
+
+ `uvm_object_utils(riscv_amo_instr_stream)
+ `uvm_object_new
+
+ virtual function void gen_amo_instr();
+ amo_instr = new[num_amo];
+ foreach (amo_instr[i]) begin
+ amo_instr[i] = riscv_rand_instr::type_id::create($sformatf("amo_instr_%0d", i));
+ amo_instr[i].cfg = cfg;
+ amo_instr[i].disable_a_extension_c.constraint_mode(0);
+ `DV_CHECK_RANDOMIZE_WITH_FATAL(amo_instr[i],
+ rs1 == rs1_reg;
+ rd != rs1_reg;
+ category == AMO;)
+ instr_list.push_front(amo_instr[i]);
+ end
+ endfunction
+
+endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
index f11e5eb..9011cb9 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
@@ -31,6 +31,8 @@
riscv_instr_sequence sub_program[];
// Program in binary format, stored in the data section, used to inject illegal/HINT instruction
riscv_instr_sequence bin_program;
+ riscv_instr_sequence debug_program;
+ riscv_instr_sequence debug_sub_program[];
string instr_binary[$];
// Kernel programs
// These programs are called in the interrupt/exception handling routine based on the privileged
@@ -68,6 +70,7 @@
gen_program_header();
// Initialize general purpose registers
init_gpr();
+ setup_misa();
// Create all page tables
create_page_table();
// Setup privileged mode registers and enter target privileged mode
@@ -78,6 +81,7 @@
if(cfg.enable_illegal_instruction || cfg.enable_hint_instruction) begin
bin_program = riscv_instr_sequence::type_id::create("bin_program");
bin_program.instr_cnt = cfg.bin_program_instr_cnt;
+ bin_program.is_debug_program = 0;
bin_program.label_name = bin_program.get_name();
bin_program.cfg = cfg;
if (cfg.enable_illegal_instruction) begin
@@ -87,32 +91,18 @@
bin_program.hint_instr_pct = $urandom_range(5, 20);
end
`DV_CHECK_RANDOMIZE_FATAL(bin_program)
- bin_program.gen_instr(.is_main_program(0), .enable_hint_instr(cfg.enable_hint_instruction));
+ bin_program.gen_instr(.is_main_program(0));
bin_program.post_process_instr();
bin_program.generate_binary_stream(instr_binary);
end
// Init section
gen_init_section();
// Generate sub program
- if(cfg.num_of_sub_program > 0) begin
- sub_program = new[cfg.num_of_sub_program];
- foreach(sub_program[i]) begin
- sub_program[i] = riscv_instr_sequence::type_id::create($sformatf("sub_%0d",i+1));
- sub_program[i].instr_cnt = cfg.sub_program_instr_cnt[i];
- generate_directed_instr_stream(.label(sub_program[i].get_name()),
- .original_instr_cnt(sub_program[i].instr_cnt),
- .min_insert_cnt(0),
- .instr_stream(sub_program[i].directed_instr));
- sub_program[i].label_name = sub_program[i].get_name();
- sub_program[i].cfg = cfg;
- `DV_CHECK_RANDOMIZE_FATAL(sub_program[i])
- sub_program[i].gen_instr(0);
- sub_program_name.push_back(sub_program[i].label_name);
- end
- end
+ gen_sub_program(sub_program, sub_program_name, cfg.num_of_sub_program);
// Generate main program
main_program = riscv_instr_sequence::type_id::create("main_program");
main_program.instr_cnt = cfg.main_program_instr_cnt;
+ main_program.is_debug_program = 0;
main_program.label_name = "_main";
generate_directed_instr_stream(.label("main"),
.original_instr_cnt(main_program.instr_cnt),
@@ -122,30 +112,7 @@
`DV_CHECK_RANDOMIZE_FATAL(main_program)
main_program.gen_instr(1);
// Setup jump instruction among main program and sub programs
- if(cfg.num_of_sub_program != 0) begin
- callstack_gen = riscv_callstack_gen::type_id::create("callstack_gen");
- callstack_gen.init(cfg.num_of_sub_program+1);
- `uvm_info(get_full_name(), "Randomizing call stack", UVM_LOW)
- if(callstack_gen.randomize()) begin
- program_id_t pid;
- int idx;
- // Insert the jump instruction based on the call stack
- foreach(callstack_gen.program_h[i]) begin
- foreach(callstack_gen.program_h[i].sub_program_id[j]) begin
- idx++;
- pid = callstack_gen.program_h[i].sub_program_id[j] - 1;
- `uvm_info(get_full_name(), $sformatf(
- "Gen jump instr %0d -> sub[%0d] %0d", i, j, pid+1), UVM_HIGH)
- if(i == 0)
- main_program.insert_jump_instr(sub_program_name[pid], idx);
- else
- sub_program[i-1].insert_jump_instr(sub_program_name[pid], idx);
- end
- end
- end else begin
- `uvm_fatal(get_full_name(), "Failed to generate callstack")
- end
- end
+ gen_callstack(main_program, sub_program, sub_program_name, cfg.num_of_sub_program);
if (bin_program != null) begin
main_program.insert_jump_instr("sub_bin", 0);
end
@@ -155,12 +122,7 @@
// Test done section
gen_test_done();
// Shuffle the sub programs and insert to the instruction stream
- sub_program.shuffle();
- foreach(sub_program[i]) begin
- sub_program[i].post_process_instr();
- sub_program[i].generate_instr_stream();
- instr_stream = {instr_stream, sub_program[i].instr_string_list};
- end
+ insert_sub_program(sub_program, instr_stream);
// Reserve some space to copy instruction from data section
if (instr_binary.size() > 0) begin
instr_stream.push_back(".align 2");
@@ -174,8 +136,10 @@
gen_privileged_mode_switch_routine();
// Program end
gen_program_end();
- // Generate debug mode section
- gen_debug_mode_section();
+ // Generate debug rom section
+ gen_debug_rom();
+ // Generate debug mode exception handler
+ gen_debug_exception_handler();
// Starting point of data section
gen_data_page_begin();
// Generate the sub program in binary format
@@ -199,13 +163,17 @@
virtual function void gen_kernel_sections();
instr_stream.push_back("_kernel_start: .align 12");
// Kernel programs
- smode_accessible_umode_program = riscv_instr_sequence::type_id::
- create("smode_accessible_umode_program");
+ if (cfg.init_privileged_mode != MACHINE_MODE) begin
+ smode_accessible_umode_program = riscv_instr_sequence::type_id::
+ create("smode_accessible_umode_program");
+ gen_kernel_program(smode_accessible_umode_program);
+ end
smode_program = riscv_instr_sequence::type_id::create("smode_program");
- gen_kernel_program(smode_accessible_umode_program);
gen_kernel_program(smode_program);
- smode_ls_umem_program = riscv_instr_sequence::type_id::create("smode_ls_umem_program");
- gen_kernel_program(smode_ls_umem_program);
+ if (cfg.init_privileged_mode != MACHINE_MODE) begin
+ smode_ls_umem_program = riscv_instr_sequence::type_id::create("smode_ls_umem_program");
+ gen_kernel_program(smode_ls_umem_program);
+ end
// All trap/interrupt handling is in the kernel region
// Trap/interrupt delegation to user mode is not supported now
// Trap handler
@@ -234,6 +202,7 @@
.instr_stream(seq.directed_instr),
.access_u_mode_mem(1'b0));
seq.label_name = seq.get_name();
+ seq.is_debug_program = 0;
seq.cfg = cfg;
`DV_CHECK_RANDOMIZE_FATAL(seq)
seq.gen_instr(0);
@@ -243,6 +212,80 @@
endfunction
//---------------------------------------------------------------------------------------
+ // Generate any subprograms and set up the callstack
+ //---------------------------------------------------------------------------------------
+
+ virtual function void gen_sub_program(ref riscv_instr_sequence sub_program[],
+ ref string sub_program_name[$],
+ input int num_sub_program,
+ bit is_debug = 1'b0,
+ string prefix = "sub");
+ if(num_sub_program > 0) begin
+ sub_program = new[num_sub_program];
+ foreach(sub_program[i]) begin
+ sub_program[i] = riscv_instr_sequence::type_id::create($sformatf("%s_%0d",prefix,i+1));
+ `uvm_info(`gfn, $sformatf("sub program name: %s", prefix), UVM_LOW)
+ sub_program[i].is_debug_program = is_debug;
+ if (is_debug) begin
+ sub_program[i].instr_cnt = cfg.debug_sub_program_instr_cnt[i];
+ end else begin
+ sub_program[i].instr_cnt = cfg.sub_program_instr_cnt[i];
+ end
+ generate_directed_instr_stream(.label(sub_program[i].get_name()),
+ .original_instr_cnt(sub_program[i].instr_cnt),
+ .min_insert_cnt(0),
+ .instr_stream(sub_program[i].directed_instr));
+ sub_program[i].label_name = sub_program[i].get_name();
+ sub_program[i].cfg = cfg;
+ `DV_CHECK_RANDOMIZE_FATAL(sub_program[i])
+ sub_program[i].gen_instr(0);
+ sub_program_name.push_back(sub_program[i].label_name);
+ end
+ end
+ endfunction
+
+ virtual function void gen_callstack(riscv_instr_sequence main_program,
+ ref riscv_instr_sequence sub_program[],
+ ref string sub_program_name[$],
+ input int num_sub_program);
+ if(num_sub_program != 0) begin
+ callstack_gen = riscv_callstack_gen::type_id::create("callstack_gen");
+ callstack_gen.init(num_sub_program+1);
+ `uvm_info(get_full_name(), "Randomizing call stack", UVM_LOW)
+ if(callstack_gen.randomize()) begin
+ program_id_t pid;
+ int idx;
+ // Insert the jump instruction based on the call stack
+ foreach(callstack_gen.program_h[i]) begin
+ foreach(callstack_gen.program_h[i].sub_program_id[j]) begin
+ idx++;
+ pid = callstack_gen.program_h[i].sub_program_id[j] - 1;
+ `uvm_info(get_full_name(), $sformatf(
+ "Gen jump instr %0d -> sub[%0d] %0d", i, j, pid+1), UVM_HIGH)
+ if(i == 0)
+ main_program.insert_jump_instr(sub_program_name[pid], idx);
+ else
+ sub_program[i-1].insert_jump_instr(sub_program_name[pid], idx);
+ end
+ end
+ end else begin
+ `uvm_fatal(get_full_name(), "Failed to generate callstack")
+ end
+ end
+ `uvm_info(get_full_name(), "Randomizing call stack..done", UVM_LOW)
+ endfunction
+
+ virtual function void insert_sub_program(ref riscv_instr_sequence sub_program[],
+ ref string instr_list[$]);
+ sub_program.shuffle();
+ foreach(sub_program[i]) begin
+ sub_program[i].post_process_instr();
+ sub_program[i].generate_instr_stream();
+ instr_list = {instr_list, sub_program[i].instr_string_list};
+ end
+ endfunction
+
+ //---------------------------------------------------------------------------------------
// Major sections - init, stack, data, test_done etc.
//---------------------------------------------------------------------------------------
@@ -314,8 +357,8 @@
instr_stream.push_back(str);
// Init stack pointer to point to the end of the user stack
str = {indent, "la sp, _user_stack_end"};
- setup_misa();
instr_stream.push_back(str);
+ core_is_initialized();
// Copy the instruction from data section to instruction section
if (instr_binary.size() > 0) begin
instr_stream.push_back({indent, "la x31, instr_bin"});
@@ -342,6 +385,7 @@
RV32C, RV64C, RV128C : misa[MISA_EXT_C] = 1'b1;
RV32I, RV64I, RV128I : misa[MISA_EXT_I] = 1'b1;
RV32M, RV64M : misa[MISA_EXT_M] = 1'b1;
+ RV32A, RV64A : misa[MISA_EXT_A] = 1'b1;
default : `uvm_fatal(`gfn, $sformatf("%0s is not yet supported", supported_isa[i].name()))
endcase
end
@@ -352,6 +396,19 @@
instr_stream.push_back({indent, "csrw misa, x15"});
endfunction
+ // Write to the signature_addr with values to indicate to the core testbench
+ // that is safe to start sending interrupt and debug stimulus
+ virtual function void core_is_initialized();
+ if (cfg.require_signature_addr) begin
+ if (cfg.signature_addr != 32'hdead_beef) begin
+ string str;
+ gen_signature_handshake(instr_stream, CORE_STATUS, INITIALIZED);
+ end else begin
+ `uvm_fatal(`gfn, "The signature_addr is not properly configured!")
+ end
+ end
+ endfunction
+
// Initialize general purpose registers with random value
virtual function void init_gpr();
string str;
@@ -520,9 +577,9 @@
USER_MODE: trap_vec_reg = UTVEC;
endcase
// Skip utvec init if trap delegation to u_mode is not supported
- // TODO: For now the default mode is direct mode, needs to support vector mode
- if((riscv_instr_pkg::supported_privileged_mode[i] == USER_MODE) && !riscv_instr_pkg::support_umode_trap) continue;
- if(riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
+ if ((riscv_instr_pkg::supported_privileged_mode[i] == USER_MODE) &&
+ !riscv_instr_pkg::support_umode_trap) continue;
+ if (riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
tvec_name = trap_vec_reg.name();
instr = {instr, $sformatf("la a0, %0s_handler", tvec_name.tolower())};
if(SATP_MODE != BARE && riscv_instr_pkg::supported_privileged_mode[i] != MACHINE_MODE) begin
@@ -533,6 +590,7 @@
$sformatf("slli a0, a0, %0d", XLEN - 20),
$sformatf("srli a0, a0, %0d", XLEN - 20)};
end
+ instr = {instr, $sformatf("ori a0, a0, %0d", cfg.mtvec_mode)};
instr = {instr, $sformatf("csrw 0x%0x, a0 # %0s", trap_vec_reg, trap_vec_reg.name())};
end
gen_section("trap_vec_init", instr);
@@ -566,10 +624,11 @@
// Generate page table fault handling routine
// Page table fault is always handled in machine mode, as virtual address translation may be
// broken when page fault happens.
+ gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
if(page_table_list != null) begin
page_table_list.gen_page_fault_handling_routine(instr);
end else begin
- instr = {"nop"};
+ instr.push_back("nop");
end
gen_section("pt_fault_handler", instr);
endfunction
@@ -584,21 +643,37 @@
bit is_interrupt = 'b1;
string tvec_name;
string instr[$];
- // Push user mode GPR to kernel stack before executing exception handling, this is to avoid
- // exception handling routine modify user program state unexpectedly
- push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, instr);
- // Checking xStatus can be optional if ISS (like spike) has different implementation of certain
- // fields compared with the RTL processor.
- if (cfg.check_xstatus) begin
- instr = {instr, $sformatf("csrr x15, 0x%0x # %0s", status, status.name())};
+ if (cfg.mtvec_mode == VECTORED) begin
+ gen_interrupt_vector_table(mode, status, cause, scratch, instr);
+ end else begin
+ // Push user mode GPR to kernel stack before executing exception handling, this is to avoid
+ // exception handling routine modify user program state unexpectedly
+ push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, instr);
+ // Checking xStatus can be optional if ISS (like spike) has different implementation of certain
+ // fields compared with the RTL processor.
+ if (cfg.check_xstatus) begin
+ instr = {instr, $sformatf("csrr x15, 0x%0x # %0s", status, status.name())};
+ end
+ instr = {instr,
+ // Use scratch CSR to save a GPR value
+ // Check if the exception is caused by an interrupt, if yes, jump to interrupt handler
+ // Interrupt is indicated by xCause[XLEN-1]
+ $sformatf("csrr a1, 0x%0x # %0s", cause, cause.name()),
+ $sformatf("srli a1, a1, %0d", XLEN-1),
+ $sformatf("bne a1, x0, %0smode_intr_handler", mode)};
end
+ // The trap handler will occupy one 4KB page, it will be allocated one entry in the page table
+ // with a specific privileged mode.
+ instr_stream.push_back(".align 12");
+ tvec_name = tvec.name();
+ gen_section($sformatf("%0s_handler", tvec_name.tolower()), instr);
+ // Exception handler
+ instr = {};
+ if (cfg.mtvec_mode == VECTORED) begin
+ push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, instr);
+ end
+ gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
instr = {instr,
- // Use scratch CSR to save a GPR value
- // Check if the exception is caused by an interrupt, if yes, jump to interrupt handler
- // Interrupt is indicated by xCause[XLEN-1]
- $sformatf("csrr a1, 0x%0x # %0s", cause, cause.name()),
- $sformatf("srli a1, a1, %0d", XLEN-1),
- $sformatf("bne a1, x0, %0smode_intr_handler", mode),
// The trap is caused by an exception, read back xCAUSE, xEPC to see if these
// CSR values are set properly. The checking is done by comparing against the log
// generated by ISA simulator (spike).
@@ -634,13 +709,42 @@
$sformatf("csrr x30, 0x%0x # %0s", tval, tval.name()),
"1: jal x1, test_done "
};
+ gen_section($sformatf("%0smode_exception_handler", mode), instr);
+ endfunction
- // The trap handler will occupy one 4KB page, it will be allocated one entry in the page table
- // with a specific privileged mode.
- instr_stream.push_back(".align 12");
- tvec_name = tvec.name();
- gen_section($sformatf("%0s_handler", tvec_name.tolower()), instr);
+ // Generate for interrupt vector table
+ virtual function void gen_interrupt_vector_table(string mode,
+ privileged_reg_t status,
+ privileged_reg_t cause,
+ privileged_reg_t scratch,
+ ref string instr[$]);
+ // In vector mode, the BASE address is shared between interrupt 0 and exception handling.
+ // When vectored interrupts are enabled, interrupt cause 0, which corresponds to user-mode
+ // software interrupts, are vectored to the same location as synchronous exceptions. This
+ // ambiguity does not arise in practice, since user-mode software interrupts are either
+ // disabled or delegated
+ instr = {instr, ".option norvc;",
+ $sformatf("j %0smode_exception_handler", mode)};
+ // Redirect the interrupt to the corresponding interrupt handler
+ for (int i = 1; i < 16; i++) begin
+ instr.push_back($sformatf("j %0smode_intr_vector_%0d", mode, i));
+ end
+ instr = {instr, ".option rvc;"};
+ for (int i = 1; i < 16; i++) begin
+ string intr_handler[$];
+ push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, intr_handler);
+ gen_signature_handshake(intr_handler, CORE_STATUS, HANDLING_IRQ);
+ intr_handler = {intr_handler,
+ $sformatf("csrr a1, 0x%0x # %0s", cause, cause.name()),
+ // Terminate the test if xCause[31] != 0 (indicating exception)
+ $sformatf("bltz a1, 1f"),
+ // TODO(taliu) write xCause to the signature address
+ // Jump to commmon interrupt handling routine
+ $sformatf("j %0smode_intr_handler", mode),
+ "1: j test_done"};
+ gen_section($sformatf("%0smode_intr_vector_%0d", mode, i), intr_handler);
+ end
endfunction
// ECALL trap handler
@@ -665,10 +769,12 @@
// TODO: Support random operations in debug mode
// TODO: Support ebreak exception delegation
virtual function void gen_ebreak_handler();
- string instr[$] = {
- "csrr x31, mepc",
- "addi x31, x31, 4",
- "csrw mepc, x31"
+ string instr[$];
+ gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
+ instr = {instr,
+ "csrr x31, mepc",
+ "addi x31, x31, 4",
+ "csrw mepc, x31"
};
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, instr);
instr.push_back("mret");
@@ -682,10 +788,12 @@
// 4 and resumes execution. The way that the illegal instruction is injected guarantees that
// PC + 4 is a valid instruction boundary.
virtual function void gen_illegal_instr_handler();
- string instr[$] = {
- "csrr x31, mepc",
- "addi x31, x31, 4",
- "csrw mepc, x31"
+ string instr[$];
+ gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
+ instr = {instr,
+ "csrr x31, mepc",
+ "addi x31, x31, 4",
+ "csrw mepc, x31"
};
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, instr);
instr.push_back("mret");
@@ -792,6 +900,14 @@
// Helper functions
//---------------------------------------------------------------------------------------
+ // Format a code section, without generating it
+ virtual function void format_section(ref string instr[$]);
+ string prefix = format_string(" ", LABEL_STR_LEN);
+ foreach(instr[i]) begin
+ instr[i] = {prefix, instr[i]};
+ end
+ endfunction
+
// Generate a code section
virtual function void gen_section(string label, string instr[$]);
string str;
@@ -821,6 +937,88 @@
`uvm_info(get_full_name(), $sformatf("%0s is generated", test_name), UVM_LOW)
endfunction
+ // Helper function to generate the proper sequence of handshake instructions
+ // to signal the testbench (see riscv_signature_pkg.sv)
+ function void gen_signature_handshake(ref string instr[$],
+ input signature_type_t signature_type,
+ core_status_t core_status = INITIALIZED,
+ test_result_t test_result = TEST_FAIL,
+ privileged_reg_t csr = MSCRATCH);
+ if (cfg.require_signature_addr) begin
+ string str;
+ str = $sformatf("li x%0d, 0x%0h", cfg.signature_addr_reg, cfg.signature_addr);
+ instr.push_back(str);
+ case (signature_type)
+ // A single data word is written to the signature address.
+ // Bits [7:0] contain the signature_type of CORE_STATUS, and the upper
+ // XLEN-8 bits contain the core_status_t data.
+ CORE_STATUS: begin
+ str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, core_status);
+ instr.push_back(str);
+ str = $sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg);
+ instr.push_back(str);
+ str = $sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
+ cfg.signature_data_reg, signature_type);
+ instr.push_back(str);
+ str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
+ instr.push_back(str);
+ end
+ // A single data word is written to the signature address.
+ // Bits [7:0] contain the signature_type of TEST_RESULT, and the upper
+ // XLEN-8 bits contain the test_result_t data.
+ TEST_RESULT: begin
+ str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, test_result);
+ instr.push_back(str);
+ str = $sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg);
+ instr.push_back(str);
+ str = $sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
+ cfg.signature_data_reg, signature_type);
+ instr.push_back(str);
+ str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
+ instr.push_back(str);
+ end
+ // The first write to the signature address contains just the
+ // signature_type of WRITE_GPR.
+ // It is followed by 32 consecutive writes to the signature address,
+ // each writing the data contained in one GPR, starting from x0 as the
+ // first write, and ending with x31 as the 32nd write.
+ WRITE_GPR: begin
+ str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, signature_type);
+ instr.push_back(str);
+ str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
+ instr.push_back(str);
+ for(int i = 0; i < 32; i++) begin
+ str = $sformatf("sw x%0x, 0(x%0d)", i, cfg.signature_addr_reg);
+ instr.push_back(str);
+ end
+ end
+ // The first write to the signature address contains the
+ // signature_type of WRITE_CSR in bits [7:0], and the CSR address in
+ // the upper XLEN-8 bits.
+ // It is followed by a second write to the signature address,
+ // containing the data stored in the specified CSR.
+ WRITE_CSR: begin
+ str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, csr);
+ instr.push_back(str);
+ str = $sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg);
+ instr.push_back(str);
+ str = $sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
+ cfg.signature_data_reg, signature_type);
+ instr.push_back(str);
+ str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
+ instr.push_back(str);
+ str = $sformatf("csrr x%0d, 0x%0h", cfg.signature_data_reg, csr);
+ instr.push_back(str);
+ str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
+ instr.push_back(str);
+ end
+ default: begin
+ `uvm_fatal(`gfn, "signature_type is not defined")
+ end
+ endcase
+ end
+ endfunction
+
//---------------------------------------------------------------------------------------
// Inject directed instruction stream
//---------------------------------------------------------------------------------------
@@ -913,11 +1111,49 @@
// Generate the program in the debug ROM
// Processor will fetch instruction from here upon receiving debug request from debug module
- virtual function void gen_debug_mode_section();
- string instr[];
+ virtual function void gen_debug_rom();
+ string push_gpr[$];
+ string pop_gpr[$];
+ string instr[$];
+ string dret;
+ string debug_sub_program_name[$] = {};
if (riscv_instr_pkg::support_debug_mode) begin
- instr = {"dret"};
+ // Signal that the core entered the debug rom regardless of whether the
+ // main debug rom program has been generated
+ gen_signature_handshake(instr, CORE_STATUS, IN_DEBUG_MODE);
+ format_section(instr);
+ // The main debug rom
+ if (cfg.gen_debug_section) begin
+ gen_sub_program(debug_sub_program, debug_sub_program_name,
+ cfg.num_debug_sub_program, 1'b1, "debug_sub");
+ debug_program = riscv_instr_sequence::type_id::create("debug_program");
+ debug_program.instr_cnt = cfg.debug_program_instr_cnt;
+ debug_program.is_debug_program = 1;
+ debug_program.cfg = cfg;
+ `DV_CHECK_RANDOMIZE_FATAL(debug_program)
+ debug_program.gen_instr(.is_main_program(1'b1), .no_branch(1'b0));
+ gen_callstack(debug_program, debug_sub_program, debug_sub_program_name,
+ cfg.num_debug_sub_program);
+ debug_program.post_process_instr();
+ debug_program.generate_instr_stream(.no_label(1'b1));
+ // Need to save off GPRs to avoid modifying program flow
+ push_gpr_to_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, push_gpr);
+ format_section(push_gpr);
+ pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, pop_gpr);
+ format_section(pop_gpr);
+ instr = {push_gpr, instr, debug_program.instr_string_list, pop_gpr};
+ insert_sub_program(debug_sub_program, instr_stream);
+ end
+ dret = {format_string(" ", LABEL_STR_LEN), "dret"};
+ instr = {instr, dret};
gen_section("debug_rom", instr);
+ end
+ endfunction
+
+ // Generate exception handling routine for debug ROM
+ virtual function void gen_debug_exception_handler();
+ if (riscv_instr_pkg::support_debug_mode) begin
+ string instr[];
instr = {"dret"};
gen_section("debug_exception", instr);
end
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv
index 4b4ec70..bd86547 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv
@@ -93,7 +93,8 @@
rand riscv_instr_base jump;
rand riscv_instr_base addi;
rand riscv_pseudo_instr la;
- rand riscv_instr_base branch;
+ rand riscv_rand_instr branch;
+ rand int imm;
rand bit enable_branch;
rand int mixed_instr_cnt;
riscv_instr_base stack_exit_instr[];
@@ -110,6 +111,7 @@
addi.rd == la.rd;
// Avoid using negative offset -1024
addi.imm != 'hFFFF_FC00;
+ addi.imm != 1024;
jump.imm == ~addi.imm + 1;
jump.rs1 == addi.rd;
addi.instr_name == ADDI;
@@ -125,10 +127,14 @@
jump = riscv_instr_base::type_id::create("jump");
la = riscv_pseudo_instr::type_id::create("la");
addi = riscv_instr_base::type_id::create("addi");
- branch = riscv_instr_base::type_id::create("branch");
+ branch = riscv_rand_instr::type_id::create("branch");
instr_list.rand_mode(0);
endfunction
+ function void pre_randomize();
+ branch.cfg = cfg;
+ endfunction
+
function void post_randomize();
riscv_instr_base instr[];
// Generate some random instructions to mix with jump instructions
@@ -171,7 +177,7 @@
int num_of_redudant_instr;
riscv_instr_base push_stack_instr[];
riscv_reg_t saved_regs[];
- rand riscv_instr_base branch_instr;
+ rand riscv_rand_instr branch_instr;
rand bit enable_branch;
string push_start_label;
@@ -179,7 +185,6 @@
function new(string name = "");
super.new(name);
- branch_instr = riscv_instr_base::type_id::create("branch_instr");
endfunction
function void init();
@@ -225,6 +230,8 @@
end
if(enable_branch) begin
// Cover jal -> branch scenario, the branch is added before push stack operation
+ branch_instr = riscv_rand_instr::type_id::create("branch_instr");
+ branch_instr.cfg = cfg;
`DV_CHECK_RANDOMIZE_WITH_FATAL(branch_instr,
category == BRANCH;)
branch_instr.imm_str = push_start_label;
@@ -330,9 +337,7 @@
backward_branch_instr_stream.initialize_instr_list(branch_instr_stream_len);
endfunction
- virtual function void gen_instr(bit no_branch = 1'b0,
- bit no_load_store = 1'b1,
- bit enable_hint_instr = 1'b0);
+ virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1);
int branch_offset;
super.gen_instr(1'b1);
forward_branch_instr_stream.gen_instr();
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_illegal_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_illegal_instr.sv
index 03b354b..2cd25c6 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_illegal_instr.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_illegal_instr.sv
@@ -125,14 +125,25 @@
}
}
+ // TODO: Enable atomic instruction
+ constraint no_atomic_c {
+ opcode != 7'b0101111;
+ }
+
constraint illegal_func3_c {
solve opcode before func3;
if (!compressed) {
if (exception == kIllegalFunc3) {
(opcode == 7'b1100111) -> (func3 != 3'b000);
(opcode == 7'b1100011) -> (func3 inside {3'b010, 3'b011});
- (opcode == 7'b0000011) -> (func3 == 3'b111);
- (opcode == 7'b0100011) -> (func3 >= 3'b011);
+
+ if (XLEN == 32) {
+ (opcode == 7'b0100011) -> (func3 >= 3'b011);
+ (opcode == 7'b0000011) -> (func3 inside {3'b011, 3'b111});
+ } else {
+ (opcode == 7'b0100011) -> (func3 > 3'b011);
+ (opcode == 7'b0000011) -> (func3 == 3'b111);
+ }
(opcode == 7'b0001111) -> (!(func3 inside {3'b000, 3'b001}));
(opcode == 7'b1110011) -> (func3 == 3'b100);
(opcode == 7'b0011011) -> (!(func3 inside {3'b000, 3'b001, 3'b101}));
@@ -142,8 +153,13 @@
} else {
(opcode == 7'b1100111) -> (func3 == 3'b000);
(opcode == 7'b1100011) -> (!(func3 inside {3'b010, 3'b011}));
- (opcode == 7'b0000011) -> (func3 != 3'b111);
- (opcode == 7'b0100011) -> (func3 < 3'b011);
+ if (XLEN == 32) {
+ (opcode == 7'b0100011) -> (func3 < 3'b011);
+ (opcode == 7'b0000011) -> !(func3 inside {3'b011, 3'b111});
+ } else {
+ (opcode == 7'b0100011) -> (func3 <= 3'b011);
+ (opcode == 7'b0000011) -> (func3 != 3'b111);
+ }
(opcode == 7'b0001111) -> (func3 inside {3'b000, 3'b001});
(opcode == 7'b1110011) -> (func3 != 3'b100);
(opcode == 7'b0011011) -> (func3 inside {3'b000, 3'b001, 3'b101});
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_base.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_base.sv
index d371fcf..9f9bf87 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_base.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_base.sv
@@ -18,7 +18,6 @@
rand riscv_instr_group_t group;
rand riscv_instr_format_t format;
- rand bit [3:0] latency;
rand riscv_instr_cateogry_t category;
rand riscv_instr_name_t instr_name;
rand bit [11:0] csr;
@@ -30,6 +29,8 @@
rand imm_t imm_type;
rand bit [4:0] imm_len;
rand bit is_pseudo_instr;
+ rand bit aq;
+ rand bit rl;
bit is_branch_target;
bit has_label = 1'b1;
bit atomic = 0;
@@ -38,27 +39,20 @@
bit is_compressed;
bit is_illegal_instr;
bit is_hint_instr;
-
+ bit has_imm;
+ bit has_rs1;
+ bit has_rs2;
+ bit has_rd;
+ bit [31:0] imm_mask = '1;
string imm_str;
string comment;
string label;
bit is_local_numeric_label;
int idx = -1;
- `uvm_object_utils_begin(riscv_instr_base)
- `uvm_field_enum(riscv_instr_group_t, group, UVM_DEFAULT)
- `uvm_field_enum(riscv_instr_format_t, format, UVM_DEFAULT)
- `uvm_field_enum(riscv_instr_cateogry_t, category, UVM_DEFAULT)
- `uvm_field_enum(riscv_instr_name_t, instr_name, UVM_DEFAULT)
- `uvm_field_enum(riscv_reg_t, rs2, UVM_DEFAULT)
- `uvm_field_enum(riscv_reg_t, rs1, UVM_DEFAULT)
- `uvm_field_enum(riscv_reg_t, rd, UVM_DEFAULT)
- `uvm_field_int(imm, UVM_DEFAULT)
- `uvm_field_enum(imm_t, imm_type, UVM_DEFAULT)
- `uvm_object_utils_end
+ `uvm_object_utils(riscv_instr_base)
constraint default_c {
- soft latency == 1;
soft is_pseudo_instr == 0;
instr_name != INVALID_INSTR;
}
@@ -106,6 +100,10 @@
}
}
+ constraint aq_rl_c {
+ aq && rl == 0;
+ }
+
// Avoid generating HINT or illegal instruction by default as it's not supported by the compiler
constraint no_hint_illegal_instr_c {
if (instr_name inside {C_ADDI, C_ADDIW, C_LI, C_LUI, C_SLLI, C_SLLI64,
@@ -176,6 +174,20 @@
}
}
+ constraint rvc_csr_c {
+ // Registers specified by the three-bit rs1’, rs2’, and rd’ fields of the CIW, CL, CS,
+ // and CB formats
+ if(format inside {CIW_FORMAT, CL_FORMAT, CS_FORMAT, CB_FORMAT}) {
+ rs1 inside {[S0:A5]};
+ rs2 inside {[S0:A5]};
+ rd inside {[S0:A5]};
+ }
+ // C_ADDI16SP is only valid when rd == SP
+ if(instr_name == C_ADDI16SP) {
+ rd == SP;
+ }
+ }
+
//////////// RV32I instructions //////////////
// LOAD instructions
`add_instr(LB, I_FORMAT, LOAD, RV32I)
@@ -232,7 +244,7 @@
`add_instr(URET, I_FORMAT, SYSTEM, RV32I)
`add_instr(SRET, I_FORMAT, SYSTEM, RV32I)
`add_instr(MRET, I_FORMAT, SYSTEM, RV32I)
- `add_instr(WFI, I_FORMAT, SYSTEM, RV32I)
+ `add_instr(WFI, I_FORMAT, INTERRUPT, RV32I)
// CSR instructions
`add_instr(CSRRW, R_FORMAT, CSR, RV32I, UIMM)
`add_instr(CSRRS, R_FORMAT, CSR, RV32I, UIMM)
@@ -366,29 +378,123 @@
`add_instr(C_FLDSP, CI_FORMAT, LOAD, RV32DC, UIMM)
`add_instr(C_FSDSP, CSS_FORMAT, STORE, RV32DC, UIMM)
+ // RV32A
+ `add_instr(LR_W, R_FORMAT, LOAD, RV32A)
+ `add_instr(SC_W, R_FORMAT, STORE, RV32A)
+ `add_instr(AMOSWAP_W, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOADD_W, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOAND_W, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOOR_W, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOXOR_W, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOMIN_W, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOMAX_W, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOMINU_W, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOMAXU_W, R_FORMAT, AMO, RV32A)
+
+ // RV64A
+ `add_instr(LR_D, R_FORMAT, LOAD, RV32A)
+ `add_instr(SC_D, R_FORMAT, STORE, RV32A)
+ `add_instr(AMOSWAP_D, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOADD_D, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOAND_D, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOOR_D, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOXOR_D, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOMIN_D, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOMAX_D, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOMINU_D, R_FORMAT, AMO, RV32A)
+ `add_instr(AMOMAXU_D, R_FORMAT, AMO, RV32A)
+
// Supervisor Instructions
`add_instr(SFENCE_VMA, R_FORMAT,SYNCH,RV32I)
function void post_randomize();
+ if (group inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) begin
+ is_compressed = 1'b1;
+ end
+ if (!(format inside {R_FORMAT, CR_FORMAT})) begin
+ imm_mask = '1;
+ imm_mask = imm_mask << imm_len;
+ has_imm = 1'b1;
+ mask_imm();
+ if (imm_str == "") begin
+ update_imm_str();
+ end
+ end
+ if (format inside {R_FORMAT, S_FORMAT, B_FORMAT, CSS_FORMAT, CS_FORMAT}) begin
+ has_rs2 = 1'b1;
+ end
+ if (!(format inside {J_FORMAT, U_FORMAT, CJ_FORMAT, CSS_FORMAT})) begin
+ has_rs1 = 1'b1;
+ end
+ if (!(format inside {CJ_FORMAT, CB_FORMAT, CS_FORMAT, CSS_FORMAT, B_FORMAT, S_FORMAT})) begin
+ has_rd = 1'b1;
+ end
+ endfunction
+
+ function void mask_imm();
// Process the immediate value and sign extension
- bit [31:0] imm_mask = '1;
- imm_mask = imm_mask << imm_len;
- if(imm_type inside {UIMM, NZUIMM}) begin
+ if (imm_type inside {UIMM, NZUIMM}) begin
imm = imm & ~imm_mask;
end else begin
- if(imm[imm_len-1])
+ if (imm[imm_len-1]) begin
imm = imm | imm_mask;
- else
+ end else begin
imm = imm & ~imm_mask;
+ end
end
// Give a random value if imm is zero after masking unexpectedly
if((imm_type inside {NZIMM, NZUIMM}) && (imm == '0)) begin
imm = $urandom_range(2 ** (imm_len-1) - 1, 1);
end
- if (group inside {RV32C, RV64C, RV128C, RV32DC, RV32FC})
- is_compressed = 1'b1;
- if(imm_str == "")
- imm_str = $sformatf("%0d", $signed(imm));
+ endfunction
+
+ function void gen_rand_imm();
+ if (!randomize(imm)) begin
+ `uvm_fatal(`gfn, "Cannot randomize imm")
+ end
+ mask_imm();
+ update_imm_str();
+ endfunction
+
+ function void update_imm_str();
+ imm_str = $sformatf("%0d", $signed(imm));
+ endfunction
+
+ function void set_imm(int imm);
+ this.imm = imm;
+ mask_imm();
+ update_imm_str();
+ endfunction
+
+ function riscv_reg_t gen_rand_gpr(riscv_reg_t included_reg[] = {},
+ riscv_reg_t excluded_reg[] = {});
+ riscv_reg_t gpr;
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(gpr,
+ if (is_compressed) {
+ gpr inside {[S0:A5]};
+ }
+ if (excluded_reg.size() != 0) {
+ !(gpr inside {excluded_reg});
+ }
+ if (included_reg.size() != 0) {
+ gpr inside {included_reg};
+ })
+ return gpr;
+ endfunction
+
+ function void gen_rand_csr(bit illegal_csr_instr = 0,
+ privileged_mode_t privileged_mode = MACHINE_MODE);
+ if (illegal_csr_instr) begin
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(csr, !(csr inside {implemented_csr});)
+ end else begin
+ // Use scratch register to avoid the side effect of modifying other privileged mode CSR.
+ if (privileged_mode == MACHINE_MODE)
+ csr = MSCRATCH;
+ else if (privileged_mode == SUPERVISOR_MODE)
+ csr = SSCRATCH;
+ else
+ csr = USCRATCH;
+ end
endfunction
function new(string name = "");
@@ -408,7 +514,7 @@
virtual function string convert2asm(string prefix = "");
string asm_str;
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
- if(category != SYSTEM) begin
+ if((category != SYSTEM) && !(group inside {RV32A, RV64A})) begin
case(format)
J_FORMAT, U_FORMAT : // instr rd,imm
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm());
@@ -431,12 +537,13 @@
else
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rs1.name(), rs2.name(), get_imm());
R_FORMAT: // instr rd,rs1,rs2
- if(category == CSR)
+ if(category == CSR) begin
asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, rs1.name());
- else if(instr_name == SFENCE_VMA)
+ end else if(instr_name == SFENCE_VMA) begin
asm_str = "sfence.vma x0, x0"; // TODO: Support all possible sfence
- else
+ end else begin
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
+ end
CI_FORMAT, CIW_FORMAT:
if(instr_name == C_NOP)
asm_str = "c.nop";
@@ -458,6 +565,12 @@
CJ_FORMAT:
asm_str = $sformatf("%0s%0s", asm_str, get_imm());
endcase
+ end else if (group inside {RV32A, RV64A}) begin
+ if (instr_name inside {LR_W, LR_D}) begin
+ asm_str = $sformatf("%0s %0s, (%0s)", asm_str, rd.name(), rs1.name());
+ end else begin
+ asm_str = $sformatf("%0s %0s, %0s, (%0s)", asm_str, rd.name(), rs2.name(), rs1.name());
+ end
end else begin
// For EBREAK,C.EBREAK, making sure pc+4 is a valid instruction boundary
// This is needed to resume execution from epc+4 after ebreak handling
@@ -835,6 +948,14 @@
get_instr_name = instr_name.name();
if(get_instr_name.substr(0, 1) == "C_") begin
get_instr_name = {"c.", get_instr_name.substr(2, get_instr_name.len() - 1)};
+ end else if (group == RV32A) begin
+ get_instr_name = {get_instr_name.substr(0, get_instr_name.len() - 3), ".w"};
+ get_instr_name = aq ? {get_instr_name, ".aq"} :
+ rl ? {get_instr_name, ".rl"} : get_instr_name;
+ end else if (group == RV64A) begin
+ get_instr_name = {get_instr_name.substr(0, get_instr_name.len() - 3), ".d"};
+ get_instr_name = aq ? {get_instr_name, ".aq"} :
+ rl ? {get_instr_name, ".rl"} : get_instr_name;
end
return get_instr_name;
endfunction
@@ -856,6 +977,30 @@
end
endfunction
+ // Copy the rand fields of the base instruction
+ virtual function void copy_base_instr(riscv_instr_base obj);
+ this.group = obj.group;
+ this.format = obj.format;
+ this.category = obj.category;
+ this.instr_name = obj.instr_name;
+ this.rs2 = obj.rs2;
+ this.rs1 = obj.rs1;
+ this.rd = obj.rd;
+ this.imm = obj.imm;
+ this.imm_type = obj.imm_type;
+ this.imm_len = obj.imm_len;
+ this.imm_mask = obj.imm_mask;
+ this.imm_str = obj.imm_str;
+ this.is_pseudo_instr = obj.is_pseudo_instr;
+ this.aq = obj.aq;
+ this.rl = obj.rl;
+ this.is_compressed = obj.is_compressed;
+ this.has_imm = obj.has_imm;
+ this.has_rs1 = obj.has_rs1;
+ this.has_rs2 = obj.has_rs2;
+ this.has_rd = obj.has_rd;
+ endfunction
+
endclass
// Psuedo instructions are used to simplify assembly program writing
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv
index ead5225..7ce2bc9 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv
@@ -30,6 +30,12 @@
// Instruction count of each sub-program
rand int sub_program_instr_cnt[];
+ // Instruction count of the debug rom
+ rand int debug_program_instr_cnt;
+
+ // Instruction count of debug sub-programs
+ rand int debug_sub_program_instr_cnt[];
+
// Pattern of data section: RAND_DATA, ALL_ZERO, INCR_VAL
rand data_pattern_t data_page_pattern;
@@ -52,6 +58,7 @@
rand bit mstatus_mxr;
rand bit mstatus_sum;
rand bit mstatus_tvm;
+ rand mtvec_mode_t mtvec_mode;
// Enable sfence.vma instruction
rand bit enable_sfence;
@@ -63,6 +70,14 @@
bit check_xstatus = 1'b1;
//-----------------------------------------------------------------------------
+ // Instruction list based on the config, generate by build_instruction_template
+ //-----------------------------------------------------------------------------
+ riscv_instr_base instr_template[riscv_instr_name_t];
+ riscv_instr_name_t basic_instr[$];
+ riscv_instr_name_t instr_group[riscv_instr_cateogry_t][$];
+ riscv_instr_name_t instr_category[riscv_instr_cateogry_t][$];
+
+ //-----------------------------------------------------------------------------
// Command line options or control knobs
//-----------------------------------------------------------------------------
// Main options for RISC-V assembly program generation
@@ -79,6 +94,7 @@
bit no_ebreak = 1; // No ebreak instruction
bit no_fence; // No fence instruction
bit no_wfi = 1; // No WFI instruction
+ bit enable_unaligned_load_store;
bit enable_illegal_instruction;
bit enable_hint_instruction;
int bin_program_instr_cnt = 200;
@@ -101,6 +117,20 @@
bit force_m_delegation = 0;
bit force_s_delegation = 0;
bit support_supervisor_mode;
+ // "Memory mapped" address that when written to will indicate some event to
+ // the testbench - testbench will take action based on the value written
+ int signature_addr = 32'hdead_beef;
+ bit require_signature_addr = 1'b0;
+ rand riscv_reg_t signature_addr_reg;
+ rand riscv_reg_t signature_data_reg;
+ bit gen_debug_section = 1'b0;
+ // Enable a full or empty debug_rom section.
+ // Full debug_rom will contain random instruction streams.
+ // Empty debug_rom will contain just dret instruction and will return immediately.
+ // Will be empty by default.
+ bit empty_debug_section = 1'b0;
+ // Number of sub programs in the debug rom
+ int num_debug_sub_program = 0;
// Stack space allocated to each program, need to be enough to store necessary context
// Example: RA, SP, T0, loop registers
int min_stack_len_per_program = 10 * (XLEN/8);
@@ -122,10 +152,21 @@
constraint default_c {
sub_program_instr_cnt.size() == num_of_sub_program;
- main_program_instr_cnt + sub_program_instr_cnt.sum() == instr_cnt;
- main_program_instr_cnt inside {[1 : instr_cnt]};
+ debug_sub_program_instr_cnt.size() == num_debug_sub_program;
+ if (riscv_instr_pkg::support_debug_mode) {
+ main_program_instr_cnt + sub_program_instr_cnt.sum()
+ + debug_program_instr_cnt
+ + debug_sub_program_instr_cnt.sum() == instr_cnt;
+ debug_program_instr_cnt inside {[100 : 300]};
+ foreach(debug_sub_program_instr_cnt[i]) {
+ debug_sub_program_instr_cnt[i] inside {[100 : 300]};
+ }
+ } else {
+ main_program_instr_cnt + sub_program_instr_cnt.sum() == instr_cnt;
+ }
+ main_program_instr_cnt inside {[10 : instr_cnt]};
foreach(sub_program_instr_cnt[i]) {
- sub_program_instr_cnt[i] inside {[1 : instr_cnt]};
+ sub_program_instr_cnt[i] inside {[10 : instr_cnt]};
}
// Disable sfence if the program is not boot to supervisor mode
// If sfence exception is allowed, we can enable sfence instruction in any priviledged mode.
@@ -154,6 +195,10 @@
}
}
+ constraint mtvec_c {
+ mtvec_mode inside {supported_interrupt_mode};
+ }
+
constraint mstatus_c {
// This is default disabled at setup phase. It can be enabled in the exception and interrupt
// handling routine
@@ -210,6 +255,9 @@
foreach(loop_regs[i]) {
!(loop_regs[i] inside {default_reserved_regs});
}
+ !(signature_addr_reg inside {ZERO, default_reserved_regs, loop_regs});
+ !(signature_data_reg inside {ZERO, default_reserved_regs, loop_regs});
+ signature_addr_reg != signature_data_reg;
}
constraint legal_loop_regs_c {
@@ -249,10 +297,17 @@
get_bool_arg_value("+no_directed_instr=", no_directed_instr);
get_bool_arg_value("+no_fence=", no_fence);
get_bool_arg_value("+no_delegation=", no_delegation);
+ get_bool_arg_value("+enable_unaligned_load_store=", enable_unaligned_load_store);
get_bool_arg_value("+enable_illegal_instruction=", enable_illegal_instruction);
get_bool_arg_value("+enable_hint_instruction=", enable_hint_instruction);
get_bool_arg_value("+force_m_delegation=", force_m_delegation);
get_bool_arg_value("+force_s_delegation=", force_s_delegation);
+ get_bool_arg_value("+require_signature_addr=", require_signature_addr);
+ if (this.require_signature_addr) begin
+ get_hex_arg_value("+signature_addr=", signature_addr);
+ end
+ get_bool_arg_value("+gen_debug_section=", gen_debug_section);
+ get_int_arg_value("+num_debug_sub_program=", num_debug_sub_program);
if(inst.get_arg_value("+boot_mode=", boot_mode_opts)) begin
`uvm_info(get_full_name(), $sformatf(
"Got boot mode option - %0s", boot_mode_opts), UVM_LOW)
@@ -276,7 +331,8 @@
uvm_split_string(s, ",", cmdline_march_list);
riscv_instr_pkg::supported_isa.delete();
foreach(cmdline_march_list[i]) begin
- if(uvm_enum_wrapper#(riscv_instr_group_t)::from_name(cmdline_march_list[i], march)) begin
+ if(uvm_enum_wrapper#(riscv_instr_group_t)::from_name(
+ cmdline_march_list[i].toupper(), march)) begin
riscv_instr_pkg::supported_isa.push_back(march);
end else begin
`uvm_fatal(get_full_name(), $sformatf(
@@ -361,15 +417,80 @@
// Get an integer argument from comand line
function void get_int_arg_value(string cmdline_str, ref int val);
string s;
- if(inst.get_arg_value(cmdline_str, s))
+ if(inst.get_arg_value(cmdline_str, s)) begin
val = s.atoi();
+ end
endfunction
// Get a bool argument from comand line
function void get_bool_arg_value(string cmdline_str, ref bit val);
string s;
- if(inst.get_arg_value(cmdline_str, s))
+ if(inst.get_arg_value(cmdline_str, s)) begin
val = s.atobin();
+ end
+ endfunction
+
+ // Get a hex argument from command line
+ function void get_hex_arg_value(string cmdline_str, ref int val);
+ string s;
+ if(inst.get_arg_value(cmdline_str, s)) begin
+ val = s.atohex();
+ end
+ endfunction
+
+ // Build instruction template
+ virtual function void build_instruction_template();
+ riscv_instr_name_t instr_name;
+ riscv_instr_name_t excluded_instr[$];
+ get_excluded_instr(excluded_instr);
+ instr_name = instr_name.first;
+ do begin
+ riscv_instr_base instr;
+ if (!(instr_name inside {unsupported_instr, excluded_instr})) begin
+ instr = riscv_instr_base::type_id::create("instr");
+ `DV_CHECK_RANDOMIZE_WITH_FATAL(instr, instr_name == local::instr_name;)
+ if (instr.group inside {supported_isa}) begin
+ `uvm_info(`gfn, $sformatf("Adding [%s] %s to the list",
+ instr.group.name(), instr.instr_name.name()), UVM_HIGH)
+ if (instr.category inside {SHIFT, ARITHMETIC, LOGICAL, COMPARE}) begin
+ basic_instr.push_back(instr_name);
+ end
+ instr_group[instr.group].push_back(instr_name);
+ instr_category[instr.category].push_back(instr_name);
+ instr_template[instr_name] = instr;
+ end
+ end
+ instr_name = instr_name.next;
+ end
+ while (instr_name != instr_name.first);
+ if (no_ebreak == 0) begin
+ basic_instr = {basic_instr, EBREAK};
+ end
+ if (no_fence == 0) begin
+ basic_instr = {basic_instr, instr_category[SYNCH]};
+ end
+ // TODO: Support CSR instruction in other mode
+ if ((no_csr_instr == 0) && (init_privileged_mode == MACHINE_MODE)) begin
+ basic_instr = {basic_instr, instr_category[CSR]};
+ end
+ if (no_wfi == 0) begin
+ basic_instr = {basic_instr, WFI};
+ end
+ endfunction
+
+ virtual function void get_excluded_instr(ref riscv_instr_name_t excluded[$]);
+ excluded = {excluded, INVALID_INSTR};
+ // Below instrutions will modify stack pointer, not allowed in normal instruction stream.
+ // It can be used in stack operation instruction stream.
+ excluded = {excluded, C_SWSP, C_SDSP, C_ADDI16SP};
+ if (!enable_sfence) begin
+ excluded = {excluded, SFENCE_VMA};
+ end
+ if (no_fence) begin
+ excluded = {excluded, FENCE, FENCEI, SFENCE_VMA};
+ end
+ // TODO: Support C_ADDI4SPN
+ excluded = {excluded, C_ADDI4SPN};
endfunction
endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_pkg.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_pkg.sv
index 6b035a2..d76ae8a 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_pkg.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_pkg.sv
@@ -17,6 +17,7 @@
package riscv_instr_pkg;
import uvm_pkg::*;
+ import riscv_signature_pkg::*;
`include "uvm_macros.svh"
`include "dv_defines.svh"
@@ -33,6 +34,11 @@
SV64 = 4'b1011
} satp_mode_t;
+ typedef enum bit [1:0] {
+ DIRECT = 2'b00,
+ VECTORED = 2'b01
+ } mtvec_mode_t;
+
typedef enum bit [2:0] {
IMM, // Signed immediate
UIMM, // Unsigned immediate
@@ -230,6 +236,30 @@
C_FSD,
C_FLDSP,
C_FSDSP,
+ // RV32A
+ LR_W,
+ SC_W,
+ AMOSWAP_W,
+ AMOADD_W,
+ AMOAND_W,
+ AMOOR_W,
+ AMOXOR_W,
+ AMOMIN_W,
+ AMOMAX_W,
+ AMOMINU_W,
+ AMOMAXU_W,
+ // RV64A
+ LR_D,
+ SC_D,
+ AMOSWAP_D,
+ AMOADD_D,
+ AMOAND_D,
+ AMOOR_D,
+ AMOXOR_D,
+ AMOMIN_D,
+ AMOMAX_D,
+ AMOMINU_D,
+ AMOMAXU_D,
// Supervisor instruction
MRET,
URET,
@@ -310,7 +340,8 @@
CSR,
CHANGELEVEL,
TRAP,
- INTERRUPT
+ INTERRUPT,
+ AMO
} riscv_instr_cateogry_t;
typedef bit [11:0] riscv_csr_t;
@@ -729,7 +760,7 @@
// need to use the virtual address to access the kernel stack.
if((status == MSTATUS) && (SATP_MODE != BARE)) begin
// We temporarily use tp to check mstatus to avoid changing other GPR. The value of sp has
- // been saved to xStatus and can be restored later.
+ // been saved to xScratch and can be restored later.
if(mprv) begin
instr.push_back($sformatf("csrr tp, 0x%0x // MSTATUS", status));
instr.push_back("srli tp, tp, 11"); // Move MPP to bit 0
@@ -769,6 +800,7 @@
end
endfunction
+ `include "riscv_instr_base.sv"
`include "riscv_instr_gen_config.sv"
`include "riscv_illegal_instr.sv"
`include "riscv_reg.sv"
@@ -779,13 +811,13 @@
`include "riscv_page_table_list.sv"
`include "riscv_privileged_common_seq.sv"
`include "riscv_callstack_gen.sv"
- `include "riscv_instr_base.sv"
`include "riscv_data_page_gen.sv"
`include "riscv_rand_instr.sv"
`include "riscv_instr_stream.sv"
`include "riscv_loop_instr.sv"
`include "riscv_directed_instr_lib.sv"
`include "riscv_load_store_instr_lib.sv"
+ `include "riscv_amo_instr_lib.sv"
`include "riscv_instr_sequence.sv"
`include "riscv_asm_program_gen.sv"
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_sequence.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_sequence.sv
index cd7fac9..b29be22 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_sequence.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_sequence.sv
@@ -40,6 +40,7 @@
riscv_pop_stack_instr instr_stack_exit; // Stack pop instructions for sub-programs
riscv_rand_instr_stream instr_stream; // Main instruction streams
bit is_main_program; // Type of this sequence (main or sub program)
+ bit is_debug_program; // Indicates whether sequence is debug program
string label_name; // Label of the sequence (program name)
riscv_instr_gen_config cfg; // Configuration class handle
string instr_string_list[$]; // Save the instruction list in string format
@@ -47,7 +48,6 @@
riscv_instr_stream directed_instr[]; // List of all directed instruction stream
riscv_illegal_instr illegal_instr; // Illegal instruction generator
int illegal_instr_pct; // Percentage of illegal instruction
- bit enable_hint_instr; // Enable HINT instruction
int hint_instr_pct; // Percentage of HINT instruction
`uvm_object_utils(riscv_instr_sequence)
@@ -70,7 +70,7 @@
// considerably as the instruction stream becomes longer. The downside is we cannot specify
// constraints between instructions. The way to solve it is to have a dedicated directed
// instruction stream for such scenarios, like hazard sequence.
- virtual function void gen_instr(bit is_main_program, bit enable_hint_instr = 1'b0);
+ virtual function void gen_instr(bit is_main_program, bit no_branch = 1'b0);
this.is_main_program = is_main_program;
instr_stream.cfg = cfg;
instr_stream.initialize_instr_list(instr_cnt);
@@ -78,7 +78,7 @@
instr_stream.instr_list.size()), UVM_LOW)
// Do not generate load/store instruction here
// The load/store instruction will be inserted as directed instruction stream
- instr_stream.gen_instr(.no_load_store(1'b1), .enable_hint_instr(enable_hint_instr));
+ instr_stream.gen_instr(.no_branch(no_branch), .no_load_store(1'b1));
if(!is_main_program) begin
gen_stack_enter_instr();
gen_stack_exit_instr();
@@ -91,6 +91,7 @@
// pointer(SP) is reduced by the amount the stack space allocated to this program.
function void gen_stack_enter_instr();
bit allow_branch = ((illegal_instr_pct > 0) || (hint_instr_pct > 0)) ? 1'b0 : 1'b1;
+ allow_branch &= !cfg.no_branch_jump;
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(program_stack_len,
program_stack_len inside {[cfg.min_stack_len_per_program : cfg.max_stack_len_per_program]};
// Keep stack len word aligned to avoid unaligned load/store
@@ -234,21 +235,25 @@
jump_instr.jump.rd == RA;
},
"Cannot randomize jump_instr")
- `uvm_info(get_full_name(), $sformatf("%0s -> %0s",
- jump_instr.jump.instr_name.name(), label_name), UVM_HIGH)
instr_stream.insert_instr_stream(jump_instr.instr_list);
+ `uvm_info(get_full_name(), $sformatf("%0s -> %0s...done",
+ jump_instr.jump.instr_name.name(), label_name), UVM_LOW)
endfunction
// Convert the instruction stream to the string format.
// Label is attached to the instruction if available, otherwise attach proper space to make
// the code indent consistent.
- function void generate_instr_stream();
+ function void generate_instr_stream(bit no_label = 1'b0);
string prefix, str;
int i;
instr_string_list = {};
for(i = 0; i < instr_stream.instr_list.size(); i++) begin
if(i == 0) begin
- prefix = format_string($sformatf("%0s:", label_name), LABEL_STR_LEN);
+ if (no_label) begin
+ prefix = format_string(" ", LABEL_STR_LEN);
+ end else begin
+ prefix = format_string($sformatf("%0s:", label_name), LABEL_STR_LEN);
+ end
instr_stream.instr_list[i].has_label = 1'b1;
end else begin
if(instr_stream.instr_list[i].has_label) begin
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_stream.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_stream.sv
index 77c2141..3441c7b 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_stream.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_stream.sv
@@ -23,6 +23,8 @@
rand riscv_instr_base instr_list[$];
int unsigned instr_cnt;
string label = "";
+ // User can specify a small group of available registers to generate various hazard condition
+ rand riscv_reg_t avail_regs[];
`uvm_object_utils(riscv_instr_stream)
`uvm_object_new
@@ -64,11 +66,27 @@
function void insert_instr_stream(riscv_instr_base new_instr[], int idx = -1, bit replace = 1'b0);
int current_instr_cnt = instr_list.size();
int new_instr_cnt = new_instr.size();
+ if(current_instr_cnt == 0) begin
+ instr_list = new_instr;
+ return;
+ end
if(idx == -1) begin
idx = $urandom_range(0, current_instr_cnt-1);
- while(instr_list[idx].atomic) begin
+ repeat(10) begin
+ if (instr_list[idx].atomic) break;
idx = $urandom_range(0, current_instr_cnt-1);
end
+ if (instr_list[idx].atomic) begin
+ foreach (instr_list[i]) begin
+ if (!instr_list[i].atomic) begin
+ idx = i;
+ break;
+ end
+ end
+ if (instr_list[idx].atomic) begin
+ `uvm_fatal(`gfn, $sformatf("Cannot inject the instruction"))
+ end
+ end
end else if((idx > current_instr_cnt) || (idx < 0)) begin
`uvm_error(`gfn, $sformatf("Cannot insert instr stream at idx %0d", idx))
end
@@ -129,10 +147,11 @@
bit access_u_mode_mem = 1'b1;
int max_load_store_offset;
int max_data_page_id;
+ riscv_instr_name_t allowed_instr[$];
// Some additional reserved registers that should not be used as rd register
// by this instruction stream
- riscv_reg_t reserved_rd[];
+ riscv_reg_t reserved_rd[];
constraint avoid_reserved_rd_c {
if(reserved_rd.size() > 0) {
@@ -146,14 +165,9 @@
`uvm_object_new
virtual function void create_instr_instance();
- riscv_rand_instr instr;
- if(cfg == null) begin
- `uvm_fatal(get_full_name(), "cfg object is null")
- end
+ riscv_instr_base instr;
for(int i = 0; i < instr_cnt; i++) begin
- instr = riscv_rand_instr::type_id::create($sformatf("instr_%0d", i));
- instr.cfg = cfg;
- instr.reserved_rd = reserved_rd;
+ instr = riscv_instr_base::type_id::create($sformatf("instr_%0d", i));
instr_list.push_back(instr);
end
endfunction
@@ -168,18 +182,69 @@
end
endfunction
- virtual function void gen_instr(bit no_branch = 1'b0,
- bit no_load_store = 1'b1,
- bit enable_hint_instr = 1'b0);
+ virtual function setup_allowed_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1);
+ allowed_instr = cfg.basic_instr;
+ if (no_branch == 0) begin
+ allowed_instr = {allowed_instr, cfg.instr_category[BRANCH]};
+ end
+ if (no_load_store == 0) begin
+ allowed_instr = {allowed_instr, cfg.instr_category[LOAD], cfg.instr_category[STORE]};
+ end
+ endfunction
+
+ virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1);
+ setup_allowed_instr(no_branch, no_load_store);
foreach(instr_list[i]) begin
- `DV_CHECK_RANDOMIZE_WITH_FATAL(instr_list[i],
- // The last instruction cannot be branch instruction as there's no forward branch target.
- if((i == instr_list.size() - 1) || no_branch) {
- category != BRANCH;
- }
- if(no_load_store) {
- !(category inside {LOAD, STORE});
- })
+ randomize_instr(instr_list[i]);
+ end
+ // Do not allow branch instruction as the last instruction because there's no
+ // forward branch target
+ while (instr_list[$].category == BRANCH) begin
+ void'(instr_list.pop_back());
+ if (instr_list.size() == 0) break;
+ end
+ endfunction
+
+ function void randomize_instr(riscv_instr_base instr,
+ bit skip_rs1 = 1'b0,
+ bit skip_rs2 = 1'b0,
+ bit skip_rd = 1'b0,
+ bit skip_imm = 1'b0,
+ bit skip_csr = 1'b0);
+ riscv_instr_name_t instr_name;
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name,
+ instr_name inside {allowed_instr};)
+ instr.copy_base_instr(cfg.instr_template[instr_name]);
+ `uvm_info(`gfn, $sformatf("%s: rs1:%0d, rs2:%0d, rd:%0d, imm:%0d",
+ instr.instr_name.name(),
+ instr.has_rs1,
+ instr.has_rs2,
+ instr.has_rd,
+ instr.has_imm), UVM_HIGH)
+ if (instr.has_imm && !skip_imm) begin
+ instr.gen_rand_imm();
+ end
+ if (instr.has_rs1 && !skip_rs1) begin
+ if (instr.is_compressed) begin
+ // Compressed instruction could use the same register for rs1 and rd
+ instr.rs1 = instr.gen_rand_gpr(
+ .included_reg(avail_regs),
+ .excluded_reg({reserved_rd, cfg.reserved_regs}));
+ end else begin
+ instr.rs1 = instr.gen_rand_gpr(.included_reg(avail_regs));
+ end
+ end
+ if (instr.has_rs2 && !skip_rs2) begin
+ instr.rs2 = instr.gen_rand_gpr(.included_reg(avail_regs));
+ end
+ if (instr.has_rd && !skip_rd) begin
+ instr.rd = instr.gen_rand_gpr(
+ .included_reg(avail_regs),
+ .excluded_reg({reserved_rd, cfg.reserved_regs}));
+ end
+ if ((instr.category == CSR) && !skip_csr) begin
+ instr.gen_rand_csr(.privileged_mode(cfg.init_privileged_mode),
+ .illegal_csr_instr(cfg.enable_illegal_csr_instruction));
end
endfunction
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv
index 5ed069f..f019616 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv
@@ -15,7 +15,6 @@
*/
// Base class for all load/store instruction stream
-// TODO: Support load/store from instruction section.
class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream;
@@ -26,9 +25,6 @@
rand int addr[];
rand int unsigned data_page_id;
rand riscv_reg_t rs1_reg;
- riscv_reg_t reserved_rd[$];
- // User can specify a small group of available registers to generate various hazard condition
- rand riscv_reg_t avail_regs[];
`uvm_object_utils(riscv_load_store_base_instr_stream)
@@ -58,11 +54,11 @@
endfunction
function void post_randomize();
- gen_load_store_instr();
// rs1 cannot be modified by other instructions
if(!(rs1_reg inside {reserved_rd})) begin
- reserved_rd.push_back(rs1_reg);
+ reserved_rd = {reserved_rd, rs1_reg};
end
+ gen_load_store_instr();
add_mixed_instr();
add_rs1_init_la_instr();
super.post_randomize();
@@ -86,68 +82,77 @@
// Generate each load/store instruction
virtual function void gen_load_store_instr();
- riscv_rand_instr rand_instr;
- riscv_instr_name_t allowed_instr[];
+ bit enable_compressed_load_store;
+ riscv_instr_base instr;
if(avail_regs.size() > 0) begin
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(avail_regs,
unique{avail_regs};
+ avail_regs[0] inside {[S0 : A5]};
foreach(avail_regs[i]) {
- !(avail_regs[i] inside {cfg.reserved_regs});
+ !(avail_regs[i] inside {cfg.reserved_regs, reserved_rd});
},
"Cannot randomize avail_regs")
end
+ if (rs1_reg inside {[S0 : A5]}) begin
+ enable_compressed_load_store = 1;
+ end
foreach(addr[i]) begin
- rand_instr = riscv_rand_instr::type_id::create("rand_instr");
- rand_instr.cfg = cfg;
- rand_instr.reserved_rd = reserved_rd;
+ instr = riscv_instr_base::type_id::create("instr");
// Assign the allowed load/store instructions based on address alignment
// This is done separately rather than a constraint to improve the randomization performance
allowed_instr = {LB, LBU, SB};
if (addr[i][0] == 1'b0) begin
allowed_instr = {LH, LHU, SH, allowed_instr};
end
- if (addr[i][1:0] == 2'b00) begin
- allowed_instr = {LW, SW, LWU, allowed_instr};
- if((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0)) begin
+ if (!cfg.enable_unaligned_load_store) begin
+ if (addr[i][1:0] == 2'b00) begin
+ allowed_instr = {LW, SW, allowed_instr};
+ if((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0) &&
+ (RV32C inside {riscv_instr_pkg::supported_isa}) &&
+ enable_compressed_load_store) begin
+ allowed_instr = {C_LW, C_SW, allowed_instr};
+ end
+ end
+ if ((XLEN >= 64) && (addr[i][2:0] == 3'b000)) begin
+ allowed_instr = {LWU, LD, SD, allowed_instr};
+ if((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0) &&
+ (RV64C inside {riscv_instr_pkg::supported_isa} &&
+ enable_compressed_load_store)) begin
+ allowed_instr = {C_LD, C_SD, allowed_instr};
+ end
+ end
+ end else begin
+ allowed_instr = {LW, SW, allowed_instr};
+ if ((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0) &&
+ (RV32C inside {riscv_instr_pkg::supported_isa}) &&
+ enable_compressed_load_store) begin
allowed_instr = {C_LW, C_SW, allowed_instr};
end
- end
- if(addr[i][2:0] == 3'b000) begin
- allowed_instr = {LD, SD, allowed_instr};
- if((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0)) begin
- allowed_instr = {C_LD, C_SD, allowed_instr};
+ if (XLEN >= 64) begin
+ allowed_instr = {LWU, LD, SD, allowed_instr};
+ if ((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0) &&
+ (RV64C inside {riscv_instr_pkg::supported_isa}) &&
+ enable_compressed_load_store) begin
+ allowed_instr = {C_LD, C_SD, allowed_instr};
+ end
end
end
- `DV_CHECK_RANDOMIZE_WITH_FATAL(rand_instr,
- solve rs1 before rd;
- rs1 == rs1_reg;
- instr_name inside {allowed_instr};
- if(avail_regs.size() > 0) {
- rd inside {avail_regs};
- }
- rd != rs1;
- )
- rand_instr.process_load_store = 0;
- rand_instr.imm_str = $sformatf("%0d", offset[i]);
- instr_list.push_back(rand_instr);
+ randomize_instr(instr, .skip_rs1(1'b1), .skip_imm(1'b1));
+ instr.rs1 = rs1_reg;
+ instr.set_imm(offset[i]);
+ instr.process_load_store = 0;
+ instr_list.push_back(instr);
end
endfunction
// Insert some other instructions to mix with load/store instruction
virtual function void add_mixed_instr();
- riscv_rand_instr rand_instr;
+ riscv_instr_base instr;
+ setup_allowed_instr(1, 1);
for(int i = 0; i < num_mixed_instr; i ++) begin
- rand_instr = riscv_rand_instr::type_id::create("rand_instr");
- rand_instr.cfg = cfg;
- rand_instr.reserved_rd = reserved_rd;
- `DV_CHECK_RANDOMIZE_WITH_FATAL(rand_instr,
- if(avail_regs.size() > 0) {
- rs1 inside {avail_regs};
- rd inside {avail_regs};
- }
- !(category inside {LOAD, STORE, BRANCH, JUMP});,
- "Cannot randomize instruction")
- insert_instr(rand_instr);
+ instr = riscv_instr_base::type_id::create("instr");
+ randomize_instr(instr);
+ insert_instr(instr);
end
endfunction
@@ -310,7 +315,8 @@
// Make sure each load/store sequence doesn't override the rs1 of other sequences.
foreach(rs1_reg[j]) begin
if(i != j) begin
- load_store_instr_stream[i].reserved_rd.push_back(rs1_reg[j]);
+ load_store_instr_stream[i].reserved_rd =
+ {load_store_instr_stream[i].reserved_rd, rs1_reg[j]};
end
end
`DV_CHECK_RANDOMIZE_WITH_FATAL(load_store_instr_stream[i],
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_list.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_list.sv
index 1b88b35..4a7b35d 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_list.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_list.sv
@@ -244,7 +244,7 @@
// 2. For normal test, a page table fault typically means the program is accessing a large
// virtual address which currently not mapped a valid physical address. Need to do a
// memcpy to move data from lower physical address to the place the virtual address map to.
- virtual function void gen_page_fault_handling_routine(output string instr[$]);
+ virtual function void gen_page_fault_handling_routine(ref string instr[$]);
int unsigned level;
string load_store_unit;
bit[XLEN-1:0] bit_mask = '1;
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_rand_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_rand_instr.sv
index 27c2b9c..b43f5fe 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_rand_instr.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_rand_instr.sv
@@ -23,12 +23,23 @@
`uvm_object_utils(riscv_rand_instr)
+ constraint category_c {
+ soft category inside {LOAD, STORE, SHIFT, ARITHMETIC, LOGICAL,
+ BRANCH, COMPARE, CSR, SYSTEM, SYNCH};
+ }
+
+ // Atomic extension instructions are default disabled
+ // AMO instruction generation is handled by riscv_amo_instr_lib.sv
+ constraint disable_a_extension_c {
+ group != RV32A;
+ group != RV64A;
+ }
+
constraint instr_c {
solve instr_name before imm;
solve instr_name before rs1;
solve instr_name before rs2;
!(instr_name inside {riscv_instr_pkg::unsupported_instr});
- category inside {LOAD, STORE, SHIFT, ARITHMETIC, LOGICAL, BRANCH, COMPARE, CSR, SYSTEM, SYNCH};
group inside {riscv_instr_pkg::supported_isa};
// Avoid using any special purpose register as rd, those registers are reserved for
// special instructions
@@ -57,20 +68,6 @@
instr_name != C_ADDI4SPN;
}
- constraint rvc_csr_c {
- // Registers specified by the three-bit rs1’, rs2’, and rd’ fields of the CIW, CL, CS,
- // and CB formats
- if(format inside {CIW_FORMAT, CL_FORMAT, CS_FORMAT, CB_FORMAT}) {
- rs1 inside {[S0:A5]};
- rs2 inside {[S0:A5]};
- rd inside {[S0:A5]};
- }
- // C_ADDI16SP is only valid when rd == SP
- if(instr_name == C_ADDI16SP) {
- rd == SP;
- }
- }
-
constraint constraint_cfg_knob_c {
if(cfg.no_ebreak) {
instr_name != EBREAK;
@@ -110,6 +107,14 @@
}
}
+ // No label is needed if there's no branch/jump instruction
+ function void post_randomize();
+ super.post_randomize();
+ if (cfg.no_branch_jump) begin
+ has_label = 1'b0;
+ end
+ endfunction
+
`uvm_object_new
endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_signature_pkg.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_signature_pkg.sv
new file mode 100644
index 0000000..45194d2
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_signature_pkg.sv
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package riscv_signature_pkg;
+
+ // Will be the lowest 8 bits of the data word
+ typedef enum bit[7:0] {
+ // Information sent to the core relating its current status.
+ // Bits [12:8] of the data word will be the core_status_t value
+ // corresponding to the current core status.
+ CORE_STATUS,
+ // Information sent to the core conveying the uvm simulation result.
+ // Bit [8] of the data word will be the test_result_t value.
+ TEST_RESULT,
+ // Sent to the core to indicate a dump of GPRs to testbench.
+ // Will be followed by 32 writes of registers x0-x32.
+ WRITE_GPR,
+ // Sent to the core to indicate a write of a CSR's data.
+ // Bits [19:8] of the data word will be the CSR address.
+ // Will be followed by a second write of the actual data from the CSR.
+ WRITE_CSR
+ } signature_type_t;
+
+ typedef enum bit[4:0] {
+ INITIALIZED,
+ IN_DEBUG_MODE,
+ IN_MACHINE_MODE,
+ IN_HYPERVISOR_MODE,
+ IN_SUPERVISOR_MODE,
+ IN_USER_MODE,
+ HANDLING_IRQ,
+ HANDLING_EXCEPTION
+ } core_status_t;
+
+ typedef enum bit {
+ TEST_PASS,
+ TEST_FAIL
+ } test_result_t;
+
+
+endpackage
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_base_test.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_base_test.sv
index d878c49..f1d8186 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_base_test.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_base_test.sv
@@ -64,20 +64,21 @@
endfunction
function void get_directed_instr_stream_opts();
- string instr_name;
- int ratio;
string cmd_opts_prefix;
+ string opts;
+ string opt[$];
int i = 0;
while(1) begin
cmd_opts_prefix = $sformatf("directed_instr_%0d", i);
- if($value$plusargs({cmd_opts_prefix, "=%0s"}, instr_name) &&
- $value$plusargs({cmd_opts_prefix, "_ratio=%0d"}, ratio)) begin
- asm_gen.add_directed_instr_stream(instr_name, ratio);
+ if($value$plusargs({cmd_opts_prefix, "=%0s"}, opts)) begin
+ uvm_split_string(opts, ",", opt);
+ `DV_CHECK_FATAL(opt.size() == 2)
+ asm_gen.add_directed_instr_stream(opt[0], opt[1].atoi());
end else begin
break;
end
- `uvm_info(`gfn, $sformatf("Got directed instr[%0d] %0s, ratio = %0d/1000",
- i, instr_name, ratio), UVM_LOW)
+ `uvm_info(`gfn, $sformatf("Got directed instr[%0d] %0s, ratio = %0s/1000",
+ i, opt[0], opt[1]), UVM_LOW)
i++;
end
@@ -98,6 +99,7 @@
test_name = $sformatf("%0s.%0d.S", asm_file_name, i);
apply_directed_instr();
`uvm_info(`gfn, "All directed instruction is applied", UVM_LOW)
+ cfg.build_instruction_template();
asm_gen.gen_program();
asm_gen.gen_test_file(test_name);
end
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv
index 8761448..e4be2f4 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv
@@ -14,120 +14,6 @@
* limitations under the License.
*/
-//================================================================================================
-// RISC-V Test Library
-//------------------------------------------------------------------------------------------------
-// riscv_arithmetic_basic_test :
-// - Simple arithmetic instruction test, [machine mode]
-//
-// riscv_machine_mode_rand_test :
-// - Random instruction test, include sub-programs, branch, load/store [machine mode]
-//
-// riscv_privileged_mode_rand_test :
-// - Similar to riscv_machine_mode_rand_test, run in supervisor mode or user mode if supported
-//
-// riscv_rand_instr_test :
-// - A full random test, with a mix of directed instruction stream
-//
-// riscv_rand_jump_test :
-// - Random jump among a large number of sub programs
-//
-// riscv_mmu_stress_test:
-// - A mixed of intense load/store instructions
-//
-// riscv_page_table_exception_test:
-// - Running test in privileged mode with page table exceptions
-//
-// riscv_no_fence_test
-// - Random instruction with fence disabled, allow more intense instruction execution
-//
-// riscv_sfence_exception_test
-// - Random instruction with sfence exception. sfence.vma could be excuted in non-supervisor mode
-// or mstatus.tvm is set.
-//
-// riscv_illegal_instr_test:
-// - Random instruction mixed with illegal instructions
-//
-// riscv_hint_instr_test:
-// - Random instruction mixed with HINT instructions
-//
-// riscv_ebreak_test:
-// - Randomly inject ebreak instruction, verify core can be halted and resumed properly
-//
-// riscv_wfi_test:
-// - Randomly inject wfi instruction, verify core can be halted and resumed properly(by interrupt)
-//
-// riscv_csr_test:
-// - Random instructions with CSR intruction enabled
-//
-// riscv_illegal_csr_test:
-// - Accessing non-existence CSR or CSR with the wrong privileged mode
-//
-//================================================================================================
-
-class riscv_arithmetic_basic_test extends riscv_instr_base_test;
-
- `uvm_component_utils(riscv_arithmetic_basic_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.instr_cnt = 10000;
- cfg.num_of_sub_program = 0;
- cfg.no_fence = 1;
- cfg.no_data_page = 1'b1;
- cfg.no_branch_jump = 1'b1;
- `DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
- init_privileged_mode == MACHINE_MODE;
- max_nested_loop == 0;)
- `uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
- cfg.sprint()), UVM_LOW)
- endfunction
-
-endclass
-
-class riscv_machine_mode_rand_test extends riscv_instr_base_test;
-
- `uvm_component_utils(riscv_machine_mode_rand_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.instr_cnt = 10000;
- cfg.num_of_sub_program = 5;
- `DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
- init_privileged_mode == MACHINE_MODE;
- max_nested_loop == 0;)
- `uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
- cfg.sprint()), UVM_LOW)
- endfunction
-
- virtual function void apply_directed_instr();
- // Add load/store instruction stream
- asm_gen.add_directed_instr_stream("riscv_load_store_rand_instr_stream", 10);
- endfunction
-
-endclass
-
-class riscv_privileged_mode_rand_test extends riscv_instr_base_test;
-
- `uvm_component_utils(riscv_privileged_mode_rand_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.instr_cnt = 10000;
- cfg.num_of_sub_program = 5;
- `DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
- init_privileged_mode != MACHINE_MODE;
- max_nested_loop == 0;)
- `uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
- cfg.sprint()), UVM_LOW)
- endfunction
-
- virtual function void apply_directed_instr();
- // Add load/store instruction stream
- asm_gen.add_directed_instr_stream("riscv_load_store_rand_instr_stream", 10);
- endfunction
-
-endclass
class riscv_rand_instr_test extends riscv_instr_base_test;
@@ -154,142 +40,3 @@
endfunction
endclass
-
-class riscv_rand_jump_test extends riscv_instr_base_test;
-
- `uvm_component_utils(riscv_rand_jump_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.instr_cnt = 20000;
- cfg.num_of_sub_program = 20;
- `DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
- max_nested_loop == 1;)
- `uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
- cfg.sprint()), UVM_LOW)
- endfunction
-
- virtual function void apply_directed_instr();
- asm_gen.add_directed_instr_stream("riscv_load_store_rand_instr_stream", 10);
- endfunction
-
-endclass
-
-class riscv_mmu_stress_test extends riscv_instr_base_test;
-
- `uvm_component_utils(riscv_mmu_stress_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.instr_cnt = 500;
- cfg.num_of_sub_program = 0;
- `DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
- max_nested_loop == 0;)
- `uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
- cfg.sprint()), UVM_LOW)
- endfunction
-
- virtual function void apply_directed_instr();
- // Mix below directed instructino streams with the random instructions
- asm_gen.add_directed_instr_stream("riscv_cache_line_stress_instr_stream", 80);
- asm_gen.add_directed_instr_stream("riscv_load_store_hazard_instr_stream", 80);
- asm_gen.add_directed_instr_stream("riscv_multi_page_load_store_instr_stream", 80);
- endfunction
-
-endclass
-
-class riscv_page_table_exception_test extends riscv_rand_instr_test;
-
- `uvm_component_utils(riscv_page_table_exception_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.enable_page_table_exception = 1'b1;
- super.randomize_cfg();
- endfunction
-
-endclass
-
-class riscv_no_fence_test extends riscv_rand_instr_test;
-
- `uvm_component_utils(riscv_no_fence_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.no_fence = 1'b1;
- super.randomize_cfg();
- endfunction
-
-endclass
-
-class riscv_sfence_exception_test extends riscv_rand_instr_test;
-
- `uvm_component_utils(riscv_sfence_exception_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.allow_sfence_exception = 1'b1;
- super.randomize_cfg();
- endfunction
-
-endclass
-
-class riscv_illegal_instr_test extends riscv_rand_instr_test;
-
- `uvm_component_utils(riscv_illegal_instr_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.enable_illegal_instruction = 1'b1;
- super.randomize_cfg();
- endfunction
-
-endclass
-
-class riscv_hint_instr_test extends riscv_rand_instr_test;
-
- `uvm_component_utils(riscv_hint_instr_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.enable_hint_instruction = 1'b1;
- super.randomize_cfg();
- endfunction
-
-endclass
-
-class riscv_ebreak_test extends riscv_rand_instr_test;
-
- `uvm_component_utils(riscv_ebreak_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.no_ebreak = 1'b0;
- super.randomize_cfg();
- endfunction
-
-endclass
-
-class riscv_wfi_test extends riscv_rand_instr_test;
-
- `uvm_component_utils(riscv_wfi_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.no_wfi = 1'b0;
- super.randomize_cfg();
- endfunction
-
-endclass
-
-class riscv_illegal_csr_test extends riscv_rand_instr_test;
-
- `uvm_component_utils(riscv_illegal_csr_test)
- `uvm_component_new
-
- virtual function void randomize_cfg();
- cfg.enable_illegal_csr_instruction = 1'b1;
- super.randomize_cfg();
- endfunction
-
-endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/testlist b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/testlist
deleted file mode 100644
index ec6f707..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/testlist
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2018 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//====================================================================
-// Test name : iterations : options
-//--------------------------------------------------------------------
-riscv_arithmetic_basic_test : 2 :
-riscv_machine_mode_rand_test : 2 :
-riscv_privileged_mode_rand_test : 2 :
-riscv_rand_instr_test : 2 :
-riscv_rand_jump_test : 2 :
-riscv_mmu_stress_test : 2 :
-riscv_page_table_exception_test : 2 :
-riscv_no_fence_test : 2 :
-riscv_sfence_exception_test : 2 :
-riscv_illegal_instr_test : 2 :
-riscv_hint_instr_test : 2 :
-riscv_ebreak_test : 2 :
-riscv_wfi_test : 2 :
-//--------------------------------------------------------------------
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/csr_template.yaml b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/csr_template.yaml
index fed03e0..feeb096 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/csr_template.yaml
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/csr_template.yaml
@@ -4,7 +4,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http:#www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,12 +17,13 @@
#- csr: CSR_NAME
# description: >
# BRIEF_DESCRIPTION
+# address: 0x###
# privilege_mode: MODE (D/M/S/H/U)
# rv32:
# - MSB_FIELD_NAME:
# - description: >
# BRIEF_DESCRIPTION
-# - type: TYPE (WPRI/WLRL/WARL)
+# - type: TYPE (WPRI/WLRL/WARL/R)
# - reset_val: RESET_VAL
# - msb: MSB_POS
# - lsb: LSB_POS
@@ -36,7 +37,7 @@
# - MSB_FIELD_NAME:
# - description: >
# BRIEF_DESCRIPTION
-# - type: TYPE (WPRI/WLRL/WARL)
+# - type: TYPE (WPRI/WLRL/WARL/R)
# - reset_val: RESET_VAL
# - msb: MSB_POS
# - lsb: LSB_POS
@@ -53,6 +54,7 @@
- csr: misa
description: >
Machine ISA Register
+ address: 0x301
privilege_mode: M
rv32:
- field_name: MXL
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/iss.yaml b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/iss.yaml
index a5be72f..216cc6d 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/iss.yaml
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/iss.yaml
@@ -4,7 +4,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http:#www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -26,3 +26,8 @@
--override riscvOVPsim/cpu/simulateexceptions=T
--trace --tracechange --traceshowicount --program <elf>
--finishafter 500000
+
+- iss: sail
+ path_var: SAIL_RISCV
+ cmd: >
+ <path_var> <elf>
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/simulator.yaml b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/simulator.yaml
index 15a6bba..f73eca2 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/simulator.yaml
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/simulator.yaml
@@ -4,7 +4,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http:#www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -36,15 +36,16 @@
compile_cmd:
- "vmap mtiUvm $QUESTA_HOME/questasim/uvm-1.2"
- "vlog -64
- -access=rwc
- -f <cwd>/files.f
- -sv
- -mfcu -cuname design_cuname
- +define+UVM_REGEX_NO_DPI
- -writetoplevels <out>/top.list
- -l <out>/compile.log <cmp_opts>"
+ -access=rwc
+ -f <cwd>/files.f
+ -sv
+ -mfcu -cuname design_cuname
+ +define+UVM_REGEX_NO_DPI
+ -writetoplevels <out>/top.list
+ -l <out>/compile.log <cmp_opts>"
- "vopt -64 -debug
- +designfile -f <out>/top.list
- -o design_opt"
+ +designfile -f <out>/top.list
+ -l <out>/optimize.log <cmp_opts>
+ -o design_opt"
sim_cmd: >
- vsim -64 -c -do <cwd>/questa_sim.tcl design_opt <sim_opts> -svseed <seed>
+ vsim -64 -c -do <cwd>/questa_sim.tcl design_opt <sim_opts> -sv_seed <seed>
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/testlist.yaml b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/testlist.yaml
index 4a7315b..22ce918 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/testlist.yaml
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/testlist.yaml
@@ -4,7 +4,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http:#www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -12,19 +12,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# ======================================================================
+# ================================================================================
# Regression test list format
-# ----------------------------------------------------------------------
-# test : Assembly test name
-# description : Description of this test
-# gen_opts : Instruction generator options
-# iterations : Number of iterations of this test
-# gen_test : Test name used by the instruction generator
-# rtl_test : RTL simulation test name
-# cmp_opts : Compile options passed to the instruction generator
-# sim_opts : Simulation options passed to the instruction generator
-# compare_opts : Options for the RTL & ISS trace comparison
-# ----------------------------------------------------------------------
+# --------------------------------------------------------------------------------
+# test : Assembly test name
+# description : Description of this test
+# gen_opts : Instruction generator options
+# iterations : Number of iterations of this test
+# no_iss : Enable/disable ISS simulator (Optional)
+# gen_test : Test name used by the instruction generator
+# rtl_test : RTL simulation test name
+# cmp_opts : Compile options passed to the instruction generator
+# sim_opts : Simulation options passed to the instruction generator
+# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional)
+# compare_opts : Options for the RTL & ISS trace comparison
+# gcc_opts : gcc compile options
+# --------------------------------------------------------------------------------
- test: riscv_arithmetic_basic_test
description: >
@@ -77,6 +80,18 @@
+directed_instr_5=riscv_multi_page_load_store_instr_stream,4
rtl_test: core_base_test
+# TODO: Temporarily disable this as compiler seems to generate compressed instruction with rv64im
+- test: riscv_non_compressed_instr_test
+ description: >
+ Random instruction test without compressed instructions
+ iterations: 0
+ gen_test: riscv_rand_instr_test
+ gen_opts: >
+ +march=RV32I,RV32M,RV64I,RV64M
+ gcc_opts: >
+ -march=rv64im
+ rtl_test: core_base_test
+
- test: riscv_rand_jump_test
description: >
Jump among large number of sub-programs, stress testing iTLB operations.
@@ -95,7 +110,7 @@
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
- +instr_cnt=10000
+ +instr_cnt=5000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,40
+directed_instr_1=riscv_load_store_hazard_instr_stream,40
@@ -175,33 +190,57 @@
+no_ebreak=0
rtl_test: core_base_test
sim_opts: >
+ +require_signature_addr=1
+enable_debug_seq=1
compare_opts: >
+compare_final_value_only=1
-- test: riscv_fast_interrupt_test
- description: >
- WFI(wait for interrupt) instruction test. If WFI is supported, processor
- should halt execution upon decoding WFI instruction and resume execution
- by interrupt. Otherwise WFI should be executed as NOP instruction.
- Interrupt handling routine is skipped to allow instruction strace comparison
- with ISS which is not interrupted during execution.
- iterations: 2
- gen_test: riscv_rand_instr_test
- gen_opts: >
- +skip_trap_handling=1
- +no_wfi=0
- rtl_test: core_base_test
- sim_opts: >
- +enable_irq_seq=1
-
- test: riscv_full_interrupt_test
description: >
Random instruction test with complete interrupt handling
iterations: 2
gen_test: riscv_rand_instr_test
+ gen_opts: >
rtl_test: core_base_test
sim_opts: >
+enable_irq_seq=1
compare_opts: >
+compare_final_value_only=1
+
+ # Please enable this test for your RTL simulation
+- test: riscv_csr_test
+ description: >
+ Test all CSR instructions on all implemented CSR registers
+ iterations: 0
+ no_iss: 1
+ rtl_test: core_ibex_csr_test
+ no_post_compare: 1
+
+- test: riscv_unaligned_load_store_test
+ description: >
+ Unaligned load/store test, ibex should handle it correctly without raising any exception
+ iterations: 1
+ gen_test: riscv_instr_base_test
+ gcc_opts: >
+ -mno-strict-align
+ gen_opts: >
+ +instr_cnt=6000
+ +num_of_sub_program=5
+ +directed_instr_0=riscv_load_store_rand_instr_stream,20
+ +directed_instr_1=riscv_load_store_hazard_instr_stream,20
+ +directed_instr_2=riscv_cache_line_stress_instr_stream,20
+ +directed_instr_3=riscv_multi_page_load_store_instr_stream,20
+ +enable_unaligned_load_store=1
+ rtl_test: core_ibex_base_test
+
+- test: riscv_amo_test
+ description: >
+ RISC-V atomic instruction extension test
+ iterations: 2
+ gen_test: riscv_rand_instr_test
+ gen_opts: >
+ +instr_cnt=5000
+ +num_of_sub_program=5
+ +directed_instr_0=riscv_lr_sc_instr_stream,10
+ +directed_instr_1=riscv_amo_instr_stream,10
+ rtl_test: core_base_test