Update lowrisc_ibex to lowRISC/ibex@f30e84b
Update code from upstream repository
https://github.com/lowRISC/ibex.git to revision
f30e84ba00b1c5e630dea0ba6fbf117ec69ebcc8
* [rtl] Remove outdated assertion (Tom Roberts)
* [doc] Document branch prediction configuration (Greg Chadwick)
* [rtl] Introduce static branch prediction (Greg Chadwick)
* [ibex/rtl] Remove duplicate check for irq_fast[5] (Udi)
* Fix `RegFile` parameter overriding in ArtyA7 example (Pirmin Vogel)
* List all Python requirements for dvsim (Philipp Wagner)
* Add `RegFile` parameter for selecting register file implementation
(Pirmin Vogel)
* [rtl] Fix FENCE comment in decoder (Tom Roberts)
* Add private CI trigger (Philipp Wagner)
* CI: Factor out installation of build dependencies (Philipp Wagner)
* CI: Script to convert CI variables (Philipp Wagner)
* Add lowRISC-specific version of Spike to CI config (Philipp Wagner)
* Factor out CI variables into separate file (Philipp Wagner)
* Fix PRJ_DIR in DV Makefile (Philipp Wagner)
* Update google_riscv-dv to google/riscv-dv@2e52518 (Philipp Wagner)
* Doc support for overriding enum/string parameters at the top level
(Pirmin Vogel)
* Add a single `RV32M` enum parameter to select multiplier
implementation (Pirmin Vogel)
* B extension: Correct doc and parameter usage (Pirmin Vogel)
* Use a RV32IMCB toolchain in CI (Philipp Wagner)
* [ibex/dv] Add dependency on bus_params_pkg (Udi)
* Update google_riscv-dv to google/riscv-dv@17d7984 (Udi)
* Update lowrisc_ip to lowRISC/opentitan@92e92424 (Rupert Swarbrick)
Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
diff --git a/hw/ip/rv_core_ibex/lint/rv_core_ibex.waiver b/hw/ip/rv_core_ibex/lint/rv_core_ibex.waiver
index 76d2314..2317b33 100644
--- a/hw/ip/rv_core_ibex/lint/rv_core_ibex.waiver
+++ b/hw/ip/rv_core_ibex/lint/rv_core_ibex.waiver
@@ -16,6 +16,8 @@
-comment "testability signal used in some versions of register file"
waive -rules INPUT_NOT_READ -location {ibex_register_file_ff.sv} -regexp {Input port 'test_en_i' is not read from} \
-comment "testability signal used in some versions of register file"
+waive -rules INPUT_NOT_READ -location {ibex_register_file_fpga.sv} -regexp {Input port 'test_en_i' is not read from} \
+ -comment "testability signal used in some versions of register file"
waive -rules INPUT_NOT_READ -location {ibex_core.sv} -regexp {Input port 'clock_en_i' is not read from} \
-comment "clock enable signal used in behavioral code"
waive -rules HIER_NET_NOT_READ -location {rv_core_ibex.sv} -regexp {Net 'instr_addr_o.1.0.' is not read from} \
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 4e151ef..3ec0352 100644
--- a/hw/ip/rv_core_ibex/rtl/rv_core_ibex.sv
+++ b/hw/ip/rv_core_ibex/rtl/rv_core_ibex.sv
@@ -9,23 +9,25 @@
* Instruction and data bus are 32 bit wide TileLink-UL (TL-UL).
*/
module rv_core_ibex #(
- parameter bit PMPEnable = 1'b0,
- parameter int unsigned PMPGranularity = 0,
- parameter int unsigned PMPNumRegions = 4,
- parameter int unsigned MHPMCounterNum = 8,
- parameter int unsigned MHPMCounterWidth = 40,
- parameter bit RV32E = 0,
- parameter bit RV32M = 1,
- parameter bit BranchTargetALU = 1,
- parameter bit WritebackStage = 1,
- parameter MultiplierImplementation = "single-cycle",
- parameter bit ICache = 1'b0,
- parameter bit ICacheECC = 1'b0,
- parameter bit DbgTriggerEn = 1'b1,
- parameter bit SecureIbex = 1'b0,
- parameter int unsigned DmHaltAddr = 32'h1A110800,
- parameter int unsigned DmExceptionAddr = 32'h1A110808,
- parameter bit PipeLine = 0
+ parameter bit PMPEnable = 1'b0,
+ parameter int unsigned PMPGranularity = 0,
+ parameter int unsigned PMPNumRegions = 4,
+ parameter int unsigned MHPMCounterNum = 8,
+ parameter int unsigned MHPMCounterWidth = 40,
+ parameter bit RV32E = 0,
+ parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MSingleCycle,
+ parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
+ parameter ibex_pkg::regfile_e RegFile = ibex_pkg::RegFileFF,
+ parameter bit BranchTargetALU = 1'b1,
+ parameter bit WritebackStage = 1'b1,
+ parameter bit ICache = 1'b0,
+ parameter bit ICacheECC = 1'b0,
+ parameter bit BranchPredictor = 1'b0,
+ parameter bit DbgTriggerEn = 1'b1,
+ parameter bit SecureIbex = 1'b0,
+ parameter int unsigned DmHaltAddr = 32'h1A110800,
+ parameter int unsigned DmExceptionAddr = 32'h1A110808,
+ parameter bit PipeLine = 1'b0
) (
// Clock and Reset
input logic clk_i,
@@ -146,11 +148,13 @@
.MHPMCounterWidth ( MHPMCounterWidth ),
.RV32E ( RV32E ),
.RV32M ( RV32M ),
+ .RV32B ( RV32B ),
+ .RegFile ( RegFile ),
.BranchTargetALU ( BranchTargetALU ),
.WritebackStage ( WritebackStage ),
- .MultiplierImplementation ( MultiplierImplementation ),
.ICache ( ICache ),
.ICacheECC ( ICacheECC ),
+ .BranchPredictor ( BranchPredictor ),
.DbgTriggerEn ( DbgTriggerEn ),
.SecureIbex ( SecureIbex ),
.DmHaltAddr ( DmHaltAddr ),
diff --git a/hw/top_earlgrey/data/top_earlgrey.sv.tpl b/hw/top_earlgrey/data/top_earlgrey.sv.tpl
index 0317f8e..2fff9f4 100644
--- a/hw/top_earlgrey/data/top_earlgrey.sv.tpl
+++ b/hw/top_earlgrey/data/top_earlgrey.sv.tpl
@@ -192,12 +192,14 @@
.MHPMCounterNum (8),
.MHPMCounterWidth (40),
.RV32E (0),
- .RV32M (1),
+ .RV32M (ibex_pkg::RV32MSingleCycle),
+ .RV32B (ibex_pkg::RV32BNone),
+ .RegFile (ibex_pkg::RegFileFF),
.BranchTargetALU (1),
.WritebackStage (1),
- .MultiplierImplementation ("single-cycle"),
.ICache (0),
.ICacheECC (0),
+ .BranchPredictor (0),
.DbgTriggerEn (1),
.SecureIbex (0),
.DmHaltAddr (ADDR_SPACE_DEBUG_MEM + dm::HaltAddress),
diff --git a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
index f05f4df..549e191 100644
--- a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
+++ b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
@@ -284,12 +284,14 @@
.MHPMCounterNum (8),
.MHPMCounterWidth (40),
.RV32E (0),
- .RV32M (1),
+ .RV32M (ibex_pkg::RV32MSingleCycle),
+ .RV32B (ibex_pkg::RV32BNone),
+ .RegFile (ibex_pkg::RegFileFF),
.BranchTargetALU (1),
.WritebackStage (1),
- .MultiplierImplementation ("single-cycle"),
.ICache (0),
.ICacheECC (0),
+ .BranchPredictor (0),
.DbgTriggerEn (1),
.SecureIbex (0),
.DmHaltAddr (ADDR_SPACE_DEBUG_MEM + dm::HaltAddress),
diff --git a/hw/vendor/lowrisc_ibex.lock.hjson b/hw/vendor/lowrisc_ibex.lock.hjson
index 1adb826..b5ee602 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: 4c813a0422091d3c0f82df16eb28d2c746c36218
+ rev: f30e84ba00b1c5e630dea0ba6fbf117ec69ebcc8
}
}
diff --git a/hw/vendor/lowrisc_ibex/azure-pipelines.yml b/hw/vendor/lowrisc_ibex/azure-pipelines.yml
index 31c90aa..04a81da 100644
--- a/hw/vendor/lowrisc_ibex/azure-pipelines.yml
+++ b/hw/vendor/lowrisc_ibex/azure-pipelines.yml
@@ -6,10 +6,7 @@
# Documentation at https://aka.ms/yaml
variables:
- VERILATOR_VERSION: 4.032
- RISCV_TOOLCHAIN_TAR_VERSION: 20200323-1
- RISCV_COMPLIANCE_GIT_VERSION: 844c6660ef3f0d9b96957991109dfd80cc4938e2
- VERIBLE_VERSION: v0.0-493-g617b404
+- template: ci/vars.yml
trigger:
batch: true
@@ -35,60 +32,9 @@
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.
- #
- # Updating pip and setuptools is required to have these tools properly parse
- # Python-version metadata, which some packages uses to specify that an older
- # version of a package must be used for a certain Python version. If that
- # information is not read, pip installs the latest version, which then fails
- # to run.
- bash: |
- curl -L https://download.opensuse.org/repositories/home:phiwag:edatools/xUbuntu_16.04/Release.key | sudo apt-key add -
- sudo sh -c "echo 'deb http://download.opensuse.org/repositories/home:/phiwag:/edatools/xUbuntu_16.04/ /' > /etc/apt/sources.list.d/edatools.list"
- # Uninstall distribution-provided version to get a newer version through pip
- sudo apt-get remove -y python3-yaml
- sudo apt-get update
- sudo apt-get install -y \
- python3 \
- python3-pip \
- python3-setuptools \
- python3-wheel \
- srecord \
- zlib1g-dev \
- git \
- make \
- autoconf \
- g++ \
- flex \
- bison \
- curl \
- libelf-dev \
- clang-format \
- verilator-$(VERILATOR_VERSION) \
- && sudo pip3 install -U setuptools pip six \
- && sudo pip3 install -U -r python-requirements.txt
- displayName: Install dependencies
-
- - bash: |
- set -e
- mkdir -p build/verible
- cd build/verible
- curl -Ls -o verible.tar.gz https://github.com/google/verible/releases/download/$(VERIBLE_VERSION)/verible-$(VERIBLE_VERSION)-Ubuntu-16.04-xenial-x86_64.tar.gz
- sudo mkdir -p /tools/verible && sudo chmod 777 /tools/verible
- tar -C /tools/verible -xf verible.tar.gz --strip-components=1
- echo "##vso[task.setvariable variable=PATH]/tools/verible/bin:$PATH"
- displayName: Install Verible
-
- - 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
+ ci/install-build-deps.sh
+ displayName: Install build dependencies
- bash: |
echo $PATH
@@ -139,7 +85,7 @@
cd build
git clone https://github.com/riscv/riscv-compliance.git
cd riscv-compliance
- git checkout "$(RISCV_COMPLIANCE_GIT_VERSION)"
+ git checkout "$RISCV_COMPLIANCE_GIT_VERSION"
displayName: Get RISC-V Compliance test suite
# Run Ibex RTL CI per supported configuration
@@ -149,6 +95,7 @@
- small
- experimental-maxperf-pmp
- experimental-maxperf-pmp-bmfull
+ - experimental-branch-predictor
# Run lint on simple system
- bash: |
diff --git a/hw/vendor/lowrisc_ibex/ci/azp-private.yml b/hw/vendor/lowrisc_ibex/ci/azp-private.yml
new file mode 100644
index 0000000..04df3f4
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/ci/azp-private.yml
@@ -0,0 +1,31 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+#
+# Private CI trigger. Used to run tooling that can't currently be shared
+# publicly.
+
+trigger:
+ batch: true
+ branches:
+ include:
+ - '*'
+ tags:
+ include:
+ - "*"
+pr:
+ branches:
+ include:
+ - '*'
+
+# The runner used for private CI enforces the use of the template below. All
+# build steps need to be placed into the template.
+resources:
+ repositories:
+ - repository: lowrisc-private-ci
+ type: github
+ endpoint: lowRISC
+ name: lowrisc/lowrisc-private-ci
+
+extends:
+ template: jobs-ibex.yml@lowrisc-private-ci
diff --git a/hw/vendor/lowrisc_ibex/ci/install-build-deps.sh b/hw/vendor/lowrisc_ibex/ci/install-build-deps.sh
new file mode 100755
index 0000000..8666416
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/ci/install-build-deps.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+#
+# Install development build dependencies for different Linux distributions
+#
+
+set -e
+
+[ -f /etc/os-release ] || (echo "/etc/os-release doesn't exist."; exit 1)
+. /etc/os-release
+
+[ ! -z "$VERILATOR_VERSION" ] || (echo "VERILATOR_VERSION must be set."; exit 1)
+[ ! -z "$VERIBLE_VERSION" ] || (echo "VERIBLE_VERSION must be set."; exit 1)
+[ ! -z "$RISCV_TOOLCHAIN_TAR_VERSION" ] || (echo "RISCV_TOOLCHAIN_TAR_VERSION must be set."; exit 1)
+[ ! -z "$RISCV_TOOLCHAIN_TAR_VARIANT" ] || (echo "RISCV_TOOLCHAIN_TAR_VARIANT must be set."; exit 1)
+
+SUDO_CMD=""
+if [ $(id -u) -ne 0 ]; then
+ SUDO_CMD="sudo "
+fi
+
+case "$ID-$VERSION_ID" in
+ ubuntu-16.04)
+ # Curl must be available to get the repo key below.
+ $SUDO_CMD apt-get update
+ $SUDO_CMD apt-get install -y curl
+
+ # Make Verilator repository available
+ curl -Ls https://download.opensuse.org/repositories/home:phiwag:edatools/xUbuntu_16.04/Release.key | $SUDO_CMD apt-key add -
+ $SUDO_CMD sh -c "echo 'deb http://download.opensuse.org/repositories/home:/phiwag:/edatools/xUbuntu_16.04/ /' > /etc/apt/sources.list.d/edatools.list"
+ $SUDO_CMD apt-get update
+
+ # Uninstall distribution-provided version to get a newer version through pip
+ $SUDO_CMD apt-get remove -y python3-yaml
+
+ # Packaged dependencies
+ $SUDO_CMD apt-get install -y \
+ device-tree-compiler \
+ python3 \
+ python3-pip \
+ python3-setuptools \
+ python3-wheel \
+ srecord \
+ zlib1g-dev \
+ git \
+ make \
+ autoconf \
+ g++ \
+ flex \
+ bison \
+ libelf-dev \
+ clang-format \
+ "verilator-$VERILATOR_VERSION" \
+ xz-utils
+
+ # Python dependencies
+ #
+ # 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.
+ #
+ # Updating pip and setuptools is required to have these tools properly
+ # parse Python-version metadata, which some packages uses to specify that
+ # an older version of a package must be used for a certain Python version.
+ # If that information is not read, pip installs the latest version, which
+ # then fails to run.
+ $SUDO_CMD pip3 install -U setuptools pip six
+ $SUDO_CMD pip3 install -U -r python-requirements.txt
+
+ # Install Verible
+ mkdir -p build/verible
+ cd build/verible
+ curl -Ls -o verible.tar.gz "https://github.com/google/verible/releases/download/$VERIBLE_VERSION/verible-$VERIBLE_VERSION-Ubuntu-16.04-xenial-x86_64.tar.gz"
+ $SUDO_CMD mkdir -p /tools/verible && $SUDO_CMD chmod 777 /tools/verible
+ tar -C /tools/verible -xf verible.tar.gz --strip-components=1
+ echo "##vso[task.prependpath]/tools/verible/bin"
+ ;;
+
+ *)
+ echo Unknown distribution. Please extend this script!
+ exit 1
+ ;;
+esac
+
+# Install pre-compiled toolchain (for all distributions)
+TOOLCHAIN_URL="https://github.com/lowRISC/lowrisc-toolchains/releases/download/$RISCV_TOOLCHAIN_TAR_VERSION/$RISCV_TOOLCHAIN_TAR_VARIANT-$RISCV_TOOLCHAIN_TAR_VERSION.tar.xz"
+mkdir -p build/toolchain
+curl -Ls -o build/toolchain/rv32-toolchain.tar.xz "$TOOLCHAIN_URL"
+$SUDO_CMD mkdir -p /tools/riscv && $SUDO_CMD chmod 777 /tools/riscv
+tar -C /tools/riscv -xf build/toolchain/rv32-toolchain.tar.xz --strip-components=1
+echo "##vso[task.prependpath]/tools/riscv/bin"
diff --git a/hw/vendor/lowrisc_ibex/ci/vars.yml b/hw/vendor/lowrisc_ibex/ci/vars.yml
new file mode 100644
index 0000000..c72bde3
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/ci/vars.yml
@@ -0,0 +1,15 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+# Pipeline variables, used by the public and private CI pipelines
+# Quote values to ensure they are parsed as string (version numbers might
+# end up as float otherwise).
+variables:
+ VERILATOR_VERSION: "4.032"
+ RISCV_TOOLCHAIN_TAR_VERSION: "20200626-1"
+ RISCV_TOOLCHAIN_TAR_VARIANT: "lowrisc-toolchain-gcc-rv32imcb"
+ RISCV_COMPLIANCE_GIT_VERSION: "844c6660ef3f0d9b96957991109dfd80cc4938e2"
+ VERIBLE_VERSION: "v0.0-493-g617b404"
+ # lowRISC-internal version numbers of Ibex-specific Spike builds.
+ SPIKE_IBEX_VERSION: "20200819-git-57023895458bc5206fe59fa229e0be6b05aa2f25"
diff --git a/hw/vendor/lowrisc_ibex/ci/vars_to_logging_cmd.py b/hw/vendor/lowrisc_ibex/ci/vars_to_logging_cmd.py
new file mode 100755
index 0000000..c719a0c
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/ci/vars_to_logging_cmd.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+# Read an Azure Pipelines-compatible variables file, and convert it into
+# logging commands that Azure Pipelines understands, effectively setting the
+# variables at runtime.
+#
+# This script can be used as a workaround if variables cannot be included in the
+# Pipeline definition directly.
+#
+# See https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands
+# for more information on logging commands.
+
+import sys
+import yaml
+
+def vars_to_logging_cmd(vars_file):
+ data = {}
+ print(vars_file)
+ with open(vars_file, 'r', encoding="utf-8") as fp:
+ data = yaml.load(fp, Loader=yaml.SafeLoader)
+
+ if not (isinstance(data, dict) and 'variables' in data):
+ print("YAML file wasn't a dictionary with a 'variables' key. Got: {}"
+ .format(data))
+
+ print("Setting variables from {}".format(vars_file))
+ for key, value in data['variables'].items():
+ # Note: These lines won't show up in the Azure Pipelines output unless
+ # "System Diagnostics" are enabled (go to the Azure Pipelines web UI,
+ # click on "Run pipeline" to manually run a pipeline, and check "Enable
+ # system diagnostics".)
+ print("##vso[task.setvariable variable={}]{}".format(key, value))
+
+ return 0
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print("Usage: {} VARS_FILE".format(sys.argv[0]))
+ sys.exit(1)
+ sys.exit(vars_to_logging_cmd(sys.argv[1]))
diff --git a/hw/vendor/lowrisc_ibex/doc/getting_started.rst b/hw/vendor/lowrisc_ibex/doc/getting_started.rst
index 21c5939..c58407a 100644
--- a/hw/vendor/lowrisc_ibex/doc/getting_started.rst
+++ b/hw/vendor/lowrisc_ibex/doc/getting_started.rst
@@ -8,7 +8,6 @@
Register File
-------------
-Ibex comes with two different register file implementations.
-Depending on the target technology, either the implementation in ``ibex_register_file_ff.sv`` or the one in ``ibex_register_file_latch.sv`` should be selected.
-For more information about the two register file implementations and their trade-offs, check out :ref:`register-file`.
-
+Ibex comes with three different register file implementations that can be selected using the enumerated parameter ``RegFile`` defined in :file:`rtl/ibex_pkg.sv`.
+Depending on the target technology, either the flip-flop-based ("ibex_pkg::RegFileFF", default), the latch-based ("ibex_pkg::RegFileLatch") or an FPGA-targeted ("ibex_pkg::RegFileFPGA") implementation should be selected.
+For more information about the three register file implementations and their trade-offs, check out :ref:`register-file`.
diff --git a/hw/vendor/lowrisc_ibex/doc/instruction_decode_execute.rst b/hw/vendor/lowrisc_ibex/doc/instruction_decode_execute.rst
index 92cf24b..b79d5e4 100644
--- a/hw/vendor/lowrisc_ibex/doc/instruction_decode_execute.rst
+++ b/hw/vendor/lowrisc_ibex/doc/instruction_decode_execute.rst
@@ -42,7 +42,7 @@
Register File
-------------
-Source Files: :file:`rtl/ibex_register_file_ff.sv` :file:`rtl/ibex_register_file_latch.sv`
+Source Files: :file:`rtl/ibex_register_file_ff.sv` :file:`rtl/ibex_register_file_fpga.sv` :file:`rtl/ibex_register_file_latch.sv`
See :ref:`register-file` for more details.
@@ -67,10 +67,13 @@
Bit Manipulation Extension
Support for the `RISC-V Bit Manipulation Extension (draft version 0.92 from November 8, 2019) <https://github.com/riscv/riscv-bitmanip/blob/master/bitmanip-0.92.pdf>`_ is optional. [#B_draft]_
It can be enabled via the enumerated parameter ``RV32B`` defined in :file:`rtl/ibex_pkg.sv`.
+ By default, this parameter is set to "ibex_pkg::RV32BNone" to disable the bit manipulation extension.
There are two versions of the bit manipulation extension available:
The balanced implementation comprises a set of sub-extensions aiming for good benefits at a reasonable area overhead.
+ It can be selected by setting the ``RV32B`` parameter to "ibex_pkg::RV32BBalanced".
The full implementation comprises all 32 bit instructions defined in the extension.
+ This version can be selected by setting the ``RV32B`` parameter to "ibex_pkg::RV32BFull".
The following table lists the implemented instructions in each version.
Multi-cycle instructions are completed in 2 cycles.
All remaining instructions complete in a single cycle.
@@ -84,7 +87,7 @@
+---------------------------------+---------------+--------------------------+
| Zbp (Permutation) | Full | None |
+---------------------------------+---------------+--------------------------+
- | Zbp (Bit extract/deposit) | Full | All |
+ | Zbe (Bit extract/deposit) | Full | All |
+---------------------------------+---------------+--------------------------+
| Zbf (Bit-field place) | Balanced/Full | All |
+---------------------------------+---------------+--------------------------+
@@ -113,10 +116,12 @@
The fast and slow versions differ in multiplier only. All versions implement the same form of long division algorithm. The ALU block is used by the long division algorithm in all versions.
Multiplier
- The multiplier can be implemented in three variants controlled via the parameter ``MultiplierImplementation``.
+ The multiplier can be implemented in three variants controlled via the enumerated parameter ``RV32M`` defined in :file:`rtl/ibex_pkg.sv`.
Single-Cycle Multiplier
- This implementation is chosen by setting the ``MultiplierImplementation`` parameter to "single-cycle". The single-cycle multiplier makes use of three parallel multiplier units, designed to be mapped to hardware multiplier primitives on FPGAs. It is therefore the **first choice for FPGA synthesis**.
+ This implementation is chosen by setting the ``RV32M`` parameter to "ibex_pkg::RV32MSingleCycle".
+ The single-cycle multiplier makes use of three parallel multiplier units, designed to be mapped to hardware multiplier primitives on FPGAs.
+ It is therefore the **first choice for FPGA synthesis**.
- Using three parallel 17-bit x 17-bit multiplication units and a 34-bit accumulator, it completes a MUL instruction in 1 cycle. MULH is completed in 2 cycles.
- This MAC is internal to the mult/div block (no external ALU use).
@@ -124,7 +129,8 @@
- ASIC synthesis has not yet been tested but is expected to consume 3-4x the area of the fast multiplier for ASIC.
Fast Multi-Cycle Multiplier
- This implementation is chosen by setting the ``MultiplierImplementation`` parameter to "fast". The fast multi-cycle multiplier provides a reasonable trade-off between area and performance. It is the **first choice for ASIC synthesis**.
+ This implementation is chosen by setting the ``RV32M`` parameter to "ibex_pkg::RV32MFast".
+ The fast multi-cycle multiplier provides a reasonable trade-off between area and performance. It is the **first choice for ASIC synthesis**.
- Completes multiply in 3-4 cycles using a MAC (multiply accumulate) which is capable of a 17-bit x 17-bit multiplication with a 34-bit accumulator.
- A MUL instruction takes 3 cycles, MULH takes 4.
@@ -133,7 +139,7 @@
- In some cases it may be desirable to replace this with a specific implementation such as an explicit gate level implementation.
Slow Multi-Cycle Multiplier
- To select the slow multi-cycle multiplier, set the ``MultiplierImplementation`` parameter to "slow".
+ To select the slow multi-cycle multiplier, set the ``RV32M`` parameter to "ibex_pkg::RV32MSlow".
- Completes multiply in clog2(``op_b``) + 1 cycles (for MUL) or 33 cycles (for MULH) using a Baugh-Wooley multiplier.
- The ALU block is used to compute additions.
@@ -146,6 +152,8 @@
- Cycle 2: Compute absolute value of operand B
- Cycles 4 - 36: Perform long division as described here: https://en.wikipedia.org/wiki/Division_algorithm#Integer_division_(unsigned)_with_remainder.
+By setting the ``RV32M`` parameter to "ibex_pkg::RV32MNone", the M-extension can be disabled completely.
+
Control and Status Register Block (CSR)
---------------------------------------
Source File: :file:`rtl/ibex_cs_registers.sv`
diff --git a/hw/vendor/lowrisc_ibex/doc/instruction_fetch.rst b/hw/vendor/lowrisc_ibex/doc/instruction_fetch.rst
index e160c23..c723c0d 100644
--- a/hw/vendor/lowrisc_ibex/doc/instruction_fetch.rst
+++ b/hw/vendor/lowrisc_ibex/doc/instruction_fetch.rst
@@ -26,6 +26,16 @@
Firstly, a signal to enable the cache which is driven from a custom CSR.
Secondly a signal to the flush the cache which is set every time a ``fence.i`` instruction is executed.
+Branch Prediction
+-----------------
+
+Ibex can be configured to use static branch prediction by setting the ``BranchPrediction`` parameter to 1.
+This improves performance by predicting that any branch with a negative offset is taken and that any branch with a positive offset is not.
+When successful, the prediction removes a stall cycle from a taken branch.
+However, there is a mis-predict penalty if a branch is wrongly predicted to be taken.
+This penalty is at least one cycle, or at least two cycles if the instruction following the branch is uncompressed and not aligned.
+This feature is *EXPERIMENTAL* and its effects are not yet fully documented.
+
Instruction-Side Memory Interface
---------------------------------
diff --git a/hw/vendor/lowrisc_ibex/doc/integration.rst b/hw/vendor/lowrisc_ibex/doc/integration.rst
index 2cfc55c..da066f8 100644
--- a/hw/vendor/lowrisc_ibex/doc/integration.rst
+++ b/hw/vendor/lowrisc_ibex/doc/integration.rst
@@ -12,21 +12,22 @@
.. code-block:: verilog
ibex_core #(
- .PMPEnable ( 0 ),
- .PMPGranularity ( 0 ),
- .PMPNumRegions ( 4 ),
- .MHPMCounterNum ( 0 ),
- .MHPMCounterWidth ( 40 ),
- .RV32E ( 0 ),
- .RV32M ( 1 ),
- .RV32B ( ibex_pkg::RV32BNone ),
- .MultiplierImplementation ( "fast" ),
- .ICache ( 0 ),
- .ICacheECC ( 0 ),
- .SecureIbex ( 0 ),
- .DbgTriggerEn ( 0 ),
- .DmHaltAddr ( 32'h1A110800 ),
- .DmExceptionAddr ( 32'h1A110808 )
+ .PMPEnable ( 0 ),
+ .PMPGranularity ( 0 ),
+ .PMPNumRegions ( 4 ),
+ .MHPMCounterNum ( 0 ),
+ .MHPMCounterWidth ( 40 ),
+ .RV32E ( 0 ),
+ .RV32M ( ibex_pkg::RV32MFast ),
+ .RV32B ( ibex_pkg::RV32BNone ),
+ .RegFile ( ibex_pkg::RegFileFF ),
+ .ICache ( 0 ),
+ .ICacheECC ( 0 ),
+ .BranchPrediction ( 0 ),
+ .SecureIbex ( 0 ),
+ .DbgTriggerEn ( 0 ),
+ .DmHaltAddr ( 32'h1A110800 ),
+ .DmExceptionAddr ( 32'h1A110808 )
) u_core (
// Clock and reset
.clk_i (),
@@ -76,58 +77,73 @@
Parameters
----------
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| 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..10) | 0 | Number of performance monitor event counters |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``MHPMCounterWidth`` | int (64..1) | 40 | Bit width of performance monitor event counters |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``RV32E`` | bit | 0 | RV32E mode enable (16 integer registers only) |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``RV32M`` | bit | 1 | M(ultiply) extension enable |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``RV32B`` | ibex_pkg::rv32b_e | RV32BNone | *EXPERIMENTAL* - B(itmanipulation) extension select: |
-| | | | "RV32BNone": No B-extension |
-| | | | "RV32BBalanced": Sub-extensions Zbb, Zbs, Zbf and |
-| | | | Zbt |
-| | | | "RV32Full": All sub-extensions |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``BranchTargetALU`` | bit | 0 | *EXPERIMENTAL* - Enables branch target ALU removing a stall |
-| | | | cycle from taken branches |
-+------------------------------+------------------ +------------+-----------------------------------------------------------------+
-| ``WritebackStage`` | bit | 0 | *EXPERIMENTAL* - Enables third pipeline stage (writeback) |
-| | | | improving performance of loads and stores |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``MultiplierImplementation`` | string | "fast" | Multiplicator type: |
-| | | | "slow": multi-cycle slow, |
-| | | | "fast": multi-cycle fast, |
-| | | | "single-cycle": single-cycle |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``ICache`` | bit | 0 | *EXPERIMENTAL* Enable instruction cache instead of prefetch |
-| | | | buffer |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``ICacheECC`` | bit | 0 | *EXPERIMENTAL* Enable SECDED ECC protection in ICache (if |
-| | | | ICache == 1) |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``SecureIbex`` | bit | 0 | *EXPERIMENTAL* Enable various additional features targeting |
-| | | | secure code execution. |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``DbgTriggerEn`` | bit | 0 | Enable debug trigger support (one trigger only) |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
-| ``DmExceptionAddr`` | int | 0x1A110808 | Address to jump to when an exception occurs while in Debug Mode |
-+------------------------------+-------------------+------------+-----------------------------------------------------------------+
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| 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..10) | 0 | Number of performance monitor event counters |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``MHPMCounterWidth`` | int (64..1) | 40 | Bit width of performance monitor event counters |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``RV32E`` | bit | 0 | RV32E mode enable (16 integer registers only) |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``RV32M`` | ibex_pkg::rv32m_e | RV32MFast | M(ultiply) extension select: |
+| | | | "ibex_pkg::RV32MNone": No M-extension |
+| | | | "ibex_pkg::RV32MSlow": Slow multi-cycle multiplier, iterative divider |
+| | | | "ibex_pkg::RV32MFast": 3-4 cycle multiplier, iterative divider |
+| | | | "ibex_pkg::RV32MSingleCycle": 1-2 cycle multiplier, iterative divider |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``RV32B`` | ibex_pkg::rv32b_e | RV32BNone | B(itmanipulation) extension select: |
+| | | | "ibex_pkg::RV32BNone": No B-extension |
+| | | | "ibex_pkg::RV32BBalanced": Sub-extensions Zbb, Zbs, Zbf and Zbt |
+| | | | "ibex_pkg::RV32Full": All sub-extensions |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``RegFile`` | ibex_pkg::regfile_e | RegFileFF | Register file implementation select: |
+| | | | "ibex_pkg::RegFileFF": Generic flip-flop-based register file |
+| | | | "ibex_pkg::RegFileFPGA": Register file for FPGA targets |
+| | | | "ibex_pkg::RegFileLatch": Latch-based register file for ASIC targets |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``BranchTargetALU`` | bit | 0 | *EXPERIMENTAL* - Enables branch target ALU removing a stall |
+| | | | cycle from taken branches |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``WritebackStage`` | bit | 0 | *EXPERIMENTAL* - Enables third pipeline stage (writeback) |
+| | | | improving performance of loads and stores |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``ICache`` | bit | 0 | *EXPERIMENTAL* Enable instruction cache instead of prefetch |
+| | | | buffer |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``ICacheECC`` | bit | 0 | *EXPERIMENTAL* Enable SECDED ECC protection in ICache (if |
+| | | | ICache == 1) |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``BranchPrediction`` | bit | 0 | *EXPERIMENTAL* Enable Static branch prediction |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``SecureIbex`` | bit | 0 | *EXPERIMENTAL* Enable various additional features targeting |
+| | | | secure code execution. |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``DbgTriggerEn`` | bit | 0 | Enable debug trigger support (one trigger only) |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
+| ``DmExceptionAddr`` | int | 0x1A110808 | Address to jump to when an exception occurs while in Debug Mode |
++------------------------------+---------------------+------------+-----------------------------------------------------------------------+
Any parameter marked *EXPERIMENTAL* when enabled is not verified to the same standard as the rest of the Ibex core.
+Note that Ibex uses SystemVerilog enum parameters e.g. for ``RV32M`` and ``RV32B``.
+This is well supported by most tools but some care is needed when overriding these parameters at the top level:
+
+* Synopsys VCS does not support overriding enum and string parameters at the top level via command line.
+ As a workaround, SystemVerilog defines are used in Ibex top level files simulated with VCS.
+ These defines can be set via command line.
+
+* Yosys does not support overriding enum parameters at the top level by setting enum names.
+ Instead, the enum values need to be used.
+
Interfaces
----------
diff --git a/hw/vendor/lowrisc_ibex/doc/register_file.rst b/hw/vendor/lowrisc_ibex/doc/register_file.rst
index c5c4c0f..0cf0099 100644
--- a/hw/vendor/lowrisc_ibex/doc/register_file.rst
+++ b/hw/vendor/lowrisc_ibex/doc/register_file.rst
@@ -2,7 +2,7 @@
Register File
=============
-Source FIles: :file:`rtl/ibex_register_file_ff.sv` :file:`rtl/ibex_register_file_latch.sv`
+Source Files: :file:`rtl/ibex_register_file_ff.sv` :file:`rtl/ibex_register_file_fpga.sv` :file:`rtl/ibex_register_file_latch.sv`
Ibex has either 31 or 15 32-bit registers if the RV32E extension is disabled or enabled, respectively.
Register ``x0`` is statically bound to 0 and can only be read, it does not contain any sequential logic.
@@ -10,7 +10,8 @@
The register file has two read ports and one write port, register file data is available the same cycle a read is requested.
There is no write to read forwarding path so if one register is being both read and written the read will return the current value rather than the value being written.
-There are two flavors of register file available, both having their own benefits and trade-offs.
+There are three flavors of register file available, each having their own benefits and trade-offs.
+The register file flavor is selected via the enumerated parameter ``RegFile`` defined in :file:`rtl/ibex_pkg.sv`.
Flip-Flop-Based Register File
-----------------------------
@@ -19,10 +20,11 @@
This makes it the **first choice when simulating the design using Verilator**.
-To select the flip-flop-based register file, make sure to use the source file ``ibex_register_file_ff.sv`` in your project.
+This implementation can be selected by setting the ``RegFile`` parameter to "ibex_pkg::RegFileFF".
+It is the default selection.
FPGA Register File
---------------------------
+------------------
The FPGA register file leverages synchronous-write / asynchronous-read RAM design elements, where available on FPGA targets.
@@ -30,7 +32,7 @@
This makes it the **first choice for FPGA synthesis**.
-To select the FPGA register file, make sure to use the source file ``ibex_register_file_fpga.sv`` in your project.
+To select the FPGA register file, set the ``RegFile`` parameter to "ibex_pkg::RegFileFPGA".
Latch-Based Register File
-------------------------
@@ -44,7 +46,7 @@
The latch-based register file can also be used for FPGA synthesis, but this is not recommended as FPGAs usually do not well support latches.
-To select the latch-based register file, make sure to use the source file ``ibex_register_file_latch.sv`` in your project.
+To select the latch-based register file, set the ``RegFile`` parameter to "ibex_pkg::RegFileLatch".
In addition, a technology-specific clock gating cell must be provided to keep the clock inactive when the latches are not written.
This cell must be wrapped in a module called ``prim_clock_gating``.
For more information regarding the clock gating cell, checkout :ref:`getting-started`.
diff --git a/hw/vendor/lowrisc_ibex/examples/fpga/artya7/rtl/top_artya7.sv b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/rtl/top_artya7.sv
index 37304b4..c26ca45 100644
--- a/hw/vendor/lowrisc_ibex/examples/fpga/artya7/rtl/top_artya7.sv
+++ b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/rtl/top_artya7.sv
@@ -43,6 +43,7 @@
ibex_core #(
+ .RegFile(ibex_pkg::RegFileFPGA),
.DmHaltAddr(32'h00000000),
.DmExceptionAddr(32'h00000000)
) u_core (
diff --git a/hw/vendor/lowrisc_ibex/examples/simple_system/README.md b/hw/vendor/lowrisc_ibex/examples/simple_system/README.md
index 2eb2944..4e37281 100644
--- a/hw/vendor/lowrisc_ibex/examples/simple_system/README.md
+++ b/hw/vendor/lowrisc_ibex/examples/simple_system/README.md
@@ -28,7 +28,7 @@
repository root run:
```
-fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_simple_system --RV32M=1 --RV32E=0
+fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_simple_system --RV32E=0 --RV32M=ibex_pkg::RV32MFast
```
## Building Software
@@ -103,7 +103,7 @@
Similar to the Verilator flow the Simple System simulator binary can be built using:
```
-fusesoc --cores-root=. run --target=sim --tool=vcs --setup --build lowrisc:ibex:ibex_simple_system --RV32M=1 --RV32E=0 --SRAMInitFile=`<sw_vmem_file>`
+fusesoc --cores-root=. run --target=sim --tool=vcs --setup --build lowrisc:ibex:ibex_simple_system --RV32E=0 --RV32M=ibex_pkg::RV32MFast --SRAMInitFile=`<sw_vmem_file>`
```
`<sw_vmem_file>` should be a path to a vmem file built as described above, use
@@ -123,7 +123,7 @@
To build and run Simple System run:
```
-fusesoc --cores-root=. run --target=sim --tool=rivierapro lowrisc:ibex:ibex_simple_system --RV32M=1 --RV32E=0 --SRAMInitFile=\"$(readlink -f <sw_vmem_file>)\"
+fusesoc --cores-root=. run --target=sim --tool=rivierapro lowrisc:ibex:ibex_simple_system --RV32E=0 --RV32M=ibex_pkg::RV32MFast --SRAMInitFile=\"$(readlink -f <sw_vmem_file>)\"
```
`<sw_vmem_file>` should be a path to a vmem file built as described above, use
diff --git a/hw/vendor/lowrisc_ibex/examples/simple_system/ibex_simple_system.core b/hw/vendor/lowrisc_ibex/examples/simple_system/ibex_simple_system.core
index 4e8a93e..dc45297 100644
--- a/hw/vendor/lowrisc_ibex/examples/simple_system/ibex_simple_system.core
+++ b/hw/vendor/lowrisc_ibex/examples/simple_system/ibex_simple_system.core
@@ -22,36 +22,40 @@
- ibex_simple_system.cc: { file_type: cppSource }
- lint/verilator_waiver.vlt: {file_type: vlt}
-parameters:
- RV32M:
- datatype: int
- paramtype: vlogparam
- default: 1
- description: "Enable the M ISA extension (hardware multiply/divide) [0/1]"
+ files_lint_verible:
+ files:
+ - lint/verible_waiver.vbw: {file_type: veribleLintWaiver}
+parameters:
RV32E:
datatype: int
paramtype: vlogparam
default: 0
description: "Enable the E ISA extension (reduced register set) [0/1]"
+ RV32M:
+ datatype: str
+ default: ibex_pkg::RV32MFast
+ paramtype: vlogdefine
+ description: "RV32M implementation parameter enum. See the ibex_pkg::rv32m_e enum in ibex_pkg.sv for permitted values."
+
RV32B:
datatype: str
default: ibex_pkg::RV32BNone
paramtype: vlogdefine
- description: "Bitmanip implementation parameter enum. See ibex_pkg.sv (EXPERIMENTAL)"
+ description: "Bitmanip implementation parameter enum. See the ibex_pkg::rv32b_e enum in ibex_pkg.sv for permitted values."
+
+ RegFile:
+ datatype: str
+ default: ibex_pkg::RegFileFF
+ paramtype: vlogdefine
+ description: "Register file implementation parameter enum. See the ibex_pkg::regfile_e enum in ibex_pkg.sv for permitted values."
SRAMInitFile:
datatype: str
paramtype: vlogparam
description: "Path to a vmem file to initialize the RAM with"
- MultiplierImplementation:
- datatype: str
- paramtype: vlogparam
- description: "Multiplier implementation. Valid values: fast, slow, single-cycle"
- default: "fast"
-
BranchTargetALU:
datatype: int
paramtype: vlogparam
@@ -70,6 +74,12 @@
paramtype: vlogparam
description: "Enables security hardening features (EXPERIMENTAL) [0/1]"
+ BranchPredictor:
+ datatype: int
+ paramtype: vlogparam
+ default: 0
+ description: "Enables static branch prediction (EXPERIMENTAL)"
+
PMPEnable:
datatype: int
default: 0
@@ -92,16 +102,18 @@
default: &default_target
filesets:
- tool_verilator ? (files_verilator)
+ - tool_veriblelint ? (files_lint_verible)
- files_sim
toplevel: ibex_simple_system
parameters:
- - RV32M
- RV32E
+ - RV32M
- RV32B
- - MultiplierImplementation
+ - RegFile
- BranchTargetALU
- WritebackStage
- SecureIbex
+ - BranchPredictor
- PMPEnable
- PMPGranularity
- PMPNumRegions
diff --git a/hw/vendor/lowrisc_ibex/examples/simple_system/lint/verible_waiver.vbw b/hw/vendor/lowrisc_ibex/examples/simple_system/lint/verible_waiver.vbw
new file mode 100644
index 0000000..4a1696f
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/examples/simple_system/lint/verible_waiver.vbw
@@ -0,0 +1 @@
+waive --rule=macro-name-style --location="ibex_simple_system.sv" --regex="RegFile"
\ No newline at end of file
diff --git a/hw/vendor/lowrisc_ibex/examples/simple_system/lint/verilator_waiver.vlt b/hw/vendor/lowrisc_ibex/examples/simple_system/lint/verilator_waiver.vlt
index 1959a78..26c8230 100644
--- a/hw/vendor/lowrisc_ibex/examples/simple_system/lint/verilator_waiver.vlt
+++ b/hw/vendor/lowrisc_ibex/examples/simple_system/lint/verilator_waiver.vlt
@@ -19,7 +19,7 @@
// We have some boolean top-level parameters in e.g. simple_system.sv.
// When building with fusesoc, these get set with defines like
-// -GRV32M=1 (rather than -GRV32M=1'b1), leading to warnings like:
+// -GRV32E=1 (rather than -GRV32E=1'b1), leading to warnings like:
//
// Operator VAR '<varname>' expects 1 bits on the Initial value, but
// Initial value's CONST '32'h1' generates 32 bits.
diff --git a/hw/vendor/lowrisc_ibex/examples/simple_system/rtl/ibex_simple_system.sv b/hw/vendor/lowrisc_ibex/examples/simple_system/rtl/ibex_simple_system.sv
index f4c630e..abe3779 100644
--- a/hw/vendor/lowrisc_ibex/examples/simple_system/rtl/ibex_simple_system.sv
+++ b/hw/vendor/lowrisc_ibex/examples/simple_system/rtl/ibex_simple_system.sv
@@ -2,10 +2,22 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
+// VCS does not support overriding enum and string parameters via command line. Instead, a `define
+// is used that can be set from the command line. If no value has been specified, this gives a
+// default. Other simulators don't take the detour via `define and can override the corresponding
+// parameters directly.
+`ifndef RV32M
+ `define RV32M ibex_pkg::RV32MFast
+`endif
+
`ifndef RV32B
`define RV32B ibex_pkg::RV32BNone
`endif
+`ifndef RegFile
+ `define RegFile ibex_pkg::RegFileFF
+`endif
+
/**
* Ibex simple system
*
@@ -23,17 +35,18 @@
input IO_RST_N
);
- parameter bit SecureIbex = 1'b0;
- parameter bit PMPEnable = 1'b0;
- parameter int unsigned PMPGranularity = 0;
- parameter int unsigned PMPNumRegions = 4;
- parameter bit RV32E = 1'b0;
- parameter bit RV32M = 1'b1;
- parameter ibex_pkg::rv32b_e RV32B = `RV32B;
- parameter bit BranchTargetALU = 1'b0;
- parameter bit WritebackStage = 1'b0;
- parameter MultiplierImplementation = "fast";
- parameter SRAMInitFile = "";
+ parameter bit SecureIbex = 1'b0;
+ parameter bit PMPEnable = 1'b0;
+ parameter int unsigned PMPGranularity = 0;
+ parameter int unsigned PMPNumRegions = 4;
+ parameter bit RV32E = 1'b0;
+ parameter ibex_pkg::rv32m_e RV32M = `RV32M;
+ parameter ibex_pkg::rv32b_e RV32B = `RV32B;
+ parameter ibex_pkg::regfile_e RegFile = `RegFile;
+ parameter bit BranchTargetALU = 1'b0;
+ parameter bit WritebackStage = 1'b0;
+ parameter bit BranchPredictor = 1'b0;
+ parameter SRAMInitFile = "";
logic clk_sys = 1'b0, rst_sys_n;
@@ -147,19 +160,20 @@
);
ibex_core_tracing #(
- .SecureIbex ( SecureIbex ),
- .PMPEnable ( PMPEnable ),
- .PMPGranularity ( PMPGranularity ),
- .PMPNumRegions ( PMPNumRegions ),
- .MHPMCounterNum ( 29 ),
- .RV32E ( RV32E ),
- .RV32M ( RV32M ),
- .RV32B ( RV32B ),
- .BranchTargetALU ( BranchTargetALU ),
- .WritebackStage ( WritebackStage ),
- .MultiplierImplementation ( MultiplierImplementation ),
- .DmHaltAddr ( 32'h00100000 ),
- .DmExceptionAddr ( 32'h00100000 )
+ .SecureIbex ( SecureIbex ),
+ .PMPEnable ( PMPEnable ),
+ .PMPGranularity ( PMPGranularity ),
+ .PMPNumRegions ( PMPNumRegions ),
+ .MHPMCounterNum ( 29 ),
+ .RV32E ( RV32E ),
+ .RV32M ( RV32M ),
+ .RV32B ( RV32B ),
+ .RegFile ( RegFile ),
+ .BranchTargetALU ( BranchTargetALU ),
+ .WritebackStage ( WritebackStage ),
+ .BranchPredictor ( BranchPredictor ),
+ .DmHaltAddr ( 32'h00100000 ),
+ .DmExceptionAddr ( 32'h00100000 )
) u_core (
.clk_i (clk_sys),
.rst_ni (rst_sys_n),
diff --git a/hw/vendor/lowrisc_ibex/examples/sw/benchmarks/README.md b/hw/vendor/lowrisc_ibex/examples/sw/benchmarks/README.md
index d2ad4a7..49bebb6 100644
--- a/hw/vendor/lowrisc_ibex/examples/sw/benchmarks/README.md
+++ b/hw/vendor/lowrisc_ibex/examples/sw/benchmarks/README.md
@@ -11,7 +11,7 @@
for running them can be built with:
```
-fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_simple_system --RV32M=1 --RV32E=0
+fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_simple_system --RV32E=0 --RV32M=ibex_pkg::RV32MFast
```
See examples/simple_system/README.md for full details.
diff --git a/hw/vendor/lowrisc_ibex/ibex_configs.yaml b/hw/vendor/lowrisc_ibex/ibex_configs.yaml
index ed0913c..6841125 100644
--- a/hw/vendor/lowrisc_ibex/ibex_configs.yaml
+++ b/hw/vendor/lowrisc_ibex/ibex_configs.yaml
@@ -9,11 +9,12 @@
# (4 cycles for mulh), resulting in 2 stall cycles for mul (3 for mulh)
small:
RV32E : 0
- RV32M : 1
+ RV32M : "ibex_pkg::RV32MFast"
RV32B : "ibex_pkg::RV32BNone"
+ RegFile : "ibex_pkg::RegFileFF"
BranchTargetALU : 0
WritebackStage : 0
- MultiplierImplementation : "fast"
+ BranchPredictor : 0
PMPEnable : 0
PMPGranularity : 0
PMPNumRegions : 4
@@ -27,11 +28,12 @@
# maximum performance configuration.
experimental-maxperf:
RV32E : 0
- RV32M : 1
+ RV32M : "ibex_pkg::RV32MSingleCycle"
RV32B : "ibex_pkg::RV32BNone"
+ RegFile : "ibex_pkg::RegFileFF"
BranchTargetALU : 1
WritebackStage : 1
- MultiplierImplementation : "single-cycle"
+ BranchPredictor : 0
PMPEnable : 0
PMPGranularity : 0
PMPNumRegions : 4
@@ -39,11 +41,12 @@
# experimental-maxperf config above plus PMP enabled with 16 regions.
experimental-maxperf-pmp:
RV32E : 0
- RV32M : 1
+ RV32M : "ibex_pkg::RV32MSingleCycle"
RV32B : "ibex_pkg::RV32BNone"
+ RegFile : "ibex_pkg::RegFileFF"
BranchTargetALU : 1
WritebackStage : 1
- MultiplierImplementation : "single-cycle"
+ BranchPredictor : 0
PMPEnable : 1
PMPGranularity : 0
PMPNumRegions : 16
@@ -51,11 +54,12 @@
# experimental-maxperf-pmp config above with balanced bitmanip extension
experimental-maxperf-pmp-bmbalanced:
RV32E : 0
- RV32M : 1
+ RV32M : "ibex_pkg::RV32MSingleCycle"
RV32B : "ibex_pkg::RV32BBalanced"
+ RegFile : "ibex_pkg::RegFileFF"
BranchTargetALU : 1
WritebackStage : 1
- MultiplierImplementation : "single-cycle"
+ BranchPredictor : 0
PMPEnable : 1
PMPGranularity : 0
PMPNumRegions : 16
@@ -63,12 +67,29 @@
# experimental-maxperf-pmp config above with full bitmanip extension
experimental-maxperf-pmp-bmfull:
RV32E : 0
- RV32M : 1
+ RV32M : "ibex_pkg::RV32MSingleCycle"
RV32B : "ibex_pkg::RV32BFull"
+ RegFile : "ibex_pkg::RegFileFF"
BranchTargetALU : 1
WritebackStage : 1
- MultiplierImplementation : "single-cycle"
+ BranchPredictor : 0
PMPEnable : 1
PMPGranularity : 0
PMPNumRegions : 16
+# experimental-maxperf with branch predictor switched on. This exists to allow
+# easy use of Ibex with the branch predictor in particular for CI runs. The
+# branch predictor will be enabled in all the 'maxperf' configs after further
+# development.
+experimental-branch-predictor:
+ RV32E : 0
+ RV32M : "ibex_pkg::RV32MSingleCycle"
+ RV32B : "ibex_pkg::RV32BNone"
+ RegFile : "ibex_pkg::RegFileFF"
+ BranchTargetALU : 1
+ WritebackStage : 1
+ BranchPredictor : 1
+ PMPEnable : 0
+ PMPGranularity : 0
+ PMPNumRegions : 4
+
diff --git a/hw/vendor/lowrisc_ibex/ibex_core.core b/hw/vendor/lowrisc_ibex/ibex_core.core
index 836b274..977c389 100644
--- a/hw/vendor/lowrisc_ibex/ibex_core.core
+++ b/hw/vendor/lowrisc_ibex/ibex_core.core
@@ -15,6 +15,7 @@
- lowrisc:ibex:ibex_icache
files:
- rtl/ibex_alu.sv
+ - rtl/ibex_branch_predict.sv
- rtl/ibex_compressed_decoder.sv
- rtl/ibex_controller.sv
- rtl/ibex_cs_registers.sv
@@ -31,11 +32,9 @@
- rtl/ibex_pmp.sv
- rtl/ibex_wb_stage.sv
- rtl/ibex_dummy_instr.sv
- # XXX: Figure out the best way to switch these two implementations
- # dynamically on the target.
-# - rtl/ibex_register_file_latch.sv # ASIC
-# - rtl/ibex_register_file_fpga.sv # FPGA
- rtl/ibex_register_file_ff.sv # generic FF-based
+ - rtl/ibex_register_file_fpga.sv # FPGA
+ - rtl/ibex_register_file_latch.sv # ASIC
- rtl/ibex_core.sv
file_type: systemVerilogSource
@@ -72,21 +71,22 @@
paramtype: vlogparam
RV32M:
- datatype: int
- default: 1
- paramtype: vlogparam
+ datatype: str
+ default: ibex_pkg::RV32MFast
+ paramtype: vlogdefine
+ description: "RV32M implementation parameter enum. See the ibex_pkg::rv32m_e enum in ibex_pkg.sv for permitted values."
RV32B:
datatype: str
default: ibex_pkg::RV32BNone
paramtype: vlogdefine
- description: "Bitmanip implementation parameter enum. See ibex_pkg.sv (EXPERIMENTAL)"
+ description: "Bitmanip implementation parameter enum. See the ibex_pkg::rv32b_e enum in ibex_pkg.sv for permitted values."
- MultiplierImplementation:
+ RegFile:
datatype: str
- paramtype: vlogparam
- description: "Multiplier implementation. Valid values: fast, slow, single-cycle"
- default: "fast"
+ default: ibex_pkg::RegFileFF
+ paramtype: vlogdefine
+ description: "Register file implementation parameter enum. See the ibex_pkg::regfile_e enum in ibex_pkg.sv for permitted values."
ICache:
datatype: int
@@ -112,6 +112,12 @@
paramtype: vlogparam
description: "Enables third pipeline stage (EXPERIMENTAL) [0/1]"
+ BranchPredictor:
+ datatype: int
+ paramtype: vlogparam
+ default: 0
+ description: "Enables static branch prediction (EXPERIMENTAL)"
+
SecureIbex:
datatype: int
default: 0
diff --git a/hw/vendor/lowrisc_ibex/ibex_core_tracing.core b/hw/vendor/lowrisc_ibex/ibex_core_tracing.core
index f568cb1..a7697e1 100644
--- a/hw/vendor/lowrisc_ibex/ibex_core_tracing.core
+++ b/hw/vendor/lowrisc_ibex/ibex_core_tracing.core
@@ -30,21 +30,22 @@
paramtype: vlogparam
RV32M:
- datatype: int
- default: 1
- paramtype: vlogparam
+ datatype: str
+ default: ibex_pkg::RV32MFast
+ paramtype: vlogdefine
+ description: "RV32M implementation parameter enum. See the ibex_pkg::rv32m_e enum in ibex_pkg.sv for permitted values."
RV32B:
datatype: str
default: ibex_pkg::RV32BNone
paramtype: vlogdefine
- description: "Bitmanip implementation parameter enum. See ibex_pkg.sv (EXPERIMENTAL)"
+ description: "Bitmanip implementation parameter enum. See the ibex_pkg::rv32b_e enum in ibex_pkg.sv for permitted values."
- MultiplierImplementation:
+ RegFile:
datatype: str
- paramtype: vlogparam
- description: "Multiplier implementation. Valid values: fast, slow, single-cycle"
- default: "fast"
+ default: ibex_pkg::RegFileFF
+ paramtype: vlogdefine
+ description: "Register file implementation parameter enum. See the ibex_pkg::regfile_e enum in ibex_pkg.sv for permitted values."
ICache:
datatype: int
@@ -70,6 +71,12 @@
paramtype: vlogparam
description: "Enables third pipeline stage (EXPERIMENTAL) [0/1]"
+ BranchPredictor:
+ datatype: int
+ paramtype: vlogparam
+ default: 0
+ description: "Enables static branch prediction (EXPERIMENTAL)"
+
SecureIbex:
datatype: int
default: 0
@@ -107,12 +114,13 @@
parameters:
- RVFI=true
- SYNTHESIS=true
- - RV32M
- RV32E
+ - RV32M
- RV32B
+ - RegFile
- BranchTargetALU
- WritebackStage
- - MultiplierImplementation
+ - BranchPredictor
- SecureIbex
- PMPEnable
- PMPGranularity
diff --git a/hw/vendor/lowrisc_ibex/lint/verible_waiver.vbw b/hw/vendor/lowrisc_ibex/lint/verible_waiver.vbw
index 8ed90c5..e69de29 100644
--- a/hw/vendor/lowrisc_ibex/lint/verible_waiver.vbw
+++ b/hw/vendor/lowrisc_ibex/lint/verible_waiver.vbw
@@ -1 +0,0 @@
-waive --rule=module-filename --location="ibex_register_file_.+"
diff --git a/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt b/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
index 8049d65..880dfc1 100644
--- a/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
+++ b/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
@@ -12,22 +12,24 @@
`verilator_config
lint_off -rule PINCONNECTEMPTY
-// Operator expects 1 bit on initial value but initial value's CONST generates
-// 32 bits
-lint_off -rule WIDTH -file "*/rtl/ibex_core_tracing.sv" -match "*'RV32M'*"
-lint_off -rule WIDTH -file "*/rtl/ibex_core_tracing.sv" -match "*'RV32E'*"
-lint_off -rule WIDTH -file "*/rtl/ibex_core_tracing.sv" -match "*'RV32B'*"
-lint_off -rule WIDTH -file "*/rtl/ibex_core_tracing.sv" -match "*'BranchTargetALU'*"
-lint_off -rule WIDTH -file "*/rtl/ibex_core_tracing.sv" -match "*'WritebackStage'*"
-lint_off -rule WIDTH -file "*/rtl/ibex_core_tracing.sv" -match "*'SecureIbex'*"
-lint_off -rule WIDTH -file "*/rtl/ibex_core_tracing.sv" -match "*'PMPEnable'*"
+// We have some boolean top-level parameters in e.g. ibex_core_tracing.sv.
+// When building with fusesoc, these get set with defines like
+// -GRV32M=1 (rather than -GRV32M=1'b1), leading to warnings like:
+//
+// Operator VAR '<varname>' expects 1 bits on the Initial value, but
+// Initial value's CONST '32'h1' generates 32 bits.
+//
+// This signoff rule ignores errors like this. Note that it only
+// matches when you set a 1-bit value to a literal 1, so it won't hide
+// silly mistakes like setting it to 2.
+//
+lint_off -rule WIDTH -file "*/rtl/ibex_core_tracing.sv"
+ -match "*expects 1 bits*Initial value's CONST '32'h1'*"
-// Filename 'ibex_register_file_ff' does not match MODULE name: ibex_register_file
-// ibex_register_file_ff and ibex_register_file_latch provide two
-// implementation choices for the same module.
-lint_off -rule DECLFILENAME -file "*/rtl/ibex_register_file_ff.sv"
-lint_off -rule DECLFILENAME -file "*/rtl/ibex_register_file_latch.sv"
-lint_off -rule DECLFILENAME -file "*/rtl/ibex_register_file_fpga.sv"
+// Operator expects 1 bit on initial value but initial value's CONST generates
+// 32 bits, need a specific RV32B waiver as it uses enums so the above catch-all
+// waiver doesn't work.
+lint_off -rule WIDTH -file "*/rtl/ibex_core_tracing.sv" -match "*'RV32B'*"
// Bits of signal are not used: shift_amt_compl[5]
// cleaner to write all bits even if not all are used
@@ -141,12 +143,14 @@
lint_off -rule UNUSED -file "*/rtl/ibex_pmp.sv" -match "*clk_i*"
lint_off -rule UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -match "*clk_i*"
lint_off -rule UNUSED -file "*/rtl/ibex_decoder.sv" -match "*clk_i*"
+lint_off -rule UNUSED -file "*/rtl/ibex_branch_predict.sv" -match "*clk_i*"
// Signal is not used: rst_ni
// leaving clk and reset connected in-case we want to add assertions
lint_off -rule UNUSED -file "*/rtl/ibex_pmp.sv" -match "*rst_ni*"
lint_off -rule UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -match "*rst_ni*"
lint_off -rule UNUSED -file "*/rtl/ibex_decoder.sv" -match "*rst_ni*"
+lint_off -rule UNUSED -file "*/rtl/ibex_branch_predict.sv" -match "*rst_ni*"
// Bits of signal are not used: instr_alu[24:15,11:7]
// instr flops are duplicated to reduce fan-out, neater to just leave unused
diff --git a/hw/vendor/lowrisc_ibex/python-requirements.txt b/hw/vendor/lowrisc_ibex/python-requirements.txt
index 8da5777..1914000 100644
--- a/hw/vendor/lowrisc_ibex/python-requirements.txt
+++ b/hw/vendor/lowrisc_ibex/python-requirements.txt
@@ -12,6 +12,8 @@
mako
# Needed by dvsim.py (not actually used in Ibex)
+hjson
+mistletoe>=0.7.2
premailer
# Recurse to get any requirements from riscv-dv
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_branch_predict.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_branch_predict.sv
new file mode 100644
index 0000000..988099f
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_branch_predict.sv
@@ -0,0 +1,100 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+/**
+ * Branch Predictor
+ *
+ * This implements static branch prediction. It takes an instruction and its PC and determines if
+ * it's a branch or a jump and calculates its target. For jumps it will always predict taken. For
+ * branches it will predict taken if the PC offset is negative.
+ *
+ * This handles both compressed and uncompressed instructions. Compressed instructions must be in
+ * the lower 16-bits of instr.
+ *
+ * The predictor is entirely combinational but takes clk/rst_n signals for use by assertions.
+ */
+
+`include "prim_assert.sv"
+
+module ibex_branch_predict (
+ input logic clk_i,
+ input logic rst_ni,
+
+ // Instruction from fetch stage
+ input logic [31:0] fetch_rdata_i,
+ input logic [31:0] fetch_pc_i,
+ input logic fetch_valid_i,
+
+ // Prediction for supplied instruction
+ output logic predict_branch_taken_o,
+ output logic [31:0] predict_branch_pc_o
+);
+ import ibex_pkg::*;
+
+ logic [31:0] imm_j_type;
+ logic [31:0] imm_b_type;
+ logic [31:0] imm_cj_type;
+ logic [31:0] imm_cb_type;
+
+ logic [31:0] branch_imm;
+
+ logic [31:0] instr;
+
+ logic instr_j;
+ logic instr_b;
+ logic instr_cj;
+ logic instr_cb;
+
+ logic instr_b_taken;
+
+ // Provide short internal name for fetch_rdata_i due to reduce line wrapping
+ assign instr = fetch_rdata_i;
+
+ // Extract and sign-extend to 32-bit the various immediates that may be used to calculate the
+ // target
+
+ // Uncompressed immediates
+ assign imm_j_type = { {12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0 };
+ assign imm_b_type = { {19{instr[31]}}, instr[31], instr[7], instr[30:25], instr[11:8], 1'b0 };
+
+ // Compressed immediates
+ assign imm_cj_type = { {20{instr[12]}}, instr[12], instr[8], instr[10:9], instr[6], instr[7],
+ instr[2], instr[11], instr[5:3], 1'b0 };
+
+ assign imm_cb_type = { {23{instr[12]}}, instr[12], instr[6:5], instr[2], instr[11:10],
+ instr[4:3], 1'b0};
+
+ // Determine if the instruction is a branch or a jump
+
+ // Uncompressed branch/jump
+ assign instr_b = opcode_e'(instr[6:0]) == OPCODE_BRANCH;
+ assign instr_j = opcode_e'(instr[6:0]) == OPCODE_JAL;
+
+ // Compressed branch/jump
+ assign instr_cb = (instr[1:0] == 2'b01) & ((instr[15:13] == 3'b110) | (instr[15:13] == 3'b111));
+ assign instr_cj = (instr[1:0] == 2'b01) & ((instr[15:13] == 3'b101) | (instr[15:13] == 3'b001));
+
+ // Select out the branch offset for target calculation based upon the instruction type
+ always_comb begin
+ branch_imm = imm_b_type;
+
+ unique case (1'b1)
+ instr_j : branch_imm = imm_j_type;
+ instr_b : branch_imm = imm_b_type;
+ instr_cj : branch_imm = imm_cj_type;
+ instr_cb : branch_imm = imm_cb_type;
+ default : ;
+ endcase
+ end
+
+ `ASSERT_IF(BranchInsTypeOneHot, $onehot0({instr_j, instr_b, instr_cj, instr_cb}), fetch_valid_i);
+
+ // Determine branch prediction, taken if offset is negative
+ assign instr_b_taken = (instr_b & imm_b_type[31]) | (instr_cb & imm_cb_type[31]);
+
+ // Always predict jumps taken otherwise take prediction from `instr_b_taken`
+ assign predict_branch_taken_o = fetch_valid_i & (instr_j | instr_cj | instr_b_taken);
+ // Calculate target
+ assign predict_branch_pc_o = fetch_pc_i + branch_imm;
+endmodule
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
index 832a03b..afa7fff 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
@@ -10,7 +10,8 @@
`include "prim_assert.sv"
module ibex_controller #(
- parameter bit WritebackStage = 0
+ parameter bit WritebackStage = 0,
+ parameter bit BranchPredictor = 0
) (
input logic clk_i,
input logic rst_ni,
@@ -26,14 +27,15 @@
input logic ebrk_insn_i, // decoder has EBREAK 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 instr_fetch_err_plus2_i, // instr from IF-ID reg error is x32
- input logic [31:0] pc_id_i, // instr from IF-ID reg address
+ // instr from IF-ID pipeline stage
+ input logic instr_valid_i, // instr is valid
+ input logic [31:0] instr_i, // uncompressed instr data for mtval
+ input logic [15:0] instr_compressed_i, // instr compressed data for mtval
+ input logic instr_is_compressed_i, // instr is compressed
+ input logic instr_bp_taken_i, // instr was predicted taken branch
+ input logic instr_fetch_err_i, // instr has error
+ input logic instr_fetch_err_plus2_i, // instr error is x32
+ input logic [31:0] pc_id_i, // instr address
// to IF-ID pipeline stage
output logic instr_valid_clear_o, // kill instr in IF-ID reg
@@ -47,6 +49,8 @@
output logic pc_set_spec_o, // speculative branch
output ibex_pkg::pc_sel_e pc_mux_o, // IF stage fetch address selector
// (boot, normal, exception...)
+ output logic nt_branch_mispredict_o, // Not-taken branch in ID/EX was
+ // mispredicted (predicted taken)
output ibex_pkg::exc_pc_sel_e exc_pc_mux_o, // IF stage selector for exception PC
output ibex_pkg::exc_cause_e exc_cause_o, // for IF stage, CSRs
@@ -57,8 +61,11 @@
output logic wb_exception_o, // Instruction in WB taking an exception
// jump/branch signals
- input logic branch_set_i, // branch taken set signal
- input logic branch_set_spec_i, // speculative branch signal
+ input logic branch_set_i, // branch set signal (branch definitely
+ // taken)
+ input logic branch_set_spec_i, // speculative branch signal (branch
+ // may be taken)
+ input logic branch_not_set_i, // branch is definitely not taken
input logic jump_set_i, // jump taken set signal
// interrupt signals
@@ -337,7 +344,6 @@
else if (irqs_i.irq_fast[ 7]) mfip_id = 4'd7;
else if (irqs_i.irq_fast[ 6]) mfip_id = 4'd6;
else if (irqs_i.irq_fast[ 5]) mfip_id = 4'd5;
- else if (irqs_i.irq_fast[ 5]) mfip_id = 4'd5;
else if (irqs_i.irq_fast[ 4]) mfip_id = 4'd4;
else if (irqs_i.irq_fast[ 3]) mfip_id = 4'd3;
else if (irqs_i.irq_fast[ 2]) mfip_id = 4'd2;
@@ -367,30 +373,31 @@
// below always set pc_mux and exc_pc_mux but only set pc_set if certain conditions are met.
// This avoid having to factor those conditions into the pc_mux and exc_pc_mux select signals
// helping timing.
- pc_mux_o = PC_BOOT;
- pc_set_o = 1'b0;
- pc_set_spec_o = 1'b0;
+ pc_mux_o = PC_BOOT;
+ pc_set_o = 1'b0;
+ pc_set_spec_o = 1'b0;
+ nt_branch_mispredict_o = 1'b0;
- exc_pc_mux_o = EXC_PC_IRQ;
- exc_cause_o = EXC_CAUSE_INSN_ADDR_MISA; // = 6'h00
+ exc_pc_mux_o = EXC_PC_IRQ;
+ exc_cause_o = EXC_CAUSE_INSN_ADDR_MISA; // = 6'h00
- ctrl_fsm_ns = ctrl_fsm_cs;
+ ctrl_fsm_ns = ctrl_fsm_cs;
- ctrl_busy_o = 1'b1;
+ ctrl_busy_o = 1'b1;
- halt_if = 1'b0;
- retain_id = 1'b0;
- flush_id = 1'b0;
+ halt_if = 1'b0;
+ retain_id = 1'b0;
+ flush_id = 1'b0;
- debug_csr_save_o = 1'b0;
- debug_cause_o = DBG_CAUSE_EBREAK;
- debug_mode_d = debug_mode_q;
- nmi_mode_d = nmi_mode_q;
+ debug_csr_save_o = 1'b0;
+ debug_cause_o = DBG_CAUSE_EBREAK;
+ debug_mode_d = debug_mode_q;
+ nmi_mode_d = nmi_mode_q;
- perf_tbranch_o = 1'b0;
- perf_jump_o = 1'b0;
+ perf_tbranch_o = 1'b0;
+ perf_jump_o = 1'b0;
- controller_run_o = 1'b0;
+ controller_run_o = 1'b0;
unique case (ctrl_fsm_cs)
RESET: begin
@@ -494,16 +501,29 @@
end
end
- if ((branch_set_i || jump_set_i) && !special_req_branch) begin
- pc_set_o = 1'b1;
+ if (!special_req_branch) begin
+ if (branch_set_i || jump_set_i) begin
+ // Only set the PC if the branch predictor hasn't already done the branch for us
+ pc_set_o = BranchPredictor ? ~instr_bp_taken_i : 1'b1;
- perf_tbranch_o = branch_set_i;
- perf_jump_o = jump_set_i;
+ perf_tbranch_o = branch_set_i;
+ perf_jump_o = jump_set_i;
+ end
+
+ if (BranchPredictor) begin
+ if (instr_bp_taken_i & branch_not_set_i) begin
+ // If the instruction is a branch that was predicted to be taken but was not taken
+ // signal a mispredict.
+ nt_branch_mispredict_o = 1'b1;
+ end
+ end
end
// pc_set signal excluding branch taken condition
if ((branch_set_spec_i || jump_set_i) && !special_req_branch) begin
- pc_set_spec_o = 1'b1;
+ // Only speculatively set the PC if the branch predictor hasn't already done the branch
+ // for us
+ pc_set_spec_o = BranchPredictor ? ~instr_bp_taken_i : 1'b1;
end
// If entering debug mode or handling an IRQ the core needs to wait
@@ -810,6 +830,8 @@
// Assertions //
////////////////
+ `ASSERT(AlwaysInstrClearOnMispredict, nt_branch_mispredict_o -> instr_valid_clear_o);
+
// Selectors must be known/valid.
`ASSERT(IbexCtrlStateValid, ctrl_fsm_cs inside {
RESET, BOOT_SET, WAIT_SLEEP, SLEEP, FIRST_FETCH, DECODE, FLUSH,
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
index 370d1a0..2e7d091 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
@@ -9,31 +9,28 @@
`include "prim_assert.sv"
-`ifndef RV32B
- `define RV32B ibex_pkg::RV32BNone
-`endif
-
/**
* Top level module of the ibex RISC-V core
*/
module ibex_core #(
- parameter bit PMPEnable = 1'b0,
- parameter int unsigned PMPGranularity = 0,
- parameter int unsigned PMPNumRegions = 4,
- parameter int unsigned MHPMCounterNum = 0,
- parameter int unsigned MHPMCounterWidth = 40,
- parameter bit RV32E = 1'b0,
- parameter bit RV32M = 1'b1,
- parameter ibex_pkg::rv32b_e RV32B = `RV32B,
- parameter bit BranchTargetALU = 1'b0,
- parameter bit WritebackStage = 1'b0,
- parameter MultiplierImplementation = "fast",
- parameter bit ICache = 1'b0,
- parameter bit ICacheECC = 1'b0,
- parameter bit DbgTriggerEn = 1'b0,
- parameter bit SecureIbex = 1'b0,
- parameter int unsigned DmHaltAddr = 32'h1A110800,
- parameter int unsigned DmExceptionAddr = 32'h1A110808
+ parameter bit PMPEnable = 1'b0,
+ parameter int unsigned PMPGranularity = 0,
+ parameter int unsigned PMPNumRegions = 4,
+ parameter int unsigned MHPMCounterNum = 0,
+ parameter int unsigned MHPMCounterWidth = 40,
+ parameter bit RV32E = 1'b0,
+ parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast,
+ parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
+ parameter ibex_pkg::regfile_e RegFile = ibex_pkg::RegFileFF,
+ parameter bit BranchTargetALU = 1'b0,
+ parameter bit WritebackStage = 1'b0,
+ parameter bit ICache = 1'b0,
+ parameter bit ICacheECC = 1'b0,
+ parameter bit BranchPredictor = 1'b0,
+ parameter bit DbgTriggerEn = 1'b0,
+ parameter bit SecureIbex = 1'b0,
+ parameter int unsigned DmHaltAddr = 32'h1A110800,
+ parameter int unsigned DmExceptionAddr = 32'h1A110808
) (
// Clock and Reset
input logic clk_i,
@@ -131,6 +128,7 @@
// ease fan-out)
logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage
logic instr_is_compressed_id;
+ logic instr_bp_taken_id;
logic instr_fetch_err; // Bus error on instr fetch
logic instr_fetch_err_plus2; // Instruction error is misaligned
logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage
@@ -154,6 +152,7 @@
logic instr_valid_clear;
logic pc_set;
logic pc_set_spec;
+ logic nt_branch_mispredict;
pc_sel_e pc_mux_id; // Mux selector for next PC
exc_pc_sel_e exc_pc_mux_id; // Mux selector for exception PC
exc_cause_e exc_cause; // Exception cause
@@ -397,7 +396,8 @@
.DummyInstructions ( DummyInstructions ),
.ICache ( ICache ),
.ICacheECC ( ICacheECC ),
- .SecureIbex ( SecureIbex )
+ .SecureIbex ( SecureIbex ),
+ .BranchPredictor ( BranchPredictor )
) if_stage_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
@@ -421,6 +421,7 @@
.instr_rdata_alu_id_o ( instr_rdata_alu_id ),
.instr_rdata_c_id_o ( instr_rdata_c_id ),
.instr_is_compressed_id_o ( instr_is_compressed_id ),
+ .instr_bp_taken_o ( instr_bp_taken_id ),
.instr_fetch_err_o ( instr_fetch_err ),
.instr_fetch_err_plus2_o ( instr_fetch_err_plus2 ),
.illegal_c_insn_id_o ( illegal_c_insn_id ),
@@ -433,6 +434,7 @@
.pc_set_i ( pc_set ),
.pc_set_spec_i ( pc_set_spec ),
.pc_mux_i ( pc_mux_id ),
+ .nt_branch_mispredict_i ( nt_branch_mispredict ),
.exc_pc_mux_i ( exc_pc_mux_id ),
.exc_cause ( exc_cause ),
.dummy_instr_en_i ( dummy_instr_en ),
@@ -476,7 +478,8 @@
.BranchTargetALU ( BranchTargetALU ),
.DataIndTiming ( DataIndTiming ),
.SpecBranch ( SpecBranch ),
- .WritebackStage ( WritebackStage )
+ .WritebackStage ( WritebackStage ),
+ .BranchPredictor ( BranchPredictor )
) id_stage_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
@@ -491,6 +494,7 @@
.instr_rdata_alu_i ( instr_rdata_alu_id ),
.instr_rdata_c_i ( instr_rdata_c_id ),
.instr_is_compressed_i ( instr_is_compressed_id ),
+ .instr_bp_taken_i ( instr_bp_taken_id ),
// Jumps and branches
.branch_decision_i ( branch_decision ),
@@ -503,6 +507,7 @@
.pc_set_o ( pc_set ),
.pc_set_spec_o ( pc_set_spec ),
.pc_mux_o ( pc_mux_id ),
+ .nt_branch_mispredict_o ( nt_branch_mispredict ),
.exc_pc_mux_o ( exc_pc_mux_id ),
.exc_cause_o ( exc_cause ),
.icache_inval_o ( icache_inval ),
@@ -628,8 +633,7 @@
ibex_ex_block #(
.RV32M ( RV32M ),
.RV32B ( RV32B ),
- .BranchTargetALU ( BranchTargetALU ),
- .MultiplierImplementation ( MultiplierImplementation )
+ .BranchTargetALU ( BranchTargetALU )
) ex_block_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
@@ -815,28 +819,67 @@
assign rf_ecc_err_comb = 1'b0;
end
- ibex_register_file #(
- .RV32E (RV32E),
- .DataWidth (RegFileDataWidth),
- .DummyInstructions (DummyInstructions)
- ) register_file_i (
- .clk_i ( clk_i ),
- .rst_ni ( rst_ni ),
+ if (RegFile == RegFileFF) begin : gen_regfile_ff
+ ibex_register_file_ff #(
+ .RV32E ( RV32E ),
+ .DataWidth ( RegFileDataWidth ),
+ .DummyInstructions ( DummyInstructions )
+ ) register_file_i (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
- .test_en_i ( test_en_i ),
- .dummy_instr_id_i ( dummy_instr_id ),
+ .test_en_i ( test_en_i ),
+ .dummy_instr_id_i ( dummy_instr_id ),
- // Read port a
- .raddr_a_i ( rf_raddr_a ),
- .rdata_a_o ( rf_rdata_a_ecc ),
- // Read port b
- .raddr_b_i ( rf_raddr_b ),
- .rdata_b_o ( rf_rdata_b_ecc ),
- // write port
- .waddr_a_i ( rf_waddr_wb ),
- .wdata_a_i ( rf_wdata_wb_ecc ),
- .we_a_i ( rf_we_wb )
- );
+ .raddr_a_i ( rf_raddr_a ),
+ .rdata_a_o ( rf_rdata_a_ecc ),
+ .raddr_b_i ( rf_raddr_b ),
+ .rdata_b_o ( rf_rdata_b_ecc ),
+ .waddr_a_i ( rf_waddr_wb ),
+ .wdata_a_i ( rf_wdata_wb_ecc ),
+ .we_a_i ( rf_we_wb )
+ );
+ end else if (RegFile == RegFileFPGA) begin : gen_regfile_fpga
+ ibex_register_file_fpga #(
+ .RV32E ( RV32E ),
+ .DataWidth ( RegFileDataWidth ),
+ .DummyInstructions ( DummyInstructions )
+ ) register_file_i (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+
+ .test_en_i ( test_en_i ),
+ .dummy_instr_id_i ( dummy_instr_id ),
+
+ .raddr_a_i ( rf_raddr_a ),
+ .rdata_a_o ( rf_rdata_a_ecc ),
+ .raddr_b_i ( rf_raddr_b ),
+ .rdata_b_o ( rf_rdata_b_ecc ),
+ .waddr_a_i ( rf_waddr_wb ),
+ .wdata_a_i ( rf_wdata_wb_ecc ),
+ .we_a_i ( rf_we_wb )
+ );
+ end else if (RegFile == RegFileLatch) begin : gen_regfile_latch
+ ibex_register_file_latch #(
+ .RV32E ( RV32E ),
+ .DataWidth ( RegFileDataWidth ),
+ .DummyInstructions ( DummyInstructions )
+ ) register_file_i (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+
+ .test_en_i ( test_en_i ),
+ .dummy_instr_id_i ( dummy_instr_id ),
+
+ .raddr_a_i ( rf_raddr_a ),
+ .rdata_a_o ( rf_rdata_a_ecc ),
+ .raddr_b_i ( rf_raddr_b ),
+ .rdata_b_o ( rf_rdata_b_ecc ),
+ .waddr_a_i ( rf_waddr_wb ),
+ .wdata_a_i ( rf_wdata_wb_ecc ),
+ .we_a_i ( rf_we_wb )
+ );
+ end
///////////////////
// Alert outputs //
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv
index 4fbcde0..e731b9d 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv
@@ -2,32 +2,29 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-`ifndef RV32B
- `define RV32B ibex_pkg::RV32BNone
-`endif
-
/**
* Top level module of the ibex RISC-V core with tracing enabled
*/
module ibex_core_tracing #(
- parameter bit PMPEnable = 1'b0,
- parameter int unsigned PMPGranularity = 0,
- parameter int unsigned PMPNumRegions = 4,
- parameter int unsigned MHPMCounterNum = 0,
- parameter int unsigned MHPMCounterWidth = 40,
- parameter bit RV32E = 1'b0,
- parameter bit RV32M = 1'b1,
- parameter ibex_pkg::rv32b_e RV32B = `RV32B,
- parameter bit BranchTargetALU = 1'b0,
- parameter bit WritebackStage = 1'b0,
- parameter MultiplierImplementation = "fast",
- parameter bit ICache = 1'b0,
- parameter bit ICacheECC = 1'b0,
- parameter bit DbgTriggerEn = 1'b0,
- parameter bit SecureIbex = 1'b0,
- parameter int unsigned DmHaltAddr = 32'h1A110800,
- parameter int unsigned DmExceptionAddr = 32'h1A110808
+ parameter bit PMPEnable = 1'b0,
+ parameter int unsigned PMPGranularity = 0,
+ parameter int unsigned PMPNumRegions = 4,
+ parameter int unsigned MHPMCounterNum = 0,
+ parameter int unsigned MHPMCounterWidth = 40,
+ parameter bit RV32E = 1'b0,
+ parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast,
+ parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
+ parameter ibex_pkg::regfile_e RegFile = ibex_pkg::RegFileFF,
+ parameter bit BranchTargetALU = 1'b0,
+ parameter bit WritebackStage = 1'b0,
+ parameter bit ICache = 1'b0,
+ parameter bit ICacheECC = 1'b0,
+ parameter bit BranchPredictor = 1'b0,
+ parameter bit DbgTriggerEn = 1'b0,
+ parameter bit SecureIbex = 1'b0,
+ parameter int unsigned DmHaltAddr = 32'h1A110800,
+ parameter int unsigned DmExceptionAddr = 32'h1A110808
) (
// Clock and Reset
input logic clk_i,
@@ -107,23 +104,24 @@
logic [31:0] rvfi_mem_wdata;
ibex_core #(
- .PMPEnable ( PMPEnable ),
- .PMPGranularity ( PMPGranularity ),
- .PMPNumRegions ( PMPNumRegions ),
- .MHPMCounterNum ( MHPMCounterNum ),
- .MHPMCounterWidth ( MHPMCounterWidth ),
- .RV32E ( RV32E ),
- .RV32M ( RV32M ),
- .RV32B ( RV32B ),
- .BranchTargetALU ( BranchTargetALU ),
- .MultiplierImplementation ( MultiplierImplementation ),
- .ICache ( ICache ),
- .ICacheECC ( ICacheECC ),
- .DbgTriggerEn ( DbgTriggerEn ),
- .WritebackStage ( WritebackStage ),
- .SecureIbex ( SecureIbex ),
- .DmHaltAddr ( DmHaltAddr ),
- .DmExceptionAddr ( DmExceptionAddr )
+ .PMPEnable ( PMPEnable ),
+ .PMPGranularity ( PMPGranularity ),
+ .PMPNumRegions ( PMPNumRegions ),
+ .MHPMCounterNum ( MHPMCounterNum ),
+ .MHPMCounterWidth ( MHPMCounterWidth ),
+ .RV32E ( RV32E ),
+ .RV32M ( RV32M ),
+ .RV32B ( RV32B ),
+ .RegFile ( RegFile ),
+ .BranchTargetALU ( BranchTargetALU ),
+ .ICache ( ICache ),
+ .ICacheECC ( ICacheECC ),
+ .BranchPredictor ( BranchPredictor ),
+ .DbgTriggerEn ( DbgTriggerEn ),
+ .WritebackStage ( WritebackStage ),
+ .SecureIbex ( SecureIbex ),
+ .DmHaltAddr ( DmHaltAddr ),
+ .DmExceptionAddr ( DmExceptionAddr )
) u_ibex_core (
.clk_i,
.rst_ni,
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
index 50d1107..45d1bcd 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
@@ -13,17 +13,17 @@
`include "prim_assert.sv"
module ibex_cs_registers #(
- parameter bit DbgTriggerEn = 0,
- parameter bit DataIndTiming = 1'b0,
- parameter bit DummyInstructions = 1'b0,
- parameter bit ICache = 1'b0,
- parameter int unsigned MHPMCounterNum = 10,
- 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
+ parameter bit DbgTriggerEn = 0,
+ parameter bit DataIndTiming = 1'b0,
+ parameter bit DummyInstructions = 1'b0,
+ parameter bit ICache = 1'b0,
+ parameter int unsigned MHPMCounterNum = 10,
+ parameter int unsigned MHPMCounterWidth = 40,
+ parameter bit PMPEnable = 0,
+ parameter int unsigned PMPGranularity = 0,
+ parameter int unsigned PMPNumRegions = 4,
+ parameter bit RV32E = 0,
+ parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast
) (
// Clock and Reset
input logic clk_i,
@@ -116,6 +116,8 @@
import ibex_pkg::*;
+ localparam int unsigned RV32MEnabled = (RV32M == RV32MNone) ? 0 : 1;
+
// misa
localparam logic [31:0] MISA_VALUE =
(0 << 0) // A - Atomic Instructions extension
@@ -124,7 +126,7 @@
| (32'(RV32E) << 4) // E - RV32E base ISA
| (0 << 5) // F - Single precision floating-point extension
| (32'(!RV32E) << 8) // I - RV32I/64I/128I base ISA
- | (32'(RV32M) << 12) // M - Integer Multiply/Divide extension
+ | (RV32MEnabled << 12) // M - Integer Multiply/Divide extension
| (0 << 13) // N - User level interrupts supported
| (0 << 18) // S - Supervisor mode implemented
| (1 << 20) // U - User mode implemented
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
index 5788f8d..f55b719 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
@@ -14,10 +14,10 @@
`include "prim_assert.sv"
module ibex_decoder #(
- parameter bit RV32E = 0,
- parameter bit RV32M = 1,
- parameter bit BranchTargetALU = 0,
- parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone
+ parameter bit RV32E = 0,
+ parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast,
+ parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
+ parameter bit BranchTargetALU = 0
) (
input logic clk_i,
input logic rst_ni,
@@ -486,42 +486,42 @@
{7'b000_0001, 3'b000}: begin // mul
multdiv_operator_o = MD_OP_MULL;
multdiv_signed_mode_o = 2'b00;
- illegal_insn = RV32M ? 1'b0 : 1'b1;
+ illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0;
end
{7'b000_0001, 3'b001}: begin // mulh
multdiv_operator_o = MD_OP_MULH;
multdiv_signed_mode_o = 2'b11;
- illegal_insn = RV32M ? 1'b0 : 1'b1;
+ illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0;
end
{7'b000_0001, 3'b010}: begin // mulhsu
multdiv_operator_o = MD_OP_MULH;
multdiv_signed_mode_o = 2'b01;
- illegal_insn = RV32M ? 1'b0 : 1'b1;
+ illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0;
end
{7'b000_0001, 3'b011}: begin // mulhu
multdiv_operator_o = MD_OP_MULH;
multdiv_signed_mode_o = 2'b00;
- illegal_insn = RV32M ? 1'b0 : 1'b1;
+ illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0;
end
{7'b000_0001, 3'b100}: begin // div
multdiv_operator_o = MD_OP_DIV;
multdiv_signed_mode_o = 2'b11;
- illegal_insn = RV32M ? 1'b0 : 1'b1;
+ illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0;
end
{7'b000_0001, 3'b101}: begin // divu
multdiv_operator_o = MD_OP_DIV;
multdiv_signed_mode_o = 2'b00;
- illegal_insn = RV32M ? 1'b0 : 1'b1;
+ illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0;
end
{7'b000_0001, 3'b110}: begin // rem
multdiv_operator_o = MD_OP_REM;
multdiv_signed_mode_o = 2'b11;
- illegal_insn = RV32M ? 1'b0 : 1'b1;
+ illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0;
end
{7'b000_0001, 3'b111}: begin // remu
multdiv_operator_o = MD_OP_REM;
multdiv_signed_mode_o = 2'b00;
- illegal_insn = RV32M ? 1'b0 : 1'b1;
+ illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0;
end
default: begin
illegal_insn = 1'b1;
@@ -535,11 +535,9 @@
/////////////
OPCODE_MISC_MEM: begin
- // For now, treat the FENCE (funct3 == 000) instruction as a NOP. This may not be correct
- // in a system with caches and should be revisited.
- // FENCE.I will flush the IF stage and prefetch buffer (or ICache) but nothing else.
unique case (instr[14:12])
3'b000: begin
+ // FENCE is treated as a NOP since all memory operations are already strictly ordered.
rf_we = 1'b0;
end
3'b001: begin
@@ -1037,35 +1035,35 @@
// RV32M instructions, all use the same ALU operation
{7'b000_0001, 3'b000}: begin // mul
alu_operator_o = ALU_ADD;
- mult_sel_o = RV32M ? 1'b1 : 1'b0;
+ mult_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1;
end
{7'b000_0001, 3'b001}: begin // mulh
alu_operator_o = ALU_ADD;
- mult_sel_o = RV32M ? 1'b1 : 1'b0;
+ mult_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1;
end
{7'b000_0001, 3'b010}: begin // mulhsu
alu_operator_o = ALU_ADD;
- mult_sel_o = RV32M ? 1'b1 : 1'b0;
+ mult_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1;
end
{7'b000_0001, 3'b011}: begin // mulhu
alu_operator_o = ALU_ADD;
- mult_sel_o = RV32M ? 1'b1 : 1'b0;
+ mult_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1;
end
{7'b000_0001, 3'b100}: begin // div
alu_operator_o = ALU_ADD;
- div_sel_o = RV32M ? 1'b1 : 1'b0;
+ div_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1;
end
{7'b000_0001, 3'b101}: begin // divu
alu_operator_o = ALU_ADD;
- div_sel_o = RV32M ? 1'b1 : 1'b0;
+ div_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1;
end
{7'b000_0001, 3'b110}: begin // rem
alu_operator_o = ALU_ADD;
- div_sel_o = RV32M ? 1'b1 : 1'b0;
+ div_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1;
end
{7'b000_0001, 3'b111}: begin // remu
alu_operator_o = ALU_ADD;
- div_sel_o = RV32M ? 1'b1 : 1'b0;
+ div_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1;
end
default: ;
@@ -1078,16 +1076,15 @@
/////////////
OPCODE_MISC_MEM: begin
- // For now, treat the FENCE (funct3 == 000) instruction as a NOP. This may not be correct
- // in a system with caches and should be revisited.
- // FENCE.I will flush the IF stage and prefetch buffer but nothing else.
unique case (instr_alu[14:12])
3'b000: begin
+ // FENCE is treated as a NOP since all memory operations are already strictly ordered.
alu_operator_o = ALU_ADD; // nop
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
end
3'b001: begin
+ // FENCE.I will flush the IF stage, prefetch buffer and ICache if present.
if (BranchTargetALU) begin
bt_a_mux_sel_o = OP_A_CURRPC;
bt_b_mux_sel_o = IMM_B_INCR_PC;
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
index eccc68e..62e0396 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
@@ -9,10 +9,9 @@
* Execution block: Hosts ALU and MUL/DIV unit
*/
module ibex_ex_block #(
- parameter bit RV32M = 1,
- parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
- parameter bit BranchTargetALU = 0,
- parameter MultiplierImplementation = "fast"
+ parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast,
+ parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
+ parameter bit BranchTargetALU = 0
) (
input logic clk_i,
input logic rst_ni,
@@ -70,11 +69,11 @@
logic [ 1:0] multdiv_imd_val_we;
/*
- The multdiv_i output is never selected if RV32M=0
+ The multdiv_i output is never selected if RV32M=RV32MNone
At synthesis time, all the combinational and sequential logic
from the multdiv_i module are eliminated
*/
- if (RV32M) begin : gen_multdiv_m
+ if (RV32M != RV32MNone) begin : gen_multdiv_m
assign multdiv_sel = mult_sel_i | div_sel_i;
end else begin : gen_multdiv_no_m
assign multdiv_sel = 1'b0;
@@ -138,7 +137,7 @@
// Multiplier //
////////////////
- if (MultiplierImplementation == "slow") begin : gen_multdiv_slow
+ if (RV32M == RV32MSlow) begin : gen_multdiv_slow
ibex_multdiv_slow multdiv_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@@ -163,59 +162,32 @@
.multdiv_ready_id_i ( multdiv_ready_id_i ),
.multdiv_result_o ( multdiv_result )
);
- end else if (MultiplierImplementation == "fast") begin : gen_multdiv_fast
- ibex_multdiv_fast # (
- .SingleCycleMultiply (0)
- ) multdiv_i (
- .clk_i ( clk_i ),
- .rst_ni ( rst_ni ),
- .mult_en_i ( mult_en_i ),
- .div_en_i ( div_en_i ),
- .mult_sel_i ( mult_sel_i ),
- .div_sel_i ( div_sel_i ),
- .operator_i ( multdiv_operator_i ),
- .signed_mode_i ( multdiv_signed_mode_i ),
- .op_a_i ( multdiv_operand_a_i ),
- .op_b_i ( multdiv_operand_b_i ),
- .alu_operand_a_o ( multdiv_alu_operand_a ),
- .alu_operand_b_o ( multdiv_alu_operand_b ),
- .alu_adder_ext_i ( alu_adder_result_ext ),
- .alu_adder_i ( alu_adder_result_ex_o ),
- .equal_to_zero_i ( alu_is_equal_result ),
- .data_ind_timing_i ( data_ind_timing_i ),
- .imd_val_q_i ( imd_val_q_i ),
- .imd_val_d_o ( multdiv_imd_val_d ),
- .imd_val_we_o ( multdiv_imd_val_we ),
- .multdiv_ready_id_i ( multdiv_ready_id_i ),
- .valid_o ( multdiv_valid ),
- .multdiv_result_o ( multdiv_result )
- );
- end else if (MultiplierImplementation == "single-cycle") begin: gen_multdiv_single_cycle
- ibex_multdiv_fast #(
- .SingleCycleMultiply(1)
- ) multdiv_i (
- .clk_i ( clk_i ),
- .rst_ni ( rst_ni ),
- .mult_en_i ( mult_en_i ),
- .div_en_i ( div_en_i ),
- .mult_sel_i ( mult_sel_i ),
- .div_sel_i ( div_sel_i ),
- .operator_i ( multdiv_operator_i ),
- .signed_mode_i ( multdiv_signed_mode_i ),
- .op_a_i ( multdiv_operand_a_i ),
- .op_b_i ( multdiv_operand_b_i ),
- .alu_operand_a_o ( multdiv_alu_operand_a ),
- .alu_operand_b_o ( multdiv_alu_operand_b ),
- .alu_adder_ext_i ( alu_adder_result_ext ),
- .alu_adder_i ( alu_adder_result_ex_o ),
- .equal_to_zero_i ( alu_is_equal_result ),
- .data_ind_timing_i ( data_ind_timing_i ),
- .imd_val_q_i ( imd_val_q_i ),
- .imd_val_d_o ( multdiv_imd_val_d ),
- .imd_val_we_o ( multdiv_imd_val_we ),
- .multdiv_ready_id_i ( multdiv_ready_id_i ),
- .valid_o ( multdiv_valid ),
- .multdiv_result_o ( multdiv_result )
+ end else if (RV32M == RV32MFast || RV32M == RV32MSingleCycle) begin : gen_multdiv_fast
+ ibex_multdiv_fast # (
+ .RV32M ( RV32M )
+ ) multdiv_i (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .mult_en_i ( mult_en_i ),
+ .div_en_i ( div_en_i ),
+ .mult_sel_i ( mult_sel_i ),
+ .div_sel_i ( div_sel_i ),
+ .operator_i ( multdiv_operator_i ),
+ .signed_mode_i ( multdiv_signed_mode_i ),
+ .op_a_i ( multdiv_operand_a_i ),
+ .op_b_i ( multdiv_operand_b_i ),
+ .alu_operand_a_o ( multdiv_alu_operand_a ),
+ .alu_operand_b_o ( multdiv_alu_operand_b ),
+ .alu_adder_ext_i ( alu_adder_result_ext ),
+ .alu_adder_i ( alu_adder_result_ex_o ),
+ .equal_to_zero_i ( alu_is_equal_result ),
+ .data_ind_timing_i ( data_ind_timing_i ),
+ .imd_val_q_i ( imd_val_q_i ),
+ .imd_val_d_o ( multdiv_imd_val_d ),
+ .imd_val_we_o ( multdiv_imd_val_we ),
+ .multdiv_ready_id_i ( multdiv_ready_id_i ),
+ .valid_o ( multdiv_valid ),
+ .multdiv_result_o ( multdiv_result )
);
end
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
index 5223a25..c5e9074 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
@@ -32,6 +32,7 @@
output logic out_valid_o,
input logic out_ready_i,
output logic [31:0] out_addr_o,
+ output logic [31:0] out_addr_next_o,
output logic [31:0] out_rdata_o,
output logic out_err_o,
output logic out_err_plus2_o
@@ -55,6 +56,7 @@
logic aligned_is_compressed, unaligned_is_compressed;
logic addr_incr_two;
+ logic [31:1] instr_addr_next;
logic [31:1] instr_addr_d, instr_addr_q;
logic instr_addr_en;
logic unused_addr_in;
@@ -140,10 +142,12 @@
assign addr_incr_two = instr_addr_q[1] ? unaligned_is_compressed :
aligned_is_compressed;
+ assign instr_addr_next = (instr_addr_q[31:1] +
+ // Increment address by 4 or 2
+ {29'd0,~addr_incr_two,addr_incr_two});
+
assign instr_addr_d = clear_i ? in_addr_i[31:1] :
- (instr_addr_q[31:1] +
- // Increment address by 4 or 2
- {29'd0,~addr_incr_two,addr_incr_two});
+ instr_addr_next;
always_ff @(posedge clk_i) begin
if (instr_addr_en) begin
@@ -151,8 +155,11 @@
end
end
- assign out_addr_o[31:1] = instr_addr_q[31:1];
- assign out_addr_o[0] = 1'b0;
+ // Output both PC of current instruction and instruction following. PC of instruction following is
+ // required for the branch predictor. It's used to fetch the instruction following a branch that
+ // was not-taken but (mis)predicted taken.
+ assign out_addr_next_o = {instr_addr_next, 1'b0};
+ assign out_addr_o = {instr_addr_q, 1'b0};
// The LSB of the address is unused, since all addresses are halfword aligned
assign unused_addr_in = in_addr_i[0];
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
index 5e3be70..5ca2e22 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
@@ -18,12 +18,13 @@
module ibex_id_stage #(
parameter bit RV32E = 0,
- parameter bit RV32M = 1,
+ parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast,
parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
parameter bit DataIndTiming = 1'b0,
parameter bit BranchTargetALU = 0,
parameter bit SpecBranch = 0,
- parameter bit WritebackStage = 0
+ parameter bit WritebackStage = 0,
+ parameter bit BranchPredictor = 0
) (
input logic clk_i,
input logic rst_ni,
@@ -37,6 +38,7 @@
input logic [31:0] instr_rdata_alu_i, // from IF-ID pipeline registers
input logic [15:0] instr_rdata_c_i, // from IF-ID pipeline registers
input logic instr_is_compressed_i,
+ input logic instr_bp_taken_i,
output logic instr_req_o,
output logic instr_first_cycle_id_o,
output logic instr_valid_clear_o, // kill instr in IF-ID reg
@@ -50,6 +52,7 @@
output logic pc_set_o,
output logic pc_set_spec_o,
output ibex_pkg::pc_sel_e pc_mux_o,
+ output logic nt_branch_mispredict_o,
output ibex_pkg::exc_pc_sel_e exc_pc_mux_o,
output ibex_pkg::exc_cause_e exc_cause_o,
@@ -195,6 +198,7 @@
logic branch_in_dec;
logic branch_spec, branch_set_spec;
logic branch_set, branch_set_d;
+ logic branch_not_set;
logic branch_taken;
logic jump_in_dec;
logic jump_set_dec;
@@ -519,7 +523,8 @@
assign illegal_insn_o = instr_valid_i & (illegal_insn_dec | illegal_csr_insn_i);
ibex_controller #(
- .WritebackStage ( WritebackStage )
+ .WritebackStage ( WritebackStage ),
+ .BranchPredictor ( BranchPredictor )
) controller_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@@ -540,6 +545,7 @@
.instr_i ( instr_rdata_i ),
.instr_compressed_i ( instr_rdata_c_i ),
.instr_is_compressed_i ( instr_is_compressed_i ),
+ .instr_bp_taken_i ( instr_bp_taken_i ),
.instr_fetch_err_i ( instr_fetch_err_i ),
.instr_fetch_err_plus2_i ( instr_fetch_err_plus2_i ),
.pc_id_i ( pc_id_i ),
@@ -554,6 +560,7 @@
.pc_set_o ( pc_set_o ),
.pc_set_spec_o ( pc_set_spec_o ),
.pc_mux_o ( pc_mux_o ),
+ .nt_branch_mispredict_o ( nt_branch_mispredict_o ),
.exc_pc_mux_o ( exc_pc_mux_o ),
.exc_cause_o ( exc_cause_o ),
@@ -566,6 +573,7 @@
// jump/branch control
.branch_set_i ( branch_set ),
.branch_set_spec_i ( branch_set_spec ),
+ .branch_not_set_i ( branch_not_set ),
.jump_set_i ( jump_set ),
// interrupt signals
@@ -687,11 +695,11 @@
end
- // Holding branch_set/jump_set high for more than one cycle may not cause a functional issue but
- // could generate needless prefetch buffer flushes and instruction fetches. ID/EX is designed such
- // that this shouldn't ever happen.
- `ASSERT(NeverDoubleBranch, branch_set |=> ~branch_set)
- `ASSERT(NeverDoubleJump, jump_set |=> ~jump_set)
+ // Holding branch_set/jump_set high for more than one cycle should not cause a functional issue.
+ // However it could generate needless prefetch buffer flushes and instruction fetches. The ID/EX
+ // designs ensures that this never happens for non-predicted branches.
+ `ASSERT(NeverDoubleBranch, branch_set & ~instr_bp_taken_i |=> ~branch_set)
+ `ASSERT(NeverDoubleJump, jump_set & ~instr_bp_taken_i |=> ~jump_set)
///////////////
// ID-EX FSM //
@@ -722,6 +730,7 @@
stall_alu = 1'b0;
branch_set_d = 1'b0;
branch_spec = 1'b0;
+ branch_not_set = 1'b0;
jump_set = 1'b0;
perf_branch_o = 1'b0;
@@ -757,6 +766,11 @@
MULTI_CYCLE : FIRST_CYCLE;
stall_branch = (~BranchTargetALU & branch_decision_i) | data_ind_timing_i;
branch_set_d = branch_decision_i | data_ind_timing_i;
+
+ if (BranchPredictor) begin
+ branch_not_set = ~branch_decision_i;
+ end
+
// Speculative branch (excludes branch_decision_i)
branch_spec = SpecBranch ? 1'b1 : branch_decision_i;
perf_branch_o = 1'b1;
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
index 6b74c2e..3e58a20 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
@@ -18,7 +18,8 @@
parameter bit DummyInstructions = 1'b0,
parameter bit ICache = 1'b0,
parameter bit ICacheECC = 1'b0,
- parameter bit SecureIbex = 1'b0
+ parameter bit SecureIbex = 1'b0,
+ parameter bit BranchPredictor = 1'b0
) (
input logic clk_i,
input logic rst_ni,
@@ -46,6 +47,8 @@
// 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_bp_taken_o, // instruction was predicted to be
+ // a taken branch
output logic instr_fetch_err_o, // bus error on fetch
output logic instr_fetch_err_plus2_o, // bus error misaligned
output logic illegal_c_insn_id_o, // compressed decoder thinks this
@@ -59,6 +62,8 @@
input logic pc_set_i, // set the PC to a new value
input logic pc_set_spec_i,
input ibex_pkg::pc_sel_e pc_mux_i, // selector for PC multiplexer
+ input logic nt_branch_mispredict_i, // Not-taken branch in ID/EX was
+ // mispredicted (predicted taken)
input ibex_pkg::exc_pc_sel_e exc_pc_mux_i, // selects ISR address
input ibex_pkg::exc_cause_e exc_cause, // selects ISR address for
// vectorized interrupt lines
@@ -96,6 +101,8 @@
// prefetch buffer related signals
logic prefetch_busy;
logic branch_req;
+ logic branch_spec;
+ logic predicted_branch;
logic [31:0] fetch_addr_n;
logic fetch_valid;
@@ -105,6 +112,11 @@
logic fetch_err;
logic fetch_err_plus2;
+ logic if_instr_valid;
+ logic [31:0] if_instr_rdata;
+ logic [31:0] if_instr_addr;
+ logic if_instr_err;
+
logic [31:0] exc_pc;
logic [5:0] irq_id;
@@ -113,13 +125,17 @@
logic if_id_pipe_reg_we; // IF-ID pipeline reg write enable
// Dummy instruction signals
- logic fetch_valid_out;
logic stall_dummy_instr;
logic [31:0] instr_out;
logic instr_is_compressed_out;
logic illegal_c_instr_out;
logic instr_err_out;
+ logic predict_branch_taken;
+ logic [31:0] predict_branch_pc;
+
+ ibex_pkg::pc_sel_e pc_mux_internal;
+
logic [7:0] unused_boot_addr;
logic [7:0] unused_csr_mtvec;
@@ -141,14 +157,22 @@
endcase
end
+ // The Branch predictor can provide a new PC which is internal to if_stage. Only override the mux
+ // select to choose this if the core isn't already trying to set a PC.
+ assign pc_mux_internal =
+ (BranchPredictor && predict_branch_taken && !pc_set_i) ? PC_BP : pc_mux_i;
+
// fetch address selection mux
always_comb begin : fetch_addr_mux
- unique case (pc_mux_i)
+ unique case (pc_mux_internal)
PC_BOOT: fetch_addr_n = { boot_addr_i[31:8], 8'h80 };
PC_JUMP: fetch_addr_n = branch_target_ex_i;
PC_EXC: fetch_addr_n = exc_pc; // set PC to exception handler
PC_ERET: fetch_addr_n = csr_mepc_i; // restore PC when returning from EXC
PC_DRET: fetch_addr_n = csr_depc_i;
+ // Without branch predictor will never get pc_mux_internal == PC_BP. We still handle no branch
+ // predictor case here to ensure redundant mux logic isn't synthesised.
+ PC_BP: fetch_addr_n = BranchPredictor ? predict_branch_pc : { boot_addr_i[31:8], 8'h80 };
default: fetch_addr_n = { boot_addr_i[31:8], 8'h80 };
endcase
end
@@ -167,7 +191,7 @@
.req_i ( req_i ),
.branch_i ( branch_req ),
- .branch_spec_i ( pc_set_spec_i ),
+ .branch_spec_i ( branch_spec ),
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
.ready_i ( fetch_ready ),
@@ -191,32 +215,36 @@
);
end else begin : gen_prefetch_buffer
// prefetch buffer, caches a fixed number of instructions
- ibex_prefetch_buffer prefetch_buffer_i (
- .clk_i ( clk_i ),
- .rst_ni ( rst_ni ),
+ ibex_prefetch_buffer #(
+ .BranchPredictor (BranchPredictor)
+ ) prefetch_buffer_i (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
- .req_i ( req_i ),
+ .req_i ( req_i ),
- .branch_i ( branch_req ),
- .branch_spec_i ( pc_set_spec_i ),
- .addr_i ( {fetch_addr_n[31:1], 1'b0} ),
+ .branch_i ( branch_req ),
+ .branch_spec_i ( branch_spec ),
+ .predicted_branch_i ( predicted_branch ),
+ .branch_mispredict_i ( nt_branch_mispredict_i ),
+ .addr_i ( {fetch_addr_n[31:1], 1'b0} ),
- .ready_i ( fetch_ready ),
- .valid_o ( fetch_valid ),
- .rdata_o ( fetch_rdata ),
- .addr_o ( fetch_addr ),
- .err_o ( fetch_err ),
- .err_plus2_o ( fetch_err_plus2 ),
+ .ready_i ( fetch_ready ),
+ .valid_o ( fetch_valid ),
+ .rdata_o ( fetch_rdata ),
+ .addr_o ( fetch_addr ),
+ .err_o ( fetch_err ),
+ .err_plus2_o ( fetch_err_plus2 ),
- .instr_req_o ( instr_req_o ),
- .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 ( instr_pmp_err_i ),
+ .instr_req_o ( instr_req_o ),
+ .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 ( instr_pmp_err_i ),
- .busy_o ( prefetch_busy )
+ .busy_o ( prefetch_busy )
);
// ICache tieoffs
logic unused_icen, unused_icinv;
@@ -224,10 +252,10 @@
assign unused_icinv = icache_inval_i;
end
- assign branch_req = pc_set_i;
- assign fetch_ready = id_in_ready_i & ~stall_dummy_instr;
+ assign branch_req = pc_set_i | predict_branch_taken;
+ assign branch_spec = pc_set_spec_i | predict_branch_taken;
- assign pc_if_o = fetch_addr;
+ assign pc_if_o = if_instr_addr;
assign if_busy_o = prefetch_busy;
// compressed instruction decoding, or more precisely compressed instruction
@@ -243,7 +271,7 @@
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.valid_i ( fetch_valid & ~fetch_err ),
- .instr_i ( fetch_rdata ),
+ .instr_i ( if_instr_rdata ),
.instr_o ( instr_decompressed ),
.is_compressed_o ( instr_is_compressed ),
.illegal_instr_o ( illegal_c_insn )
@@ -268,11 +296,10 @@
);
// Mux between actual instructions and dummy instructions
- assign fetch_valid_out = insert_dummy_instr | fetch_valid;
assign instr_out = insert_dummy_instr ? dummy_instr_data : instr_decompressed;
assign instr_is_compressed_out = insert_dummy_instr ? 1'b0 : instr_is_compressed;
assign illegal_c_instr_out = insert_dummy_instr ? 1'b0 : illegal_c_insn;
- assign instr_err_out = insert_dummy_instr ? 1'b0 : fetch_err;
+ assign instr_err_out = insert_dummy_instr ? 1'b0 : if_instr_err;
// Stall the IF stage if we insert a dummy instruction. The dummy will execute between whatever
// is currently in the ID stage and whatever is valid from the prefetch buffer this cycle. The
@@ -298,11 +325,10 @@
assign unused_dummy_mask = dummy_instr_mask_i;
assign unused_dummy_seed_en = dummy_instr_seed_en_i;
assign unused_dummy_seed = dummy_instr_seed_i;
- assign fetch_valid_out = fetch_valid;
assign instr_out = instr_decompressed;
assign instr_is_compressed_out = instr_is_compressed;
assign illegal_c_instr_out = illegal_c_insn;
- assign instr_err_out = fetch_err;
+ assign instr_err_out = if_instr_err;
assign stall_dummy_instr = 1'b0;
assign dummy_instr_id_o = 1'b0;
end
@@ -310,9 +336,9 @@
// The ID stage becomes valid as soon as any instruction is registered in the ID stage flops.
// Note that the current instruction is squashed by the incoming pc_set_i signal.
// Valid is held until it is explicitly cleared (due to an instruction completing or an exception)
- assign instr_valid_id_d = (fetch_valid_out & id_in_ready_i & ~pc_set_i) |
+ assign instr_valid_id_d = (if_instr_valid & id_in_ready_i & ~pc_set_i) |
(instr_valid_id_q & ~instr_valid_clear_i);
- assign instr_new_id_d = fetch_valid_out & id_in_ready_i;
+ assign instr_new_id_d = if_instr_valid & id_in_ready_i;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
@@ -338,7 +364,7 @@
instr_rdata_alu_id_o <= instr_out;
instr_fetch_err_o <= instr_err_out;
instr_fetch_err_plus2_o <= fetch_err_plus2;
- instr_rdata_c_id_o <= fetch_rdata[15:0];
+ instr_rdata_c_id_o <= if_instr_rdata[15:0];
instr_is_compressed_id_o <= instr_is_compressed_out;
illegal_c_insn_id_o <= illegal_c_instr_out;
pc_id_o <= pc_if_o;
@@ -371,25 +397,204 @@
assign pc_mismatch_alert_o = 1'b0;
end
+ if (BranchPredictor) begin : g_branch_predictor
+ logic [31:0] instr_skid_data_q;
+ logic [31:0] instr_skid_addr_q;
+ logic instr_skid_bp_taken_q;
+ logic instr_skid_valid_q, instr_skid_valid_d;
+ logic instr_skid_en;
+ logic instr_bp_taken_q, instr_bp_taken_d;
+
+ logic predict_branch_taken_raw;
+
+ // ID stages needs to know if branch was predicted taken so it can signal mispredicts
+ always_ff @(posedge clk_i) begin
+ if (if_id_pipe_reg_we) begin
+ instr_bp_taken_q <= instr_bp_taken_d;
+ end
+ end
+
+ // When branch prediction is enabled a skid buffer between the IF and ID/EX stage is introduced.
+ // If an instruction in IF is predicted to be a taken branch and ID/EX is not ready the
+ // instruction in IF is moved to the skid buffer which becomes the output of the IF stage until
+ // the ID/EX stage accepts the instruction. The skid buffer is required as otherwise the ID/EX
+ // ready signal is coupled to the instr_req_o output which produces a feedthrough path from
+ // data_gnt_i -> instr_req_o (which needs to be avoided as for some interconnects this will
+ // result in a combinational loop).
+
+ assign instr_skid_en = predicted_branch & ~id_in_ready_i & ~instr_skid_valid_q;
+
+ assign instr_skid_valid_d = (instr_skid_valid_q & ~id_in_ready_i & ~stall_dummy_instr) |
+ instr_skid_en;
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ instr_skid_valid_q <= 1'b0;
+ end else begin
+ instr_skid_valid_q <= instr_skid_valid_d;
+ end
+ end
+
+ always_ff @(posedge clk_i) begin
+ if (instr_skid_en) begin
+ instr_skid_bp_taken_q <= predict_branch_taken;
+ instr_skid_data_q <= fetch_rdata;
+ instr_skid_addr_q <= fetch_addr;
+ end
+ end
+
+ ibex_branch_predict branch_predict_i (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .fetch_rdata_i ( fetch_rdata ),
+ .fetch_pc_i ( fetch_addr ),
+ .fetch_valid_i ( fetch_valid ),
+
+ .predict_branch_taken_o ( predict_branch_taken_raw ),
+ .predict_branch_pc_o ( predict_branch_pc )
+ );
+
+ // If there is an instruction in the skid buffer there must be no branch prediction.
+ // Instructions are only placed in the skid after they have been predicted to be a taken branch
+ // so with the skid valid any prediction has already occurred.
+ // Do not branch predict on instruction errors.
+ assign predict_branch_taken = predict_branch_taken_raw & ~instr_skid_valid_q & ~fetch_err;
+
+ // pc_set_i takes precendence over branch prediction
+ assign predicted_branch = predict_branch_taken & ~pc_set_i;
+
+ assign if_instr_valid = fetch_valid | instr_skid_valid_q;
+ assign if_instr_rdata = instr_skid_valid_q ? instr_skid_data_q : fetch_rdata;
+ assign if_instr_addr = instr_skid_valid_q ? instr_skid_addr_q : fetch_addr;
+
+ // Don't branch predict on instruction error so only instructions without errors end up in the
+ // skid buffer.
+ assign if_instr_err = ~instr_skid_valid_q & fetch_err;
+ assign instr_bp_taken_d = instr_skid_valid_q ? instr_skid_bp_taken_q : predict_branch_taken;
+
+ assign fetch_ready = id_in_ready_i & ~stall_dummy_instr & ~instr_skid_valid_q;
+
+ assign instr_bp_taken_o = instr_bp_taken_q;
+
+ `ASSERT(NoPredictSkid, instr_skid_valid_q |-> ~predict_branch_taken);
+ `ASSERT(NoPredictIllegal, predict_branch_taken |-> ~illegal_c_insn);
+ end else begin : g_no_branch_predictor
+ assign instr_bp_taken_o = 1'b0;
+ assign predict_branch_taken = 1'b0;
+ assign predicted_branch = 1'b0;
+ assign predict_branch_pc = 32'b0;
+
+ assign if_instr_valid = fetch_valid;
+ assign if_instr_rdata = fetch_rdata;
+ assign if_instr_addr = fetch_addr;
+ assign if_instr_err = fetch_err;
+ assign fetch_ready = id_in_ready_i & ~stall_dummy_instr;
+ end
+
////////////////
// Assertions //
////////////////
// Selectors must be known/valid.
`ASSERT_KNOWN(IbexExcPcMuxKnown, exc_pc_mux_i)
- `ASSERT(IbexPcMuxValid, pc_mux_i inside {
- PC_BOOT,
- PC_JUMP,
- PC_EXC,
- PC_ERET,
- PC_DRET})
+
+ if (BranchPredictor) begin : g_branch_predictor_asserts
+ `ASSERT_IF(IbexPcMuxValid, pc_mux_internal inside {
+ PC_BOOT,
+ PC_JUMP,
+ PC_EXC,
+ PC_ERET,
+ PC_DRET,
+ PC_BP},
+ pc_set_i)
+
+`ifdef INC_ASSERT
+ /**
+ * Checks for branch prediction interface to fetch_fifo/icache
+ *
+ * The interface has two signals:
+ * - predicted_branch_i: When set with a branch (branch_i) indicates the branch is a predicted
+ * one, it should be ignored when a branch_i isn't set.
+ * - branch_mispredict_i: Indicates the previously predicted branch was mis-predicted and
+ * execution should resume with the not-taken side of the branch (i.e. continue with the PC
+ * that followed the predicted branch). This must be raised before the instruction that is
+ * made available following a predicted branch is accepted (Following a cycle with branch_i
+ * & predicted_branch_i, branch_mispredict_i can only be asserted before or on the same cycle
+ * as seeing fetch_valid & fetch_ready). When branch_mispredict_i is asserted, fetch_valid may
+ * be asserted in response. If fetch_valid is asserted on the same cycle as
+ * branch_mispredict_i this indicates the fetch_fifo/icache has the not-taken side of the
+ * branch immediately ready for use
+ */
+ logic predicted_branch_live_q, predicted_branch_live_d;
+ logic [31:0] predicted_branch_nt_pc_q, predicted_branch_nt_pc_d;
+ logic [31:0] awaiting_instr_after_mispredict_q, awaiting_instr_after_mispredict_d;
+ logic [31:0] next_pc;
+
+ logic mispredicted, mispredicted_d, mispredicted_q;
+
+ assign next_pc = fetch_addr + (instr_is_compressed_out ? 32'd2 : 32'd4);
+
+ always_comb begin
+ predicted_branch_live_d = predicted_branch_live_q;
+ mispredicted_d = mispredicted_q;
+
+ if (branch_req & predicted_branch) begin
+ predicted_branch_live_d = 1'b1;
+ mispredicted_d = 1'b0;
+ end else if (predicted_branch_live_q) begin
+ if (fetch_valid & fetch_ready) begin
+ predicted_branch_live_d = 1'b0;
+ end else if (nt_branch_mispredict_i) begin
+ mispredicted_d = 1'b1;
+ end
+ end
+ end
+
+ always @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ predicted_branch_live_q <= 1'b0;
+ mispredicted_q <= 1'b0;
+ end else begin
+ predicted_branch_live_q <= predicted_branch_live_d;
+ mispredicted_q <= mispredicted_d;
+ end
+ end
+
+ always @(posedge clk_i) begin
+ if (branch_req & predicted_branch) begin
+ predicted_branch_nt_pc_q <= next_pc;
+ end
+ end
+
+ // Must only see mispredict after we've performed a predicted branch but before we've accepted
+ // any instruction (with fetch_ready & fetch_valid) that follows that predicted branch.
+ `ASSERT(MispredictOnlyImmediatelyAfterPredictedBranch,
+ nt_branch_mispredict_i |-> predicted_branch_live_q);
+ // Check that on mispredict we get the correct PC for the non-taken side of the branch when
+ // prefetch buffer/icache makes that PC available.
+ `ASSERT(CorrectPCOnMispredict,
+ predicted_branch_live_q & mispredicted_d & fetch_valid |-> fetch_addr == predicted_branch_nt_pc_q);
+ // Must not signal mispredict over multiple cycles but it's possible to have back to back
+ // mispredicts for different branches (core signals mispredict, prefetch buffer/icache immediate
+ // has not-taken side of the mispredicted branch ready, which itself is a predicted branch,
+ // following cycle core signal that that branch has mispredicted).
+ `ASSERT(MispredictSingleCycle,
+ nt_branch_mispredict_i & ~(fetch_valid & fetch_ready) |=> ~nt_branch_mispredict_i);
+`endif
+
+ end else begin : g_no_branch_predictor_asserts
+ `ASSERT_IF(IbexPcMuxValid, pc_mux_internal inside {
+ PC_BOOT,
+ PC_JUMP,
+ PC_EXC,
+ PC_ERET,
+ PC_DRET},
+ pc_set_i)
+ end
// Boot address must be aligned to 256 bytes.
`ASSERT(IbexBootAddrUnaligned, boot_addr_i[7:0] == 8'h00)
- // Errors must only be sent together with rvalid.
- `ASSERT(IbexInstrErrWithoutRvalid, instr_err_i |-> instr_rvalid_i)
-
// Address must not contain X when request is sent.
`ASSERT(IbexInstrAddrUnknown, instr_req_o |-> !$isunknown(instr_addr_o))
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
index 617bb51..40b6fcb 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
@@ -15,7 +15,7 @@
`include "prim_assert.sv"
module ibex_multdiv_fast #(
- parameter bit SingleCycleMultiply = 0
+ parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast
) (
input logic clk_i,
input logic rst_ni,
@@ -132,7 +132,7 @@
// The single cycle multiplier uses three 17 bit multipliers to compute MUL instructions in a
// single cycle and MULH instructions in two cycles.
- if (SingleCycleMultiply) begin : gen_multiv_single_cycle
+ if (RV32M == RV32MSingleCycle) begin : gen_mult_single_cycle
typedef enum logic {
MULL, MULH
@@ -249,7 +249,7 @@
// The fast multiplier uses one 17 bit multiplier to compute MUL instructions in 3 cycles
// and MULH instructions in 4 cycles.
- end else begin : gen_multdiv_fast
+ end else begin : gen_mult_fast
logic [15:0] mult_op_a;
logic [15:0] mult_op_b;
@@ -365,7 +365,7 @@
// States must be knwon/valid.
`ASSERT_KNOWN(IbexMultStateKnown, mult_state_q)
- end // gen_multdiv_fast
+ end // gen_mult_fast
// Divider
assign res_adder_h = alu_adder_ext_i[33:1];
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv
index bb086ec..42ac486 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv
@@ -8,14 +8,27 @@
*/
package ibex_pkg;
-/////////////////////////
-// RV32B Paramter Enum //
-/////////////////////////
+/////////////////////
+// Parameter Enums //
+/////////////////////
typedef enum integer {
- RV32BNone,
- RV32BBalanced,
- RV32BFull
+ RegFileFF = 0,
+ RegFileFPGA = 1,
+ RegFileLatch = 2
+} regfile_e;
+
+typedef enum integer {
+ RV32MNone = 0,
+ RV32MSlow = 1,
+ RV32MFast = 2,
+ RV32MSingleCycle = 3
+} rv32m_e;
+
+typedef enum integer {
+ RV32BNone = 0,
+ RV32BBalanced = 1,
+ RV32BFull = 2
} rv32b_e;
/////////////
@@ -239,7 +252,8 @@
PC_JUMP,
PC_EXC,
PC_ERET,
- PC_DRET
+ PC_DRET,
+ PC_BP
} pc_sel_e;
// Exception PC mux selection
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv
index 9343fc0..f206b2a 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv
@@ -9,7 +9,9 @@
* Prefetch Buffer that caches instructions. This cuts overly long critical
* paths to the instruction cache.
*/
-module ibex_prefetch_buffer (
+module ibex_prefetch_buffer #(
+ parameter bit BranchPredictor = 1'b0
+) (
input logic clk_i,
input logic rst_ni,
@@ -17,6 +19,8 @@
input logic branch_i,
input logic branch_spec_i,
+ input logic predicted_branch_i,
+ input logic branch_mispredict_i,
input logic [31:0] addr_i,
@@ -57,20 +61,30 @@
logic stored_addr_en;
logic [31:0] fetch_addr_d, fetch_addr_q;
logic fetch_addr_en;
+ logic [31:0] branch_mispredict_addr;
logic [31:0] instr_addr, instr_addr_w_aligned;
logic instr_or_pmp_err;
logic fifo_valid;
+ logic [31:0] fifo_addr;
logic fifo_ready;
logic fifo_clear;
logic [NUM_REQS-1:0] fifo_busy;
+ logic valid_raw;
+
+ logic [31:0] addr_next;
+
+ logic branch_or_mispredict;
+
////////////////////////////
// Prefetch buffer status //
////////////////////////////
assign busy_o = (|rdata_outstanding_q) | instr_req_o;
+ assign branch_or_mispredict = branch_i | branch_mispredict_i;
+
//////////////////////////////////////////////
// Fetch fifo - consumes addresses and data //
//////////////////////////////////////////////
@@ -82,7 +96,7 @@
// A branch will invalidate any previously fetched instructions.
// Note that the FENCE.I instruction relies on this flushing behaviour on branch. If it is
// altered the FENCE.I implementation may require changes.
- assign fifo_clear = branch_i;
+ assign fifo_clear = branch_or_mispredict;
// Reversed version of rdata_outstanding_q which can be overlaid with fifo fill state
for (genvar i = 0; i < NUM_REQS; i++) begin : gen_rd_rev
@@ -104,14 +118,15 @@
.busy_o ( fifo_busy ),
.in_valid_i ( fifo_valid ),
- .in_addr_i ( addr_i ),
+ .in_addr_i ( fifo_addr ),
.in_rdata_i ( instr_rdata_i ),
.in_err_i ( instr_or_pmp_err ),
- .out_valid_o ( valid_o ),
+ .out_valid_o ( valid_raw ),
.out_ready_i ( ready_i ),
.out_rdata_o ( rdata_o ),
.out_addr_o ( addr_o ),
+ .out_addr_next_o ( addr_next ),
.out_err_o ( err_o ),
.out_err_plus2_o ( err_plus2_o )
);
@@ -124,7 +139,7 @@
assign branch_suppress = branch_spec_i & ~branch_i;
// Make a new request any time there is space in the FIFO, and space in the request queue
- assign valid_new_req = ~branch_suppress & req_i & (fifo_ready | branch_i) &
+ assign valid_new_req = ~branch_suppress & req_i & (fifo_ready | branch_or_mispredict) &
~rdata_outstanding_q[NUM_REQS-1];
assign valid_req = valid_req_q | valid_new_req;
@@ -141,7 +156,7 @@
assign valid_req_d = valid_req & ~gnt_or_pmp_err;
// Record whether an outstanding bus request is cancelled by a branch
- assign discard_req_d = valid_req_q & (branch_i | discard_req_q);
+ assign discard_req_d = valid_req_q & (branch_or_mispredict | discard_req_q);
////////////////
// Fetch addr //
@@ -172,13 +187,40 @@
end
end
+ if (BranchPredictor) begin : g_branch_predictor
+ // Where the branch predictor is present record what address followed a predicted branch. If
+ // that branch is predicted taken but mispredicted (so not-taken) this is used to resume on
+ // the not-taken code path.
+ logic [31:0] branch_mispredict_addr_q;
+ logic branch_mispredict_addr_en;
+
+ assign branch_mispredict_addr_en = branch_i & predicted_branch_i;
+
+ always_ff @(posedge clk_i) begin
+ if (branch_mispredict_addr_en) begin
+ branch_mispredict_addr_q <= addr_next;
+ end
+ end
+
+ assign branch_mispredict_addr = branch_mispredict_addr_q;
+ end else begin : g_no_branch_predictor
+ logic unused_predicted_branch;
+ logic [31:0] unused_addr_next;
+
+ assign unused_predicted_branch = predicted_branch_i;
+ assign unused_addr_next = addr_next;
+
+ assign branch_mispredict_addr = '0;
+ end
+
// 2. fetch_addr_q
// Update on a branch or as soon as a request is issued
- assign fetch_addr_en = branch_i | (valid_new_req & ~valid_req_q);
+ assign fetch_addr_en = branch_or_mispredict | (valid_new_req & ~valid_req_q);
- assign fetch_addr_d = (branch_i ? addr_i :
- {fetch_addr_q[31:2], 2'b00}) +
+ assign fetch_addr_d = (branch_i ? addr_i :
+ branch_mispredict_i ? {branch_mispredict_addr[31:2], 2'b00} :
+ {fetch_addr_q[31:2], 2'b00}) +
// Current address + 4
{{29{1'b0}},(valid_new_req & ~valid_req_q),2'b00};
@@ -189,9 +231,10 @@
end
// Address mux
- assign instr_addr = valid_req_q ? stored_addr_q :
- branch_spec_i ? addr_i :
- fetch_addr_q;
+ assign instr_addr = valid_req_q ? stored_addr_q :
+ branch_spec_i ? addr_i :
+ branch_mispredict_i ? branch_mispredict_addr :
+ fetch_addr_q;
assign instr_addr_w_aligned = {instr_addr[31:2], 2'b00};
@@ -209,7 +252,8 @@
// If a branch is received at any point while a request is outstanding, it must be tracked
// to ensure we discard the data once received
assign branch_discard_n[i] = (valid_req & gnt_or_pmp_err & discard_req_d) |
- (branch_i & rdata_outstanding_q[i]) | branch_discard_q[i];
+ (branch_or_mispredict & rdata_outstanding_q[i]) |
+ branch_discard_q[i];
// Record whether this request received a PMP error
assign rdata_pmp_err_n[i] = (valid_req & ~rdata_outstanding_q[i] & instr_pmp_err_i) |
rdata_pmp_err_q[i];
@@ -223,7 +267,8 @@
rdata_outstanding_q[i];
assign branch_discard_n[i] = (valid_req & gnt_or_pmp_err & discard_req_d &
rdata_outstanding_q[i-1]) |
- (branch_i & rdata_outstanding_q[i]) | branch_discard_q[i];
+ (branch_or_mispredict & rdata_outstanding_q[i]) |
+ branch_discard_q[i];
assign rdata_pmp_err_n[i] = (valid_req & ~rdata_outstanding_q[i] & instr_pmp_err_i &
rdata_outstanding_q[i-1]) |
rdata_pmp_err_q[i];
@@ -241,6 +286,8 @@
// Push a new entry to the FIFO once complete (and not cancelled by a branch)
assign fifo_valid = rvalid_or_pmp_err & ~branch_discard_q[0];
+ assign fifo_addr = branch_mispredict_i ? branch_mispredict_addr : addr_i;
+
///////////////
// Registers //
///////////////
@@ -268,4 +315,6 @@
assign instr_req_o = valid_req;
assign instr_addr_o = instr_addr_w_aligned;
+ assign valid_o = valid_raw & ~branch_mispredict_i;
+
endmodule
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 fe42fe9..0589249 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_ff.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_ff.sv
@@ -10,7 +10,7 @@
* This register file is based on flip flops. Use this register file when
* targeting FPGA synthesis or Verilator simulation.
*/
-module ibex_register_file #(
+module ibex_register_file_ff #(
parameter bit RV32E = 0,
parameter int unsigned DataWidth = 32,
parameter bit DummyInstructions = 0
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_fpga.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_fpga.sv
index aa88cdc..5065545 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_fpga.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_fpga.sv
@@ -11,7 +11,7 @@
* This register file is designed to make FPGA synthesis tools infer RAM primitives. For Xilinx
* FPGA architectures, it will produce RAM32M primitives. Other vendors have not yet been tested.
*/
-module ibex_register_file #(
+module ibex_register_file_fpga #(
parameter bit RV32E = 0,
parameter int unsigned DataWidth = 32,
parameter bit DummyInstructions = 0
@@ -64,4 +64,4 @@
logic unused_dummy_instr;
assign unused_dummy_instr = dummy_instr_id_i;
-endmodule : ibex_register_file
+endmodule
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 0feb7a6..8c5fb35 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_latch.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_latch.sv
@@ -11,7 +11,7 @@
* based RF. It requires a target technology-specific clock gating cell. Use this
* register file when targeting ASIC synthesis or event-based simulators.
*/
-module ibex_register_file #(
+module ibex_register_file_latch #(
parameter bit RV32E = 0,
parameter int unsigned DataWidth = 32,
parameter bit DummyInstructions = 0
diff --git a/hw/vendor/lowrisc_ibex/syn/lec_sv2v.sh b/hw/vendor/lowrisc_ibex/syn/lec_sv2v.sh
index 089f428..ba89dc3 100755
--- a/hw/vendor/lowrisc_ibex/syn/lec_sv2v.sh
+++ b/hw/vendor/lowrisc_ibex/syn/lec_sv2v.sh
@@ -64,12 +64,6 @@
for file in *.v; do
export LEC_TOP=`basename -s .v $file`
- # special case is file ibex_register_file_ff.sv, whose module has a
- # different name than its file name
- if [[ $LEC_TOP == "ibex_register_file_ff" ]]; then
- export LEC_TOP="ibex_register_file"
- fi
-
# run Conformal LEC
lec -xl -nogui -nobanner \
-dofile ../lec_sv2v.do \
diff --git a/hw/vendor/lowrisc_ibex/syn/tcl/lr_synth_flow_var_setup.tcl b/hw/vendor/lowrisc_ibex/syn/tcl/lr_synth_flow_var_setup.tcl
index cda1cac..8e2dd10 100644
--- a/hw/vendor/lowrisc_ibex/syn/tcl/lr_synth_flow_var_setup.tcl
+++ b/hw/vendor/lowrisc_ibex/syn/tcl/lr_synth_flow_var_setup.tcl
@@ -15,8 +15,9 @@
set_flow_bool_var timing_run 0 "timing run"
set_flow_bool_var ibex_branch_target_alu 0 "Enable branch target ALU in Ibex"
set_flow_bool_var ibex_writeback_stage 0 "Enable writeback stage in Ibex"
-set_flow_var ibex_bitmanip 0 "Bitmanip extenion setting for Ibex (0,1,2 - enums not supported)"
-set_flow_var ibex_multiplier "fast" "Multiplier implementation for Ibex (slow/fast/single-cycle)"
+set_flow_var ibex_bitmanip 0 "Bitmanip extenion setting for Ibex (see ibex_pkg::rv32b_e for permitted values. Enum names are not supported in Yosys.)"
+set_flow_var ibex_multiplier 2 "Multiplier extension setting for Ibex (see ibex_pkg::rv32m_e for permitted values. Enum names are not supported in Yosys.)"
+set_flow_var ibex_regfile 2 "Register file implementation selection for Ibex (see ibex_pkg::regfile_e for permitted values. Enum names are not supported in Yosys.)"
source $lr_synth_config_file
diff --git a/hw/vendor/lowrisc_ibex/syn/tcl/yosys_run_synth.tcl b/hw/vendor/lowrisc_ibex/syn/tcl/yosys_run_synth.tcl
index 7f5bb9b..7986f32 100644
--- a/hw/vendor/lowrisc_ibex/syn/tcl/yosys_run_synth.tcl
+++ b/hw/vendor/lowrisc_ibex/syn/tcl/yosys_run_synth.tcl
@@ -26,7 +26,9 @@
yosys "chparam -set RV32B $lr_synth_ibex_bitmanip ibex_core"
-yosys "chparam -set MultiplierImplementation \"$lr_synth_ibex_multiplier\" ibex_core"
+yosys "chparam -set RV32M $lr_synth_ibex_multiplier ibex_core"
+
+yosys "chparam -set RegFile $lr_synth_ibex_regfile ibex_core"
yosys "synth $flatten_opt -top $lr_synth_top_module"
yosys "opt -purge"
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 446124a..3ceb7e7 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: 61755c001bec0433fb69458f74d95476d2101cf3
+ rev: 2e5251846efb5fa42882a2b6b571ef8693e8cd60
}
}
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_cov_instr.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_cov_instr.py
new file mode 100644
index 0000000..1f4187d
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_cov_instr.py
@@ -0,0 +1,516 @@
+"""Copyright 2020 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.
+"""
+
+import os
+import sys
+import vsc
+import logging
+from enum import Enum, IntEnum, auto
+from bitstring import BitArray
+from pygen.pygen_src.target.rv32i import riscv_core_setting as rcs
+from pygen.pygen_src.riscv_instr_pkg import *
+
+
+class operand_sign_e(IntEnum):
+ POSITIVE = 0
+ NEGATIVE = auto()
+
+
+class div_result_e(IntEnum):
+ DIV_NORMAL = 0
+ DIV_BY_ZERO = auto()
+ DIV_OVERFLOW = auto()
+
+
+class compare_result_e(IntEnum):
+ EQUAL = 0
+ LARGER = auto()
+ SMALLER = auto()
+
+
+class logical_similarity_e(IntEnum):
+ IDENTICAL = 0
+ OPPOSITE = auto()
+ SIMILAR = auto()
+ DIFFERENT = auto()
+
+
+class special_val_e(IntEnum):
+ NORMAL_VAL = 0
+ MIN_VAL = auto()
+ MAX_VAL = auto()
+ ZERO_VAL = auto()
+
+
+class riscv_cov_instr:
+ """ Class for a riscv instruction in functional coverage phase;
+ data parsed from the CSV file fill different fields of an instruction """
+ # class attr. to keep track of reg_name:reg_value throughout the program
+ gpr_state = {}
+
+ def __init__(self):
+ # Program counter (PC) of the instruction
+ self.pc = vsc.bit_t(rcs.XLEN)
+ self.instr = None
+ # self.gpr = None # destination operand of the instruction
+ self.binary = vsc.bit_t(32) # Instruction binary
+ # self.mode = None # Instruction mode
+ self.trace = "None" # String representation of the instruction
+ # self.operands = "None" # Instruction operands (srcss/dests)
+ # self.pad = None # Not used
+
+ self.rs1_value = vsc.int_t(rcs.XLEN)
+ self.rs2_value = vsc.int_t(rcs.XLEN)
+ self.rs3_value = vsc.int_t(rcs.XLEN)
+ self.rd_value = vsc.int_t(rcs.XLEN)
+ self.fs1_value = vsc.int_t(rcs.XLEN)
+ self.fs2_value = vsc.int_t(rcs.XLEN)
+ self.fs3_value = vsc.int_t(rcs.XLEN)
+ self.fd_value = vsc.int_t(rcs.XLEN)
+
+ self.mem_addr = vsc.int_t(rcs.XLEN)
+ self.unaligned_pc = 0
+ self.unaligned_mem_access = 0
+ self.compressed = 0
+ self.branch_hit = 0
+ self.div_result = None
+ self.rs1_sign = 0
+ self.rs2_sign = 0
+ self.rs3_sign = 0
+ self.fs1_sign = 0
+ self.fs2_sign = 0
+ self.fs3_sign = 0
+ self.imm_sign = 0
+ self.rd_sign = 0
+ self.fd_sign = 0
+ self.gpr_hazard = hazard_e.NO_HAZARD
+ self.lsu_hazard = hazard_e.NO_HAZARD
+ self.rs1_special_value = 0
+ self.rs2_special_value = 0
+ self.rs3_special_value = 0
+ self.rd_special_value = 0
+ self.imm_special_value = 0
+ self.compare_result = 0
+ self.logical_similarity = 0
+
+ self.group = None
+ self.format = None
+ self.category = None
+ self.imm_type = None
+
+ self.csr = vsc.bit_t(12)
+ ''' TODO: rs2, rs1, rd, group, format, category, imm_type will be
+ changed to vsc.enum_t once the issue with set/get_val is fixed '''
+ self.rs2 = 0
+ self.rs1 = 0
+ self.rd = 0
+ self.imm = vsc.int_t(32)
+ self.has_rs1 = 1
+ self.has_rs2 = 1
+ self.has_rd = 1
+ self.has_imm = 1
+ self.imm_len = 0
+
+ def assign_attributes(self):
+ attr_list = get_attr_list(self.instr)
+ self.format = attr_list[0]
+ self.category = attr_list[1]
+ self.group = attr_list[2]
+ self.imm_type = imm_t.IMM
+ if len(attr_list) > 3:
+ self.imm_type = attr_list[3]
+ self.set_imm_len()
+ self.set_mode()
+
+ def set_imm_len(self):
+ if self.format.name in ["U_FORMAT", "J_FORMAT"]:
+ self.imm_len = 20
+ elif self.format.name in ["I_FORMAT", "S_FORMAT", "B_FORMAT"]:
+ if self.imm_type.name == "UIMM":
+ self.imm_len = 5
+ else:
+ self.imm_len = 11
+
+ def set_mode(self):
+ # mode setting for Instruction Format
+ if self.format.name == "R_FORMAT":
+ self.has_imm = 0
+ if self.format.name == "I_FORMAT":
+ self.has_rs2 = 0
+ if self.format.name in ["S_FORMAT", "B_FORMAT"]:
+ self.has_rd = 0
+ if self.format.name in ["U_FORMAT", "J_FORMAT"]:
+ self.has_rs1 = 0
+ self.has_rs2 = 0
+
+ # mode setting for Instruction Category
+ if self.category.name == "CSR":
+ self.has_rs2 = 0
+ if self.format.name == "I_FORMAT":
+ self.has_rs1 = 0
+
+ def pre_sample(self):
+ unaligned_pc = self.pc.get_val() % 4 != 0
+ self.rs1_sign = self.get_operand_sign(self.rs1_value)
+ self.rs2_sign = self.get_operand_sign(self.rs2_value)
+ self.rs3_sign = self.get_operand_sign(self.rs3_value)
+ self.rd_sign = self.get_operand_sign(self.rd_value)
+ self.fs1_sign = self.get_operand_sign(self.fs1_value)
+ self.fs2_sign = self.get_operand_sign(self.fs2_value)
+ self.fs3_sign = self.get_operand_sign(self.fs3_value)
+ self.fd_sign = self.get_operand_sign(self.fd_value)
+ self.imm_sign = self.get_imm_sign(self.imm)
+ self.rs1_special_value = self.get_operand_special_value(self.rs1_value)
+ self.rd_special_value = self.get_operand_special_value(self.rd_value)
+ self.rs2_special_value = self.get_operand_special_value(self.rs2_value)
+ self.rs3_special_value = self.get_operand_special_value(self.rs3_value)
+ if self.format.name not in ["R_FORMAT", "CR_FORMAT"]:
+ self.imm_special_value = self.get_imm_special_val(self.imm)
+ if self.category.name in ["COMPARE", "BRANCH"]:
+ self.compare_result = self.get_compare_result()
+ if self.category.name in ["LOAD", "STORE"]:
+ self.mem_addr.set_val(self.rs1_value.get_val() +
+ self.imm.get_val())
+ self.unaligned_mem_access = self.is_unaligned_mem_access()
+ if self.unaligned_mem_access:
+ logging.info("Unaligned: {}, mem_addr: {}".format(
+ self.instr.name, self.mem_addr.get_val()))
+ if self.category.name == "LOGICAL":
+ self.logical_similarity = self.get_logical_similarity()
+ if self.category.name == "BRANCH":
+ self.branch_hit = self.is_branch_hit()
+ if self.instr.name in ["DIV", "DIVU", "REM", "REMU", "DIVW", "DIVUW",
+ "REMW", "REMUW"]:
+ self.div_result = self.get_div_result()
+
+ @staticmethod
+ def get_operand_sign(operand):
+ # TODO: Currently handled using string formatting as part select
+ # isn't yet supported for global vsc variables
+ operand_bin = format(operand.get_val(), '#0{}b'.format(rcs.XLEN + 2))
+ # "0b" is the prefix, so operand_bin[2] is the sign bit
+ if operand_bin[2] == "0":
+ return operand_sign_e["POSITIVE"]
+ else:
+ return operand_sign_e["NEGATIVE"]
+
+ def is_unaligned_mem_access(self):
+ if (self.instr.name in ["LWU", "LD", "SD", "C_LD", "C_SD"] and
+ self.mem_addr.get_val() % 8 != 0):
+ return 1
+ elif (self.instr.name in ["LW", "SW", "C_LW", "C_SW"] and
+ self.mem_addr.get_val() % 4 != 0):
+ return 1
+ elif (self.instr.name in ["LH", "LHU", "SH"] and
+ self.mem_addr.get_val() % 2 != 0):
+ return 1
+ return 0
+
+ @staticmethod
+ def get_imm_sign(imm):
+ # TODO: Currently handled using string formatting as part select
+ # isn't yet supported for global vsc variables
+ imm_bin = format(imm.get_val(), '#0{}b'.format(rcs.XLEN + 2))
+ # "0b" is the prefix, so imm_bin[2] is the sign bit
+ if imm_bin[2] == "0":
+ return operand_sign_e["POSITIVE"]
+ else:
+ return operand_sign_e["NEGATIVE"]
+
+ def get_div_result(self):
+ if self.rs2_value.get_val() == 0:
+ return div_result_e["DIV_BY_ZERO"]
+ elif (self.rs2_value.get_val() == 1
+ and self.rs1_value.get_val() == (1 << (rcs.XLEN - 1))):
+ return div_result_e["DIV_OVERFLOW"]
+ else:
+ return div_result_e["DIV_NORMAL"]
+
+ @staticmethod
+ def get_operand_special_value(operand):
+ if operand.get_val() == 0:
+ return special_val_e["ZERO_VAL"]
+ elif operand.get_val() == 1 << (rcs.XLEN - 1):
+ return special_val_e["MIN_VAL"]
+ elif operand.get_val() == 1 >> 1:
+ return special_val_e["MAX_VAL"]
+ else:
+ return special_val_e["NORMAL_VAL"]
+
+ def get_imm_special_val(self, imm):
+ if imm.get_val() == 0:
+ return special_val_e["ZERO_VAL"]
+ elif self.format == riscv_instr_format_t.U_FORMAT:
+ # unsigned immediate value
+ max_val = vsc.int_t(32, (1 << self.imm_len) - 1)
+ if imm.get_val() == 0:
+ return special_val_e["MIN_VAL"]
+ if imm.get_val() == max_val.get_val():
+ return special_val_e["MAX_VAL"]
+ else:
+ # signed immediate value
+ max_val = vsc.int_t(32, (2 ** (self.imm_len - 1)) - 1)
+ min_val = vsc.int_t(32, -2 ** (self.imm_len - 1))
+ if min_val.get_val() == imm.get_val():
+ return special_val_e["MIN_VAL"]
+ if max_val.get_val() == imm.get_val():
+ return special_val_e["MAX_VAL"]
+ return special_val_e["NORMAL_VAL"]
+
+ def get_compare_result(self):
+ val1 = vsc.int_t(rcs.XLEN, self.rs1_value.get_val())
+ val2 = vsc.int_t(rcs.XLEN, self.imm.get_val() if (
+ self.format == riscv_instr_format_t.I_FORMAT) else
+ self.rs2_value.val)
+ if val1.get_val() == val2.get_val():
+ return compare_result_e["EQUAL"]
+ elif val1.get_val() < val2.get_val():
+ return compare_result_e["SMALLER"]
+ else:
+ return compare_result_e["LARGER"]
+
+ def is_branch_hit(self):
+ if self.instr.name == "BEQ":
+ return int(self.rs1_value.get_val() == self.rs2_value.get_val())
+ elif self.instr.name == "C_BEQZ":
+ return int(self.rs1_value.get_val() == 0)
+ elif self.instr.name == "BNE":
+ return int(self.rs1_value.get_val() != self.rs2_value.get_val())
+ elif self.instr.name == "C_BNEZ":
+ return int(self.rs1_value.get_val() != 0)
+ elif self.instr.name == "BLT" or self.instr.name == "BLTU":
+ return int(self.rs1_value.get_val() < self.rs2_value.get_val())
+ elif self.instr.name == "BGE" or self.instr.name == "BGEU":
+ return int(self.rs1_value.get_val() >= self.rs2_value.get_val())
+ else:
+ logging.error("Unexpected instruction {}".format(self.instr.name))
+
+ def get_logical_similarity(self):
+ val1 = vsc.int_t(rcs.XLEN, self.rs1_value.get_val())
+ val2 = vsc.int_t(rcs.XLEN, (self.imm.get_val() if
+ self.format == riscv_instr_format_t.I_FORMAT
+ else self.rs2_value.val))
+ temp = bin(val1.get_val() ^ val2.get_val())
+ bit_difference = len([[ones for ones in temp[2:] if ones == '1']])
+ if val1.get_val() == val2.get_val():
+ return logical_similarity_e["IDENTICAL"]
+ elif bit_difference == 32:
+ return logical_similarity_e["OPPOSITE"]
+ elif bit_difference < 5:
+ return logical_similarity_e["SIMILAR"]
+ else:
+ return logical_similarity_e["DIFFERENT"]
+
+ def check_hazard_condition(self, pre_instr):
+ '''TODO: There are cases where instruction actually has destination but
+ ovpsim doesn't log it because of no change in its value. Hence,
+ the result of the check_hazard_condition won't be accurate. Need to
+ explicitly extract the destination register from the operands '''
+ if pre_instr.has_rd:
+ if ((self.has_rs1 and self.rs1 == pre_instr.rd) or
+ (self.has_rs2 and self.rs1 == pre_instr.rd)):
+ self.gpr_hazard = hazard_e["RAW_HAZARD"]
+ elif self.has_rd and self.rd == pre_instr.rd:
+ self.gpr_hazard = hazard_e["WAW_HAZARD"]
+ elif (self.has_rd and
+ ((pre_instr.has_rs1 and (pre_instr.rs1 == self.rd)) or
+ (pre_instr.has_rs2 and (pre_instr.rs2 == self.rd)))):
+ self.gpr_hazard = hazard_e["WAR_HAZARD"]
+ else:
+ self.gpr_hazard = hazard_e["NO_HAZARD"]
+ if self.category == riscv_instr_category_t.LOAD:
+ if (pre_instr.category == riscv_instr_category_t.STORE and
+ pre_instr.mem_addr.get_val() == self.mem_addr.get_val()):
+ self.lsu_hazard = hazard_e["RAW_HAZARD"]
+ else:
+ self.lsu_hazard = hazard_e["NO_HAZARD"]
+ if self.category == riscv_instr_category_t.STORE:
+ if (pre_instr.category == riscv_instr_category_t.STORE and
+ pre_instr.mem_addr.get_val() == self.mem_addr.get_val()):
+ self.lsu_hazard = hazard_e["WAW_HAZARD"]
+ elif (pre_instr.category == riscv_instr_category_t.LOAD and
+ pre_instr.mem_addr.get_val() == self.mem_addr.get_val()):
+ self.lsu_hazard = hazard_e["WAR_HAZARD"]
+ else:
+ self.lsu_hazard = hazard_e["NO_HAZARD"]
+ logging.debug("Pre PC/name: {}/{}, Cur PC/name: {}/{}, "
+ "Hazard: {}/{}".format(pre_instr.pc.get_val(),
+ pre_instr.instr.name,
+ self.pc.get_val(),
+ self.instr.name,
+ self.gpr_hazard.name,
+ self.lsu_hazard.name))
+
+ def get_instr_name(self):
+ get_instr_name = self.instr.name
+ for i in get_instr_name:
+ if i == "_":
+ get_instr_name = get_instr_name.replace(i, ".")
+ return get_instr_name
+
+ def update_src_regs(self, operands):
+ if self.format.name in ["J_FORMAT", "U_FORMAT"]:
+ # instr rd,imm
+ assert len(operands) == 2
+ self.imm.set_val(get_val(operands[1]))
+ elif self.format.name == "I_FORMAT":
+ assert len(operands) == 3
+ if self.category.name == "LOAD":
+ # load rd, imm(rs1)
+ self.rs1 = self.get_gpr(operands[2])
+ self.rs1_value.set_val(self.get_gpr_state(operands[2]))
+ self.imm.set_val(get_val(operands[1]))
+ elif self.category.name == "CSR":
+ # csrrwi rd, csr, imm
+ self.imm.set_val(get_val(operands[2]))
+ if operands[1].upper() in privileged_reg_t.__members__:
+ self.csr.set_val(
+ privileged_reg_t[operands[1].upper()].value)
+ else:
+ self.csr.set_val(get_val(operands[1]))
+ else:
+ # addi rd, rs1, imm
+ self.rs1 = self.get_gpr(operands[1])
+ self.rs1_value.set_val(self.get_gpr_state(operands[1]))
+ self.imm.set_val(get_val(operands[2]))
+ elif self.format.name in ["S_FORMAT", "B_FORMAT"]:
+ assert len(operands) == 3
+ if self.category.name == "STORE":
+ self.rs2 = self.get_gpr(operands[0])
+ self.rs2_value.set_val(self.get_gpr_state(operands[0]))
+ self.rs1 = self.get_gpr(operands[2])
+ self.rs1_value.set_val(self.get_gpr_state(operands[2]))
+ self.imm.set_val(get_val(operands[1]))
+ else:
+ # bne rs1, rs2, imm
+ self.rs1 = self.get_gpr(operands[0])
+ self.rs1_value.set_val(self.get_gpr_state(operands[0]))
+ self.rs2 = self.get_gpr(operands[1])
+ self.rs2_value.set_val(self.get_gpr_state(operands[1]))
+ self.imm.set_val(get_val(operands[2]))
+ elif self.format.name == "R_FORMAT":
+ if self.has_rs2 or self.category.name == "CSR":
+ assert len(operands) == 3
+ else:
+ assert len(operands) == 2
+ if self.category.name == "CSR":
+ # csrrw rd, csr, rs1
+ if operands[1].upper() in privileged_reg_t.__members__:
+ self.csr.set_val(
+ privileged_reg_t[operands[1].upper()].value)
+ else:
+ self.csr.set_val(get_val(operands[1]))
+ self.rs1 = self.get_gpr(operands[2])
+ self.rs1_value.set_val(self.get_gpr_state(operands[2]))
+ else:
+ # add rd, rs1, rs2
+ self.rs1 = self.get_gpr(operands[1])
+ self.rs1_value.set_val(self.get_gpr_state(operands[1]))
+ if self.has_rs2:
+ self.rs2 = self.get_gpr(operands[2])
+ self.rs2_value.set_val(self.get_gpr_state(operands[2]))
+ elif self.format.name == "R4_FORMAT":
+ assert len(operands) == 4
+ self.rs1 = self.get_gpr(operands[1])
+ self.rs1_value.set_val(self.get_gpr_state(operands[1]))
+ self.rs2 = self.get_gpr(operands[2])
+ self.rs2_value.set_val(self.get_gpr_state(operands[2]))
+ self.rs2 = self.get_gpr(operands[3])
+ self.rs2_value.set_val(self.get_gpr_state(operands[3]))
+ elif self.format.name in ["CI_FORMAT", "CIW_FORMAT"]:
+ if self.instr.name == "C_ADDI16SP":
+ self.imm.set_val(get_val(operands[1]))
+ self.rs1 = riscv_reg_t.SP
+ self.rs1_value.set_val(self.get_gpr_state("sp"))
+ elif self.instr.name == "C_ADDI4SPN":
+ self.rs1 = riscv_reg_t.SP
+ self.rs1_value.set_val(self.get_gpr_state("sp"))
+ elif self.instr.name in ["C_LDSP", "C_LWSP", "C_LQSP"]:
+ # c.ldsp rd, imm
+ self.imm.set_val(get_val(operands[1]))
+ self.rs1 = riscv_reg_t.SP
+ self.rs1_value.set_val(self.get_gpr_state("sp"))
+ else:
+ # c.lui rd, imm
+ self.imm.set_val(get_val(operands[1]))
+ elif self.format.name == "CL_FORMAT":
+ # c.lw rd, imm(rs1)
+ self.imm.set_val(get_val(operands[1]))
+ self.rs1 = self.get_gpr(operands[2])
+ self.rs1_value.set_val(self.get_gpr_state(operands[2]))
+ elif self.format.name == "CS_FORMAT":
+ # c.sw rs2,imm(rs1)
+ self.rs2 = self.get_gpr(operands[0])
+ self.rs2_value.set_val(self.get_gpr_state(operands[0]))
+ self.rs1 = self.get_gpr(operands[2])
+ self.rs1_value.set_val(self.get_gpr_state(operands[2]))
+ self.imm.set_val(get_val(operands[1]))
+ elif self.format.name == "CA_FORMAT":
+ # c.and rd, rs2 (rs1 == rd)
+ self.rs2 = self.get_gpr(operands[1])
+ self.rs2_value.set_val(self.get_gpr_state(operands[1]))
+ self.rs1 = self.get_gpr(operands[0])
+ self.rs1_value.set_val(self.get_gpr_state(operands[0]))
+ elif self.format.name == "CB_FORMAT":
+ # c.beqz rs1, imm
+ self.rs1 = self.get_gpr(operands[0])
+ self.rs1_value.set_val(self.get_gpr_state(operands[0]))
+ self.imm.set_val(get_val(operands[1]))
+ elif self.format.name == "CSS_FORMAT":
+ # c.swsp rs2, imm
+ self.rs2 = self.get_gpr(operands[0])
+ self.rs2_value.set_val(self.get_gpr_state(operands[0]))
+ self.rs1 = riscv_reg_t.SP
+ self.rs1_value.set_val(self.get_gpr_state("sp"))
+ self.imm.set_val(get_val(operands[1]))
+ elif self.format.name == "CR_FORMAT":
+ if self.instr.name in ["C_JR", "C_JALR"]:
+ # c.jalr rs1
+ self.rs1 = self.get_gpr(operands[0])
+ self.rs1_value.set_val(self.get_gpr_state(operands[0]))
+ else:
+ # c.add rd, rs2
+ self.rs2 = self.get_gpr(operands[1])
+ self.rs2_value.set_val(self.get_gpr_state(operands[1]))
+ elif self.format.name == "CJ_FORMAT":
+ # c.j imm
+ self.imm.set_val(get_val(operands[0]))
+ else:
+ logging.error("Unsupported format {}".format(self.format.name))
+
+ def update_dst_regs(self, reg_name, val_str):
+ riscv_cov_instr.gpr_state[reg_name] = get_val(val_str, hexa=1)
+ self.rd = self.get_gpr(reg_name)
+ self.rd_value.set_val(self.get_gpr_state(reg_name))
+
+ @staticmethod
+ def get_gpr(reg_name):
+ reg_name = reg_name.upper()
+ if reg_name not in riscv_reg_t.__members__:
+ logging.error("Cannot convert {} to GPR".format(reg_name))
+ return riscv_reg_t[reg_name]
+
+ @staticmethod
+ def get_gpr_state(name):
+ if name in ["zero", "x0"]:
+ return 0
+ elif name in riscv_cov_instr.gpr_state:
+ return riscv_cov_instr.gpr_state[name]
+ else:
+ logging.warning(
+ "Cannot find GPR state: {}; initialize to 0".format(name))
+ if name.upper() in riscv_reg_t.__members__:
+ riscv_cov_instr.gpr_state[name] = 0
+ return 0
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr.py
index 7c69763..4151141 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr.py
@@ -172,16 +172,15 @@
# allowed_categories = []
for items in include_category:
- allowed_instr.append(self.instr_category[items])
-
+ allowed_instr.extend(self.instr_category[items])
for items in exclude_category:
if(items in self.instr_category):
- disallowed_instr.append(self.instr_category[items])
+ disallowed_instr.extend(self.instr_category[items])
for items in include_group:
- allowed_instr.append(self.instr_group[items])
+ allowed_instr.extend(self.instr_group[items])
for items in exclude_group:
if(items in self.instr_group):
- disallowed_instr.append(self.instr_group[items])
+ disallowed_instr.extend(self.instr_group[items])
disallowed_instr.extend(exclude_instr)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr_cov.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr_cov.py
deleted file mode 100644
index 2bbe234..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr_cov.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import sys
-import vsc
-import logging
-from enum import Enum, auto
-from pygen_src.riscv_instr_pkg import riscv_reg_t
-
-class operand_sign_e(Enum):
- POSITIVE = 0
- NEGATIVE = auto()
-
-class div_result_e(Enum):
- DIV_NORMAL = 0
- DIV_BY_ZERO = auto()
- DIV_OVERFLOW = auto()
-
-class compare_result_e(Enum):
- EQUAL = 0
- LARGER = auto()
- SMALLER = auto()
-
-class logical_similarity_e(Enum):
- IDENTICAL = 0
- OPPOSITE = auto()
- SIMILAR = auto()
- DIFFERENT = auto()
-
-class special_val_e(Enum):
- NORMAL_VAL = 0
- MIN_VAL = auto()
- MAX_VAL = auto()
- ZERO_VAL = auto()
-
-
-def get_gpr(reg_name):
- reg_name = reg_name.upper()
- if not reg_name in riscv_reg_t:
- logging.fatal("Cannot convert {} to GPR".format(reg_name))
- return riscv_reg_t[reg_name]
-
-def get_gpr_state(reg_name):
- if reg_name in ["zero", "x0"]:
- return 0
- elif reg_name in gpr_state:
- return gpr_state[reg_name]
- else:
- logging.warning("Cannot find GPR state: {}".format(reg_name))
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_asm_program_gen.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_asm_program_gen.py
index 054bdc2..7c48f53 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_asm_program_gen.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_asm_program_gen.py
@@ -15,11 +15,15 @@
import subprocess
import logging
import random
+import copy
+import sys
from bitstring import BitArray
from pygen_src.riscv_instr_sequence import riscv_instr_sequence
from pygen_src.riscv_instr_pkg import pkg_ins, privileged_reg_t, privileged_mode_t, mtvec_mode_t
-from pygen_src.riscv_instr_gen_config import cfg
+from pygen_src.riscv_instr_gen_config import cfg, args, args_dict
from pygen_src.target.rv32i import riscv_core_setting as rcs
+from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
+from pygen_src.riscv_utils import factory
'''
RISC-V assembly program generator
@@ -33,7 +37,7 @@
def __init__(self):
self.instr_stream = []
- self.directed_instr_stream_ratio = []
+ self.directed_instr_stream_ratio = {}
self.hart = 0
self.page_table_list = []
self.main_program = []
@@ -77,13 +81,20 @@
# Generate main program
gt_lbl_str = pkg_ins.get_label("main", hart)
+ label_name = gt_lbl_str
gt_lbl_str = riscv_instr_sequence()
self.main_program.append(gt_lbl_str)
self.main_program[hart].instr_cnt = cfg.main_program_instr_cnt
self.main_program[hart].is_debug_program = 0
- self.main_program[hart].label_name = "main"
- self.main_program[hart].gen_instr(is_main_program = 1, no_branch = cfg.no_branch_jump)
+ self.main_program[hart].label_name = label_name
+ self.generate_directed_instr_stream(hart=hart,
+ label=self.main_program[hart].label_name,
+ original_instr_cnt=self.main_program[hart].instr_cnt,
+ min_insert_cnt=1,
+ instr_stream=self.main_program[hart].directed_instr)
+ self.main_program[hart].gen_instr(is_main_program=1, no_branch=cfg.no_branch_jump)
+ self.main_program[hart].post_process_instr()
self.main_program[hart].generate_instr_stream()
logging.info("Generating main program instruction stream...done")
self.instr_stream.extend(self.main_program[hart].instr_string_list)
@@ -292,7 +303,20 @@
self.instr_stream.append(pkg_ins.indent + "ecall")
def gen_register_dump(self):
- pass
+ string = ""
+ # load base address
+ string = "{}la x{}, _start".format(pkg_ins.indent, cfg.gpr[0].value)
+ self.instr_stream.append(string)
+
+ # Generate sw/sd instructions
+ for i in range(32):
+ if (rcs.XLEN == 64):
+ string = "{}sd x{}, {}(x{})".format(
+ pkg_ins.indent, i, i * (rcs.XLEN / 8), cfg.gpr[0].value)
+ else:
+ string = "{}sw x{}, {}(x{})".format(
+ pkg_ins.indent, i, int(i * (rcs.XLEN / 8)), cfg.gpr[0].value)
+ self.instr_stream.append(string)
def pre_enter_privileged_mode(self, hart):
instr = []
@@ -430,7 +454,15 @@
pass
def gen_ecall_handler(self, hart):
- pass
+ string = ""
+ string = pkg_ins.format_string(pkg_ins.get_label(
+ "ecall_handler:", hart), pkg_ins.LABEL_STR_LEN)
+ self.instr_stream.append(string)
+ self.dump_perf_stats()
+ self.gen_register_dump()
+ string = pkg_ins.format_string(" ", pkg_ins.LABEL_STR_LEN)
+ string = string + "j write_tohost"
+ self.instr_stream.append(string)
def gen_ebreak_handler(self, hart):
pass
@@ -555,14 +587,60 @@
pass
def add_directed_instr_stream(self, name, ratio):
- pass
+ self.directed_instr_stream_ratio[name] = ratio
+ logging.info("Adding directed instruction stream:%0s ratio:%0d/1000", name, ratio)
def get_directed_instr_stream(self):
- pass
+ opts = []
+ for i in range(cfg.max_directed_instr_stream_seq):
+ arg = "directed_instr_{}".format(i)
+ stream_name_opts = "stream_name_{}".format(i)
+ stream_freq_opts = "stream_freq_{}".format(i)
+ if(arg in args):
+ val = args_dict[arg]
+ opts = val.split(",")
+ if(len(opts) != 2):
+ logging.critical(
+ "Incorrect directed instruction format : %0s, expect: name,ratio", val)
+ else:
+ self.add_directed_instr_stream(opts[0], int(opts[1]))
+ elif(stream_name_opts in args and stream_freq_opts in args):
+ stream_name = args_dict[stream_name_opts]
+ stream_freq = args_dict[stream_freq_opts]
+ self.add_directed_instr_stream(stream_name, stream_freq)
- def generate_directed_instr_stream(self, hart = 0, label = "", original_instr_cnt = None,
+ def generate_directed_instr_stream(self, hart = 0, label = "", original_instr_cnt = 0,
min_insert_cnt = 0, kernel_mode = 0, instr_stream = []):
- pass
+ instr_insert_cnt = 0
+ idx = 0
+ if(cfg.no_directed_instr):
+ return
+ for instr_stream_name in self.directed_instr_stream_ratio:
+ instr_insert_cnt = int(original_instr_cnt *
+ self.directed_instr_stream_ratio[instr_stream_name] // 1000)
+ if(instr_insert_cnt <= min_insert_cnt):
+ instr_insert_cnt = min_insert_cnt
+ logging.info("Insert directed instr stream %0s %0d/%0d times",
+ instr_stream_name, instr_insert_cnt, original_instr_cnt)
+ for i in range(instr_insert_cnt):
+ name = "{}_{}".format(instr_stream_name, i)
+ object_h = factory(instr_stream_name)
+ object_h.name = name
+ if(object_h is None):
+ logging.critical("Cannot create instr stream %0s", name)
+ sys.exit(1)
+ new_instr_stream = copy.copy(object_h)
+ if(new_instr_stream):
+ new_instr_stream.hart = hart
+ new_instr_stream.label = "{}_{}".format(label, idx)
+ new_instr_stream.kernel_mode = kernel_mode
+ new_instr_stream.randomize()
+ instr_stream.append(new_instr_stream)
+ else:
+ logging.critical("Cannot Create instr stream %0s", name)
+ sys.exit(1)
+ idx += 1
+ random.shuffle(instr_stream)
def gen_debug_rom(self, hart):
pass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_defines.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_defines.py
index bc1e5f5..1627883 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_defines.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_defines.py
@@ -34,3 +34,14 @@
"valid": riscv_instr.register(instr_n)
})
g[class_name] = NewClass
+
+
+'''
+TODO
+@vsc.constraint
+def add_pseudo_instr(self, instr_n, instr_format, instr_category, instr_group):
+ with vsc.if_then(self.pseudo_instr_name == instr_n):
+ self.format == instr_format.name
+ self.category == instr_category.name
+ self.group == instr_group.name
+'''
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_directed_instr_lib.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_directed_instr_lib.py
new file mode 100644
index 0000000..318ae64
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_directed_instr_lib.py
@@ -0,0 +1,98 @@
+"""
+Copyright 2020 Google LLC
+Copyright 2020 PerfectVIPs Inc.
+
+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.
+"""
+
+import vsc
+from enum import IntEnum, auto
+from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
+from pygen_src.isa.riscv_instr import riscv_instr_ins
+from pygen_src.riscv_instr_gen_config import cfg
+from pygen_src.riscv_instr_pkg import riscv_reg_t, riscv_pseudo_instr_name_t
+from pygen_src.target.rv32i import riscv_core_setting as rcs
+from pygen_src.riscv_pseudo_instr import riscv_pseudo_instr
+
+
+class riscv_directed_instr_stream(riscv_rand_instr_stream):
+
+ def __init__(self):
+ super().__init__()
+ self.name = ""
+ self.label = ""
+
+ def post_randomize(self):
+ for i in range(len(self.instr_list)):
+ self.instr_list[i].has_label = 0
+ self.instr_list[i].atomic = 1
+ self.instr_list[0].comment = "Start %0s" % (self.name)
+ self.instr_list[-1].comment = "End %0s" % (self.name)
+ if self.label != "":
+ self.instr_list[0].label = self.label
+ self.instr_list[0].has_label = 1
+
+
+class int_numeric_e(IntEnum):
+ NormalValue = auto()
+ Zero = auto()
+ AllOne = auto()
+ NegativeMax = auto()
+
+
+@vsc.randobj
+class riscv_int_numeric_corner_stream(riscv_directed_instr_stream):
+ def __init__(self):
+ super().__init__()
+ self.num_of_avail_regs = 10
+ self.num_of_instr = vsc.rand_uint8_t()
+ self.init_val = vsc.rand_list_t(vsc.rand_bit_t(rcs.XLEN - 1), sz = 10)
+ self.init_val_type = vsc.rand_list_t(vsc.enum_t(int_numeric_e), sz =10)
+ self.init_instr = []
+
+ @vsc.constraint
+ def init_val_c(self):
+ # TO DO
+ # solve init_val_type before init_val;
+ self.init_val_type.size == self.num_of_avail_regs
+ self.init_val.size == self.num_of_avail_regs
+ self.num_of_instr in vsc.rangelist(vsc.rng(15, 30))
+
+ @vsc.constraint
+ def avail_regs_c(self):
+ self.avail_regs.size == self.num_of_avail_regs
+ vsc.unique(self.avail_regs)
+ with vsc.foreach(self.avail_regs, idx = True) as i:
+ self.avail_regs[i].not_inside(cfg.reserved_regs)
+ self.avail_regs[i] != riscv_reg_t.ZERO
+
+ def pre_randomize(self):
+ pass
+
+ def post_randomize(self):
+ self.init_instr = [None] * self.num_of_avail_regs
+ for i in range(len(self.init_val_type)):
+ if self.init_val_type[i] == int_numeric_e.Zero:
+ self.init_val[i] = 0
+ elif self.init_val_type[i] == int_numeric_e.AllOne:
+ self.init_val[i] = 1
+ elif self.init_val_type[i] == int_numeric_e.NegativeMax:
+ self.init_val[i] = 1 << (rcs.XLEN - 1)
+ self.init_instr[i] = riscv_pseudo_instr()
+ self.init_instr[i].rd = self.avail_regs[i]
+ self.init_instr[i].pseudo_instr_name = riscv_pseudo_instr_name_t.LI
+ self.init_instr[i].imm_str = "0x%0x" % (self.init_val[i])
+ self.instr_list.append(self.init_instr[i])
+ for i in range(self.num_of_instr):
+ instr = riscv_instr_ins.get_rand_instr(
+ include_category = ['ARITHMETIC'],
+ exclude_group = ['RV32C', 'RV64C', 'RV32F', 'RV64F', 'RV32D', 'RV64D'])
+ instr = self.randomize_gpr(instr)
+ self.instr_list.append(instr)
+ super().post_randomize()
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py
new file mode 100644
index 0000000..b2349c3
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py
@@ -0,0 +1,1410 @@
+"""Copyright 2020 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.
+"""
+
+from pygen.pygen_src.isa.riscv_cov_instr import *
+
+
+class riscv_instr_cover_group:
+ def __init__(self):
+ self.pre_instr = riscv_cov_instr()
+ self.cfg = None
+ self.instr_list = []
+ self.instr_cnt = 0
+ self.branch_instr_cnt = 0
+ self.branch_hit_history = vsc.bit_t(5) # The last 5 branch result
+ self.ignored_exceptions = []
+ self.exception_list = []
+ '''
+ Mode of the coverage model:
+ In compliance mode, all the micro-architecture related covergroups
+ are removed. Only the ones related to RISC-V specification compliance
+ is sampled.
+ '''
+ self.compliance_mode = vsc.bit_t(1)
+ self.select_isa = vsc.bit_t(1) # Select an ISA extension to cover
+ self.cov_isa = None
+
+ '''Format specific covergroups'''
+
+ @vsc.covergroup
+ class r_instr_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+
+ @vsc.covergroup
+ class i_instr_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+
+ @vsc.covergroup
+ class u_instr_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+
+ @vsc.covergroup
+ class cmp_instr_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_result = vsc.coverpoint(lambda: instr.rd_value[0],
+ bins={
+ "Unset": vsc.bin(0),
+ "Set" : vsc.bin(1)
+ }
+ )
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+
+ @vsc.covergroup
+ class sb_instr_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit,
+ bins={
+ "Taken" : vsc.bin(1),
+ "Non-taken": vsc.bin(0)
+ }
+ )
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ @vsc.covergroup
+ class j_instr_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ '''The RISC-V hardware allows any of the 32 integer registers
+ to be given as rd. If register 0 (ZERO) is given as rd then the
+ return address is discarded and we effectively have a
+ goto rather than a function call'''
+ # if instr.rd:
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd_align = vsc.coverpoint(lambda: instr.rd_value[1],
+ bins={
+ "Aligned" : vsc.bin(1),
+ "Not-aligned": vsc.bin(0)
+ }
+ )
+
+ '''Category specific covergroups'''
+ '''Load instructions'''
+
+ @vsc.covergroup
+ class load_instr_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ '''TODO: covergroup inheritance is broken at the moment. The workaround
+ will be switched back to the inheritance approach once it gets fixed'''
+
+ # @vsc.covergroup
+ # class lb_cg(load_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class lb_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ # @vsc.covergroup
+ # class lh_cg(load_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access,
+ # bins={
+ # "aligned" : vsc.bin(0),
+ # "unaligned": vsc.bin(1)
+ # })
+ @vsc.covergroup
+ class lh_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+ self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access,
+ bins={
+ "aligned" : vsc.bin(0),
+ "unaligned": vsc.bin(1)
+ })
+
+ # @vsc.covergroup
+ # class lw_cg(load_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access,
+ # bins={
+ # "aligned" : vsc.bin(0),
+ # "unaligned": vsc.bin(1)
+ # })
+ @vsc.covergroup
+ class lw_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access,
+ bins={
+ "aligned" : vsc.bin(0),
+ "unaligned": vsc.bin(1)
+ })
+
+ # @vsc.covergroup
+ # class lbu_cg(load_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class lbu_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ # @vsc.covergroup
+ # class lhu_cg(load_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access,
+ # bins={
+ # "aligned" : vsc.bin(0),
+ # "unaligned": vsc.bin(1)
+ # })
+ @vsc.covergroup
+ class lhu_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+ self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access,
+ bins={
+ "aligned" : vsc.bin(0),
+ "unaligned": vsc.bin(1)
+ })
+
+ '''Store instructions'''
+
+ @vsc.covergroup
+ class store_instr_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+ self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.lsu_hazard,
+ cp_t=vsc.enum_t(
+ store_lsu_hazard_e))
+
+ # @vsc.covergroup
+ # class sb_cg(store_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class sb_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+ self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.lsu_hazard,
+ cp_t=vsc.enum_t(
+ store_lsu_hazard_e))
+
+ # @vsc.covergroup
+ # class sh_cg(store_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_misalign = vsc.coverpoint(
+ # lambda: instr.unaligned_mem_access,
+ # bins={
+ # "aligned" : vsc.bin(0),
+ # "unaligned": vsc.bin(1)
+ # })
+ @vsc.covergroup
+ class sh_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+ self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.lsu_hazard,
+ cp_t=vsc.enum_t(
+ store_lsu_hazard_e))
+ self.cp_misalign = vsc.coverpoint(
+ lambda: instr.unaligned_mem_access,
+ bins={
+ "aligned" : vsc.bin(0),
+ "unaligned": vsc.bin(1)
+ })
+
+ # @vsc.covergroup
+ # class sw_cg(store_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_misalign = vsc.coverpoint(
+ # lambda: instr.unaligned_mem_access,
+ # bins={
+ # "aligned" : vsc.bin(0),
+ # "unaligned": vsc.bin(1)
+ # })
+ @vsc.covergroup
+ class sw_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+ self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.lsu_hazard,
+ cp_t=vsc.enum_t(
+ store_lsu_hazard_e))
+ self.cp_misalign = vsc.coverpoint(
+ lambda: instr.unaligned_mem_access,
+ bins={
+ "aligned" : vsc.bin(0),
+ "unaligned": vsc.bin(1)
+ })
+
+ '''Shift instructions'''
+
+ # @vsc.covergroup
+ # class sll_cg(r_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_rs2_sign])
+ @vsc.covergroup
+ class sll_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+
+ @vsc.covergroup
+ class slli_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+
+ # @vsc.covergroup
+ # class srl_cg(r_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_rs2_sign])
+ @vsc.covergroup
+ class srl_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+
+ @vsc.covergroup
+ class srli_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+
+ # @vsc.covergroup
+ # class sra_cg(r_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_rs2_sign])
+ @vsc.covergroup
+ class sra_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+
+ @vsc.covergroup
+ class srai_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+
+ '''Arithmetic instructions'''
+
+ # @vsc.covergroup
+ # class add_cg(r_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
+ # self.cp_rd_sign])
+ @vsc.covergroup
+ class add_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
+ self.cp_rd_sign])
+
+ @vsc.covergroup
+ class addi_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_imm_sign,
+ self.cp_rd_sign])
+
+ # @vsc.covergroup
+ # class sub_cg(r_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
+ # self.cp_rd_sign])
+ @vsc.covergroup
+ class sub_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
+ self.cp_rd_sign])
+
+ # @vsc.covergroup
+ # class lui_cg(u_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class lui_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+
+ # @vsc.covergroup
+ # class auipc_cg(u_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class auipc_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+
+ '''Logical instructions'''
+
+ # @vsc.covergroup
+ # class xor_cg(r_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ # cp_t=vsc.enum_t(
+ # logical_similarity_e))
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_rs2_sign])
+ @vsc.covergroup
+ class xor_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ cp_t=vsc.enum_t(
+ logical_similarity_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+
+ # @vsc.covergroup
+ # class xori_cg(i_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ # cp_t=vsc.enum_t(
+ # logical_similarity_e))
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_imm_sign])
+ @vsc.covergroup
+ class xori_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ cp_t=vsc.enum_t(
+ logical_similarity_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_imm_sign])
+
+ # @vsc.covergroup
+ # class or_cg(r_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ # cp_t=vsc.enum_t(
+ # logical_similarity_e))
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_rs2_sign])
+ @vsc.covergroup
+ class or_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ cp_t=vsc.enum_t(
+ logical_similarity_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+
+ # @vsc.covergroup
+ # class ori_cg(i_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ # cp_t=vsc.enum_t(
+ # logical_similarity_e))
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_imm_sign])
+ @vsc.covergroup
+ class ori_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ cp_t=vsc.enum_t(
+ logical_similarity_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_imm_sign])
+
+ # @vsc.covergroup
+ # class and_cg(r_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ # cp_t=vsc.enum_t(
+ # logical_similarity_e))
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_rs2_sign])
+ @vsc.covergroup
+ class and_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ cp_t=vsc.enum_t(
+ logical_similarity_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+
+ # @vsc.covergroup
+ # class andi_cg(i_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ # cp_t=vsc.enum_t(
+ # logical_similarity_e))
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_imm_sign])
+ @vsc.covergroup
+ class andi_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity,
+ cp_t=vsc.enum_t(
+ logical_similarity_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_imm_sign])
+
+ '''Compare instructions'''
+
+ # @vsc.covergroup
+ # class slt_cg(cmp_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ # cp_t=vsc.enum_t(riscv_reg_t))
+ # self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ # cp_t=vsc.enum_t(operand_sign_e))
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_rs2_sign])
+ @vsc.covergroup
+ class slt_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_result = vsc.coverpoint(lambda: instr.rd_value[0],
+ bins={
+ "Unset": vsc.bin(0),
+ "Set" : vsc.bin(1)
+ }
+ )
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+
+ # @vsc.covergroup
+ # class slti_cg(cmp_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ # cp_t=vsc.enum_t(operand_sign_e))
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_imm_sign])
+ @vsc.covergroup
+ class slti_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_result = vsc.coverpoint(lambda: instr.rd_value[0],
+ bins={
+ "Unset": vsc.bin(0),
+ "Set" : vsc.bin(1)
+ }
+ )
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_imm_sign])
+
+ # @vsc.covergroup
+ # class sltu_cg(cmp_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ # cp_t=vsc.enum_t(riscv_reg_t))
+ # self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ # cp_t=vsc.enum_t(operand_sign_e))
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_rs2_sign])
+ @vsc.covergroup
+ class sltu_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_result = vsc.coverpoint(lambda: instr.rd_value[0],
+ bins={
+ "Unset": vsc.bin(0),
+ "Set" : vsc.bin(1)
+ }
+ )
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+
+ # @vsc.covergroup
+ # class sltiu_cg(cmp_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ # cp_t=vsc.enum_t(operand_sign_e))
+ # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ # self.cp_imm_sign])
+ @vsc.covergroup
+ class sltiu_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_result = vsc.coverpoint(lambda: instr.rd_value[0],
+ bins={
+ "Unset": vsc.bin(0),
+ "Set" : vsc.bin(1)
+ }
+ )
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_imm_sign])
+
+ '''Branch instructions'''
+
+ # @vsc.covergroup
+ # class beq_cg(sb_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class beq_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit,
+ bins={
+ "Non-taken": vsc.bin(0),
+ "Taken" : vsc.bin(1),
+ }
+ )
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ # @vsc.covergroup
+ # class bne_cg(sb_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class bne_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit,
+ bins={
+ "Taken" : vsc.bin(1),
+ "Non-taken": vsc.bin(0)
+ }
+ )
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ # @vsc.covergroup
+ # class blt_cg(sb_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class blt_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit,
+ bins={
+ "Taken" : vsc.bin(1),
+ "Non-taken": vsc.bin(0)
+ }
+ )
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ # @vsc.covergroup
+ # class bge_cg(sb_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class bge_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit,
+ bins={
+ "Taken" : vsc.bin(1),
+ "Non-taken": vsc.bin(0)
+ }
+ )
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ # @vsc.covergroup
+ # class bltu_cg(sb_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class bltu_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit,
+ bins={
+ "Taken" : vsc.bin(1),
+ "Non-taken": vsc.bin(0)
+ }
+ )
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ # @vsc.covergroup
+ # class bgeu_cg(sb_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ @vsc.covergroup
+ class bgeu_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit,
+ bins={
+ "Taken" : vsc.bin(1),
+ "Non-taken": vsc.bin(0)
+ }
+ )
+ self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
+ self.cp_rs2_sign])
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(
+ branch_hazard_e))
+
+ '''Jump instructions'''
+
+ # @vsc.covergroup
+ # class jal_cg(j_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # self.cp_imm_align = vsc.coverpoint(lambda: instr.imm[1],
+ # bins={
+ # "Aligned" : vsc.bin(1),
+ # "Not-aligned": vsc.bin(0)
+ # }
+ # )
+ @vsc.covergroup
+ class jal_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ '''The RISC-V hardware allows any of the 32 integer registers
+ to be given as rd. If register 0 (ZERO) is given as rd then the
+ return address is discarded and we effectively have a
+ goto rather than a function call'''
+ # if instr.rd:
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd_align = vsc.coverpoint(lambda: instr.rd_value[1],
+ bins={
+ "Aligned" : vsc.bin(1),
+ "Not-aligned": vsc.bin(0)
+ }
+ )
+ self.cp_imm_align = vsc.coverpoint(lambda: instr.imm[1],
+ bins={
+ "Aligned" : vsc.bin(1),
+ "Not-aligned": vsc.bin(0)
+ }
+ )
+
+ # @vsc.covergroup
+ # class jalr_cg(j_instr_cg):
+ # def __init__(self, instr):
+ # super().__init__(instr)
+ #
+ # '''default bins are not supported in pyvsc. We ignore it here
+ # as coverage values hit in default bin are not taken account while
+ # reporting coverage'''
+ # self.cp_rs1_link = vsc.coverpoint(lambda: instr.rs1,
+ # cp_t=vsc.enum_t(
+ # jalr_riscv_reg_t))
+ # self.cp_rd_link = vsc.coverpoint(lambda: instr.rd,
+ # cp_t=vsc.enum_t(jalr_riscv_reg_t))
+ # # left index is excluded in pyvsc bit_t type
+ # self.cp_imm_align = vsc.coverpoint(lambda: instr.imm[2:0],
+ # bins={
+ # "Zero" : vsc.bin(0),
+ # "One" : vsc.bin(1),
+ # "Two" : vsc.bin(2),
+ # "Three": vsc.bin(3)
+ # }
+ # )
+ # self.cp_rs1_align = vsc.coverpoint(lambda: instr.rs1_value[2:0],
+ # bins={
+ # "Zero" : vsc.bin(0),
+ # "One" : vsc.bin(1),
+ # "Two" : vsc.bin(2),
+ # "Three": vsc.bin(3)
+ # }
+ # )
+ # self.cp_align = vsc.cross([self.cp_imm_align, self.cp_rs1_align])
+ # self.cp_ras = vsc.cross([self.cp_rs1_link, self.cp_rd_link])
+ @vsc.covergroup
+ class jalr_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign,
+ cp_t=vsc.enum_t(operand_sign_e))
+ '''The RISC-V hardware allows any of the 32 integer registers
+ to be given as rd. If register 0 (ZERO) is given as rd then the
+ return address is discarded and we effectively have a
+ goto rather than a function call'''
+ # TODO: if instr.rd:
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_rd_align = vsc.coverpoint(lambda: instr.rd_value[1],
+ bins={
+ "Aligned" : vsc.bin(1),
+ "Not-aligned": vsc.bin(0)
+ }
+ )
+ '''default bins are not supported in pyvsc. We ignore it here
+ as coverage values hit in default bin are not taken account while
+ reporting coverage'''
+ self.cp_rs1_link = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(
+ jalr_riscv_reg_t))
+ self.cp_rd_link = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(jalr_riscv_reg_t))
+ # left index is excluded in pyvsc bit_t type
+ self.cp_imm_align = vsc.coverpoint(lambda: instr.imm[2:0],
+ bins={
+ "Zero" : vsc.bin(0),
+ "One" : vsc.bin(1),
+ "Two" : vsc.bin(2),
+ "Three": vsc.bin(3)
+ }
+ )
+ self.cp_rs1_align = vsc.coverpoint(lambda: instr.rs1_value[2:0],
+ bins={
+ "Zero" : vsc.bin(0),
+ "One" : vsc.bin(1),
+ "Two" : vsc.bin(2),
+ "Three": vsc.bin(3)
+ }
+ )
+ self.cp_align = vsc.cross([self.cp_imm_align, self.cp_rs1_align])
+ self.cp_ras = vsc.cross([self.cp_rs1_link, self.cp_rd_link])
+
+ '''CSR instructions'''
+
+ @vsc.covergroup
+ class csrrw_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_rd = vsc.coverpoint(lambda: instr.rd,
+ cp_t=vsc.enum_t(riscv_reg_t))
+ self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
+ cp_t=vsc.enum_t(hazard_e))
+ self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
+ cp_t=vsc.enum_t(riscv_reg_t))
+
+ @vsc.covergroup
+ class opcode_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_opcode = vsc.coverpoint(lambda: instr.binary[7:2],
+ bins={
+ "a": vsc.bin_array([], [0, 31])
+ }
+ )
+
+ @vsc.covergroup
+ class rv32i_misc_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_misc = vsc.coverpoint(lambda: instr.instr,
+ cp_t=vsc.enum_t(rv32i_misc_instrs))
+
+ @vsc.covergroup
+ class mepc_alignment_cg(object):
+ def __init__(self, instr):
+ super().__init__()
+
+ self.cp_align = vsc.coverpoint(lambda: instr.rd_value[2:0],
+ bins={
+ "Zero": vsc.bin(0),
+ "Two" : vsc.bin(2)
+ }
+ )
+
+ def sample(self, instr):
+ self.instr_cnt += 1
+ if self.instr_cnt > 1:
+ instr.check_hazard_condition(self.pre_instr)
+ # TODO: sampling for hint, compressed, and illegal_compressed insts
+ if instr.binary[2:0] == 3:
+ opcode_cg = self.opcode_cg(instr)
+ opcode_cg.sample()
+ try:
+ cg = eval("self." + instr.instr.name.lower() + "_cg")(instr)
+ cg.sample()
+ except Exception:
+ logging.info("Covergroup for instr {} is not supported yet".format(
+ instr.instr.name))
+ if instr.group.name == "RV32I":
+ rv32i_misc_cg = self.rv32i_misc_cg(instr)
+ rv32i_misc_cg.sample()
+ if instr.category.name == "CSR":
+ # MEPC
+ if instr.csr == 833:
+ mepc_alignment_cg = self.mepc_alignment_cg(instr)
+ mepc_alignment_cg.sample()
+ self.pre_instr = instr
+
+ def reset(self):
+ self.instr_cnt = 0
+ self.branch_instr_cnt = 0
+ self.branch_hit_history.set_val(0)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_gen_config.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_gen_config.py
index 0f56094..26f49aa 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_gen_config.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_gen_config.py
@@ -111,10 +111,22 @@
self.num_of_harts = argv.num_of_harts
self.fix_sp = argv.fix_sp
self.use_push_data_section = argv.use_push_data_section
- self.boot_mode_opts = ""
+ self.boot_mode_opts = argv.boot_mode_opts
+
+ if(self.boot_mode_opts):
+ logging.info("Got boot mode option - %0s", self.boot_mode_opts)
+ if(self.boot_mode_opts == "m"):
+ self.init_privileged_mode = privileged_mode_t.MACHINE_MODE.name
+ elif(self.boot_mode_opts == "s"):
+ self.init_privileged_mode = privileged_mode_t.SUPERVISOR_MODE.name
+ elif(self.boot_mode_opts == "u"):
+ self.init_privileged_mode = privileged_mode_t.USER_MODE.name
+ else:
+ logging.error("Illegal boot mode option - %0s", self.boot_mode_opts)
+
self.enable_page_table_exception = argv.enable_page_table_exception
self.no_directed_instr = argv.no_directed_instr
- self.asm_test_suffix = ""
+ self.asm_test_suffix = argv.asm_test_suffix
self.enable_interrupt = argv.enable_interrupt
self.enable_nested_interrupt = argv.enable_nested_interrupt
self.enable_timer_irq = argv.enable_timer_irq
@@ -153,11 +165,16 @@
self.enable_floating_point = argv.enable_floating_point
self.enable_vector_extension = argv.enable_vector_extension
self.enable_b_extension = argv.enable_b_extension
- # Commenting out for now
- # self.enable_bitmanip_groups = ['ZBB', 'ZBS', 'ZBP', 'ZBE', 'ZBF',
- # 'ZBC', 'ZBR', 'ZBM', 'ZBT', 'ZB_TMP']
+ self.enable_bitmanip_groups = argv.enable_bitmanip_groups
self.dist_control_mode = 0
self.category_dist = {}
+ self.march_isa = argv.march_isa
+
+ if(len(self.march_isa) != 0):
+ rcs.supported_isa = self.march_isa
+
+ if(rcs.supported_isa != 'RV32C'):
+ self.disable_compressed_instr = 1
@vsc.constraint
def gpr_c(self):
@@ -317,9 +334,8 @@
parse.add_argument('--no_dret', help = 'no_dret', choices = [0, 1], type = int, default = 1)
parse.add_argument('--no_wfi', help = 'no_wfi', choices = [0, 1], type = int, default = 1)
- # TODO : Enabling no_branch_jump default to 1 for now.
parse.add_argument('--no_branch_jump', help = 'no_branch_jump',
- choices = [0, 1], type = int, default = 1)
+ choices = [0, 1], type = int, default = 0)
parse.add_argument('--no_load_store', help = 'no_load_store',
choices = [0, 1], type = int, default = 0)
parse.add_argument('--no_csr_instr', help = 'no_csr_instr',
@@ -387,35 +403,35 @@
choices = [0, 1], type = int, default = 0)
parse.add_argument('--enable_b_extension', help = 'enable_b_extension',
choices = [0, 1], type = int, default = 0)
-
+ parse.add_argument('--enable_bitmanip_groups', help = 'enable_bitmanip_groups',
+ default = ['ZBB', 'ZBS', 'ZBP', 'ZBE', 'ZBF',
+ 'ZBC', 'ZBR', 'ZBM', 'ZBT', 'ZB_TMP'], nargs = '*')
+ parse.add_argument('--boot_mode_opts', help = 'boot_mode_opts', default = "")
+ parse.add_argument('--asm_test_suffix', help = 'asm_test_suffix', default = "")
+ parse.add_argument('--march_isa', help = 'march_isa', default = [],
+ choices = [i.name for i in riscv_instr_group_t], nargs = '*')
+ parse.add_argument('--directed_instr_0', help = 'directed_instr_0',
+ default = "riscv_int_numeric_corner_stream,4")
+ parse.add_argument('--stream_name_opts', help = 'stream_name_0',
+ default = "riscv_load_store_rand_instr_stream")
+ parse.add_argument('--stream_freq_opts', help = 'stream_freq_0', default = 4)
# TODO
'''
- cmdline_enum_processor #(b_ext_group_t)::get_array_values("+enable_bitmanip_groups=",
- enable_bitmanip_groups);
- 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)
- case(boot_mode_opts)
- "m" : init_privileged_mode = MACHINE_MODE;
- "s" : init_privileged_mode = SUPERVISOR_MODE;
- "u" : init_privileged_mode = USER_MODE;
- default: `uvm_fatal(get_full_name(),
- $sformatf("Illegal boot mode option - %0s", boot_mode_opts))
- endcase
- init_privileged_mode.rand_mode(0);
- addr_translaction_rnd_order_c.constraint_mode(0);
+ if ($value$plusargs("tvec_alignment=%0d", tvec_alignment)) begin
+ tvec_alignment.rand_mode(0);
end
- `uvm_info(`gfn, $sformatf("riscv_instr_pkg::supported_privileged_mode = %0d",
- riscv_instr_pkg::supported_privileged_mode.size()), UVM_LOW)
- void'(inst.get_arg_value("+asm_test_suffix=", asm_test_suffix));
- // Directed march list from the runtime options, ex. RV32I, RV32M etc.
- cmdline_enum_processor #(riscv_instr_group_t)::get_array_values("+march=", march_isa);
- if (march_isa.size != 0) riscv_instr_pkg::supported_isa = march_isa;
- '''
+ vector_cfg = riscv_vector_cfg::type_id::create("vector_cfg");
+ pmp_cfg = riscv_pmp_cfg::type_id::create("pmp_cfg");
+ pmp_cfg.rand_mode(pmp_cfg.pmp_randomize);
+ pmp_cfg.initialize(require_signature_addr);
+ setup_instr_distribution();
+ get_invalid_priv_lvl_csr();
+ '''
args = parse.parse_args()
return args
args = parse_args()
+args_dict = vars(args)
cfg = riscv_instr_gen_config(args)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py
index fd4e134..541a979 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py
@@ -13,9 +13,9 @@
"""
import logging
-from enum import Enum, auto
+from enum import Enum, IntEnum, auto
from bitstring import BitArray
-from pygen_src.target.rv32i import riscv_core_setting as rcs
+from pygen.pygen_src.target.rv32i import riscv_core_setting as rcs
class mem_region_t:
@@ -24,7 +24,7 @@
xwr = auto()
-class satp_mode_t(Enum):
+class satp_mode_t(IntEnum):
BARE = 0b0000
SV32 = 0b0001
SV39 = 0b1000
@@ -33,7 +33,7 @@
SV64 = 0b1011
-class f_rounding_mode_t(Enum):
+class f_rounding_mode_t(IntEnum):
RNE = 0b000
RTZ = 0b001
RDN = 0b010
@@ -41,26 +41,26 @@
RMM = 0b100
-class mtvec_mode_t(Enum):
+class mtvec_mode_t(IntEnum):
DIRECT = 0b00
VECTORED = 0b01
-class imm_t(Enum):
+class imm_t(IntEnum):
IMM = 0
UIMM = auto()
NZUIMM = auto()
NZIMM = auto()
-class privileged_mode_t(Enum):
+class privileged_mode_t(IntEnum):
USER_MODE = 0b00
SUPERVISOR_MODE = 0b01
RESERVED_MODE = 0b10
MACHINE_MODE = 0b11
-class riscv_instr_group_t(Enum):
+class riscv_instr_group_t(IntEnum):
RV32I = 0
RV64I = auto()
RV32M = auto()
@@ -85,7 +85,7 @@
RV64X = auto()
-class riscv_instr_name_t(Enum):
+class riscv_instr_name_t(IntEnum):
LUI = 0
AUIPC = auto()
JAL = auto()
@@ -560,7 +560,7 @@
INVALID_INSTR = auto()
-class riscv_reg_t(Enum):
+class riscv_reg_t(IntEnum):
ZERO = 0
RA = auto()
SP = auto()
@@ -595,7 +595,7 @@
T6 = auto()
-class riscv_fpr_t(Enum):
+class riscv_fpr_t(IntEnum):
FT0 = 0
FT1 = auto()
FT2 = auto()
@@ -630,7 +630,7 @@
FT11 = auto()
-class riscv_vreg_t(Enum):
+class riscv_vreg_t(IntEnum):
V0 = 0
V1 = auto()
V2 = auto()
@@ -665,7 +665,7 @@
V31 = auto()
-class riscv_instr_format_t(Enum):
+class riscv_instr_format_t(IntEnum):
J_FORMAT = 0
U_FORMAT = auto()
I_FORMAT = auto()
@@ -689,7 +689,7 @@
VS_FORMAT = auto()
-class va_variant_t(Enum):
+class va_variant_t(IntEnum):
VV = 0
VI = auto()
VX = auto()
@@ -705,7 +705,7 @@
VM = auto()
-class riscv_instr_category_t(Enum):
+class riscv_instr_category_t(IntEnum):
LOAD = 0
STORE = auto()
SHIFT = auto()
@@ -722,10 +722,12 @@
TRAP = auto()
INTERRUPT = auto()
AMO = auto()
+
+
# typedef bit[11:0] riscv_csr_t;
-class privileged_reg_t(Enum):
+class privileged_reg_t(IntEnum):
USTATUS = 0x000
UIE = 0x004
UTVEC = 0x005
@@ -956,7 +958,7 @@
VLENB = 0xC22
-class privileged_reg_fld_t(Enum):
+class privileged_reg_fld_t(IntEnum):
RSVD = 0
MXL = auto()
EXTENSION = auto()
@@ -965,30 +967,30 @@
PPN = auto()
-class privileged_level_t(Enum):
+class privileged_level_t(IntEnum):
M_LEVEL = 0b11
S_LEVEL = 0b01
U_LEVEL = 0b00
-class reg_field_access_t(Enum):
+class reg_field_access_t(IntEnum):
WPRI = 0
WLRL = auto()
WARL = auto()
-class riscv_pseudo_instr_name_t(Enum):
+class riscv_pseudo_instr_name_t(IntEnum):
LI = 0
LA = auto()
-class data_pattern_t(Enum):
+class data_pattern_t(IntEnum):
RAND_DATA = 0
ALL_ZERO = auto()
INCR_VAL = auto()
-class pte_permission_t(Enum):
+class pte_permission_t(IntEnum):
NEXT_LEVEL_PAGE = 0b000
READ_ONLY_PAGE = 0b001
READ_WRITE_PAGE = 0b011
@@ -997,7 +999,7 @@
R_W_EXECUTE_PAGE = 0b111
-class interrupt_cause_t(Enum):
+class interrupt_cause_t(IntEnum):
U_SOFTWARE_INTR = 0x0
S_SOFTWARE_INTR = 0x1
M_SOFTWARE_INTR = 0x3
@@ -1009,7 +1011,7 @@
M_EXTERNAL_INTR = 0xB
-class exception_cause_t(Enum):
+class exception_cause_t(IntEnum):
INSTRUCTION_ADDRESS_MISALIGNED = 0x0
INSTRUCTION_ACCESS_FAULT = 0x1
ILLEGAL_INSTRUCTION = 0x2
@@ -1026,7 +1028,7 @@
STORE_AMO_PAGE_FAULT = 0xF
-class misa_ext_t(Enum):
+class misa_ext_t(IntEnum):
MISA_EXT_A = 0
MISA_EXT_B = auto()
MISA_EXT_C = auto()
@@ -1055,13 +1057,77 @@
MISA_EXT_Z = auto()
-class hazard_e(Enum):
+class hazard_e(IntEnum):
NO_HAZARD = 0
RAW_HAZARD = auto()
WAR_HAZARD = auto()
WAW_HAZARD = auto()
+# TODO: ignore bins is not yet supported in pyvsc; extra enums will be removed
+# once support is added
+# Ignore WAR/WAW_HAZARD for branch instructions
+class branch_hazard_e(IntEnum):
+ NO_HAZARD = 0
+ RAW_HAZARD = auto()
+
+
+# RV32I_MISC covergroup instructions
+class rv32i_misc_instrs(IntEnum):
+ FENCE = 0
+ FENCE_I = auto()
+ EBREAK = auto()
+ ECALL = auto()
+ MRET = auto()
+
+# Ignore RAW_HAZARD for store lsu hazard
+class store_lsu_hazard_e(IntEnum):
+ NO_HAZARD = 0
+ WAR_HAZARD = auto()
+ WAW_HAZARD = auto()
+
+
+# RA/T1 for rs1/rd_link in jalr instruction
+class jalr_riscv_reg_t(IntEnum):
+ RA = 0
+ T1 = auto()
+
+
+# Ignore ZERO as src1 of load instructions
+class riscv_reg_ex_zero_t(IntEnum):
+ RA = 0
+ SP = auto()
+ GP = auto()
+ TP = auto()
+ T0 = auto()
+ T1 = auto()
+ T2 = auto()
+ S0 = auto()
+ S1 = auto()
+ A0 = auto()
+ A1 = auto()
+ A2 = auto()
+ A3 = auto()
+ A4 = auto()
+ A5 = auto()
+ A6 = auto()
+ A7 = auto()
+ S2 = auto()
+ S3 = auto()
+ S4 = auto()
+ S5 = auto()
+ S6 = auto()
+ S7 = auto()
+ S8 = auto()
+ S9 = auto()
+ S10 = auto()
+ S11 = auto()
+ T3 = auto()
+ T4 = auto()
+ T5 = auto()
+ T6 = auto()
+
+
class pmp_addr_mode_t(Enum):
OFF = 0b00
TOR = 0b01
@@ -1161,29 +1227,215 @@
INTERRUPT = auto()
AMO = auto()
+
def get_val(in_string, hexa=0):
if len(in_string) > 2:
if "0x" in in_string:
- out_val = hex(int(in_string, base=16))
+ out_val = int(in_string, base=16)
return out_val
- if hexa:
- out_val = hex(int(in_string, base=16))
- else:
- out_val = int(in_string)
- logging.info("riscv_instr_pkg: imm: {} -> {}".format(in_string, out_val))
- return out_val
+ if hexa:
+ out_val = int(in_string, base=16)
+ else:
+ out_val = int(in_string)
+ logging.info("imm: {} -> {}".format(in_string, out_val))
+ return out_val
-class hazard_e(Enum):
- NO_HAZARD = 0
- RAW_HAZARD = auto()
- WAR_HAZARD = auto()
- WAW_HAZARD = auto()
+
+def get_attr_list(instr_name):
+ switcher = {
+ # LOAD instructions
+ riscv_instr_name_t.LB: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.LOAD,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.LH: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.LOAD,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.LW: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.LOAD,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.LBU: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.LOAD,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.LHU: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.LOAD,
+ riscv_instr_group_t.RV32I],
+ # STORE instructions
+ riscv_instr_name_t.SB: [riscv_instr_format_t.S_FORMAT,
+ riscv_instr_category_t.STORE,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SH: [riscv_instr_format_t.S_FORMAT,
+ riscv_instr_category_t.STORE,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SW: [riscv_instr_format_t.S_FORMAT,
+ riscv_instr_category_t.STORE,
+ riscv_instr_group_t.RV32I],
+ # SHIFT intructions
+ riscv_instr_name_t.SLL: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.SHIFT,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SLLI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SHIFT,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SRL: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.SHIFT,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SRLI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SHIFT,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SRA: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.SHIFT,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SRAI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SHIFT,
+ riscv_instr_group_t.RV32I],
+ # ARITHMETIC intructions
+ riscv_instr_name_t.ADD: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.ARITHMETIC,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.ADDI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.ARITHMETIC,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.NOP: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.ARITHMETIC,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SUB: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.ARITHMETIC,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.LUI: [riscv_instr_format_t.U_FORMAT,
+ riscv_instr_category_t.ARITHMETIC,
+ riscv_instr_group_t.RV32I, imm_t.UIMM],
+ riscv_instr_name_t.AUIPC: [riscv_instr_format_t.U_FORMAT,
+ riscv_instr_category_t.ARITHMETIC,
+ riscv_instr_group_t.RV32I, imm_t.UIMM],
+ # LOGICAL instructions
+ riscv_instr_name_t.XOR: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.LOGICAL,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.XORI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.LOGICAL,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.OR: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.LOGICAL,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.ORI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.LOGICAL,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.AND: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.LOGICAL,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.ANDI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.LOGICAL,
+ riscv_instr_group_t.RV32I],
+ # COMPARE instructions
+ riscv_instr_name_t.SLT: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.COMPARE,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SLTI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.COMPARE,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SLTU: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.COMPARE,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SLTIU: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.COMPARE,
+ riscv_instr_group_t.RV32I],
+ # BRANCH instructions
+ riscv_instr_name_t.BEQ: [riscv_instr_format_t.B_FORMAT,
+ riscv_instr_category_t.BRANCH,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.BNE: [riscv_instr_format_t.B_FORMAT,
+ riscv_instr_category_t.BRANCH,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.BLT: [riscv_instr_format_t.B_FORMAT,
+ riscv_instr_category_t.BRANCH,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.BGE: [riscv_instr_format_t.B_FORMAT,
+ riscv_instr_category_t.BRANCH,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.BLTU: [riscv_instr_format_t.B_FORMAT,
+ riscv_instr_category_t.BRANCH,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.BGEU: [riscv_instr_format_t.B_FORMAT,
+ riscv_instr_category_t.BRANCH,
+ riscv_instr_group_t.RV32I],
+ # JUMP instructions
+ riscv_instr_name_t.JAL: [riscv_instr_format_t.J_FORMAT,
+ riscv_instr_category_t.JUMP,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.JALR: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.JUMP,
+ riscv_instr_group_t.RV32I],
+ # SYNCH instructions
+ riscv_instr_name_t.FENCE: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SYNCH,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.FENCE_I: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SYNCH,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SFENCE_VMA: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.SYNCH,
+ riscv_instr_group_t.RV32I],
+ # SYSTEM instructions
+ riscv_instr_name_t.ECALL: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SYSTEM,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.EBREAK: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SYSTEM,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.URET: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SYSTEM,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.SRET: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SYSTEM,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.MRET: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SYSTEM,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.DRET: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.SYSTEM,
+ riscv_instr_group_t.RV32I],
+ riscv_instr_name_t.WFI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.INTERRUPT,
+ riscv_instr_group_t.RV32I],
+ # CSR instructions
+ riscv_instr_name_t.CSRRW: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.CSR,
+ riscv_instr_group_t.RV32I, imm_t.UIMM],
+ riscv_instr_name_t.CSRRS: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.CSR,
+ riscv_instr_group_t.RV32I, imm_t.UIMM],
+ riscv_instr_name_t.CSRRC: [riscv_instr_format_t.R_FORMAT,
+ riscv_instr_category_t.CSR,
+ riscv_instr_group_t.RV32I, imm_t.UIMM],
+ riscv_instr_name_t.CSRRWI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.CSR,
+ riscv_instr_group_t.RV32I, imm_t.UIMM],
+ riscv_instr_name_t.CSRRSI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.CSR,
+ riscv_instr_group_t.RV32I, imm_t.UIMM],
+ riscv_instr_name_t.CSRRCI: [riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.CSR,
+ riscv_instr_group_t.RV32I, imm_t.UIMM],
+ }
+ # if instruction is not present in the dictionary,second argument well
+ # be assigned as default value of passed argument
+ attr_list = switcher.get(instr_name, "Cannot find instruction")
+ return attr_list
+
+
+def add_functions_as_methods(function):
+ def decorator(Class):
+ setattr(Class, function.__name__, function)
+ return Class
+
+ return decorator
+
class riscv_instr_pkg:
def __init__(self):
- self.MPRV_BIT_MASK = BitArray(uint= 0x1 << 0x17, length = rcs.XLEN)
- self.SUM_BIT_MASK = BitArray(uint = 0x1 << 0x18, length = rcs.XLEN)
- self.MPP_BIT_MASK = BitArray(uint = 0x3 << 0x11, length = rcs.XLEN)
+ self.MPRV_BIT_MASK = BitArray(uint=0x1 << 0x17, length=rcs.XLEN)
+ self.SUM_BIT_MASK = BitArray(uint=0x1 << 0x18, length=rcs.XLEN)
+ self.MPP_BIT_MASK = BitArray(uint=0x3 << 0x11, length=rcs.XLEN)
self.MAX_USED_VADDR_BITS = 30
self.IMM25_WIDTH = 25
self.IMM12_WIDTH = 12
@@ -1196,8 +1448,8 @@
self.MAX_CALL_PER_FUNC = 5
self.indent = self.LABEL_STR_LEN * " "
- def hart_prefix(self, hart = 0):
- if(rcs.NUM_HARTS <= 1):
+ def hart_prefix(self, hart=0):
+ if (rcs.NUM_HARTS <= 1):
return ""
else:
return f"h{hart}_"
@@ -1205,17 +1457,18 @@
def get_label(self, label, hart=0):
return (self.hart_prefix(hart) + label)
- def format_string(self, string, length = 10):
+ def format_string(self, string, length=10):
formatted_str = length * " "
if (int(length) < len(string)):
return string
formatted_str = string + formatted_str[0: (int(length) - len(string))]
return formatted_str
- def format_data(self, data, byte_per_group = 4):
+ def format_data(self, data, byte_per_group=4):
string = "0x"
for i in range(len(data)):
- if ((i % byte_per_group == 0) and (i != len(data) - 1) and (i != 0)):
+ if ((i % byte_per_group == 0) and (i != len(data) - 1) and (
+ i != 0)):
string = string + ", 0x"
string = string + f"{hex(data[i])}"
return string
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_sequence.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_sequence.py
index d0ca1c4..fef6795 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_sequence.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_sequence.py
@@ -1,89 +1,188 @@
-"""
-Copyright 2020 Google LLC
-Copyright 2020 PerfectVIPs Inc.
-
-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.
-
-"""
-import logging
-from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
-from pygen_src.riscv_instr_pkg import pkg_ins
-
-
-class riscv_instr_sequence:
-
- def __init__(self):
- self.instr_cnt = 0
- self.instr_stream = riscv_rand_instr_stream()
- self.is_main_program = 0
- self.is_debug_program = 0
- self.label_name = ""
- self.instr_string_list = [] # Save the instruction list
- self.program_stack_len = 0 # Stack space allocated for this program
- self.directed_instr = [] # List of all directed instruction stream
- self.illegal_instr_pct = 0 # Percentage of illegal instructions
- self.hint_instr_pct = 0 # Percentage of hint instructions
-
- def gen_instr(self, is_main_program, no_branch = 1):
- self.is_main_program = is_main_program
- self.instr_stream.initialize_instr_list(self.instr_cnt)
- logging.info("Start generating %d instruction" % len(self.instr_stream.instr_list))
- self.instr_stream.gen_instr(no_branch = no_branch, no_load_store = 1,
- is_debug_program = self.is_debug_program)
-
- if not is_main_program:
- self.gen_stack_enter_instr()
- self.gen_stack_exit_instr()
-
- # TODO
- def gen_stack_enter_instr(self):
- pass
-
- # TODO
- def gen_stack_exit_instr(self):
- pass
-
- # TODO
- def post_process_instr(self):
- pass
-
- # TODO
- def insert_jump_instr(self):
- pass
-
- def generate_instr_stream(self, no_label = 0):
- prefix = ''
- string = ''
- self.instr_string_list.clear()
-
- for i in range(len(self.instr_stream.instr_list)):
- if i == 0:
- if no_label:
- prefix = pkg_ins.format_string(string = ' ', length = pkg_ins.LABEL_STR_LEN)
- else:
- prefix = pkg_ins.format_string(string = '{}:'.format(
- self.label_name), length = pkg_ins.LABEL_STR_LEN)
-
- self.instr_stream.instr_list[i].has_label = 1
- else:
- if(self.instr_stream.instr_list[i].has_label):
- prefix = pkg_ins.format_string(string = '{}'.format(
- self.instr_stream.instr_list[i].label), length = pkg_ins.LABEL_STR_LEN)
- else:
- prefix = pkg_ins.format_string(string = " ", length = pkg_ins.LABEL_STR_LEN)
- string = prefix + self.instr_stream.instr_list[i].convert2asm()
- self.instr_string_list.append(string)
-
- # TODO
- def generate_return_routine(self):
- pass
-
- # TODO
- def insert_illegal_hint_instr(self):
- pass
+"""
+Copyright 2020 Google LLC
+Copyright 2020 PerfectVIPs Inc.
+
+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.
+
+"""
+import logging
+import random
+from collections import defaultdict
+from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
+from pygen_src.riscv_instr_gen_config import cfg
+from pygen_src.riscv_instr_pkg import pkg_ins, riscv_instr_category_t
+
+
+class riscv_instr_sequence:
+
+ def __init__(self):
+ self.instr_cnt = 0
+ self.instr_stream = riscv_rand_instr_stream()
+ self.is_main_program = 0
+ self.is_debug_program = 0
+ self.label_name = ""
+ self.instr_string_list = [] # Save the instruction list
+ self.program_stack_len = 0 # Stack space allocated for this program
+ self.directed_instr = [] # List of all directed instruction stream
+ self.illegal_instr_pct = 0 # Percentage of illegal instructions
+ self.hint_instr_pct = 0 # Percentage of hint instructions
+ self.branch_idx = [None] * 30
+
+ def gen_instr(self, is_main_program, no_branch = 1):
+ self.is_main_program = is_main_program
+ self.instr_stream.initialize_instr_list(self.instr_cnt)
+ logging.info("Start generating %d instruction" % len(self.instr_stream.instr_list))
+ self.instr_stream.gen_instr(no_branch = no_branch, no_load_store = 1,
+ is_debug_program = self.is_debug_program)
+
+ if not is_main_program:
+ self.gen_stack_enter_instr()
+ self.gen_stack_exit_instr()
+
+ # TODO
+ def gen_stack_enter_instr(self):
+ pass
+
+ # TODO
+ def gen_stack_exit_instr(self):
+ pass
+
+ '''
+ ----------------------------------------------------------------------------------------------
+ Instruction post-process
+
+ Post-process is required for branch instructions:
+
+ Need to assign a valid branch target. This is done by picking a random instruction label in
+ this sequence and assigning to the branch instruction. All the non-atomic instructions
+ will have a unique numeric label as the local branch target identifier.
+ The atomic instruction streams don't have labels except for the first instruction. This is
+ to avoid branching into an atomic instruction stream which breaks its atomicy. The
+ definition of an atomic instruction stream here is a sequence of instructions which must be
+ executed in-order.
+ In this sequence, only forward branch is handled. The backward branch target is implemented
+ in a dedicated loop instruction sequence. Randomly choosing a backward branch target could
+ lead to dead loops in the absence of proper loop exiting conditions.
+ ----------------------------------------------------------------------------------------------
+ '''
+
+ def post_process_instr(self):
+ label_idx = 0
+ branch_cnt = 0
+ j = 0
+ branch_target = defaultdict(lambda: None)
+
+ for instr in self.directed_instr:
+ self.instr_stream.insert_instr_stream(instr.instr_list)
+ '''
+ Assign an index for all instructions, these indexes wont change
+ even a new instruction is injected in the post process.
+ '''
+ for i in range(len(self.instr_stream.instr_list)):
+ self.instr_stream.instr_list[i].idx = label_idx
+ if(self.instr_stream.instr_list[i].has_label and
+ not(self.instr_stream.instr_list[i].atomic)):
+ if((self.illegal_instr_pct > 0) and
+ (self.instr_stream.instr_list[i].insert_illegal_instr == 0)):
+ '''
+ The illegal instruction generator always increase PC by 4 when resume execution,
+ need to make sure PC + 4 is at the correct instruction boundary.
+ '''
+ if(self.instr_stream.instr_list[i].is_compressed):
+ if(i < (len(self.instr_stream.instr_list) - 1)):
+ if(self.instr_stream.instr_list[i + 1].is_compressed):
+ self.instr_stream.instr_list[i].is_illegal_instr = random.randrange(
+ 0, min(100, self.illegal_instr_pct))
+ else:
+ self.instr_stream.instr_list[i].is_illegal_instr = random.randrange(
+ 0, min(100, self.illegal_instr_pct))
+ if(self.hint_instr_pct > 0 and
+ (self.instr_stream.instr_list[i].is_illegal_instr == 0)):
+ if(self.instr_stream.instr_list[i].is_compressed):
+ self.instr_stream.instr_list[i].is_hint_instr = random.randrange(
+ 0, min(100, self.hint_instr_pct))
+
+ self.instr_stream.instr_list[i].label = "{}".format(label_idx)
+ self.instr_stream.instr_list[i].is_local_numeric_label = 1
+ label_idx += 1
+
+ # Generate branch target
+ for i in range(len(self.branch_idx)):
+ self.branch_idx[i] = random.randint(1, cfg.max_branch_step)
+
+ while(j < len(self.instr_stream.instr_list)):
+ if((self.instr_stream.instr_list[j].category == riscv_instr_category_t.BRANCH) and
+ (not self.instr_stream.instr_list[j].branch_assigned) and
+ (not self.instr_stream.instr_list[j].is_illegal_instr)):
+ '''
+ Post process the branch instructions to give a valid local label
+ Here we only allow forward branch to avoid unexpected infinite loop
+ The loop structure will be inserted with a separate routine using
+ reserved loop registers
+ '''
+ branch_target_label = 0
+ branch_byte_offset = 0
+ branch_target_label = self.instr_stream.instr_list[j].idx + \
+ self.branch_idx[branch_cnt]
+ if(branch_target_label >= label_idx):
+ branch_target_label = label_idx - 1
+ branch_cnt += 1
+ if(branch_cnt == len(self.branch_idx)):
+ branch_cnt = 0
+ random.shuffle(self.branch_idx)
+ logging.info("Processing branch instruction[%0d]:%0s # %0d -> %0d", j,
+ self.instr_stream.instr_list[j].convert2asm(),
+ self.instr_stream.instr_list[j].idx, branch_target_label)
+ self.instr_stream.instr_list[j].imm_str = "{}f".format(branch_target_label)
+ self.instr_stream.instr_list[j].branch_assigned = 1
+ branch_target[branch_target_label] = 1
+
+ # Remove the local label which is not used as branch target
+ if(self.instr_stream.instr_list[j].has_label and
+ self.instr_stream.instr_list[j].is_local_numeric_label):
+ idx = int(self.instr_stream.instr_list[j].label)
+ if(not branch_target[idx]):
+ self.instr_stream.instr_list[j].has_label = 0
+ j += 1
+ logging.info("Finished post-processing instructions")
+
+ def insert_jump_instr(self):
+ pass # TODO
+
+ def generate_instr_stream(self, no_label = 0):
+ prefix = ''
+ string = ''
+ self.instr_string_list.clear()
+
+ for i in range(len(self.instr_stream.instr_list)):
+ if i == 0:
+ if no_label:
+ prefix = pkg_ins.format_string(string = ' ', length = pkg_ins.LABEL_STR_LEN)
+ else:
+ prefix = pkg_ins.format_string(string = '{}:'.format(
+ self.label_name), length = pkg_ins.LABEL_STR_LEN)
+
+ self.instr_stream.instr_list[i].has_label = 1
+ else:
+ if(self.instr_stream.instr_list[i].has_label):
+ prefix = pkg_ins.format_string(string = '{}:'.format(
+ self.instr_stream.instr_list[i].label), length = pkg_ins.LABEL_STR_LEN)
+ else:
+ prefix = pkg_ins.format_string(string = " ", length = pkg_ins.LABEL_STR_LEN)
+ string = prefix + self.instr_stream.instr_list[i].convert2asm()
+ self.instr_string_list.append(string)
+ prefix = pkg_ins.format_string(str(i), pkg_ins.LABEL_STR_LEN)
+
+ # TODO
+ def generate_return_routine(self):
+ pass
+
+ # TODO
+ def insert_illegal_hint_instr(self):
+ pass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_stream.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_stream.py
index ad4852a..151066a 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_stream.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_stream.py
@@ -13,12 +13,14 @@
import random
import logging
import sys
+import vsc
from pygen_src.riscv_instr_pkg import riscv_instr_name_t,\
riscv_instr_category_t, riscv_reg_t
from pygen_src.isa.riscv_instr import riscv_instr, riscv_instr_ins
from pygen_src.riscv_instr_gen_config import cfg
+@vsc.randobj
class riscv_instr_stream:
'''
Base class for RISC-V instruction stream
@@ -30,9 +32,9 @@
def __init__(self):
self.instr_list = []
self.instr_cnt = 0
- self.label = " "
+ self.label = ""
# User can specify a small group of available registers to generate various hazard condition
- self.avail_regs = []
+ self.avail_regs = vsc.randsz_list_t(vsc.enum_t(riscv_reg_t))
# Some additional reserved registers that should not be used as rd register
# by this instruction stream
self.reserved_rd = []
@@ -112,7 +114,7 @@
if idx == 0:
self.instr_list = new_instr + self.instr_list[idx:current_instr_cnt - 1]
else:
- self.instr_list = self.instr_list[0:idx - 1] + new_instr + \
+ self.instr_list = self.instr_list[0:idx] + new_instr + \
self.instr_list[idx:current_instr_cnt - 1]
def mix_instr_stream(self, new_instr, contained = 0):
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_pseudo_instr.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_pseudo_instr.py
new file mode 100644
index 0000000..c573634
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_pseudo_instr.py
@@ -0,0 +1,48 @@
+"""
+Copyright 2020 Google LLC
+Copyright 2020 PerfectVIPs Inc.
+
+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.
+
+"""
+
+import vsc
+from pygen_src.isa.riscv_instr import riscv_instr
+from pygen_src.riscv_instr_pkg import (riscv_pseudo_instr_name_t, riscv_instr_format_t,
+ riscv_instr_category_t, riscv_instr_group_t, pkg_ins)
+# from pygen_src.riscv_defines import add_pseudo_instr
+
+
+# Psuedo instructions are used to simplify assembly program writing
+@vsc.randobj
+class riscv_pseudo_instr(riscv_instr):
+ def __init__(self):
+ super().__init__()
+ self.process_load_store = 0
+ self.format = riscv_instr_format_t.I_FORMAT
+ self.pseudo_instr_name = vsc.rand_enum_t(riscv_pseudo_instr_name_t)
+
+ '''
+ TODO
+ add_pseudo_instr(self, riscv_pseudo_instr_name_t.LI, riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32I)
+ add_pseudo_instr(self, riscv_pseudo_instr_name_t.LA, riscv_instr_format_t.I_FORMAT,
+ riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32I)
+ '''
+
+ def convert2asm(self, prefix = ""):
+ asm_str = pkg_ins.format_string(self.get_instr_name(), pkg_ins.MAX_INSTR_STR_LEN)
+ asm_str = "{}{}, {}".format(asm_str, self.rd.name, self.get_imm())
+
+ if(self.comment != ""):
+ asm_str = "{} #{}".format(asm_str, self.comment)
+ return asm_str.lower()
+
+ def get_instr_name(self):
+ return self.pseudo_instr_name.name
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_utils.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_utils.py
new file mode 100644
index 0000000..e1dc710
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/riscv_utils.py
@@ -0,0 +1,30 @@
+"""
+Copyright 2020 Google LLC
+Copyright 2020 PerfectVIPs Inc.
+
+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.
+
+"""
+import sys
+import logging
+from pygen_src.riscv_directed_instr_lib import (riscv_directed_instr_stream,
+ riscv_int_numeric_corner_stream)
+
+
+def factory(obj_of):
+ objs = {
+ "riscv_directed_instr_stream": riscv_directed_instr_stream,
+ "riscv_int_numeric_corner_stream": riscv_int_numeric_corner_stream
+ }
+
+ try:
+ return objs[obj_of]()
+ except KeyError:
+ logging.critical("Cannot Create object of %s", obj_of)
+ sys.exit(1)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_base_test.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_base_test.py
index 7fa6b1e..8058e8d 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_base_test.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_base_test.py
@@ -22,10 +22,12 @@
class riscv_instr_base_test:
def __init__(self):
pass
- asm = riscv_asm_program_gen()
+
for _ in range(cfg.num_of_tests):
cfg.randomize()
+ asm = riscv_asm_program_gen()
riscv_instr_ins.create_instr_list(cfg)
- test_name = "riscv_asm_test_{}.S".format(_)
+ test_name = "riscv_arithmetic_basic_test_{}.S".format(_)
+ asm.get_directed_instr_stream()
asm.gen_program()
asm.gen_test_file(test_name)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_cov_test.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_cov_test.py
index 8cc37c5..f54b9c2 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_cov_test.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_cov_test.py
@@ -1,270 +1,36 @@
-# Lint as: python3
-"""Tests for riscv_instr_cov."""
+"""Copyright 2020 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.
+"""
+
import sys
-import os
-import logging
-import argparse
-import vsc # PyVSC library
-import csv # Python library to read/write from/to CSV files
-from bitstring import BitArray
-from pygen.pygen_src.isa.riscv_instr_cov import *
+import vsc
+import csv
+from tabulate import *
+from pygen.pygen_src.isa.riscv_cov_instr import riscv_cov_instr
+from pygen.pygen_src.riscv_instr_cover_group import *
from pygen.pygen_src.riscv_instr_pkg import *
-from pygen.pygen_src.target.rv32i import riscv_core_setting as rcs
+
+logging.basicConfig(filename='logging_two_files_new.log', filemode='w',
+ format="%(filename)s %(lineno)s %(levelname)s %(message)s",
+ level=logging.ERROR)
-
-logging.basicConfig(filename='logging.log',level=logging.DEBUG)
-
-class riscv_instr():
- """ Class for a riscv instruction; data parsed from the CSV file will fill
- different fields of an instruction """
- # class attr. to keep track of reg_name:reg_value throughout the program
- gpr_state = {}
- def __init__(self, instr_name):
- self.pc = 0 # Program counter (PC) of the instruction
- self.instr = instr_name
- self.gpr = None # destination operand of the instruction
- self.csr = None
- self.binary = 0 # Instruction binary
- self.mode = None # Instruction mode
- self.trace = "None" # String representation of the instruction
- self.operands = "None" # Instruction operands (srcss/dests)
- self.pad = None # Not used
-
- self.rs1_value = None
- self.rs2_value = None
- self.rs3_value = None
- self.rd_value = None
- self.fs1_value = None
- self.fs2_value = None
- self.fs3_value = None
- self.fd_value = None
-
- self.mem_addr = None
- self.unaligned_pc = 0
- self.unaligned_mem_access = 0
- self.compressed = 0
- self.branch_hit = 0
- self.div_result = None
- self.rs1_sign = None
- self.rs2_sign = None
- self.rs3_sign = None
- self.fs1_sign = None
- self.fs2_sign = None
- self.fs3_sign = None
- self.imm_sign = None
- self.rd_sign = None
- self.gpr_hazard = None
- self.lsu_hazard = None
- self.rs1_special_value = None
- self.rs2_special_value = None
- self.rs3_special_value = None
- self.rd_special_value = None
- self.imm_special_value = None
- self.compare_result = None
- self.logical_similarity = None
-
- # TODO: add & map...
- #self.imm
- #self.format
- #self.category
-
- def pre_sample(self):
- unaligned_pc = self.pc[-2:] != "00"
- self.rs1_sign = self.get_operand_sign(self.rs1_value)
- self.rs2_sign = self.get_operand_sign(self.rs2_value)
- self.rs3_sign = self.get_operand_sign(self.rs3_value)
- self.rd_sign = self.get_operand_sign(self.rd_value)
- self.fs1_sign = self.get_operand_sign(self.fs1_value)
- self.fs2_sign = self.get_operand_sign(self.fs2_value)
- self.fs3_sign = self.get_operand_sign(self.fs3_value)
- self.fd_sign = self.get_operand_sign(self.fd_value)
- self.imm_sign = self.get_imm_sign(self.imm)
- self.rs1_special_value = self.get_operand_special_value(self.rs1_value)
- self.rd_special_value = self.get_operand_special_value(self.rd_value)
- self.rs2_special_value = self.get_operand_special_value(self.rs2_value)
- self.rs3_special_value = self.get_operand_special_value(self.rs3_value)
- if (self.format != riscv_instr_format_t.R_FORMAT and
- self.format != riscv_instr_format_t.CR_FORMAT):
- self.imm_special_value = self.get_imm_special_val(self.imm)
- if self.category in [riscv_instr_category_t.COMPARE,
- riscv_instr_category_t.BRANCH]:
- self.compare_result = self.get_compare_result()
- if self.category in [riscv_instr_category_t.LOAD,
- riscv_instr_category_t.STORE]:
- self.mem_addr = self.rs1_value + self.imm
- self.unaligned_mem_access = self.is_unaligned_mem_access()
- if self.unaligned_mem_access:
- logging.info("Unaligned: {}, mem_addr: {}".format(
- self.instr, self.mem_addr))
- if self.category == riscv_instr_category_t.LOGICAL:
- self.logical_similarity = self.get_logical_similarity()
- if self.category == riscv_instr_category_t.BRANCH:
- self.branch_hit = self.is_branch_hit()
- #TODO: string > enumeration
- if self.instr in ["DIV", "DIVU", "REM", "REMU", "DIVW", "DIVUW",
- "REMW", "REMUW"]:
- self.div_result = self.get_div_result()
-
- def get_operand_sign(self, operand):
- #TODO: change operand to vsc.bit_t
- out = BitArray(int=operand.val, length=rcs.XLEN)
- if out[0]:
- return operand_sign_e["NEGATIVE"]
- else:
- return operand_sign_e["POSITIVE"]
-
- def is_unaligned_mem_access(self):
- #TODO: string > enumeration
- if (self.instr in ["LWU", "LD", "SD", "C_LD", "C_SD"] and
- self.mem_addr % 8 != 0):
- return True
- elif (self.instr in ["LW", "SW", "C_LW", "C_SW"] and
- self.mem_addr % 4 != 0):
- return True
- elif (self.instr in ["LH", "LHU", "SH"] and
- self.mem_addr % 2 != 0):
- return True
- return False
-
- def get_imm_sign(self, imm):
- #TODO: change imm to vsc.int_t(32)
- out = BitArray(int=imm.val, length=rcs.XLEN)
- if out[0]:
- return operand_sign_e["NEGATIVE"]
- else:
- return operand_sign_e["POSITIVE"]
-
- def get_div_result(self):
- #TODO: change rs2_value to vsc.int_t(32)
- if self.rs2_value.val == 0:
- return div_result_e["DIV_BY_ZERO"]
- elif self.rs2_value.val == 1 and self.rs1_value.val == (1 << (rcs.XLEN-1)):
- return div_result_e["DIV_OVERFLOW"]
- else:
- return div_result_e["DIV_NORMAL"]
-
- def get_operand_special_value(self, operand):
- if operand.val == 0:
- return special_val_e["ZERO_VAL"]
- elif operand.val == 1 << (rcs.XLEN-1):
- return special_val_e["MIN_VAL"]
- elif operand.val == 1 >> 1:
- return special_val_e["MAX_VAL"]
- else:
- return special_val_e["NORMAL_VAL"]
-
- def get_imm_special_val(self, imm):
- if imm.val == 0:
- return special_val_e["ZERO_VAL"]
- elif self.format == riscv_instr_format_t.U_FORMAT:
- # unsigned immediate value
- # TODO: self.imm_len
- max = vsc.int_t(32, (1 << self.imm_len)-1)
- if imm.val == 0:
- return special_val_e["MIN_VAL"]
- if imm.val == max.val:
- return special_val_e["MAX_VAL"]
- else:
- # signed immediate value
- max = vsc.int_t(32, (2 ** (self.imm_len - 1)) - 1)
- min = vsc.int_t(32, -2 ** (self.imm_len - 1))
- if min.val == imm.val:
- return special_val_e["MIN_VAL"]
- if max.val == imm.val:
- return special_val_e["MAX_VAL"]
- return special_val_e["NORMAL_VAL"]
-
- def get_compare_result(self):
- val1 = vsc.int_t(rcs.XLEN)
- val2 = vsc.int_t(rcs.XLEN)
- val1.val = self.rs1_value.val
- val2.val = self.imm.val if (
- self.format == riscv_instr_format_t.I_FORMAT) \
- else self.rs2_value.val
- if val1.val == val2.val:
- return compare_result_e["EQUAL"]
- elif val1.val < val2.val:
- return compare_result_e["SMALLER"]
- else:
- return compare_result_e["LARGER"]
-
- def is_branch_hit(self):
- # TODO: string/enumeration
- if self.instr == "BEQ":
- return self.rs1_value.val == self.rs2_value.val
- elif self.instr == "C_BEQZ":
- return self.rs1_value.val == 0
- elif self.instr == "BNE":
- return self.rs1_value.val != self.rs2_value.val
- elif self.instr == "C_BNEZ":
- return self.rs1_value.val != 0
- elif self.instr == "BLT" or self.instr == "BLTU":
- return self.rs1_value.val < self.rs2_value.val
- elif self.instr == "BGE" or self.instr == "BGEU":
- return self.rs1_value.val >= self.rs2_value.val
- else:
- logging.error("Unexpected instruction {}".format(self.instr))
-
- def get_logical_similarity(self):
- val1 = vsc.int_t(rcs.XLEN, self.rs1_value.val)
- val2 = vsc.int_t(rcs.XLEN)
- val2.val = (self.imm.val if self.format == riscv_instr_format_t.I_FORMAT
- else self.rs2_value.val)
- temp = bin(val1.val ^ val2.val)
- bit_difference = len([[ones for ones in temp[2:] if ones=='1']])
- if val1.val == val2.val:
- return logical_similarity_e["IDENTICAL"]
- elif bit_difference == 32:
- return logical_similarity_e["OPPOSITE"]
- elif bit_difference < 5:
- return logical_similarity_e["SIMILAR"]
- else:
- return logical_similarity_e["DIFFERENT"]
-
- def check_hazard_condition(self, pre_instr):
- # TODO: has_rd(), has_rs1, has_rs2, rd, category, convert2asm (from IG)
- if pre_instr.has_rd():
- if ((self.has_rs1 and self.rs1 == pre_instr.rd) or
- (self.has_rs2 and self.rs1 == pre_instr.rd)):
- self.gpr_hazard = hazard_e["RAW_HAZARD"]
- elif self.has_rd and self.rd == pre_instr.rd:
- self.gpr_hazard = hazard_e["WAW_HAZARD"]
- elif (self.has_rd and
- ((pre_instr.has_rs1 and (pre_instr.rs1 == self.rd)) or
- (pre_instr.has_rs2 and (pre_instr.rs2 == self.rd)))):
- self.gpr_hazard = hazard_e["WAR_HAZARD"]
- else:
- self.gpr_hazard = hazard_e["NO_HAZARD"]
- if self.category == riscv_instr_category_t.LOAD:
- # TODO: change mem_addr to vsc type
- if (pre_instr.category == riscv_instr_category_t.STORE and
- pre_instr.mem_addr == self.mem_addr):
- self.lsu_hazard = hazard_e["RAW_HAZARD"]
- else:
- self.lsu_hazard = hazard_e["NO_HAZARD"]
- if self.category == riscv_instr_category_t.STORE:
- if (pre_instr.category == riscv_instr_category_t.STORE and
- pre_instr.mem_addr == self.mem_addr):
- self.lsu_hazard = hazard_e["WAW_HAZARD"]
- elif (pre_instr.category == riscv_instr_category_t.LOAD and
- pre_instr.mem_addr == self.mem_addr):
- self.lsu_hazard = hazard_e["WAR_HAZARD"]
- else:
- self.lsu_hazard = hazard_e["NO_HAZARD"]
- logging.info("Pre: {}, Cur: {}, Hazard: {}/{}".format(
- pre_instr.convert2asm(), self.convert2asm(),
- self.gpr_hazard.name, self.lsu_hazard.name))
-
- def update_src_regs(self, operands):
- pass
-
- def update_dst_regs(self, reg_name, val_str):
- pass
-
-class riscv_instr_cov_test():
+class riscv_instr_cov_test:
""" Main class for applying the functional coverage test """
+
def __init__(self, argv):
+ self.instr_cg = riscv_instr_cover_group()
self.trace = {}
self.csv_trace = argv
self.entry_cnt, self.total_entry_cnt, self.skipped_cnt, \
@@ -281,7 +47,7 @@
with open("{}".format(csv_file)) as trace_file:
self.entry_cnt = 0
header = []
- entry = []
+ self.instr_cg.reset()
csv_reader = csv.reader(trace_file, delimiter=',')
line_count = 0
# Get the header line
@@ -297,27 +63,30 @@
self.skipped_cnt += 1
else:
self.trace["csv_entry"] = row
+ logging.info("-----------------------------"
+ "-----------------------------")
for idx in range(len(header)):
if "illegal" in entry[idx]:
expect_illegal_instr = True
self.trace[header[idx]] = entry[idx]
if header[idx] != "pad":
logging.info("{} = {}".format(header[idx],
- entry[idx]))
+ entry[idx]))
self.post_process_trace()
if self.trace["instr"] in ["li", "ret", "la"]:
- pass
- if "amo" in self.trace["instr"] or \
- "lr" in self.trace["instr"] or \
- "sc" in self.trace["instr"]:
+ continue
+ if ("amo" in self.trace["instr"] or
+ "lr" in self.trace["instr"] or
+ "sc" in self.trace["instr"]):
# TODO: Enable functional coverage for AMO test
- pass
+ continue
if not self.sample():
if not expect_illegal_instr:
logging.error("Found unexpected illegal "
"instr: {} "
"[{}]".format(self.trace[
- "instr"],entry))
+ "instr"],
+ entry))
self.unexpected_illegal_instr_cnt += 1
self.entry_cnt += 1
line_count += 1
@@ -326,53 +95,84 @@
self.total_entry_cnt += self.entry_cnt
logging.info("Finished processing {} trace CSV, {} "
"instructions".format(len(self.csv_trace),
- self.total_entry_cnt))
+ self.total_entry_cnt))
if self.skipped_cnt > 0 or self.unexpected_illegal_instr_cnt > 0:
logging.error("{} instruction skipped, {} illegal "
- "instructions".format(self.skipped_cnt),
- self.unexpected_illegal_instr_cnt)
+ "instructions".format(self.skipped_cnt,
+ self.unexpected_illegal_instr_cnt))
+ self.get_coverage_report()
+
+ @staticmethod
+ def get_coverage_report():
+ model = vsc.get_coverage_report_model()
+ file = open('CoverageReport.txt', 'w')
+ file.write("Groups Coverage Summary\n")
+ file.write("Total groups in report: {}\n".format(
+ len(model.covergroups)))
+ headers = ["SCORE", "WEIGHT", "NAME"]
+ table = []
+ for cg in model.covergroups:
+ table.append([cg.coverage, cg.weight, cg.name])
+ file.write(tabulate(table, headers, tablefmt="grid",
+ numalign="center", stralign="center"))
+ file.close()
+ # Write in xml format to be read by pyucis-viewer (visualization)
+ vsc.write_coverage_db("cov_db.xml")
def post_process_trace(self):
pass
def sample(self):
- instr_name, binary = "", ""
- binary = get_val(self.trace["binary"], hexa=1)
- if binary[-2:] != "11": #TODO: and RV32C in supported_isa
- #TODO: sample compressed instruction
+ binary = vsc.int_t(rcs.XLEN)
+ binary.set_val(get_val(self.trace["binary"], hexa=1))
+ # TODO: Currently handled using string formatting as part select
+ # isn't yet supported for global vsc variables
+ # width is rcs.XLEN+2 because of 0b in the beginning of binary_bin
+ binary_bin = format(binary.get_val(), '#0{}b'.format(rcs.XLEN + 2))
+ if binary_bin[-2:] != "11": # TODO: and RV32C in supported_isa
+ # TODO: sample compressed instruction
pass
- if binary[-2:] == "11":
- #TODO: sampling
+ if binary_bin[-2:] == "11":
+ # TODO: sampling
pass
- #TODO: buch of if statements to check if the instruction name is valid
- # and is a member of registered ones
- instr_name = self.process_instr_name(self.trace["instr"])
- instruction = riscv_instr(instr_name)
- #TODO: check the instruction group...
- self.assign_trace_info_to_instr(instruction)
- #TODO: instruction.pre_sample() and sample(instruction)
- return True
+ processed_instr_name = self.process_instr_name(self.trace["instr"])
+ if processed_instr_name in riscv_instr_name_t.__members__:
+ instr_name = riscv_instr_name_t[processed_instr_name]
+ instruction = riscv_cov_instr()
+ instruction.instr = instr_name
+ # cov_instr is created, time to manually assign attributes
+ # TODO: This will get fixed later when we get an inst from template
+ instruction.assign_attributes()
+ if instruction.group.name in ["RV32I", "RV32M", "RV32C", "RV64I",
+ "RV64M", "RV64C", "RV32F", "RV64F",
+ "RV32D", "RV64D", "RV32B", "RV64B"]:
+ self.assign_trace_info_to_instr(instruction)
+ instruction.pre_sample()
+ self.instr_cg.sample(instruction)
+ return True
+ logging.info("Cannot find opcode: {}".format(processed_instr_name))
+ return False
def assign_trace_info_to_instr(self, instruction):
- operands, gpr_update, pair = [], [], []
- instruction.pc = get_val(self.trace["pc"], hexa=1)
- instruction.binary = get_val(self.trace["binary"], hexa=1)
- instruction.gpr = self.trace["gpr"]
- instruction.csr = self.trace["csr"]
- instruction.mode = self.trace["mode"]
+ instruction.pc.set_val(get_val(self.trace["pc"], hexa=1))
+ instruction.binary.set_val(get_val(self.trace["binary"], hexa=1))
instruction.trace = self.trace["instr_str"]
- instruction.operands = self.trace["operand"]
+ if instruction.instr.name in ["NOP", "WFI", "FENCE", "FENCE_I",
+ "EBREAK", "C_EBREAK", "SFENCE_VMA",
+ "ECALL", "C_NOP", "MRET", "SRET",
+ "URET"]:
+ return
operands = self.trace["operand"].split(",")
instruction.update_src_regs(operands)
+
gpr_update = self.trace["gpr"].split(";")
- if len(gpr_update) == 1 and gpr_update[0] == "":
+ if len(gpr_update) == 1 and gpr_update[0] == "":
gpr_update = []
for dest in gpr_update:
pair = dest.split(":")
if len(pair) != 2:
logging.error("Illegal gpr update format: {}".format(dest))
instruction.update_dst_regs(pair[0], pair[1])
- instruction.pad = self.trace["pad"]
def process_instr_name(self, instruction):
instruction = instruction.upper()
@@ -380,18 +180,19 @@
instruction = self.update_instr_name(instruction)
return instruction
- def update_instr_name(self, instruction):
+ @staticmethod
+ def update_instr_name(instruction):
switcher = {
# Rename to new name as ovpsim still uses old name
"FMV_S_X": "FMV_W_X",
"FMV_X_S": "FMV_X_W",
# Convert pseudoinstructions
- "FMV_S": "FSGNJ_S",
- "FABS_S": "FSGNJX_S",
- "FNEG_S": "FSGNJN_S",
- "FMV_D": "FSGNJ_D",
- "FABS_D": "FSGNJX_D",
- "FNEG_D": "FSGNJN_D",
+ "FMV_S" : "FSGNJ_S",
+ "FABS_S" : "FSGNJX_S",
+ "FNEG_S" : "FSGNJN_S",
+ "FMV_D" : "FSGNJ_D",
+ "FABS_D" : "FSGNJX_D",
+ "FNEG_D" : "FSGNJN_D",
}
# if instruction is not present in the dictionary,second argument well
# be assigned as default value of passed argument
@@ -399,9 +200,10 @@
return instruction
-def main(argv):
+def main(argv):
cov_test = riscv_instr_cov_test(argv)
cov_test.run_phase()
+
if __name__ == "__main__":
main(sys.argv)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/requirements.txt b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/requirements.txt
index 3483387..26b3721 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/requirements.txt
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/requirements.txt
@@ -8,3 +8,4 @@
rst2pdf
flake8
pyvsc
+tabulate
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 84c4fce..c524e2b 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
@@ -109,9 +109,9 @@
3) A randomly generated number
"""
if iteration == 0:
- return bitarray(hex=f"0x{'a5'*int(xlen/8)}")
+ return bitarray(hex="0x{}".format('a5'*int(xlen/8)))
elif iteration == 1:
- return bitarray(hex=f"0x{'5a'*int(xlen/8)}")
+ return bitarray(hex="0x{}".format('5a'*int(xlen/8)))
elif iteration == 2:
val = bitarray(uint=0, length=xlen)
# Must randomize all 32 bits, due to randomization library limitations
@@ -193,7 +193,7 @@
elif csr_op == 'csrrci':
zero.append(rs1_val[-5:])
csr_write((~zero) & prediction, csr_val, csr_write_mask)
- return f"0x{prediction.hex}"
+ return "0x{}".format(prediction.hex)
def gen_setup(test_file):
@@ -203,12 +203,12 @@
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")
- test_file.write(f"_start:\n")
+ test_file.write(".macro init\n")
+ test_file.write(".endm\n")
+ test_file.write(".section .text.init\n")
+ test_file.write(".globl _start\n")
+ test_file.write(".option norvc\n")
+ test_file.write("_start:\n")
def gen_csr_test_fail(test_file, end_addr):
@@ -221,13 +221,13 @@
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 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, 0x{end_addr}\n")
- test_file.write(f"\tsw x1, 0(x2)\n")
- test_file.write(f"\tj csr_fail\n")
+ test_file.write("csr_fail:\n")
+ test_file.write("\tli x1, {}\n".format(TEST_FAIL))
+ test_file.write("\tslli x1, x1, 8\n")
+ test_file.write("\taddi x1, x1, {}\n".format(TEST_RESULT))
+ test_file.write("\tli x2, 0x{}\n".format(end_addr))
+ test_file.write("\tsw x1, 0(x2)\n")
+ test_file.write("\tj csr_fail\n")
def gen_csr_test_pass(test_file, end_addr):
@@ -240,13 +240,13 @@
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 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, 0x{end_addr}\n")
- test_file.write(f"\tsw x1, 0(x2)\n")
- test_file.write(f"\tj csr_pass\n")
+ test_file.write("csr_pass:\n")
+ test_file.write("\tli x1, {}\n".format(TEST_PASS))
+ test_file.write("\tslli x1, x1, 8\n")
+ test_file.write("\taddi x1, x1, {}\n".format(TEST_RESULT))
+ test_file.write("\tli x2, 0x{}\n".format(end_addr))
+ test_file.write("\tsw x1, 0(x2)\n")
+ test_file.write("\tj csr_pass\n")
def gen_csr_instr(original_csr_map, csr_instructions, xlen,
@@ -271,13 +271,13 @@
# pick two GPRs at random to act as source and destination registers
# for CSR operations
csr_map = copy.deepcopy(original_csr_map)
- source_reg, dest_reg = [f"x{i}" for i in random.sample(range(1, 16), 2)]
+ source_reg, dest_reg = ["x{}".format(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:
+ with open("{}/riscv_csr_test_{}.S".format(out, i), "w") as csr_test_file:
gen_setup(csr_test_file)
for csr in csr_list:
csr_address, csr_val, csr_write_mask, csr_read_mask = csr_map.get(csr)
- csr_test_file.write(f"\t# {csr}\n")
+ csr_test_file.write("\t# {}\n".format(csr))
for op in csr_instructions:
for i in range(3):
# hex string
@@ -286,17 +286,17 @@
first_li = ""
if op[-1] == "i":
imm = rand_rs1_val[-5:]
- csr_inst = f"\t{op} {dest_reg}, {csr_address}, 0b{imm.bin}\n"
+ csr_inst = "\t{} {}, {}, 0b{}\n".format(op, dest_reg, csr_address, imm.bin)
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")
+ predict_li = ("\tli {}, "
+ "{}\n".format(source_reg, predict_csr_val(op, imm_val, csr_val, csr_write_mask, csr_read_mask)))
else:
- first_li = f"\tli {source_reg}, 0x{rand_rs1_val.hex}\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"
+ first_li = "\tli {}, 0x{}\n".format(source_reg, rand_rs1_val.hex)
+ csr_inst = "\t{} {}, {}, {}\n".format(op, dest_reg, csr_address, source_reg)
+ predict_li = ("\tli {}, "
+ "{}\n".format(source_reg, predict_csr_val(op, rand_rs1_val, csr_val, csr_write_mask, csr_read_mask)))
+ branch_check = "\tbne {}, {}, csr_fail\n".format(source_reg, dest_reg)
csr_test_file.write(first_li)
csr_test_file.write(csr_inst)
csr_test_file.write(predict_li)
@@ -306,11 +306,11 @@
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_address}\n"
+ final_csr_read = "\tcsrr {}, {}\n".format(dest_reg, csr_address)
csrrs_read_mask = bitarray(uint=0, length=xlen)
- 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"
+ final_li = ("\tli {}, "
+ "{}\n".format(source_reg, predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_write_mask, csr_read_mask)))
+ final_branch_check = "\tbne {}, {}, csr_fail\n".format(source_reg, dest_reg)
csr_test_file.write(final_csr_read)
csr_test_file.write(final_li)
csr_test_file.write(final_branch_check)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_amo_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_amo_instr.sv
index 79be480..f2d5f71 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_amo_instr.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_amo_instr.sv
@@ -20,7 +20,7 @@
rand bit rl;
constraint aq_rl_c {
- aq && rl == 0;
+ (aq && rl) == 0;
}
`uvm_object_utils(riscv_amo_instr)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh
index 18b7925..569f639 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh
@@ -160,9 +160,6 @@
// unsigend immediate value
bit [31:0] max_val;
max_val = (1 << imm_len)-1;
- if (value == '0) begin
- return MIN_VAL;
- end
if (value == max_val) begin
return MAX_VAL;
end
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv
index 7c2155b..ffb949a 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv
@@ -97,7 +97,7 @@
// Offset of pmp_cfg[0] does not matter, since it will be set to <main>,
// so we do not constrain it here, as it will be overridden during generation
if (i != 0) {
- pmp_cfg[i].offset inside {[1 : pmp_max_offset + 1]};
+ pmp_cfg[i].offset inside {[1 : pmp_max_offset]};
} else {
pmp_cfg[i].offset == 0;
}
@@ -622,7 +622,7 @@
for (int i = 0; i < pmp_num_regions; i++) begin
pmp_addr = base_pmp_addr + i;
pmpcfg_addr = base_pmpcfg_addr + (i / cfg_per_csr);
- // We randomize the upper 31 bits of pmp_val and then add this to the
+ // We randomize the lower 31 bits of pmp_val and then add this to the
// address of <main>, guaranteeing that the random value written to
// pmpaddr[i] doesn't interfere with the safe region.
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(pmp_val, pmp_val[31] == 1'b0;)
@@ -642,12 +642,15 @@
//
// TODO: support rv64.
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(pmp_val,
- // Need to constrain pmp_val[7], pmp_val[15], ... to 1'b0
- // to ensure that the random config regions aren't locked
foreach (pmp_val[i]) {
+ // constrain each Lock bit to 0
if ((i+1) % 8 == 0) {
pmp_val[i] == 1'b0;
}
+ // prevent W=1/R=0 combination
+ if (i % 8 == 0) { // this is an R bit
+ !((pmp_val[i] == 0) && (pmp_val[i+1] == 1'b1));
+ }
}
)
// If we're writing to the pmpcfg CSR that contains region0 config information,
diff --git a/hw/vendor/lowrisc_ibex/vendor/patches/lowrisc_ip/dv_lib/0001-use-ibex-bus-params.patch b/hw/vendor/lowrisc_ibex/vendor/patches/lowrisc_ip/dv_lib/0001-use-ibex-bus-params.patch
new file mode 100644
index 0000000..24033de
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/patches/lowrisc_ip/dv_lib/0001-use-ibex-bus-params.patch
@@ -0,0 +1,12 @@
+diff --git a/dv_lib/dv_lib.core b/dv_lib/dv_lib.core
+index e6e3f9e8..ad1b98ff 100644
+--- a/dv_lib.core
++++ b/dv_lib.core
+@@ -11,6 +11,6 @@ filesets:
+ - lowrisc:dv:dv_utils
+ - lowrisc:dv:csr_utils
+ - lowrisc:dv:dv_base_reg
+- - lowrisc:opentitan:bus_params_pkg
++ - lowrisc:ibex:bus_params_pkg
+ files:
+ - dv_lib_pkg.sv
diff --git a/hw/vendor/lowrisc_ibex/vendor/patches/lowrisc_ip/dv_utils/0001-use-ibex-top-pkg.patch b/hw/vendor/lowrisc_ibex/vendor/patches/lowrisc_ip/dv_utils/0001-use-ibex-bus-params.patch
similarity index 80%
rename from hw/vendor/lowrisc_ibex/vendor/patches/lowrisc_ip/dv_utils/0001-use-ibex-top-pkg.patch
rename to hw/vendor/lowrisc_ibex/vendor/patches/lowrisc_ip/dv_utils/0001-use-ibex-bus-params.patch
index 906cec7..386ba84 100644
--- a/hw/vendor/lowrisc_ibex/vendor/patches/lowrisc_ip/dv_utils/0001-use-ibex-top-pkg.patch
+++ b/hw/vendor/lowrisc_ibex/vendor/patches/lowrisc_ip/dv_utils/0001-use-ibex-bus-params.patch
@@ -6,8 +6,8 @@
depend:
- lowrisc:dv:common_ifs
- lowrisc:prim:assert:0.1
-- - lowrisc:constants:top_pkg
-+ - lowrisc:ibex:top_pkg
+- - lowrisc:opentitan:bus_params_pkg
++ - lowrisc:ibex:bus_params_pkg
files:
- dv_utils_pkg.sv
- dv_macros.svh: {is_include_file: true}
diff --git a/util/syn_yosys.sh b/util/syn_yosys.sh
index b02c367..b3c9ec1 100755
--- a/util/syn_yosys.sh
+++ b/util/syn_yosys.sh
@@ -60,9 +60,6 @@
done
rm combined.v
-# rename ibex_register_file_ff, match filename to module name
-mv ibex_register_file{,_ff}.v
-
#-------------------------------------------------------------------------
# run LEC (generarted Verilog vs. original SystemVerilog)
#-------------------------------------------------------------------------