Update lowrisc_ibex to lowRISC/ibex@e4b8851

Update code from upstream repository
https://github.com/lowRISC/ibex.git to revision
e4b8851b4bf056444416dfcb0c91df04ffba74ab

* Revert "Re-instate an 0x in dv/uvm/core_ibex/Makefile" (Greg
  Chadwick)
* Merge pull request lowRISC/ibex#624 from ganoam/fpga-opt-perf-mon-pr
  (Noam Gallmann)
* Update google_riscv-dv to google/riscv-dv@4583049 (lowRISC/ibex#660)
  (taoliug)
* Remove stray semicolon (Rupert Swarbrick)
* Re-instate an 0x in dv/uvm/core_ibex/Makefile (Rupert Swarbrick)
* Fix qrun compile warning (danghai)
* [rtl] Break path from data_err_o -> instr_req_o (Greg Chadwick)
* [lint] Fix lint waiver (Greg Chadwick)
* Add a wrapper script to run a simple_system binary under Spike
  (Rupert Swarbrick)
* Add missing flop to bus error checking in riscv_testutil.sv (Rupert
  Swarbrick)
* Avoid two combinatorial loop warnings in riscv_compliance suite
  (Rupert Swarbrick)
* Fix last verilator warning for ibex_simple_system; add waiver
  (Rupert Swarbrick)
* Simplify the logic in check_ibex_uvm_log (Rupert Swarbrick)
* Make ibex_log_to_trace_csv.py PEP8 compliant (Rupert Swarbrick)
* Simplify usage of ibex_log_to_trace_csv.py (Rupert Swarbrick)
* Allow ibex_log_to_trace_csv.py to run from other directories (Rupert
  Swarbrick)
* Avoid unneccessary rebuilding in dv/uvm/core_ibex/Makefile (Rupert
  Swarbrick)
* Make exiting from simple_system tests work with Spike (Rupert
  Swarbrick)
* Split have_instr definition out of always block in if_stage (Rupert
  Swarbrick)
* Waive verilator warning about unused addr bits in timer.sv (Rupert
  Swarbrick)
* Waive verilator warnings about unused addr bits in simulator_ctrl.sv
  (Rupert Swarbrick)
* Add Verilator waivers to the non-lint target in ibex_core.core
  (Rupert Swarbrick)
* Fix typo in signal declaration in timer.sv (Rupert Swarbrick)
* Switch Verilator linter to matches (Stefan Wallentowitz)
* [dv] Increase timeouts to fix failures (Greg Chadwick)
* [dv] fix qrun compile warnings (lowRISC/ibex#639) (udinator)
* Make sim.py less chatty when just compiling the testbench (Rupert
  Swarbrick)
* [dv] remove usage of 0x from sim flow (lowRISC/ibex#638) (udinator)
* update riscv_core_setting (lowRISC/ibex#633) (udinator)
* Set the ELF entry point in simple system linker script (Rupert
  Swarbrick)
* Improve docs for getting started in verification.rst (Rupert
  Swarbrick)
* Dump to VPD in dv/uvm if Verdi is not available (lowRISC/ibex#630)
  (Rupert Swarbrick)
* Tiny docs fix in examples/simple_system (Rupert Swarbrick)
* Fix previous gitignore change for uvm directory rejig (Rupert
  Swarbrick)
* Add .gitignore rules for auto-generated files (Rupert Swarbrick)
* Tracer: Mark all functions "automatic" (dawidzim)
* Reorganize ibex dv files (lowRISC/ibex#618) (udinator)
* VCS compile fix (lowRISC/ibex#616) (udinator)
* Update google_riscv-dv to google/riscv-dv@6bd3233 (lowRISC/ibex#617)
  (udinator)
* [doc] Fix reference link (Tobias Wölfel)
* CI: Pin riscv-compliance repo to specific commit (Philipp Wagner)
* [rtl] Change misa for RV32E (Tobias Wölfel)
* [rtl] Alter multdiv to better match style guide (Greg Chadwick)
* Doc: Fix broken table in integration docs (Philipp Wagner)
* Doc: Documented supported tool versions (Philipp Wagner)
* Check for supported tool versions (Philipp Wagner)
* Doc: Cleanup Sphinx config file (Philipp Wagner)
* [rtl] Add Single Cycle Multiplier targeting FPGA (ganoam)
* Reduce latency of slow multiplier (Stefan Mach)
* [dv] add command line PMP option configurability (lowRISC/ibex#599)
  (udinator)
* [syn] Fix synthesis script (Greg Chadwick)
* [rtl] Fix assertion issues (Greg Chadwick)
* Update setuptools and pip to parse more metadata (Philipp Wagner)
* [rtl] Introduce default clk/reset to prim_assert (Greg Chadwick)
* update testlist typo (lowRISC/ibex#593) (udinator)
* Update google_riscv-dv to google/riscv-dv@6e2bc2e (lowRISC/ibex#589)
  (udinator)
* [dv] enable PMP (lowRISC/ibex#588) (udinator)
* Update google_riscv-dv to google/riscv-dv@e63c542 (lowRISC/ibex#587)
  (udinator)

Signed-off-by: Greg Chadwick <gac@lowrisc.org>
diff --git a/hw/vendor/lowrisc_ibex.lock.hjson b/hw/vendor/lowrisc_ibex.lock.hjson
index 7b8f16a..55aabe1 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: 3f0b730d57ee415abd2526fc283d3d16c6632d6b
+    rev: e4b8851b4bf056444416dfcb0c91df04ffba74ab
   }
 }
diff --git a/hw/vendor/lowrisc_ibex/.gitignore b/hw/vendor/lowrisc_ibex/.gitignore
index 819464a..4b60bf0 100644
--- a/hw/vendor/lowrisc_ibex/.gitignore
+++ b/hw/vendor/lowrisc_ibex/.gitignore
@@ -13,3 +13,13 @@
 # Simple system output files
 ibex_simple_system.log
 ibex_simple_system_pcount.csv
+
+# Python cache files
+__pycache__
+
+# This is generated by VCS when running DV simulations with WAVE=1.
+/dv/uvm/core_ibex/ucli.key
+
+# This is the default output directory in dv/uvm/core_ibex and
+# contains auto-generated files from building and running tests.
+/dv/uvm/core_ibex/out
diff --git a/hw/vendor/lowrisc_ibex/azure-pipelines.yml b/hw/vendor/lowrisc_ibex/azure-pipelines.yml
index 257e050..2dfc500 100644
--- a/hw/vendor/lowrisc_ibex/azure-pipelines.yml
+++ b/hw/vendor/lowrisc_ibex/azure-pipelines.yml
@@ -6,9 +6,10 @@
 # Documentation at https://aka.ms/yaml
 
 variables:
-  VERILATOR_VERSION: 4.016
+  VERILATOR_VERSION: 4.028
   VERILATOR_PATH: /opt/buildcache/verilator/$(VERILATOR_VERSION)
   RISCV_TOOLCHAIN_TAR_VERSION: 20190807-1
+  RISCV_COMPLIANCE_GIT_VERSION: 844c6660ef3f0d9b96957991109dfd80cc4938e2
 
 trigger:
   batch: true
@@ -31,6 +32,12 @@
   # 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: |
       sudo apt-get install -y \
           python3 \
@@ -47,7 +54,8 @@
           curl \
           libelf-dev \
           clang-format \
-        && sudo pip3 install -U six fusesoc
+        && sudo pip3 install -U setuptools pip six \
+        && sudo pip3 install -U fusesoc
     displayName: Install dependencies
 
   - bash: |
@@ -118,6 +126,8 @@
   - bash: |
       cd build
       git clone https://github.com/riscv/riscv-compliance.git
+      cd riscv-compliance
+      git checkout "$(RISCV_COMPLIANCE_GIT_VERSION)"
     displayName: Get RISC-V Compliance test suite
 
   - bash: |
diff --git a/hw/vendor/lowrisc_ibex/check_tool_requirements.core b/hw/vendor/lowrisc_ibex/check_tool_requirements.core
new file mode 100644
index 0000000..1276e3e
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/check_tool_requirements.core
@@ -0,0 +1,31 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:ibex:check_tool_requirements:0.1"
+description: "Check tool requirements"
+
+filesets:
+  files_check_tool_requirements:
+    files:
+      - ./util/check_tool_requirements.py : { copyto: util/check_tool_requirements.py }
+      - ./tool_requirements.py : { copyto: tool_requirements.py }
+
+scripts:
+  check_tool_requirements:
+    cmd:
+      - python3
+      - util/check_tool_requirements.py
+    # TODO: Use this syntax once https://github.com/olofk/fusesoc/issues/353 is
+    # fixed. Remove the filesets from the default target, and also remove the
+    # copyto.
+    #filesets:
+    #  - files_check_tool_requirements
+
+targets:
+  default:
+    filesets:
+      - files_check_tool_requirements
+    hooks:
+      pre_build:
+        - tool_verilator ? (check_tool_requirements)
diff --git a/hw/vendor/lowrisc_ibex/doc/conf.py b/hw/vendor/lowrisc_ibex/doc/conf.py
index de2a370..6030030 100644
--- a/hw/vendor/lowrisc_ibex/doc/conf.py
+++ b/hw/vendor/lowrisc_ibex/doc/conf.py
@@ -1,13 +1,8 @@
-# -*- coding: utf-8 -*-
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
 #
-# ibex documentation build configuration file, created by
-# sphinx-quickstart on Thu Nov  8 15:42:18 2018.
-#
-# This file is execfile()d with the current directory set to its
-# containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
+# Sphinx configuration file for the Ibex documentation
 #
 # All configuration values have a default; values that are commented out
 # serve to show the default.
@@ -16,10 +11,13 @@
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
 #
-# import os
+import os
 # import sys
 # sys.path.insert(0, os.path.abspath('.'))
 
+# Source top directory
+topsrcdir = os.path.join(os.path.dirname(__file__), '..')
+
 numfig=True
 numfig_format = {'figure': 'Figure %s', 'table': 'Table %s', 'code-block': 'Listing %s'}
 
@@ -48,28 +46,26 @@
 master_doc = 'index'
 
 # General information about the project.
-project = u'Ibex User Manual'
-copyright = u'2017-2018, ETH Zurich and University of Bologna, 2018-present lowRISC'
-author = u'lowRISC contributors'
-
-from setuptools_scm import get_version
-release = get_version(root='..', relative_to=__file__)
+project = 'Ibex User Manual'
+copyright = '2017-2018, ETH Zurich and University of Bologna, 2018-present lowRISC'
+author = 'lowRISC contributors'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-version = u''
+version = ''
 # The full version, including alpha/beta/rc tags.
-#release = u''
+from setuptools_scm import get_version
+release = get_version(root=topsrcdir)
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
 #
 # This is also used if you do content translation via gettext catalogs.
 # Usually you set "language" from the command line for these cases.
-language = None
+language = 'en'
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
@@ -111,13 +107,6 @@
         ],
     }
 
-# -- Options for HTMLHelp output ------------------------------------------
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'ibexdoc'
-
-
-
 # -- Options for LaTeX output ---------------------------------------------
 
 latex_elements = {
@@ -168,3 +157,12 @@
      author, 'ibex', 'Ibex RV32 CPU core',
      'Miscellaneous'),
 ]
+
+# -- Tool version numbers -------------------------------------------------
+
+# Add minimum versions of required tools as variables for use inside the
+# documentation.
+exec(open(os.path.join(topsrcdir, 'tool_requirements.py')).read())
+rst_epilog = ""
+for tool_name, tool_version in __TOOL_REQUIREMENTS__.items():
+    rst_epilog += ".. |tool_requirements.{}| replace:: {}\n".format(tool_name, tool_version)
diff --git a/hw/vendor/lowrisc_ibex/doc/examples.rst b/hw/vendor/lowrisc_ibex/doc/examples.rst
index b16842b..ef9007f 100644
--- a/hw/vendor/lowrisc_ibex/doc/examples.rst
+++ b/hw/vendor/lowrisc_ibex/doc/examples.rst
@@ -15,4 +15,4 @@
 The instructions memory is initialized at synthesis time by reading the output from the software build.
 The software writes to the data section the complementary lower for bits of a word every second resulting in blinking LEDs.
 
-Find the description of how to build and program the Arty board in ``examples/fpga/artya7-100/README.md``.
+Find the description of how to build and program the Arty board in ``examples/fpga/artya7/README.md``.
diff --git a/hw/vendor/lowrisc_ibex/doc/index.rst b/hw/vendor/lowrisc_ibex/doc/index.rst
index 53b76a4..31dec10 100644
--- a/hw/vendor/lowrisc_ibex/doc/index.rst
+++ b/hw/vendor/lowrisc_ibex/doc/index.rst
@@ -6,6 +6,7 @@
    :caption: Contents:
 
    introduction
+   system_requirements
    getting_started
    integration
    pipeline_details
diff --git a/hw/vendor/lowrisc_ibex/doc/instruction_decode_execute.rst b/hw/vendor/lowrisc_ibex/doc/instruction_decode_execute.rst
index af1cbef..0d1be09 100644
--- a/hw/vendor/lowrisc_ibex/doc/instruction_decode_execute.rst
+++ b/hw/vendor/lowrisc_ibex/doc/instruction_decode_execute.rst
@@ -71,19 +71,33 @@
 Source Files: :file:`rtl/ibex_multdiv_slow.sv` :file:`rtl/ibex_multdiv_fast.sv`
 
 The Multiplier/Divider (MULT/DIV) is a state machine driven block to perform multiplication and division.
-The fast and slow versions differ in multiplier only, both implement the same form of long division algorithm.
-The ALU block is used by the long division algorithm in both the fast and slow blocks.
+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.
 
-Fast Multiplier
-  - 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.
-  - This MAC is internal to the mult/div block (no external ALU use).
-  - Beware it is simply implemented with the ``*`` and ``+`` operators so results heavily depend upon the synthesis tool used.
-  - In some cases it may be desirable to replace this with a specific implementation (such as a hard macro in an FPGA or an explicit gate level implementation).
+Multiplier
+  The multiplier can be implemented in three variants controlled via the parameter ``MultiplierImplementation``.
 
-Slow Multiplier
-  - Completes multiply in 33 cycles using a Baugh-Wooley multiplier (for both MUL and MULH).
-  - The ALU block is used to compute additions.
+  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**.
+
+    - 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).
+    - Beware it is simply implemented with the ``*`` and ``+`` operators so results heavily depend upon the synthesis tool used.
+    - 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**.
+
+    - 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.
+    - This MAC is internal to the mult/div block (no external ALU use).
+    - Beware it is simply implemented with the ``*`` and ``+`` operators so results heavily depend upon the synthesis tool used.
+    - 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".
+
+    - 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.
 
 Divider
   Both the fast and slow blocks use the same long division algorithm, it takes 37 cycles to compute (though only requires 2 cycles when there is a divide by 0) and proceeds as follows:
diff --git a/hw/vendor/lowrisc_ibex/doc/integration.rst b/hw/vendor/lowrisc_ibex/doc/integration.rst
index 1270ca0..8e2828a 100644
--- a/hw/vendor/lowrisc_ibex/doc/integration.rst
+++ b/hw/vendor/lowrisc_ibex/doc/integration.rst
@@ -90,7 +90,10 @@
 | ``BranchTargetALU``          | bit         | 0          | *EXPERIMENTAL* - Enables branch target ALU removing a stall     |
 |                              |             |            | cycle from taken branches                                       |
 +------------------------------+-------------+------------+-----------------------------------------------------------------+
-| ``MultiplierImplementation`` | string      | "fast"     | Multiplicator type, "slow", or "fast"                           |
+| ``MultiplierImplementation`` | string      | "fast"     | Multiplicator type:                                             |
+|                              |             |            | "slow": multi-cycle slow,                                       |
+|                              |             |            | "fast": multi-cycle fast,                                       |
+|                              |             |            | "single-cycle": single-cycle                                    |
 +------------------------------+-------------+------------+-----------------------------------------------------------------+
 | ``DbgTriggerEn``             | bit         | 0          | Enable debug trigger support (one trigger only)                 |
 +------------------------------+-------------+------------+-----------------------------------------------------------------+
diff --git a/hw/vendor/lowrisc_ibex/doc/performance_counters.rst b/hw/vendor/lowrisc_ibex/doc/performance_counters.rst
index e42b32b..fb4c1fb 100644
--- a/hw/vendor/lowrisc_ibex/doc/performance_counters.rst
+++ b/hw/vendor/lowrisc_ibex/doc/performance_counters.rst
@@ -122,3 +122,17 @@
 +----------------------+-------------+-------------+--------------+
 | ``mhpmevent10(h)``   | 0x32A       | 0x0000_0400 |           10 |
 +----------------------+-------------+-------------+--------------+
+
+FPGA Targets
+------------
+
+For FPGA targets the performance counters constitute a particularily large structure.
+Implementing the maximum 29 event counters 32, 48 and 64 bit wide results in relative logic utilizations of the core of 100%, 111% and 129% respectively.
+The relative numbers of flip-flops are 100%, 125% and 150%.
+It is recommended to implement event counters of 32 bit width where possible.
+
+For Xilinx FPGA devices featuring the `DSP48E1` DSP slice or similar, counter logic can be absorbed into the DSP slice for widths up to 48 bits.
+The resulting relative logic utilizations with respect to the non-DSP 32 bit counter implementation are 83% and 89% respectively for 32 and 48 bit DSP counters.
+This comes at the expense of 1 DSP slice per counter.
+For 32 bit counters only, the corresponding flip-flops can be incorporated into the DSP's output pipeline register, resulting in a reduction of the number of flip-flops to 50%.
+In order to infer DSP slices for performance counters, define the preprocessor variable ``FPGA_XILINX``.
diff --git a/hw/vendor/lowrisc_ibex/doc/pipeline_details.rst b/hw/vendor/lowrisc_ibex/doc/pipeline_details.rst
index 753daed..cb2a302 100644
--- a/hw/vendor/lowrisc_ibex/doc/pipeline_details.rst
+++ b/hw/vendor/lowrisc_ibex/doc/pipeline_details.rst
@@ -30,57 +30,60 @@
 Some instructions stall for a variable time, this is indicated as a range e.g. 1 - N means the instruction stalls a minimum of 1 cycle with an indeterminate maximum cycles.
 Read the description for more information.
 
-+-----------------------+-----------------------+-------------------------------------------------------------+
-| Instruction Type      | Stall Cycles          | Description                                                 |
-+=======================+=======================+=============================================================+
-| Integer Computational | 0                     | Integer Computational Instructions are defined in the       |
-|                       |                       | RISCV-V RV32I Base Integer Instruction Set.                 |
-+-----------------------+-----------------------+-------------------------------------------------------------+
-| CSR Access            | 0                     | CSR Access Instruction are defined in 'Zicsr' of the        |
-|                       |                       | RISC-V specification.                                       |
-+-----------------------+-----------------------+-------------------------------------------------------------+
-| Load/Store            | 1 - N                 | Both loads and stores stall for at least one cycle to await |
-|                       |                       | a response.  For loads this response is the load data       |
-|                       |                       | (which is written directly to the register file the same    |
-|                       |                       | cycle it is received).  For stores this is whether an error |
-|                       |                       | was seen or not.  The longer the data side memory interface |
-|                       |                       | takes to receive a response the longer loads and stores     |
-|                       |                       | will stall.                                                 |
-+-----------------------+-----------------------+-------------------------------------------------------------+
-| Multiplication        | 2/3 (Fast Multiplier) | 2 for MUL, 3 for MULH.                                      |
-|                       |                       | See details in :ref:`mult-div`                              |
-|                       | 32 (Slow Multiplier)  |                                                             |
-+-----------------------+-----------------------+-------------------------------------------------------------+
-| Division              | 1 or 37               | 1 stall cycle if divide by 0, otherwise full long division. |
-|                       |                       | See details in :ref:`mult-div`                              |
-| Remainder             |                       |                                                             |
-+-----------------------+-----------------------+-------------------------------------------------------------+
-| Jump                  | 1 - N                 | Minimum one cycle stall to flush the prefetch counter and   |
-|                       |                       | begin fetching from the new Program Counter (PC).  The new  |
-|                       |                       | PC request will appear on the instruction-side memory       |
-|                       |                       | interface the same cycle the jump instruction enters ID/EX. |
-|                       |                       | The longer the instruction-side memory interface takes to   |
-|                       |                       | receive data the longer the jump will stall.                |
-+-----------------------+-----------------------+-------------------------------------------------------------+
-| Branch (Not-Taken)    | 0                     | Any branch where the condition is not met will              |
-|                       |                       | not stall.                                                  |
-+-----------------------+-----------------------+-------------------------------------------------------------+
-| Branch (Taken)        | 2 - N                 | Any branch where the condition is met will stall for 2      |
-|                       |                       | cycles as in the first cycle the branch is in ID/EX the ALU |
-|                       | 1 - N (Branch Target  | is used to calculate the branch condition.  The following   |
-|                       | ALU enabled)          | cycle the ALU is used again to calculate the branch target  |
-|                       |                       | where it proceeds as Jump does above (Flush IF stage and    |
-|                       |                       | prefetch buffer, new PC on instruction-side memory          |
-|                       |                       | interface the same cycle it is calculated).  The longer the |
-|                       |                       | instruction-side memory interface takes to receive data the |
-|                       |                       | longer the branch will stall. With the parameter            |
-|                       |                       | ``BranchTargetALU`` set to ``1`` a seperate ALU calculates  |
-|                       |                       | the branch target simultaneously to calculating the branch  |
-|                       |                       | condition with the main ALU so 1 less stall cycle is        |
-|                       |                       | required.                                                   |
-+-----------------------+-----------------------+-------------------------------------------------------------+
-| Instruction Fence     | 1 - N                 | The FENCE.I instruction as defined in 'Zifencei' of the     |
-|                       |                       | RISC-V specification. Internally it is implemented as a     |
-|                       |                       | jump (which does the required flushing) so it has the same  |
-|                       |                       | stall characteristics (see above).                          |
-+-----------------------+-----------------------+-------------------------------------------------------------+
++-----------------------+--------------------------------------+-------------------------------------------------------------+
+|   Instruction Type    |             Stall Cycles             |                         Description                         |
++=======================+======================================+=============================================================+
+| Integer Computational | 0                                    | Integer Computational Instructions are defined in the       |
+|                       |                                      | RISCV-V RV32I Base Integer Instruction Set.                 |
++-----------------------+--------------------------------------+-------------------------------------------------------------+
+| CSR Access            | 0                                    | CSR Access Instruction are defined in 'Zicsr' of the        |
+|                       |                                      | RISC-V specification.                                       |
++-----------------------+--------------------------------------+-------------------------------------------------------------+
+| Load/Store            | 1 - N                                | Both loads and stores stall for at least one cycle to await |
+|                       |                                      | a response.  For loads this response is the load data       |
+|                       |                                      | (which is written directly to the register file the same    |
+|                       |                                      | cycle it is received).  For stores this is whether an error |
+|                       |                                      | was seen or not.  The longer the data side memory interface |
+|                       |                                      | takes to receive a response the longer loads and stores     |
+|                       |                                      | will stall.                                                 |
++-----------------------+--------------------------------------+-------------------------------------------------------------+
+| Multiplication        | 0/1 (Single-Cycle Multiplier)        | 0 for MUL, 1 for MULH.                                      |
+|                       |                                      |                                                             |
+|                       | 2/3 (Fast Multi-Cycle Multiplier)    | 2 for MUL, 3 for MULH.                                      |
+|                       |                                      |                                                             |
+|                       | clog2(``op_b``)/32 (Slow Multi-Cycle | clog2(``op_b``) for MUL, 32 for MULH.                       |
+|                       | Multiplier)                          | See details in :ref:`mult-div`.                             |
++-----------------------+--------------------------------------+-------------------------------------------------------------+
+| Division              | 1 or 37                              | 1 stall cycle if divide by 0, otherwise full long division. |
+|                       |                                      | See details in :ref:`mult-div`                              |
+| Remainder             |                                      |                                                             |
++-----------------------+--------------------------------------+-------------------------------------------------------------+
+| Jump                  | 1 - N                                | Minimum one cycle stall to flush the prefetch counter and   |
+|                       |                                      | begin fetching from the new Program Counter (PC).  The new  |
+|                       |                                      | PC request will appear on the instruction-side memory       |
+|                       |                                      | interface the same cycle the jump instruction enters ID/EX. |
+|                       |                                      | The longer the instruction-side memory interface takes to   |
+|                       |                                      | receive data the longer the jump will stall.                |
++-----------------------+--------------------------------------+-------------------------------------------------------------+
+| Branch (Not-Taken)    | 0                                    | Any branch where the condition is not met will              |
+|                       |                                      | not stall.                                                  |
++-----------------------+--------------------------------------+-------------------------------------------------------------+
+| Branch (Taken)        | 2 - N                                | Any branch where the condition is met will stall for 2      |
+|                       |                                      | cycles as in the first cycle the branch is in ID/EX the ALU |
+|                       | 1 - N (Branch Target                 | is used to calculate the branch condition.  The following   |
+|                       | ALU enabled)                         | cycle the ALU is used again to calculate the branch target  |
+|                       |                                      | where it proceeds as Jump does above (Flush IF stage and    |
+|                       |                                      | prefetch buffer, new PC on instruction-side memory          |
+|                       |                                      | interface the same cycle it is calculated).  The longer the |
+|                       |                                      | instruction-side memory interface takes to receive data the |
+|                       |                                      | longer the branch will stall. With the parameter            |
+|                       |                                      | ``BranchTargetALU`` set to ``1`` a seperate ALU calculates  |
+|                       |                                      | the branch target simultaneously to calculating the branch  |
+|                       |                                      | condition with the main ALU so 1 less stall cycle is        |
+|                       |                                      | required.                                                   |
++-----------------------+--------------------------------------+-------------------------------------------------------------+
+| Instruction Fence     | 1 - N                                | The FENCE.I instruction as defined in 'Zifencei' of the     |
+|                       |                                      | RISC-V specification. Internally it is implemented as a     |
+|                       |                                      | jump (which does the required flushing) so it has the same  |
+|                       |                                      | stall characteristics (see above).                          |
++-----------------------+--------------------------------------+-------------------------------------------------------------+
diff --git a/hw/vendor/lowrisc_ibex/doc/system_requirements.rst b/hw/vendor/lowrisc_ibex/doc/system_requirements.rst
new file mode 100644
index 0000000..7fbd3f9
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/doc/system_requirements.rst
@@ -0,0 +1,33 @@
+System and Tool Requirements
+============================
+
+The Ibex CPU core is written in SystemVerilog.
+We try to achieve a balance between the used language features (as described in our `style guide <https://github.com/lowRISC/style-guides/blob/master/VerilogCodingStyle.md>`_) and reasonably wide tool support.
+
+The following tools are known to work with the RTL code of Ibex.
+Please `file an issue <https://github.com/lowRISC/ibex/issues>`_ if you experience problems with any of the listed tools, or if you have successfully used a tool with Ibex which is not listed here.
+
+- Synopsys Design Compiler
+- Xilinx Vivado
+- Verilator, version |tool_requirements.verilator| and up.
+- Synopsys VCS
+- Cadence Incisive/Xcelium
+- Mentor Questa
+- Aldec Riviera Pro
+
+To run the UVM testbench a RTL simulator which supports SystemVerilog and UVM 1.2 is required.
+The `documentation of riscv-dv <https://github.com/google/riscv-dv#prerequisites>`_ contains a list of supported simulators.
+
+Tools with known issues
+-----------------------
+
+Not all EDA tools have enough SystemVerilog support to be able to work with the Ibex code base.
+Users of such tools are encouraged to file issues with the vendor.
+As a workaround, tools like `sv2v <https://github.com/zachjs/sv2v>`_ can pre-process the source code to an older version of Verilog.
+
+- Intel (Altera) Quartus Prime Lite and Standard are *not* supported due to insufficient SystemVerilog support
+  (`issue #117 <https://github.com/lowRISC/ibex/issues/117>`_).
+- Yosys cannot be used directly due to insufficient SystemVerilog support
+  (`issue #60 <https://github.com/lowRISC/ibex/issues/60>`_).
+  The ``syn`` folder in the Ibex repository contains scripts to use sv2v together with Yosys.
+- Icarus Verilog is not supported due to insufficient SystemVerilog support.
diff --git a/hw/vendor/lowrisc_ibex/doc/verification.rst b/hw/vendor/lowrisc_ibex/doc/verification.rst
index cdaaf4b..67e6aaa 100644
--- a/hw/vendor/lowrisc_ibex/doc/verification.rst
+++ b/hw/vendor/lowrisc_ibex/doc/verification.rst
@@ -80,10 +80,43 @@
 Prerequisites & Environment Setup
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-- VCS RTL simulator (needed to support UVM 1.2)
-- RISCV-DV Prerequisites - https://github.com/google/riscv-dv#prerequisites
-- GCC setup - https://github.com/google/riscv-dv#compile-generated-programs-with-gcc
-- ISS setup - https://github.com/google/riscv-dv#run-iss-instruction-set-simulator-simulation - note that commit log must be enabled in spike by passing ``--enable-commitlog`` to the configure script.
+In order to run the co-simulation flow, you'll need:
+
+  - A SystemVerilog simulator that supports UVM. The flow is currently
+    tested with VCS.
+
+  - A RISC-V instruction set simulator. For example, Spike_ or
+    OVPsim_. Note that Spike must be configured with
+    ``--enable-commitlog`` and ``--enable-misaligned``. The commit log
+    is needed to track the instructions that were executed and
+    ``--enable-misaligned`` tells Spike to simulate a core that
+    handles misaligned accesses in hardware (rather than jumping to a
+    trap handler).
+
+  - A working RISC-V toolchain (to compile / assemble the generated
+    programs before simulating them). Either download and build the
+    `RISC-V GNU compiler toolchain <riscv-toolchain-source_>`_ or
+    (quicker) download a `pre-built toolchain
+    <riscv-toolchain-releases_>`_.
+
+Once these are installed, you need to set some environment variables
+to tell the RISCV-DV code where to find them:
+
+::
+
+    export RISCV_TOOLCHAIN=/path/to/riscv
+    export RISCV_GCC="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-gcc"
+    export RISCV_OBJCOPY="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-objcopy"
+    export SPIKE_PATH=/path/to/spike/bin
+    export OVPSIM_PATH=/path/to/ovpsim/bin
+
+(Obviously, you only need to set ``SPIKE_PATH`` or ``OVPSIM_PATH`` if
+you have installed the corresponding instruction set simulator)
+
+.. _Spike: https://github.com/riscv/riscv-isa-sim
+.. _OVPsim: https://github.com/riscv/riscv-ovpsim
+.. _riscv-toolchain-source: https://github.com/riscv/riscv-gnu-toolchain
+.. _riscv-toolchain-releases: https://github.com/lowRISC/lowrisc-toolchains/releases
 
 End-to-end RTL/ISS co-simulation flow
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/ibex_riscv_compliance.core b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/ibex_riscv_compliance.core
index f8120ee..f17ca31 100644
--- a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/ibex_riscv_compliance.core
+++ b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/ibex_riscv_compliance.core
@@ -18,6 +18,11 @@
       - rtl/riscv_testutil.sv
     file_type: systemVerilogSource
 
+  files_verilator_waiver:
+    files:
+      - lint/verilator_waiver.vlt: {file_type: vlt}
+
+
 parameters:
   RV32M:
     datatype: int
@@ -39,6 +44,7 @@
   sim:
     default_tool: verilator
     filesets:
+      - tool_verilator ? (files_verilator_waiver)
       - files_sim_verilator
     parameters:
       - RV32M
diff --git a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/lint/verilator_waiver.vlt b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/lint/verilator_waiver.vlt
new file mode 100644
index 0000000..cf03755
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/lint/verilator_waiver.vlt
@@ -0,0 +1,32 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Lint waivers for processing riscv_compliance RTL with Verilator
+//
+// This should be used for rules applying to things like testbench
+// top-levels. For rules that apply to the actual design (files in the
+// 'rtl' directory), see verilator_waiver_rtl.vlt in the same
+// directory.
+//
+// See https://www.veripool.org/projects/verilator/wiki/Manual-verilator#CONFIGURATION-FILES
+// for documentation.
+//
+// Important: This file must included *before* any other Verilog file is read.
+// Otherwise, only global waivers are applied, but not file-specific waivers.
+
+`verilator_config
+
+// 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:
+//
+//   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_riscv_compliance.sv"
+         -match "*expects 1 bits*Initial value's CONST '32'h1'*"
diff --git a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv
index 1a3c557..78879b1 100644
--- a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv
+++ b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv
@@ -15,9 +15,9 @@
   input IO_RST_N
 );
 
-  parameter bit RV32E           = 0;
-  parameter bit RV32M           = 1;
-  parameter bit BranchTargetALU = 0;
+  parameter bit RV32E           = 1'b0;
+  parameter bit RV32M           = 1'b1;
+  parameter bit BranchTargetALU = 1'b0;
 
   logic clk_sys, rst_sys_n;
 
diff --git a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/riscv_testutil.sv b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/riscv_testutil.sv
index 961867c..f2cbc6f 100644
--- a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/riscv_testutil.sv
+++ b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/rtl/riscv_testutil.sv
@@ -90,8 +90,17 @@
     end
   end
 
-  // only word writes are supported
-  assign dev_err_o = (~dev_we_i | dev_be_i != 4'hf) & dev_req_i;
+  // The interface is write-only, and only supports 32-bit writes. If
+  // either of these checks fails, raise dev_err_o on the next cycle.
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      dev_err_o <= 1'b0;
+    end else begin
+      dev_err_o <= (~dev_we_i | dev_be_i != 4'hf) & dev_req_i;
+    end
+  end
+
+  // Since the interface is write-only, tie rdata to 0.
   assign dev_rdata_o = 32'h0;
 
 
@@ -106,8 +115,6 @@
   logic [31:0] read_addr_d, read_addr_q;
   always_comb begin
     state_d = state_q;
-    host_req_o = 1'b0;
-
     unique case (state_q)
       WAIT: begin
         if (read_signature_and_terminate) begin
@@ -119,8 +126,6 @@
       end
 
       READ: begin
-        host_req_o = 1'b1;
-        host_addr_o = read_addr_q;
         if (host_gnt_i) begin
           read_addr_d = read_addr_q + 4;
           if (read_addr_d == end_signature_addr_q) begin
@@ -142,6 +147,11 @@
     endcase
   end
 
+  // These are the address and read request bits, respectively of the
+  // TestUtilHost master port.
+  assign host_addr_o = read_addr_q;
+  assign host_req_o = (state_q == READ);
+
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
       state_q <= WAIT;
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/Makefile b/hw/vendor/lowrisc_ibex/dv/uvm/Makefile
deleted file mode 100644
index 4789b99..0000000
--- a/hw/vendor/lowrisc_ibex/dv/uvm/Makefile
+++ /dev/null
@@ -1,164 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-
-DV_DIR              := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-GEN_DIR             := $(realpath ${DV_DIR}/../../vendor/google_riscv-dv)
-TOOLCHAIN           := ${RISCV_TOOLCHAIN}
-OUT                 := "${DV_DIR}/out"
-# Run time options for the instruction generator
-GEN_OPTS            :=
-# Run time options for ibex RTL simulation
-SIM_OPTS            :=
-# Enable waveform dumping
-WAVES               := 1
-# Enable coverage dump
-COV                 := 0
-# RTL simulator
-SIMULATOR           := "vcs"
-# ISS (spike, ovpsim)
-ISS                 := "ovpsim"
-# ISA
-ISA                 := "rv32imc"
-# Test name (default: full regression)
-TEST                := "all"
-# Seed for instruction generator and RTL simulation
-TESTLIST            := ${DV_DIR}/riscv_dv_extension/testlist.yaml
-SEED                := -1
-# Verbose logging
-VERBOSE             :=
-# Number of iterations for each test, assign a non-zero value to override the
-# iteration count in the test list
-ITERATIONS          := 0
-# LSF CMD
-LSF_CMD             :=
-# Generator timeout limit in seconds
-TIMEOUT             := 1800
-# Privileged CSR YAML description file
-CSR_FILE            := ${DV_DIR}/riscv_dv_extension/csr_description.yaml
-# Pass/fail signature address at the end of test
-SIGNATURE_ADDR      := 8ffffffc
-
-SHELL=/bin/bash
-
-export PRJ_DIR:= $(realpath ${DV_DIR}/../../..)
-
-.PHONY: rtl_sim clean gcc_compile iss_sim
-
-all: clean gen gcc_compile iss_sim compile rtl_sim post_compare
-
-instr: gen gcc_compile iss_sim
-
-sim: compile rtl_sim post_compare
-
-clean:
-	rm -rf ${OUT}
-
-# Common options for all targets
-COMMON_OPTS:=--seed=${SEED} \
-             --test=${TEST} \
-             --testlist=${TESTLIST} \
-             --iterations=${ITERATIONS}
-
-ifeq ($(VERBOSE), 1)
-	COMMON_OPTS+=--verbose
-endif
-
-# Options used for privileged CSR test generation
-CSR_OPTS=--csr_yaml=${CSR_FILE} \
-         --isa=${ISA} \
-         --end_signature_addr=0x${SIGNATURE_ADDR}
-
-RISCV_DV_OPTS=--custom_target=${DV_DIR}/riscv_dv_extension \
-              --isa=${ISA} \
-              --mabi=ilp32 \
-
-# Generate random instructions
-.SILENT gen:
-	mkdir -p ${OUT}
-	python3 ${GEN_DIR}/run.py \
-     --output=${OUT}/instr_gen ${GEN_OPTS} \
-     --steps=gen \
-     --gen_timeout=${TIMEOUT} \
-     --lsf_cmd="${LSF_CMD}" \
-     --simulator=${SIMULATOR} \
-     ${RISCV_DV_OPTS} \
-     ${COMMON_OPTS} \
-     ${CSR_OPTS} \
-     --sim_opts="+uvm_set_inst_override=riscv_asm_program_gen,ibex_asm_program_gen,"uvm_test_top.asm_gen" \
-                 +signature_addr=${SIGNATURE_ADDR}";
-
-# Compile the generated assmebly programs to ELF/BIN
-gcc_compile:
-	python3 ${GEN_DIR}/run.py \
-     --o=${OUT}/instr_gen ${GEN_OPTS} \
-     --steps=gcc_compile \
-     ${COMMON_OPTS} \
-     --gcc_opts=-mno-strict-align \
-     ${RISCV_DV_OPTS} \
-
-# ISS simulation
-iss_sim:
-	python3 ${GEN_DIR}/run.py \
-     --o=${OUT}/instr_gen ${GEN_OPTS} \
-     --steps=iss_sim \
-     ${COMMON_OPTS} \
-     --iss=${ISS} \
-     ${RISCV_DV_OPTS} \
-
-# Compile ibex core TB
-compile:
-	mkdir -p ${OUT}/rtl_sim
-	python3 ./sim.py \
-     --o=${OUT} \
-     --riscv_dv_root=${GEN_DIR} \
-     --steps=compile \
-     ${COMMON_OPTS} \
-     --simulator=${SIMULATOR} \
-     --en_cov=${COV} \
-     --en_wave=${WAVES} \
-
-# Run ibex RTL simulation with random instructions
-rtl_sim:
-	mkdir -p ${OUT}/rtl_sim
-	python3 ./sim.py \
-     --o=${OUT} \
-     --riscv_dv_root=${GEN_DIR} \
-     --steps=sim \
-     ${COMMON_OPTS} \
-     --simulator=${SIMULATOR} \
-     --en_cov ${COV} \
-     --en_wave ${WAVES} \
-     --lsf_cmd="${LSF_CMD}" \
-     --sim_opts="+signature_addr=0x${SIGNATURE_ADDR}" \
-     ${SIM_OPTS}
-
-# Compare the regression result between ISS and RTL sim
-post_compare:
-	rm -rf ${OUT}/regr.log
-	python3 ./sim.py \
-     --o=${OUT} \
-     --steps=compare \
-     ${COMMON_OPTS} \
-     --simulator=${SIMULATOR} \
-     --iss=${ISS}
-
-
-# Generate functional coverage
-fcov:
-	python3 ${GEN_DIR}/cov.py \
-          --core ibex \
-          --dir ${OUT}/rtl_sim \
-          -o ${OUT}/fcov \
-          --isa rv32imc \
-          --custom_target ${DV_DIR}/riscv_dv_extension \
-
-# Load verdi to review coverage
-cov_vcs:
-	cd ${OUT}/rtl_sim; verdi -cov -covdir test.vdb &
-
-cov_ius:
-	if [ ! -d "${OUT}/rtl_sim/cov_work/scope/merged_cov" ]; \
-	  then imc -execcmd "merge -out ${OUT}/rtl_sim/cov_work/scope/merged_cov ${OUT}/rtl_sim/cov_work/scope/test_*"; \
-  	fi
-	imc -load ${OUT}/rtl_sim/cov_work/scope/merged_cov &
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/Makefile b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/Makefile
new file mode 100644
index 0000000..5c3e064
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/Makefile
@@ -0,0 +1,402 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+DV_DIR              := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
+GEN_DIR             := $(realpath ${DV_DIR}/../../../vendor/google_riscv-dv)
+TOOLCHAIN           := ${RISCV_TOOLCHAIN}
+
+# Seed for instruction generator and RTL simulation
+#
+# By default, SEED is set to a different value on each run by picking a random
+# value in the Makefile. For overnight testing, a sensible seed might be
+# something like the output of "date +%y%m%d". For regression testing, you'll
+# need to make sure that a the seed for a failed test "sticks" (so we don't
+# start passing again without fixing the bug).
+SEED                := $(shell echo $$RANDOM)
+
+# This is the top-level output directory. Everything we generate goes in
+# here. Most generated stuff actually goes in $(OUT)/seed-$(SEED), which allows
+# us to run multiple times without deleting existing results.
+OUT                 := ${DV_DIR}/out
+OUT-SEED            := $(OUT)/seed-$(SEED)
+
+# Run time options for the instruction generator
+GEN_OPTS            :=
+# Compile time options for ibex RTL simulation
+COMPILE_OPTS        +=
+# Run time options for ibex RTL simulation
+SIM_OPTS            :=
+# Enable waveform dumping
+WAVES               := 1
+# Enable coverage dump
+COV                 := 0
+# RTL simulator
+SIMULATOR           := vcs
+# ISS (spike, ovpsim)
+ISS                 := ovpsim
+# ISS runtime options
+ISS_OPTS            :=
+# ISA
+ISA                 := rv32imc
+# Test name (default: full regression)
+TEST                := all
+TESTLIST            := ${DV_DIR}/riscv_dv_extension/testlist.yaml
+# Verbose logging
+VERBOSE             :=
+# Number of iterations for each test, assign a non-zero value to override the
+# iteration count in the test list
+ITERATIONS          := 0
+# LSF CMD
+LSF_CMD             :=
+# Generator timeout limit in seconds
+TIMEOUT             := 1800
+# Privileged CSR YAML description file
+CSR_FILE            := ${DV_DIR}/riscv_dv_extension/csr_description.yaml
+# Pass/fail signature address at the end of test
+SIGNATURE_ADDR      := 8ffffffc
+
+### Ibex top level parameters ###
+### Required by RISCV-DV, some ISS, and RTL ###
+# PMP Regions
+PMP_REGIONS         := 16
+# PMP Granularity
+PMP_GRANULARITY     := 0
+
+# TODO(udinator) - might need options for SAIL/Whisper/Spike
+ifeq (${ISS},ovpsim)
+	ISS_OPTS += --override riscvOVPsim/cpu/PMP_registers=${PMP_REGIONS}
+	ISS_OPTS += --override riscvOVPsim/cpu/PMP_grain=${PMP_GRANULARITY}
+endif
+
+# Check which simulator is being used and add correct compile options
+ifeq (${SIMULATOR},vcs)
+	COMPILE_OPTS += -pvalue+core_ibex_tb_top.dut.PMPNumRegions=${PMP_REGIONS}
+	COMPILE_OPTS += -pvalue+core_ibex_tb_top.dut.PMPGranularity=${PMP_GRANULARITY}
+else ifeq (${SIMULATOR},ius)
+	COMPILE_OPTS += -defparam core_ibex_tb_top.dut.PMPNumRegions=${PMP_REGIONS}
+	COMPILE_OPTS += -defparam core_ibex_tb_top.dut.PMPGranularity=${PMP_GRANULARITY}
+# TODO(udinator) - support dsim and riviera
+endif
+
+SHELL=/bin/bash
+
+export PRJ_DIR:= $(realpath ${DV_DIR}/../../../..)
+
+all: sim
+
+instr: iss_sim
+
+sim: post_compare
+
+.PHONY: clean
+clean:
+	rm -rf ${OUT}
+
+# Common options for all targets
+COMMON_OPTS := $(if $(call equal,$(VERBOSE),1),--verbose,)
+
+# Options for all targets that depend on the tests we're running.
+TEST_OPTS := $(COMMON_OPTS) \
+             --seed=${SEED} \
+             --test"=${TEST}" \
+             --testlist=${TESTLIST} \
+             --iterations=${ITERATIONS}
+
+# Options used for privileged CSR test generation
+CSR_OPTS=--csr_yaml=${CSR_FILE} \
+         --isa="${ISA}" \
+         --end_signature_addr=${SIGNATURE_ADDR}
+
+RISCV_DV_OPTS=--custom_target=${DV_DIR}/riscv_dv_extension \
+              --isa="${ISA}" \
+              --mabi=ilp32 \
+
+# To avoid cluttering the output directory with stamp files, we place them in
+# $(metadata).
+metadata := $(OUT-SEED)/.metadata
+
+# This is a list of directories that are automatically generated by some
+# targets. To ensure the directory has been built, add a order-only dependency
+# (with the pipe symbol before it) on the directory name and add the directory
+# to this list.
+gen-dirs := $(OUT) $(OUT-SEED) $(metadata) $(OUT)/rtl_sim
+
+$(gen-dirs): %:
+	mkdir -p $@
+
+###############################################################################
+# Utility functions.
+#
+# If VS is a list of variable names, P is a path and X is a string, then $(call
+# dump-vars,P,X,VS) will expand to a list of 'file' commands that write each
+# variable to P in Makefile syntax, but with "last-X-" prepended. At the start
+# of the file, we also define last-X-vars-loaded to 1. You can use this to
+# check whether there was a dump file at all.
+#
+# Note that this doesn't work by expanding to a command. Instead, *evaluating*
+# dump-vars causes the variables to be dumped.
+dump-var  = $(file >>$(1),last-$(2)-$(3) := $($(3)))
+dump-vars = $(file >$(1),last-$(2)-vars-loaded := .) \
+            $(foreach name,$(3),$(call dump-var,$(1),$(2),$(name)))
+
+# equal checks whether two strings are equal, evaluating to '.' if they are and
+# '' otherwise.
+both-empty = $(if $(1),,$(if $(2),,.))
+find-find = $(if $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))),.,)
+equal = $(or $(call both-empty,$(1),$(2)),$(call find-find,$(1),$(2)))
+
+# var-differs is used to check whether a variable has changed since it was
+# dumped. If it has changed, the function evaluates to '.' (with some
+# whitespace) and prints a message to the console; if not, it evaluates to ''.
+#
+# Call it as $(call var-differs,X,TGT,V).
+var-differs = \
+  $(if $(call equal,$(strip $($(3))),$(strip $(last-$(1)-$(3)))),,\
+       .$(info Repeating $(2) because variable $(3) has changed value.))
+
+# vars-differ is used to check whether several variables have the same value as
+# they had when they were dumped. If we haven't loaded the dumpfile, it
+# silently evaluates to '!'. Otherwise, if all the variables match, it
+# evaluates to '.'. If not, it evaluates to '.' and prints some messages to the
+# console explaining why a rebuild is happening.
+#
+# Call it as $(call vars-differ,X,TGT,VS).
+vars-differ-lst = $(foreach v,$(3),$(call var-differs,$(1),$(2),$(v)))
+vars-differ-sp = \
+  $(if $(last-$(1)-vars-loaded),\
+       $(if $(strip $(call vars-differ-lst,$(1),$(2),$(3))),.,),\
+       !)
+vars-differ = $(strip $(call vars-differ-sp,$(1),$(2),$(3)))
+
+# A phony target which can be used to force recompilation.
+.PHONY: FORCE
+FORCE:
+
+# vars-prereq is empty if every variable in VS matches the last run (loaded
+# with tag X), otherwise it is set to FORCE (which will force a recompile and
+# might print a message to the console explaining why we're rebuilding TGT).
+#
+# Call it as $(call vars-prereq,X,TGT,VS)
+vars-prereq = $(if $(call vars-differ,$(1),$(2),$(3)),FORCE,)
+
+###############################################################################
+# Generate random instructions
+#
+# This depends on the vendored in code in $(GEN_DIR). It also depends on the
+# values of some variables (we want to regenerate things if, for example, the
+# simulator changes). Since we're writing out to $(OUT-SEED), we don't have to
+# depend on the value of SEED. However, we do have to make sure that the
+# variables whose names are listed in $(gen-var-deps) haven't changed.
+#
+# To do this variable tracking, we dump each of the variables to a Makefile
+# fragment and try to load it up the next time around.
+gen-var-deps := GEN_OPTS SIMULATOR RISCV_DV_OPTS CSR_OPTS \
+	            SIGNATURE_ADDR PMP_REGIONS PMP_GRANULARITY TEST_OPTS
+
+# Load up the generation stage's saved variable values. If this fails, that's
+# no problem: we'll assume that the previous run either doesn't exist or
+# something went wrong.
+-include $(metadata)/gen-vars.mk
+
+# gen-vars-prereq is empty if every variable in gen-var-deps matches the last run,
+# otherwise it is set to FORCE (which will force a recompile). Note that we
+# define it with '=', not ':=', so we don't evaluate it if we're not trying to
+# run the gen target.
+gen-vars-prereq = \
+  $(call vars-prereq,gen,building instruction generator,$(gen-var-deps))
+
+# A variable containing a file list for the riscv-dv vendored-in module.
+# Depending on these files gives a safe over-approximation that will ensure we
+# rebuild things if that module changes.
+#
+# Note that this is defined with ":=". As a result, we'll always run the find
+# command exactly once. Wasteful if we're trying to make clean, but much better
+# than running it for every target otherwise.
+risc-dv-files := $(shell find $(GEN_DIR) -type f)
+
+# This actually runs the instruction generator. Note that the rule depends on
+# the (phony) FORCE target if any variables have changed. If the rule actually
+# runs, it starts by deleting any existing contents of $(OUT-SEED)/instr_gen.
+$(metadata)/instr_gen.gen.stamp: \
+  $(gen-vars-prereq) $(risc-dv-files) | $(metadata)
+	@rm -rf $(OUT-SEED)/instr_gen
+	@python3 ${GEN_DIR}/run.py \
+     --output=$(OUT-SEED)/instr_gen ${GEN_OPTS} \
+     --steps=gen \
+     --gen_timeout=${TIMEOUT} \
+     --lsf_cmd="${LSF_CMD}" \
+     --simulator="${SIMULATOR}" \
+     ${RISCV_DV_OPTS} \
+     ${TEST_OPTS} \
+     ${CSR_OPTS} \
+     --sim_opts="+uvm_set_inst_override=riscv_asm_program_gen,ibex_asm_program_gen,"uvm_test_top.asm_gen" \
+                 +signature_addr=${SIGNATURE_ADDR} +pmp_num_regions=${PMP_REGIONS} \
+                 +pmp_granularity=${PMP_GRANULARITY}"
+	$(call dump-vars,$(metadata)/gen-vars.mk,gen,$(gen-var-deps))
+	@touch $@
+
+.PHONY: gen
+gen: $(metadata)/instr_gen.gen.stamp
+
+###############################################################################
+# Compile the generated assembly programs
+#
+# We don't explicitly track dependencies on the RISCV toolchain, so this
+# doesn't depend on anything more than the instr_gen stage did.
+$(metadata)/instr_gen.compile.stamp: $(metadata)/instr_gen.gen.stamp
+	@python3 ${GEN_DIR}/run.py \
+     --o=$(OUT-SEED)/instr_gen ${GEN_OPTS} \
+     --steps=gcc_compile \
+     ${TEST_OPTS} \
+     --gcc_opts=-mno-strict-align \
+     ${RISCV_DV_OPTS} && \
+	  touch $@
+
+.PHONY: gcc_compile
+gcc_compile: $(metadata)/instr_gen.compile.stamp
+
+###############################################################################
+# Run the instruction set simulator
+#
+# This (obviously) depends on having compiled the generated programs, so we
+# don't have to worry about variables that affect the 'gen' stage. However, the
+# ISS and ISS_OPTS variables do affect the output, so we need to dump them. See
+# the 'gen' stage for more verbose explanations of how this works.
+iss-var-deps := ISS ISS_OPTS
+-include $(metadata)/iss-vars.mk
+iss-vars-prereq = $(call vars-prereq,iss,running ISS,$(iss-var-deps))
+
+$(metadata)/instr_gen.iss.stamp: \
+  $(iss-vars-prereq) $(metadata)/instr_gen.compile.stamp
+	@python3 ${GEN_DIR}/run.py \
+     --o=$(OUT-SEED)/instr_gen ${GEN_OPTS} \
+     --steps=iss_sim \
+     ${TEST_OPTS} \
+     --iss="${ISS}" \
+     --iss_opts="${ISS_OPTS}" \
+     ${RISCV_DV_OPTS}
+	$(call dump-vars,$(metadata)/iss-vars.mk,iss,$(iss-var-deps))
+	@touch $@
+
+.PHONY: iss_sim
+iss_sim: $(metadata)/instr_gen.iss.stamp
+
+
+###############################################################################
+# Compile ibex core TB
+#
+# Note that (unlike everything else) this doesn't depend on the seed: the DUT
+# doesn't depend on which test we're running!
+#
+# It does, however, depend on various variables. These are listed in
+# compile-var-deps. See the 'gen' stage for more verbose explanations of how
+# the variable dumping works.
+#
+# The compiled ibex testbench (obviously!) also depends on the design and the
+# DV code. The clever way of doing this would be to look at a dependency
+# listing generated by the simulator as a side-effect of doing the compile (a
+# bit like using the -M flags with a C compiler). Unfortunately, that doesn't
+# look like it's particularly easy, so we'll just depend on every .v, .sv or
+# .svh file in the dv or rtl directories. Note that this variable is set with
+# '=', rather than ':='. This means that we don't bother running the find
+# commands unless we need the compiled testbench.
+all-verilog = \
+  $(shell find ../../../rtl -name '*.v' -o -name '*.sv' -o -name '*.svh') \
+  $(shell find ../.. -name '*.v' -o -name '*.sv' -o -name '*.svh')
+
+compile-var-deps := COMMON_OPTS SIMULATOR COV WAVES COMPILE_OPTS
+-include $(OUT)/rtl_sim/.compile-vars.mk
+compile-vars-prereq = $(call vars-prereq,comp,compiling TB,$(compile-var-deps))
+
+$(call dump-vars-match,$(compile-var-deps),comp)
+
+$(OUT)/rtl_sim/.compile.stamp: \
+  $(compile-vars-prereq) $(all-verilog) $(risc-dv-files) | $(OUT)/rtl_sim
+	@python3 ./sim.py \
+     --o=${OUT} \
+     --riscv_dv_root=${GEN_DIR} \
+     --steps=compile \
+     ${COMMON_OPTS} \
+     --simulator="${SIMULATOR}" \
+     --en_cov=${COV} \
+     --en_wave=${WAVES} \
+     --cmp_opts="${COMPILE_OPTS}"
+	$(call dump-vars,$(OUT)/rtl_sim/.compile-vars.mk,comp,$(compile-var-deps))
+	@touch $@
+
+.PHONY: compile
+compile: $(OUT)/rtl_sim/.compile.stamp
+
+###############################################################################
+# Run ibex RTL simulation with generated programs
+#
+# Because we compile a TB once rather than for each seed, we have to copy in
+# that directory before we start. We make this step (rather than actually
+# running the test) dependent on having the right variables. That way, we'll
+# correctly delete the sim directory and re-copy it if necessary.
+#
+# Note that the variables we depend on are gen-vars-prereq. We also depend on
+# COV and WAVES, but these dependencies will come for free from the dependency
+# on the compiled TB.
+$(metadata)/rtl_sim.compile.stamp: \
+  $(gen-vars-prereq) $(risc-dv-files) $(OUT)/rtl_sim/.compile.stamp
+	rm -rf $(OUT-SEED)/rtl_sim
+	cp -r $(OUT)/rtl_sim $(OUT-SEED)
+	@touch $@
+
+# This rule actually runs the simulation. It depends on the copied-in testbench
+# and also on us having already compiled the test programs.
+$(metadata)/rtl_sim.run.stamp: \
+  $(metadata)/rtl_sim.compile.stamp $(metadata)/instr_gen.compile.stamp
+	@python3 ./sim.py \
+     --o=$(OUT-SEED) \
+     --riscv_dv_root=${GEN_DIR} \
+     --steps=sim \
+     ${TEST_OPTS} \
+     --simulator="${SIMULATOR}" \
+     --en_cov ${COV} \
+     --en_wave ${WAVES} \
+     --lsf_cmd="${LSF_CMD}" \
+     --sim_opts="+signature_addr=${SIGNATURE_ADDR}" \
+     ${SIM_OPTS}
+	@touch $@
+
+.PHONY: rtl_sim
+rtl_sim: $(metadata)/rtl_sim.run.stamp
+
+###############################################################################
+# Compare ISS and RTL sim results
+$(OUT-SEED)/regr.log: \
+  $(metadata)/instr_gen.iss.stamp \
+  $(metadata)/rtl_sim.run.stamp
+	@rm -f $@
+	@python3 ./sim.py \
+     --o=$(OUT-SEED) \
+     --steps=compare \
+     ${TEST_OPTS} \
+     --simulator="${SIMULATOR}" \
+     --iss="${ISS}"
+
+.PHONY: post_compare
+post_compare: $(OUT-SEED)/regr.log
+
+###############################################################################
+# Generate functional coverage
+fcov:
+	python3 ${GEN_DIR}/cov.py \
+          --core ibex \
+          --dir ${OUT}/rtl_sim \
+          -o ${OUT}/fcov \
+          --isa rv32imc \
+          --custom_target ${DV_DIR}/riscv_dv_extension \
+
+# Load verdi to review coverage
+cov_vcs:
+	cd ${OUT}/rtl_sim; verdi -cov -covdir test.vdb &
+
+cov_ius:
+	if [ ! -d "${OUT}/rtl_sim/cov_work/scope/merged_cov" ]; \
+	  then imc -execcmd "merge -out ${OUT}/rtl_sim/cov_work/scope/merged_cov ${OUT}/rtl_sim/cov_work/scope/test_*"; \
+    fi
+	imc -load ${OUT}/rtl_sim/cov_work/scope/merged_cov &
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_master_agent.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_master_agent.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_master_agent.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_master_agent.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_master_driver.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_master_driver.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_master_driver.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_master_driver.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_monitor.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_monitor.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_monitor.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_monitor.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_seq_item.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_seq_item.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_seq_item.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_seq_item.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_agent.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_slave_agent.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_agent.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_slave_agent.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_driver.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_slave_driver.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_driver.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_slave_driver.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_seq_lib.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_slave_seq_lib.sv
similarity index 98%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_seq_lib.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_slave_seq_lib.sv
index 681332b..7da6780 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_seq_lib.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_slave_seq_lib.sv
@@ -84,7 +84,7 @@
     end
   endtask : body
 
-  virtual function inject_error();
+  virtual function void inject_error();
     this.enable_error = 1'b1;
   endfunction
 
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_sequencer.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_slave_sequencer.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_sequencer.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_slave_sequencer.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_agent_pkg.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_agent_pkg.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_agent_pkg.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_agent_pkg.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_if.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_if.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_if.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_if.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_master_agent.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_master_agent.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_master_agent.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_master_agent.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_master_driver.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_master_driver.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_master_driver.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_master_driver.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_monitor.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_monitor.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_monitor.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_monitor.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_seq_item.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_seq_item.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/irq_agent/irq_seq_item.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/irq_agent/irq_seq_item.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/mem_model/mem_model.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/mem_model/mem_model.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/mem_model/mem_model.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/mem_model/mem_model.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/mem_model/mem_model_pkg.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/mem_model/mem_model_pkg.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/mem_model/mem_model_pkg.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/mem_model/mem_model_pkg.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/utils/clk_if.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/utils/clk_if.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/utils/clk_if.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/utils/clk_if.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/utils/dv_macros.svh b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/utils/dv_macros.svh
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/utils/dv_macros.svh
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/utils/dv_macros.svh
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/common/utils/dv_utils_pkg.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/utils/dv_utils_pkg.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/common/utils/dv_utils_pkg.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/common/utils/dv_utils_pkg.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/cover.ccf b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/cover.ccf
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/cover.ccf
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/cover.ccf
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/cover.cfg b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/cover.cfg
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/cover.cfg
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/cover.cfg
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_csr_if.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_csr_if.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_csr_if.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_csr_if.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_dut_probe_if.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_dut_probe_if.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_env.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_env.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_cfg.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_env_cfg.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_cfg.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_env_cfg.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_pkg.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_env_pkg.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_pkg.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_env_pkg.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_rvfi_if.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_rvfi_if.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_vseqr.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_vseqr.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_vseqr.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/env/core_ibex_vseqr.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/ibex_dv.f b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/ibex_dv.f
new file mode 100644
index 0000000..d25ae42
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/ibex_dv.f
@@ -0,0 +1,54 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Boot address specified in decimal to avoid single quote in number, which
+// causes parsing errors of this file in Riviera.
++define+BOOT_ADDR=2147483648 // 32'h8000_0000
++define+TRACE_EXECUTION
++define+RVFI
++incdir+${PRJ_DIR}/ibex/shared/rtl
+
+${PRJ_DIR}/ibex/shared/rtl/prim_clock_gating.sv
+
+// ibex CORE RTL files
++incdir+${PRJ_DIR}/ibex/rtl
+${PRJ_DIR}/ibex/shared/rtl/prim_assert.sv
+${PRJ_DIR}/ibex/rtl/ibex_pkg.sv
+${PRJ_DIR}/ibex/rtl/ibex_tracer_pkg.sv
+${PRJ_DIR}/ibex/rtl/ibex_tracer.sv
+${PRJ_DIR}/ibex/rtl/ibex_alu.sv
+${PRJ_DIR}/ibex/rtl/ibex_compressed_decoder.sv
+${PRJ_DIR}/ibex/rtl/ibex_controller.sv
+${PRJ_DIR}/ibex/rtl/ibex_cs_registers.sv
+${PRJ_DIR}/ibex/rtl/ibex_counters.sv
+${PRJ_DIR}/ibex/rtl/ibex_decoder.sv
+${PRJ_DIR}/ibex/rtl/ibex_ex_block.sv
+${PRJ_DIR}/ibex/rtl/ibex_id_stage.sv
+${PRJ_DIR}/ibex/rtl/ibex_if_stage.sv
+${PRJ_DIR}/ibex/rtl/ibex_load_store_unit.sv
+${PRJ_DIR}/ibex/rtl/ibex_multdiv_slow.sv
+${PRJ_DIR}/ibex/rtl/ibex_multdiv_fast.sv
+${PRJ_DIR}/ibex/rtl/ibex_prefetch_buffer.sv
+${PRJ_DIR}/ibex/rtl/ibex_fetch_fifo.sv
+${PRJ_DIR}/ibex/rtl/ibex_register_file_ff.sv
+${PRJ_DIR}/ibex/rtl/ibex_pmp.sv
+${PRJ_DIR}/ibex/rtl/ibex_core.sv
+${PRJ_DIR}/ibex/rtl/ibex_core_tracing.sv
+
+// Core DV files
+${PRJ_DIR}/ibex/vendor/google_riscv-dv/src/riscv_signature_pkg.sv
++incdir+${PRJ_DIR}/ibex/dv/uvm/core_ibex/env
++incdir+${PRJ_DIR}/ibex/dv/uvm/core_ibex/tests
++incdir+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent
++incdir+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/irq_agent
++incdir+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/mem_model
++incdir+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/utils
+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/utils/clk_if.sv
+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/utils/dv_utils_pkg.sv
+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/mem_model/mem_model_pkg.sv
+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv
+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/irq_agent/irq_agent_pkg.sv
+${PRJ_DIR}/ibex/dv/uvm/core_ibex/env/core_ibex_env_pkg.sv
+${PRJ_DIR}/ibex/dv/uvm/core_ibex/tests/core_ibex_test_pkg.sv
+${PRJ_DIR}/ibex/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/ius.tcl b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/ius.tcl
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/ius.tcl
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/ius.tcl
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/cov_testlist.yaml b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/cov_testlist.yaml
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/cov_testlist.yaml
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/cov_testlist.yaml
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/csr_description.yaml b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/csr_description.yaml
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/csr_description.yaml
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/csr_description.yaml
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_asm_program_gen.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/ibex_asm_program_gen.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_asm_program_gen.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/ibex_asm_program_gen.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/ibex_log_to_trace_csv.py b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/ibex_log_to_trace_csv.py
new file mode 100644
index 0000000..329556f
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/ibex_log_to_trace_csv.py
@@ -0,0 +1,200 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+#
+# Convert ibex log to the standard trace CSV format
+
+import argparse
+import os
+import re
+import sys
+
+_IBEX_ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__),
+                                           '../../../..'))
+_DV_SCRIPTS = os.path.join(_IBEX_ROOT, 'vendor/google_riscv-dv/scripts')
+_OLD_SYS_PATH = sys.path
+
+# Import riscv_trace_csv and lib from _DV_SCRIPTS before putting sys.path back
+# as it started.
+try:
+    sys.path.insert(0, _DV_SCRIPTS)
+
+    from riscv_trace_csv import (RiscvInstructionTraceCsv,
+                                 RiscvInstructionTraceEntry,
+                                 get_imm_hex_val)
+    from lib import RET_FATAL, gpr_to_abi, sint_to_hex
+    import logging
+
+finally:
+    sys.path = _OLD_SYS_PATH
+
+
+INSTR_RE = \
+    re.compile(r"^\s*(?P<time>\d+)\s+(?P<cycle>\d+)\s+(?P<pc>[0-9a-f]+)\s+"
+               r"(?P<bin>[0-9a-f]+)\s+(?P<instr>\S+\s+\S+)\s*")
+RD_RE = re.compile(r"(x(?P<rd>[1-9]\d*)=0x(?P<rd_val>[0-9a-f]+))")
+ADDR_RE = re.compile(r"(?P<imm>[\-0-9]+?)\((?P<rs1>.*)\)")
+
+
+def _process_ibex_sim_log_fd(log_fd, csv_fd, full_trace=True):
+    """Process ibex simulation log.
+
+    Reads from log_fd, which should be a file object containing a trace from an
+    Ibex simulation. Writes in a standard CSV format to csv_fd, which should be
+    a file object opened for writing.
+
+    If full_trace is true, this dumps information about operands for, replacing
+    absolute branch destinations with offsets relative to the current pc.
+
+    """
+    instr_cnt = 0
+
+    trace_csv = RiscvInstructionTraceCsv(csv_fd)
+    trace_csv.start_new_trace()
+
+    trace_entry = None
+
+    for line in log_fd:
+        if re.search("ecall", line):
+            break
+
+        # Extract instruction information
+        m = INSTR_RE.search(line)
+        if m:
+            instr_cnt += 1
+            # Write the extracted instruction to a csvcol buffer file
+            trace_entry = RiscvInstructionTraceEntry()
+            trace_entry.instr_str = m.group("instr")
+            trace_entry.instr = m.group("instr").split()[0]
+            trace_entry.pc = m.group("pc")
+            trace_entry.binary = m.group("bin")
+            if full_trace:
+                trace_entry.operand = m.group("instr").split()[1]
+                process_trace(trace_entry)
+
+        c = RD_RE.search(line)
+        if c:
+            trace_entry.gpr.append('{}:{}'
+                                   .format(gpr_to_abi("x%0s" % c.group("rd")),
+                                           c.group("rd_val")))
+            trace_csv.write_trace_entry(trace_entry)
+
+    return instr_cnt
+
+
+def process_ibex_sim_log(ibex_log, csv, full_trace=1):
+    """Process ibex simulation log.
+
+    Extract instruction and affected register information from ibex simulation
+    log and save to a standard CSV format.
+    """
+    logging.info("Processing ibex log : %s" % ibex_log)
+    with open(ibex_log, "r") as log_fd, open(csv, "w") as csv_fd:
+        count = _process_ibex_sim_log_fd(log_fd, csv_fd,
+                                         True if full_trace else False)
+
+    logging.info("Processed instruction count : %d" % count)
+    if not count:
+        logging.error("No instructions in logfile: %s" % ibex_log)
+        sys.exit(RET_FATAL)
+
+    logging.info("CSV saved to : %s" % csv)
+
+
+def process_trace(trace):
+    """ Process instruction trace """
+    process_imm(trace)
+    if trace.instr == 'jalr':
+        n = ADDR_RE.search(trace.operand)
+        if n:
+            trace.imm = get_imm_hex_val(n.group("imm"))
+
+
+def process_imm(trace):
+    """Process imm to follow RISC-V standard convention"""
+    if trace.instr in ['beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu', 'c.beqz',
+                       'c.bnez', 'beqz', 'bnez', 'bgez', 'bltz', 'blez',
+                       'bgtz', 'c.j', 'j', 'c.jal', 'jal']:
+        idx = trace.operand.rfind(',')
+        if idx == -1:
+            imm = trace.operand
+            imm = str(sint_to_hex(int(imm, 16) - int(trace.pc, 16)))
+            trace.operand = imm
+        else:
+            imm = trace.operand[idx + 1:]
+            imm = str(sint_to_hex(int(imm, 16) - int(trace.pc, 16)))
+            trace.operand = trace.operand[0:idx + 1] + imm
+
+
+def check_ibex_uvm_log(uvm_log, core_name, test_name, report, write=True):
+    """Process Ibex UVM simulation log.
+
+    This function will be used when a test disables the normal post_compare
+    step. Process the UVM simulation log produced by the test to check for
+    correctness
+
+    Args:
+      uvm_log: the uvm simulation log
+      core_name: the name of the core
+      test_name: name of the test being checked
+      report: the output report file
+      write: enables writing to the log file
+
+    Returns:
+      A boolean indicating whether the test passed or failed based on the
+      signature
+
+    """
+    passed = False
+    failed = False
+
+    with open(uvm_log, "r") as log:
+        for line in log:
+            if 'RISC-V UVM TEST PASSED' in line:
+                passed = True
+
+            if 'RISC-V UVM TEST FAILED' in line:
+                failed = True
+                break
+
+    # If we saw PASSED and FAILED, that's a bit odd. But we should treat the
+    # test as having failed.
+    if failed:
+        passed = False
+
+    if write:
+        fd = open(report, "a+") if report else sys.stdout
+
+        fd.write("%s uvm log : %s\n" % (core_name, uvm_log))
+        if passed:
+            fd.write("%s : [PASSED]\n\n" % test_name)
+        elif failed:
+            fd.write("%s : [FAILED]\n\n" % test_name)
+
+        if report:
+            fd.close()
+
+    return passed
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument("--log",
+                        help="Input ibex simulation log (default: stdin)",
+                        type=argparse.FileType('r'),
+                        default=sys.stdin)
+    parser.add_argument("--csv",
+                        help="Output trace csv file (default: stdout)",
+                        type=argparse.FileType('w'),
+                        default=sys.stdout)
+    parser.add_argument("--full_trace", type=int, default=1,
+                        help="Enable full log trace")
+
+    args = parser.parse_args()
+
+    _process_ibex_sim_log_fd(args.log, args.csv,
+                             True if args.full_trace else False)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ml_testlist.yaml b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/ml_testlist.yaml
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ml_testlist.yaml
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/ml_testlist.yaml
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/riscvOVPsim.ic b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/riscvOVPsim.ic
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/riscvOVPsim.ic
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/riscvOVPsim.ic
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/riscv_core_setting.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/riscv_core_setting.sv
similarity index 97%
rename from hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/riscv_core_setting.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/riscv_core_setting.sv
index 174d19f..2b751a9 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/riscv_core_setting.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/riscv_core_setting.sv
@@ -26,6 +26,9 @@
 parameter int ELEN = 64;
 parameter int SLEN = 64;
 
+// Number of harts
+parameter int NUM_HARTS = 1;
+
 // Parameter for SATP mode, set to BARE if address translation is not supported
 parameter satp_mode_t SATP_MODE = BARE;
 
@@ -50,6 +53,9 @@
 // supported
 int max_interrupt_vector_num = 32;
 
+// Physical memory protection support
+bit support_pmp = 1;
+
 // Debug mode support
 bit support_debug_mode = 1;
 
@@ -64,7 +70,7 @@
 //-----------------------------------------------------------------------------
 
 // Number of kernel data pages
-int num_of_kernel_data_pages = 2;
+int num_of_kernel_data_pages = 0;
 
 // Byte size of kernel data pages
 int kernel_data_page_size = 4096;
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml
similarity index 98%
rename from hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml
index 85fe687..6325772 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/testlist.yaml
@@ -320,7 +320,7 @@
     +gen_debug_section=1
     +enable_interrupt=1
     +randomize_csr=1
-    no_csr_instr=1
+    +no_csr_instr=1
     +no_fence=1
   rtl_test: core_ibex_debug_in_irq_test
   sim_opts: >
@@ -574,3 +574,13 @@
   rtl_test: core_ibex_invalid_csr_test
   sim_opts: >
     +require_signature_addr=1
+
+- test: riscv_pmp_test
+  desc: >
+    Random PMP settings
+  iterations: 1
+  gen_test: riscv_rand_instr_test
+  gen_opts: >
+    +instr_cnt=6000
+    +num_of_sub_program=2
+  rtl_test: core_ibex_base_test
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/user_extension.svh b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/user_extension.svh
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/user_extension.svh
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/riscv_dv_extension/user_extension.svh
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/sim.py b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/sim.py
similarity index 92%
rename from hw/vendor/lowrisc_ibex/dv/uvm/sim.py
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/sim.py
index d93fc7e..6321fc0 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/sim.py
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/sim.py
@@ -23,7 +23,7 @@
 import subprocess
 import sys
 
-sys.path.insert(0, "../../vendor/google_riscv-dv/scripts")
+sys.path.insert(0, "../../../vendor/google_riscv-dv/scripts")
 sys.path.insert(0, "./riscv_dv_extension")
 
 from lib import *
@@ -93,12 +93,11 @@
   sys.exit(1)
 
 
-def rtl_compile(compile_cmd, test_list, output_dir, lsf_cmd, opts):
+def rtl_compile(compile_cmd, output_dir, lsf_cmd, opts):
   """Run the instruction generator
 
   Args:
     compile_cmd : Compile command
-    test_list   : List of assembly programs to be compiled
     output_dir  : Output directory of the ELF files
     lsf_cmd     : LSF command to run compilation
     opts        : Compile options for the generator
@@ -267,26 +266,36 @@
 bin_dir = ("%s/instr_gen/asm_tests" % args.o)
 subprocess.run(["mkdir", "-p", output_dir])
 
-# Process regression test list
-matched_list = []
-process_regression_list(args.testlist, args.test, args.iterations,
-                        matched_list, args.riscv_dv_root)
-if len(matched_list) == 0:
-  sys.exit("Cannot find %s in %s" % (args.test, args.testlist))
+steps = {
+  'compile': args.steps == "all" or re.match("compile", args.steps),
+  'sim': args.steps == "all" or re.match("sim", args.steps),
+  'compare': args.steps == "all" or re.match("compare", args.steps)
+}
 
 compile_cmd = []
 sim_cmd = ""
-compile_cmd, sim_cmd = get_simulator_cmd(args.simulator, args.simulator_yaml,
-                                         args.en_cov, args.en_wave)
+matched_list = []
+if steps['compile'] or steps['sim']:
+  compile_cmd, sim_cmd = get_simulator_cmd(args.simulator, args.simulator_yaml,
+                                           args.en_cov, args.en_wave)
+if steps['sim'] or steps['compare']:
+  process_regression_list(args.testlist, args.test, args.iterations,
+                          matched_list, args.riscv_dv_root)
+  if not matched_list:
+    sys.exit("Cannot find %s in %s" % (args.test, args.testlist))
+
+
 # Compile TB
-if args.steps == "all" or re.match("compile", args.steps):
-  rtl_compile(compile_cmd, matched_list, output_dir, args.lsf_cmd, args.cmp_opts)
+if steps['compile']:
+  rtl_compile(compile_cmd, output_dir, args.lsf_cmd, args.cmp_opts)
+
 
 # Run RTL simulation
-if args.steps == "all" or re.match("sim", args.steps):
+if steps['sim']:
   rtl_sim(sim_cmd, args.simulator, matched_list, output_dir, bin_dir,
           args.lsf_cmd, args.seed, args.sim_opts)
 
+
 # Compare RTL & ISS simulation result.;
-if args.steps == "all" or re.match("compare", args.steps):
+if steps['compare']:
   compare(matched_list, args.iss, args.o, args.verbose)
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tb/core_ibex_tb_top.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv
similarity index 89%
rename from hw/vendor/lowrisc_ibex/dv/uvm/tb/core_ibex_tb_top.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv
index fb8f9c2..331088b 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/tb/core_ibex_tb_top.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv
@@ -27,7 +27,8 @@
   core_ibex_csr_if csr_if(.clk(clk));
 
   ibex_core_tracing #(.DmHaltAddr(`BOOT_ADDR + 'h0),
-                      .DmExceptionAddr(`BOOT_ADDR + 'h4)) dut (
+                      .DmExceptionAddr(`BOOT_ADDR + 'h4),
+                      .PMPEnable(1'b1)) dut (
     .clk_i(clk),
     .rst_ni(rst_n),
     .test_en_i(1'b1),
@@ -40,32 +41,33 @@
     .irq_nm_i(irq_vif.irq_nm),
     .fetch_enable_i(dut_if.fetch_enable),
     .debug_req_i(dut_if.debug_req),
+    .data_req_o(data_mem_vif.request),
     .data_gnt_i(data_mem_vif.grant),
     .data_rvalid_i(data_mem_vif.rvalid),
+    .data_addr_o(data_mem_vif.addr),
+    .data_we_o(data_mem_vif.we),
+    .data_be_o(data_mem_vif.be),
     .data_rdata_i(data_mem_vif.rdata),
+    .data_wdata_o(data_mem_vif.wdata),
     .data_err_i(data_mem_vif.error),
+    .instr_req_o(instr_mem_vif.request),
     .instr_gnt_i(instr_mem_vif.grant),
     .instr_rvalid_i(instr_mem_vif.rvalid),
+    .instr_addr_o(instr_mem_vif.addr),
     .instr_rdata_i(instr_mem_vif.rdata),
-    .instr_err_i(instr_mem_vif.error)
+    .instr_err_i(instr_mem_vif.error),
+    .core_sleep_o(dut_if.core_sleep)
   );
 
   // Data load/store vif connection
   assign data_mem_vif.clock     = clk;
   assign data_mem_vif.reset     = ~rst_n;
-  assign data_mem_vif.request   = dut.data_req_o;
-  assign data_mem_vif.we        = dut.data_we_o;
-  assign data_mem_vif.be        = dut.data_be_o;
-  assign data_mem_vif.addr      = dut.data_addr_o;
-  assign data_mem_vif.wdata     = dut.data_wdata_o;
   // Instruction fetch vif connnection
   assign instr_mem_vif.clock    = clk;
   assign instr_mem_vif.reset    = ~rst_n;
-  assign instr_mem_vif.request  = dut.instr_req_o;
   assign instr_mem_vif.we       = 0;
   assign instr_mem_vif.be       = 0;
   assign instr_mem_vif.wdata    = 0;
-  assign instr_mem_vif.addr     = dut.instr_addr_o;
   // RVFI interface connections
   assign rvfi_if.valid          = dut.rvfi_valid;
   assign rvfi_if.order          = dut.rvfi_order;
@@ -95,7 +97,6 @@
   assign dut_if.illegal_instr   = dut.u_ibex_core.id_stage_i.illegal_insn_dec;
   assign dut_if.dret            = dut.u_ibex_core.id_stage_i.dret_insn_dec;
   assign dut_if.mret            = dut.u_ibex_core.id_stage_i.mret_insn_dec;
-  assign dut_if.core_sleep      = dut.u_ibex_core.core_sleep_o;
   assign dut_if.reset           = ~rst_n;
   assign dut_if.priv_mode       = dut.u_ibex_core.priv_mode_id;
   // CSR interface connections
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_base_test.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_base_test.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_base_test.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_base_test.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_report_server.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_report_server.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_report_server.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_report_server.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_seq_lib.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_seq_lib.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_seq_lib.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_seq_lib.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_lib.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv
similarity index 99%
rename from hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_lib.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv
index c800a9d..10f60af 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_lib.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv
@@ -186,11 +186,11 @@
   endfunction
 
   virtual task wait_for_core_setup();
-    wait_for_csr_write(CSR_MSTATUS, 1000);
+    wait_for_csr_write(CSR_MSTATUS, 10000);
     core_init_mstatus = signature_data;
     // capture the initial privilege mode ibex will boot into
     init_operating_mode = priv_lvl_e'(core_init_mstatus[12:11]);
-    wait_for_csr_write(CSR_MIE, 500);
+    wait_for_csr_write(CSR_MIE, 5000);
     core_init_mie = signature_data;
     check_next_core_status(INITIALIZED, "Core initialization handshake failure", 500);
   endtask
@@ -438,7 +438,7 @@
   endtask
 
   // compares dcsr.ebreak against the privilege mode encoded in dcsr.prv
-  virtual function check_dcsr_ebreak();
+  virtual function void check_dcsr_ebreak();
     // dcsr.prv is the bottom two bits.
     case (signature_data[1:0])
       2'b11: begin
@@ -456,7 +456,7 @@
     endcase
   endfunction
 
-  virtual function check_dcsr_cause(dbg_cause_e cause);
+  virtual function void check_dcsr_cause(dbg_cause_e cause);
     `DV_CHECK_EQ_FATAL(cause, signature_data[8:6], "dcsr.cause has been incorrectly updated")
   endfunction
 
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_pkg.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_test_pkg.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_pkg.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_test_pkg.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_vseq.sv b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_vseq.sv
similarity index 100%
rename from hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_vseq.sv
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/tests/core_ibex_vseq.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/vcs.tcl b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/vcs.tcl
new file mode 100644
index 0000000..730d0d4
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/vcs.tcl
@@ -0,0 +1,36 @@
+# TCL file invoked from VCS's simv at run-time using this: -ucli -do <this file>
+
+if { [info exists ::env(VERDI_HOME)] } {
+	# Use FSDB for dumping data, but only if we have Verdi set up.
+
+	# Syntax: fsdbDumpfile FSDB_Name [Limit_Size]
+	fsdbDumpfile "waves.fsdb"
+
+	# Syntax: fsdbDumpvars [depth] [instance] [option]*
+	##############################################################################
+	# Option                     Description
+	##############################################################################
+	# +mda                       Dumps memory and MDA signals in all scopes.
+	# +packedmda                 Dumps packed signals
+	# +struct                    Dumps structs
+	# +skip_cell_instance=mode  Enables or disables cell dumping
+	# +strength                  Enables strength dumping
+	# +parameter                 Dumps parameters
+	# +power                     Dumps power-related signals
+	# +trace_process             Dumps VHDL processes
+	# +no_functions              Disables dumping of functions
+	# +sva                       Dumps assertions
+	# +Reg_Only                  Dumps only reg type signals
+	# +IO_Only                   Dumps only IO port signals
+	# +by_file=<filename>        File to specify objects to add
+	# +all                       Dumps memories, MDA signals, structs, unions,power, and packed structs
+	fsdbDumpvars 0 core_ibex_tb_top +all
+	fsdbDumpSVA 0 core_ibex_tb_top.dut
+} else {
+	# We don't have VERDI set up, so use VCS's standard dumping format.
+	dump -file "waves.vpd"
+	dump -add { core_ibex_tb_top } -depth 0 -aggregates -scope "."
+}
+
+run
+quit
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/yaml/rtl_simulation.yaml
similarity index 98%
rename from hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml
rename to hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/yaml/rtl_simulation.yaml
index ff30d68..bb6be56 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/core_ibex/yaml/rtl_simulation.yaml
@@ -19,6 +19,7 @@
          -l <out>/compile.log
          -sverilog -ntb_opts uvm-1.2
          +define+UVM_REGEX_NO_DPI -timescale=1ns/10ps -licqueue
+         -LDFLAGS '-Wl,--no-as-needed'
          -Mdir=<out>/vcs_simv.csrc
          -o <out>/vcs_simv
          -debug_access+pp
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f b/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f
deleted file mode 100644
index 56b5e46..0000000
--- a/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-// Boot address specified in decimal to avoid single quote in number, which
-// causes parsing errors of this file in Riviera.
-+define+BOOT_ADDR=2147483648 // 32'h8000_0000
-+define+TRACE_EXECUTION
-+define+RVFI
-+incdir+${PRJ_DIR}/ibex/shared/rtl
-
-${PRJ_DIR}/ibex/shared/rtl/prim_clock_gating.sv
-
-// ibex CORE RTL files
-+incdir+${PRJ_DIR}/ibex/rtl
-${PRJ_DIR}/ibex/shared/rtl/prim_assert.sv
-${PRJ_DIR}/ibex/rtl/ibex_pkg.sv
-${PRJ_DIR}/ibex/rtl/ibex_tracer_pkg.sv
-${PRJ_DIR}/ibex/rtl/ibex_tracer.sv
-${PRJ_DIR}/ibex/rtl/ibex_alu.sv
-${PRJ_DIR}/ibex/rtl/ibex_compressed_decoder.sv
-${PRJ_DIR}/ibex/rtl/ibex_controller.sv
-${PRJ_DIR}/ibex/rtl/ibex_cs_registers.sv
-${PRJ_DIR}/ibex/rtl/ibex_decoder.sv
-${PRJ_DIR}/ibex/rtl/ibex_ex_block.sv
-${PRJ_DIR}/ibex/rtl/ibex_id_stage.sv
-${PRJ_DIR}/ibex/rtl/ibex_if_stage.sv
-${PRJ_DIR}/ibex/rtl/ibex_load_store_unit.sv
-${PRJ_DIR}/ibex/rtl/ibex_multdiv_slow.sv
-${PRJ_DIR}/ibex/rtl/ibex_multdiv_fast.sv
-${PRJ_DIR}/ibex/rtl/ibex_prefetch_buffer.sv
-${PRJ_DIR}/ibex/rtl/ibex_fetch_fifo.sv
-${PRJ_DIR}/ibex/rtl/ibex_register_file_ff.sv
-${PRJ_DIR}/ibex/rtl/ibex_core.sv
-${PRJ_DIR}/ibex/rtl/ibex_core_tracing.sv
-
-// Core DV files
-${PRJ_DIR}/ibex/vendor/google_riscv-dv/src/riscv_signature_pkg.sv
-+incdir+${PRJ_DIR}/ibex/dv/uvm/env
-+incdir+${PRJ_DIR}/ibex/dv/uvm/tests
-+incdir+${PRJ_DIR}/ibex/dv/uvm/common/ibex_mem_intf_agent
-+incdir+${PRJ_DIR}/ibex/dv/uvm/common/irq_agent
-+incdir+${PRJ_DIR}/ibex/dv/uvm/common/mem_model
-+incdir+${PRJ_DIR}/ibex/dv/uvm/common/utils
-${PRJ_DIR}/ibex/dv/uvm/common/utils/clk_if.sv
-${PRJ_DIR}/ibex/dv/uvm/common/utils/dv_utils_pkg.sv
-${PRJ_DIR}/ibex/dv/uvm/common/mem_model/mem_model_pkg.sv
-${PRJ_DIR}/ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv
-${PRJ_DIR}/ibex/dv/uvm/common/irq_agent/irq_agent_pkg.sv
-${PRJ_DIR}/ibex/dv/uvm/env/core_ibex_env_pkg.sv
-${PRJ_DIR}/ibex/dv/uvm/tests/core_ibex_test_pkg.sv
-${PRJ_DIR}/ibex/dv/uvm/tb/core_ibex_tb_top.sv
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py
deleted file mode 100644
index ac5bd07..0000000
--- a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py
+++ /dev/null
@@ -1,146 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-#
-# Convert ibex log to the standard trace CSV format
-
-import argparse
-import re
-import sys
-
-sys.path.insert(0, "../../vendor/google_riscv-dv/scripts")
-
-from riscv_trace_csv import *
-from lib import *
-
-
-INSTR_RE = re.compile(r"^\s*(?P<time>\d+)\s+(?P<cycle>\d+)\s+(?P<pc>[0-9a-f]+)\s+" \
-                      "(?P<bin>[0-9a-f]+)\s+(?P<instr>\S+\s+\S+)\s*")
-RD_RE = re.compile(r"(x(?P<rd>[1-9]\d*)=0x(?P<rd_val>[0-9a-f]+))")
-ADDR_RE  = re.compile(r"(?P<imm>[\-0-9]+?)\((?P<rs1>.*)\)")
-
-
-def process_ibex_sim_log(ibex_log, csv, full_trace = 1):
-  """Process ibex simulation log.
-
-  Extract instruction and affected register information from ibex simulation
-  log and save to a standard CSV format.
-  """
-  logging.info("Processing ibex log : %s" % ibex_log)
-  instr_cnt = 0
-  ibex_instr = ""
-
-  with open(ibex_log, "r") as f, open(csv, "w") as csv_fd:
-    trace_csv = RiscvInstructionTraceCsv(csv_fd)
-    trace_csv.start_new_trace()
-    for line in f:
-      if re.search("ecall", line):
-        break
-      # Extract instruction information
-      m = INSTR_RE.search(line)
-      if m:
-        instr_cnt += 1
-        # Write the extracted instruction to a csvcol buffer file
-        rv_instr_trace = RiscvInstructionTraceEntry()
-        rv_instr_trace.instr_str = m.group("instr")
-        rv_instr_trace.instr = m.group("instr").split()[0]
-        rv_instr_trace.pc = m.group("pc")
-        rv_instr_trace.binary = m.group("bin")
-        if full_trace:
-          rv_instr_trace.operand = m.group("instr").split()[1]
-          process_trace(rv_instr_trace)
-      c = RD_RE.search(line)
-      if c:
-        rv_instr_trace.gpr.append(gpr_to_abi("x%0s" % c.group("rd")) + ":" + c.group("rd_val"))
-        trace_csv.write_trace_entry(rv_instr_trace)
-
-  logging.info("Processed instruction count : %d" % instr_cnt)
-  if instr_cnt == 0:
-    logging.error("No instructions in logfile: %s" % ibex_log)
-    sys.exit(RET_FATAL)
-  logging.info("CSV saved to : %s" % csv)
-
-
-def process_trace(trace):
-  """ Process instruction trace """
-  process_imm(trace)
-  if trace.instr == 'jalr':
-    n = ADDR_RE.search(trace.operand)
-    if n:
-      trace.imm = get_imm_hex_val(n.group("imm"))
-
-
-def process_imm(trace):
-  """ Process imm to follow RISC-V standard convention """
-  if trace.instr in ['beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu', 'c.beqz',
-                     'c.bnez', 'beqz', 'bnez', 'bgez', 'bltz', 'blez', 'bgtz',
-                     'c.j', 'j', 'c.jal', 'jal']:
-    idx = trace.operand.rfind(',')
-    if idx == -1:
-      imm = trace.operand
-      imm = str(sint_to_hex(int(imm, 16) - int(trace.pc, 16)))
-      trace.operand = imm
-    else:
-      imm = trace.operand[idx + 1 : ]
-      imm = str(sint_to_hex(int(imm, 16) - int(trace.pc, 16)))
-      trace.operand = trace.operand[0 : idx + 1] + imm
-
-
-def check_ibex_uvm_log(uvm_log, core_name, test_name, report, write=True):
-  """Process Ibex UVM simulation log.
-
-  This function will be used when a test disables the normal post_compare step.
-  Process the UVM simulation log produced by the test to check for correctness
-
-  Args:
-    uvm_log: the uvm simulation log
-    core_name: the name of the core
-    test_name: name of the test being checked
-    report: the output report file
-    write: enables writing to the log file
-
-  Returns:
-    A boolean indicating whether the test passed or failed based on the signature
-  """
-  pass_cnt = 0
-  fail_cnt = 0
-  with open(uvm_log, "r") as log:
-    for line in log:
-      if 'RISC-V UVM TEST PASSED' in line:
-        pass_cnt += 1
-        break
-      elif 'RISC-V UVM TEST FAILED' in line:
-        fail_cnt += 1
-        break
-
-  if write:
-    if report:
-      fd = open(report, "a+")
-    else:
-      fd = sys.stdout
-    fd.write("%s uvm log : %s\n" % (core_name, uvm_log))
-    if pass_cnt == 1:
-      fd.write("%s : [PASSED]\n\n" % test_name)
-    elif fail_cnt == 1:
-      fd.write("%s : [FAILED]\n\n" % test_name)
-    if report:
-      fd.close()
-
-  return pass_cnt == 1
-
-
-def main():
-  instr_trace = []
-  # Parse input arguments
-  parser = argparse.ArgumentParser()
-  parser.add_argument("--log", type=str, help="Input ibex simulation log")
-  parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
-  parser.add_argument("--full_trace", type=int, default=1,
-                      help="Enable full log trace")
-  args = parser.parse_args()
-  # Process ibex log
-  process_ibex_sim_log(args.log, args.csv, args.full_trace)
-
-
-if __name__ == "__main__":
-  main()
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/vcs.tcl b/hw/vendor/lowrisc_ibex/dv/uvm/vcs.tcl
deleted file mode 100644
index 716e459..0000000
--- a/hw/vendor/lowrisc_ibex/dv/uvm/vcs.tcl
+++ /dev/null
@@ -1,28 +0,0 @@
-# TCL file invoked from VCS's simv at run-time using this: -ucli -do <this file>
-
-# Syntax: fsdbDumpfile FSDB_Name [Limit_Size]
-fsdbDumpfile "waves.fsdb"
-
-# Syntax: fsdbDumpvars [depth] [instance] [option]*
-##############################################################################
-# Option                     Description
-##############################################################################
-# +mda                       Dumps memory and MDA signals in all scopes.
-# +packedmda                 Dumps packed signals
-# +struct                    Dumps structs
-# +skip_cell_instance=mode  Enables or disables cell dumping
-# +strength                  Enables strength dumping
-# +parameter                 Dumps parameters
-# +power                     Dumps power-related signals
-# +trace_process             Dumps VHDL processes
-# +no_functions              Disables dumping of functions
-# +sva                       Dumps assertions
-# +Reg_Only                  Dumps only reg type signals
-# +IO_Only                   Dumps only IO port signals
-# +by_file=<filename>        File to specify objects to add
-# +all                       Dumps memories, MDA signals, structs, unions,power, and packed structs
-fsdbDumpvars 0 core_ibex_tb_top +all
-fsdbDumpSVA 0 core_ibex_tb_top.dut
-
-run
-quit
diff --git a/hw/vendor/lowrisc_ibex/examples/fpga/artya7/top_artya7.core b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/top_artya7.core
index 632f068..6b903b4 100644
--- a/hw/vendor/lowrisc_ibex/examples/fpga/artya7/top_artya7.core
+++ b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/top_artya7.core
@@ -31,6 +31,12 @@
     default: "../../../../../examples/sw/led/led.vmem"
     paramtype: vlogdefine
 
+  FPGA_XILINX:
+    datatype: str
+    description: Identifies Xilinx FPGA targets to set DSP pragmas for performance counters.
+    default: 1
+    paramtype: vlogdefine
+
 targets:
   synth:
     default_tool: vivado
@@ -40,6 +46,7 @@
     toplevel: top_artya7
     parameters:
       - SRAM_INIT_FILE
+      - FPGA_XILINX
     tools:
       vivado:
         part: "xc7a100tcsg324-1"  # Default to Arty A7-100
diff --git a/hw/vendor/lowrisc_ibex/examples/simple_system/README.md b/hw/vendor/lowrisc_ibex/examples/simple_system/README.md
index fc6be03..9a921b9 100644
--- a/hw/vendor/lowrisc_ibex/examples/simple_system/README.md
+++ b/hw/vendor/lowrisc_ibex/examples/simple_system/README.md
@@ -61,9 +61,10 @@
 `./examples/sw/simple_system/hello_test/hello_test.elf` to run the `hello_test`
 binary.
 
-Pass `-t` to get an FST trace of execution that be viewed with [GTKWave](http://gtkwave.sourceforge.net/)
-If using the `hello_test` binary the simulator will halt itself, outputting some
-simulation statistics:
+Pass `-t` to get an FST trace of execution that can be viewed with
+[GTKWave](http://gtkwave.sourceforge.net/). If using the `hello_test`
+binary the simulator will halt itself, outputting some simulation
+statistics:
 
 ```
 Simulation statistics
@@ -130,7 +131,7 @@
 | Address             | Description                                                                                            |
 |---------------------|--------------------------------------------------------------------------------------------------------|
 | 0x20000             | ASCII Out, write ASCII characters here that will get output to the log file                            |
-| 0x20004             | Simulator Halt, write 1 here to halt the simulation                                                    |
+| 0x20008             | Simulator Halt, write 1 here to halt the simulation                                                    |
 | 0x30000             | RISC-V timer `mtime` register                                                                          |
 | 0x30004             | RISC-V timer `mtimeh` register                                                                         |
 | 0x30008             | RISC-V timer `mtimecmp` register                                                                       |
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 0d3e636..736367c 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
@@ -17,6 +17,11 @@
       - ibex_simple_system.cc: { file_type: cppSource }
     file_type: systemVerilogSource
 
+  files_verilator_waiver:
+    files:
+      - lint/verilator_waiver.vlt: {file_type: vlt}
+
+
 parameters:
   RV32M:
     datatype: int
@@ -42,6 +47,7 @@
   sim:
     default_tool: verilator
     filesets:
+      - tool_verilator ? (files_verilator_waiver)
       - files_sim_verilator
     parameters:
       - RV32M
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
new file mode 100644
index 0000000..1959a78
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/examples/simple_system/lint/verilator_waiver.vlt
@@ -0,0 +1,32 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Lint waivers for processing simple_system RTL with Verilator
+//
+// This should be used for rules applying to things like testbench
+// top-levels. For rules that apply to the actual design (files in the
+// 'rtl' directory), see verilator_waiver_rtl.vlt in the same
+// directory.
+//
+// See https://www.veripool.org/projects/verilator/wiki/Manual-verilator#CONFIGURATION-FILES
+// for documentation.
+//
+// Important: This file must included *before* any other Verilog file is read.
+// Otherwise, only global waivers are applied, but not file-specific waivers.
+
+`verilator_config
+
+// 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:
+//
+//   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_simple_system.sv"
+         -match "*expects 1 bits*Initial value's CONST '32'h1'*"
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 aa71e6f..fd4abcb 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
@@ -18,9 +18,9 @@
   input IO_RST_N
 );
 
-  parameter bit RV32E           = 0;
-  parameter bit RV32M           = 1;
-  parameter bit BranchTargetALU = 0;
+  parameter bit RV32E           = 1'b0;
+  parameter bit RV32M           = 1'b1;
+  parameter bit BranchTargetALU = 1'b0;
 
   logic clk_sys = 1'b0, rst_sys_n;
 
diff --git a/hw/vendor/lowrisc_ibex/examples/simple_system/spike-simple-system.sh b/hw/vendor/lowrisc_ibex/examples/simple_system/spike-simple-system.sh
new file mode 100755
index 0000000..20e810e
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/examples/simple_system/spike-simple-system.sh
@@ -0,0 +1,108 @@
+#!/bin/bash
+
+set -u
+set -e
+
+# This is a simple bash script to allow you to run a binary compiled
+# for the simple_system environment using Spike.
+#
+
+error() {
+    echo >&2 "$@"
+    exit 1
+}
+
+usage () {
+    echo >&2 "Usage:  spike-simple-system [-h] [-v] [-n] [--] [options] <elf>"
+    echo >&2
+    echo >&2 "  Where <elf> is the path to an ELF binary that was"
+    echo >&2 "  compiled for the simple_system environment. Any arguments "
+    echo >&2 "  in <options> will be passed to Spike after those to set up "
+    echo >&2 "  the environment for simple_system tests."
+    echo >&2
+    echo >&2 "  If the -v argument is passed, the Spike command will be "
+    echo >&2 "  echoed to stderr before it runs. If the -n argument is passed "
+    echo >&2 "  (which implies -v), we don't actually run the command."
+    echo >&2
+    echo >&2 "  This will write the Spike instruction log to stderr."
+
+    exit $1
+}
+
+declare -a opts
+opts=()
+
+verbose=0
+dryrun=0
+
+at_start=1
+
+# We can be rather lazy when building our command line here, and don't
+# need to distinguish between [options] and <elf>, since they end up
+# appended to the Spike command line in the same order.
+while [ $# != 0 ]; do
+    if [ $at_start = 1 ]; then
+        case "$1" in
+            --help|-h)
+                usage 0
+                ;;
+
+            --verbose|-v)
+                verbose=1
+                ;;
+
+            --dry-run|-n)
+                dryrun=1
+                verbose=1
+                ;;
+
+            --)
+                at_start=0
+                ;;
+
+            *)
+                at_start=0
+                opts=("$1")
+                ;;
+        esac
+    else
+        opts+=("$1")
+    fi
+    shift
+done
+
+# If opts is empty, that's definitely an error (since the <elf>
+# parameter was compulsory). Moan here.
+if [ ${#opts[*]} = 0 ]; then
+    usage 1
+fi
+
+# Time to figure out how to call the Spike binary. If the user has set
+# SPIKE_PATH, we should obey that. Otherwise, we'll just assume that
+# they've got their PATH set up sensibly.
+if [ x"$SPIKE_PATH" = x ]; then
+    spike='spike'
+else
+    spike="$SPIKE_PATH/spike"
+fi
+
+# Here are the Spike options you need to run in a simple_system world.
+declare -a ss_opts
+ss_opts=(--isa=rv32imc
+         --log-commits
+         -l
+         -m0x10000:0x30000,0x100000:0x100000)
+
+cmd=("$spike" "${ss_opts[@]}" "${opts[@]}")
+
+if [ $verbose = 1 ]; then
+    # Echo the command that we're going to run in the same style as
+    # 'set -x' would.
+    echo >&2 + "${cmd[@]}"
+fi
+
+if [ $dryrun = 1 ]; then
+    exit 0
+fi
+
+exec "${cmd[@]}"
diff --git a/hw/vendor/lowrisc_ibex/examples/sw/simple_system/common/link.ld b/hw/vendor/lowrisc_ibex/examples/sw/simple_system/common/link.ld
index 485cbaf..b1c2307 100644
--- a/hw/vendor/lowrisc_ibex/examples/sw/simple_system/common/link.ld
+++ b/hw/vendor/lowrisc_ibex/examples/sw/simple_system/common/link.ld
@@ -16,12 +16,27 @@
 _stack_len     = LENGTH(stack);
 _stack_start   = ORIGIN(stack) + LENGTH(stack);
 
+_entry_point = _vectors_start + 0x80;
+ENTRY(_entry_point)
+
+/* The tohost address is used by Spike for a magic "stop me now" message. This
+   is set to equal SIM_CTRL_CTRL (see simple_system_regs.h), which has that
+   effect in simple_system simulations. Note that it must be 8-byte aligned.
+
+   We don't read data back from Spike, so fromhost is set to some dummy value:
+   we place it just above the top of the stack.
+ */
+tohost   = 0x20008;
+fromhost = _stack_start + 0x10;
+
 SECTIONS
 {
     .vectors :
     {
         . = ALIGN(4);
+		_vectors_start = .;
         KEEP(*(.vectors))
+		_vectors_end = .;
     } > ram
 
     .text : {
diff --git a/hw/vendor/lowrisc_ibex/examples/sw/simple_system/common/simple_system_regs.h b/hw/vendor/lowrisc_ibex/examples/sw/simple_system/common/simple_system_regs.h
index d28d473..36b1e6b 100644
--- a/hw/vendor/lowrisc_ibex/examples/sw/simple_system/common/simple_system_regs.h
+++ b/hw/vendor/lowrisc_ibex/examples/sw/simple_system/common/simple_system_regs.h
@@ -7,7 +7,7 @@
 
 #define SIM_CTRL_BASE 0x20000
 #define SIM_CTRL_OUT 0x0
-#define SIM_CTRL_CTRL 0x4
+#define SIM_CTRL_CTRL 0x8
 
 #define TIMER_BASE 0x30000
 #define TIMER_MTIME 0x0
diff --git a/hw/vendor/lowrisc_ibex/ibex_core.core b/hw/vendor/lowrisc_ibex/ibex_core.core
index 4d71538..09009ca 100644
--- a/hw/vendor/lowrisc_ibex/ibex_core.core
+++ b/hw/vendor/lowrisc_ibex/ibex_core.core
@@ -4,6 +4,7 @@
 # SPDX-License-Identifier: Apache-2.0
 name: "lowrisc:ibex:ibex_core:0.1"
 description: "CPU core with 2 stage pipeline implementing the RV32IMC_Zicsr ISA"
+
 filesets:
   files_rtl:
     depend:
@@ -14,6 +15,7 @@
       - rtl/ibex_compressed_decoder.sv
       - rtl/ibex_controller.sv
       - rtl/ibex_cs_registers.sv
+      - rtl/ibex_counters.sv
       - rtl/ibex_decoder.sv
       - rtl/ibex_ex_block.sv
       - rtl/ibex_fetch_fifo.sv
@@ -40,6 +42,10 @@
     files:
       - lint/verilator_waiver.vlt: {file_type: vlt}
 
+  files_check_tool_requirements:
+    depend:
+     - lowrisc:ibex:check_tool_requirements
+
 parameters:
   RVFI:
     datatype: bool
@@ -72,13 +78,15 @@
 targets:
   default:
     filesets:
+      - tool_verilator ? (files_lint_verilator)
       - files_rtl
-
+      - files_check_tool_requirements
   lint:
     filesets:
       - tool_verilator ? (files_lint_verilator)
       - files_rtl
       - files_lint
+      - files_check_tool_requirements
     parameters:
       - SYNTHESIS=true
       - RVFI=true
diff --git a/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt b/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
index 7be67c3..bc57bb3 100644
--- a/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
+++ b/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
@@ -10,58 +10,124 @@
 // Otherwise, only global waivers are applied, but not file-specific waivers.
 
 `verilator_config
-lint_off -msg PINCONNECTEMPTY
+lint_off -rule PINCONNECTEMPTY
 
 // 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 -msg DECLFILENAME -file "*/rtl/ibex_register_file_ff.sv"
-lint_off -msg DECLFILENAME -file "*/rtl/ibex_register_file_latch.sv"
-lint_off -msg DECLFILENAME -file "*/rtl/ibex_register_file_fpga.sv"
+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"
 
 // Bits of signal are not used: fetch_addr_n[0]
 // cleaner to write all bits even if not all are used
-lint_off -msg UNUSED -file "*/rtl/ibex_if_stage.sv" -lines 85
+lint_off -rule UNUSED -file "*/rtl/ibex_if_stage.sv" -match "*'fetch_addr_n'[0]*"
 
 // Bits of signal are not used: shift_right_result_ext[32]
 // cleaner to write all bits even if not all are used
-lint_off -msg UNUSED -file "*/rtl/ibex_alu.sv" -lines 104
+lint_off -rule UNUSED -file "*/rtl/ibex_alu.sv" -match "*'shift_right_result_ext'[32]*"
 
 // Bits of signal are not used: alu_adder_ext_i[0]
 // Bottom bit is round, not needed
-lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 26
+lint_off -rule UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -match "*'alu_adder_ext_i'[0]*"
 
 // Bits of signal are not used: mac_res_ext[34]
 // cleaner to write all bits even if not all are used
-lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 51
+lint_off -rule UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -match "*mac_res_ext*"
 
 // Bits of signal are not used: res_adder_h[32]
 // cleaner to write all bits even if not all are used
-lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 71
+lint_off -rule UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -match "*'res_adder_h'[32]*"
+
+// Bits of signal are not used: be_i[3:1]
+// Bits of signal are not used: addr_i[31:10,1:0]
+// Bits of signal are not used: wdata_i[31:8]
+//
+// simulator_ctrl exposes a 32-bit write-only interface to its control
+// registers, but actually only looks at the bottom byte and rounds addresses
+// down to be 4-byte aligned.
+//
+lint_off -rule UNUSED -file "*/rtl/sim/simulator_ctrl.sv" -match "*'be_i'[3:1]*"
+lint_off -rule UNUSED -file "*/rtl/sim/simulator_ctrl.sv" -match "*'addr_i'[31:10,1:0]*"
+lint_off -rule UNUSED -file "*/rtl/sim/simulator_ctrl.sv" -match "*'wdata_i'[31:8]*"
+
+// Bits of signal are not used: timer_addr_i[31:10]
+//
+// The upper bits of this address are used to select whether the timer is
+// addressed at all (encoded in the timer_req_i input). However, we pass the
+// entire 32-bit address around to make the code a bit cleaner.
+lint_off -rule UNUSED -file "*/rtl/timer.sv" -match "*'timer_addr_i'[31:10]*"
+
+// Bits of signal are not used for MHPMCounterNum < 29: mhpmcounter_we[31:MHPMCounterNum+3]
+// cleaner to write all bits even if not all are used
+lint_off -rule UNUSED -file "*/rtl/ibex_cs_registers.sv" -match "*'mhpmcounter_we'[31:MHPMCounterNum+3]*"
+
+// Bits of signal are not used: mhpmcounter_we[1]
+// Bits of signal are not used: mhpmcounterh_we[1]
+// Bits of signal are not used: mhpmcounter_incr[1]
+//
+// cleaner to write all bits even if not all are used
+//
+lint_off -rule UNUSED -file "*/rtl/ibex_cs_registers.sv" -match "*'mhpmcounter_we'[1]*"
+lint_off -rule UNUSED -file "*/rtl/ibex_cs_registers.sv" -match "*'mhpmcounterh_we'[1]*"
+lint_off -rule UNUSED -file "*/rtl/ibex_cs_registers.sv" -match "*'mhpmcounter_incr'[1]*"
+
+// Signals are unused if MHPMCounterNum == 0: clk_i, rst_ni
+// Signal is unused if MHPMCounterNum == 0: counter_val_i[31:0]
+//
+// If no counters are implemented, no flops are elaborated. No clock, reset or
+// next-state logic is used.
+//
+lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*'clk_i'"
+lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*'rst_ni'"
+lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*'counter_val_i'"
+
+// Bits of signal are not used for MHPMCounterNum < 29: counter_inc_i[28:MHPMCounterNum]
+// Bits of signal are not used for MHPMCounterNum < 29: counterh_we_i[28:MHPMCounterNum]
+// Bits of signal are not used for MHPMCounterNum < 29: counter_we_i[28:MHPMCounterNum]
+//
+// cleaner to write all bits even if not all are used
+//
+// lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*'counter_inc_i'[28:*]*"
+// lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*'counterh_we_i'[28:*]*"
+// lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*'counter_we_i'[28:*]*"
+
+lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*counter_inc_i*"
+lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*counterh_we_i*"
+lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*counter_we_i*"
+
+// Bits of signal are not used for MHPMCounterWidth < 64: counter_upd[63:MHPMCounterWidth]
+// Bits of signal are not used for MHPMCounterWidth < 64: counter_load[63:MHPMCounterWidth]
+//
+// cleaner to write all bits even if not all are used
+//
+lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*'counter_upd'[63:*]*"
+lint_off -rule UNUSED -file "*/rtl/ibex_counters.sv" -match "*'counter_load'[63:*]*"
 
 // Signal is not used: test_en_i
 // testability signal
-lint_off -msg UNUSED -file "*/rtl/ibex_register_file_ff.sv" -lines 21
-lint_off -msg UNUSED -file "*/rtl/ibex_register_file_fpga.sv" -lines 22
+lint_off -rule UNUSED -file "*/rtl/ibex_register_file_ff.sv" -match "*test_en_i*"
+lint_off -rule UNUSED -file "*/rtl/ibex_register_file_fpga.sv" -match "*test_en_i*"
 
 // Signal is not used: clk_i
 // leaving clk and reset connected in-case we want to add assertions
-lint_off -msg UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -lines 17
-lint_off -msg UNUSED -file "*/rtl/ibex_decoder.sv" -lines 25
+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*"
 
 // Signal is not used: rst_ni
 // leaving clk and reset connected in-case we want to add assertions
-lint_off -msg UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -lines 18
-lint_off -msg UNUSED -file "*/rtl/ibex_decoder.sv" -lines 26
-lint_off -msg UNUSED -file "*/rtl/ibex_register_file_fpga.sv" -lines 20
-
-// Signal unoptimizable: Feedback to clock or circular logic:
-// ibex_core.cs_registers_i.mie_q
-// Issue lowrisc/ibex#212
-lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 158
+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*"
 
 // 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
 // bits in fully duplicated instr for synthesiser to optimise out rather than
 // explicitly flopping only the bits we want.
-lint_off -msg UNUSED -file "*/rtl/ibex_decoder.sv" -lines 106
+lint_off -rule UNUSED -file "*/rtl/ibex_decoder.sv" -match "*instr_alu*"
+
+// Signal unoptimizable: Feedback to clock or circular logic:
+// ibex_core.cs_registers_i.mie_q
+// Issue lowrisc/ibex#212
+lint_off -rule UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -match "*ibex_core.cs_registers_i.mie_q*"
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv
index 442b579..12a487f 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv
@@ -284,17 +284,17 @@
 
   // Selectors must be known/valid.
   `ASSERT(IbexInstrLSBsKnown, valid_i |->
-      !$isunknown(instr_i[1:0]), clk_i, !rst_ni)
+      !$isunknown(instr_i[1:0]))
   `ASSERT(IbexC0Known1, (valid_i && (instr_i[1:0] == 2'b00)) |->
-      !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
+      !$isunknown(instr_i[15:13]))
   `ASSERT(IbexC1Known1, (valid_i && (instr_i[1:0] == 2'b01)) |->
-      !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
+      !$isunknown(instr_i[15:13]))
   `ASSERT(IbexC1Known2, (valid_i && (instr_i[1:0] == 2'b01) && (instr_i[15:13] == 3'b100)) |->
-      !$isunknown(instr_i[11:10]), clk_i, !rst_ni)
+      !$isunknown(instr_i[11:10]))
   `ASSERT(IbexC1Known3, (valid_i &&
       (instr_i[1:0] == 2'b01) && (instr_i[15:13] == 3'b100) && (instr_i[11:10] == 2'b11)) |->
-      !$isunknown({instr_i[12], instr_i[6:5]}), clk_i, !rst_ni)
+      !$isunknown({instr_i[12], instr_i[6:5]}))
   `ASSERT(IbexC2Known1, (valid_i && (instr_i[1:0] == 2'b10)) |->
-      !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
+      !$isunknown(instr_i[15:13]))
 
 endmodule
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
index aee4f55..138800d 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
@@ -116,7 +116,8 @@
   logic illegal_dret;
   logic illegal_umode;
   logic exc_req_lsu;
-  logic special_req;
+  logic special_req_all;
+  logic special_req_branch;
   logic enter_debug_mode;
   logic ebreak_into_debug;
   logic handle_irq;
@@ -187,10 +188,29 @@
   // LSU exception requests
   assign exc_req_lsu = store_err_i | load_err_i;
 
+
   // special requests: special instructions, pipeline flushes, exceptions...
-  assign special_req = mret_insn | dret_insn | wfi_insn | csr_pipe_flush |
+
+  // To avoid creating a path from data_err_i -> instr_req_o and to help timing the below
+  // special_req_all has a version that only applies to branches. For a branch the controller needs
+  // to set pc_set_o but only if there is no special request. If the generic special_req_all signal
+  // is used then a variety of signals that will never cause a special request during a branch
+  // instruction end up factored into pc_set_o. The special_req_branch only considers the special
+  // request reasons that are relevant to a branch.
+
+  // generic special request signal, applies to all instructions
+  assign special_req_all = mret_insn | dret_insn | wfi_insn | csr_pipe_flush |
       exc_req_d | exc_req_lsu;
 
+  // special request that can specifically occur during branch instructions
+  assign special_req_branch = (illegal_insn_d | instr_fetch_err) & (ctrl_fsm_cs != FLUSH);
+
+  `ASSERT(SpecialReqBranchGivesSpecialReqAll,
+    special_req_branch |-> special_req_all)
+
+  `ASSERT(SpecialReqAllGivesSpecialReqBranchIfBranchInst,
+    special_req_all && (branch_set_i || jump_set_i) |-> special_req_branch)
+
   ////////////////
   // Interrupts //
   ////////////////
@@ -363,14 +383,15 @@
         if (instr_valid_i) begin
 
           // get ready for special instructions, exceptions, pipeline flushes
-          if (special_req) begin
+          if (special_req_all) begin
             // Halt IF but don't flush ID. This leaves a valid instruction in
             // ID so controller can determine appropriate action in the
             // FLUSH state.
             ctrl_fsm_ns = FLUSH;
             halt_if     = 1'b1;
-          // set PC in IF stage to branch or jump target
-          end else if (branch_set_i || jump_set_i) begin
+          end
+
+          if ((branch_set_i || jump_set_i) && ~special_req_branch) begin
             pc_set_o       = 1'b1;
 
             perf_tbranch_o = branch_set_i;
@@ -385,7 +406,7 @@
           end
         end // instr_valid_i
 
-        if (!stall && !special_req) begin
+        if (!stall && !special_req_all) begin
           if (enter_debug_mode) begin
             // enter debug mode
             ctrl_fsm_ns = DBG_TAKEN_IF;
@@ -660,7 +681,6 @@
   // Selectors must be known/valid.
   `ASSERT(IbexCtrlStateValid, ctrl_fsm_cs inside {
       RESET, BOOT_SET, WAIT_SLEEP, SLEEP, FIRST_FETCH, DECODE, FLUSH,
-      IRQ_TAKEN, DBG_TAKEN_IF, DBG_TAKEN_ID
-      }, clk_i, !rst_ni)
+      IRQ_TAKEN, DBG_TAKEN_IF, DBG_TAKEN_ID})
 
 endmodule
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_core.f b/hw/vendor/lowrisc_ibex/rtl/ibex_core.f
index 68dc349..83e8396 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_core.f
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_core.f
@@ -2,6 +2,7 @@
 ibex_alu.sv
 ibex_compressed_decoder.sv
 ibex_controller.sv
+ibex_counter.sv
 ibex_cs_registers.sv
 ibex_decoder.sv
 ibex_ex_block.sv
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
index 7291d2b..b17c25d 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
@@ -567,7 +567,10 @@
       .load_err_o            ( lsu_load_err        ),
       .store_err_o           ( lsu_store_err       ),
 
-      .busy_o                ( lsu_busy            )
+      .busy_o                ( lsu_busy            ),
+
+      .illegal_insn_id_i     ( illegal_insn_id     ),
+      .instr_valid_id_i      ( instr_valid_id      )
   );
 
 
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_counters.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_counters.sv
new file mode 100644
index 0000000..9a28b9a
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_counters.sv
@@ -0,0 +1,86 @@
+module ibex_counters #(
+  parameter int MaxNumCounters = 29,
+  parameter int NumCounters = 0,
+  parameter int CounterWidth = 32
+) (
+  input                             clk_i,
+  input                             rst_ni,
+
+  input  logic [MaxNumCounters-1:0] counter_inc_i,
+  input  logic [MaxNumCounters-1:0] counterh_we_i,
+  input  logic [MaxNumCounters-1:0] counter_we_i,
+  input  logic [31:0]               counter_val_i,
+  output logic [63:0]               counter_val_o [MaxNumCounters]
+);
+  logic [63:0] counter [MaxNumCounters];
+
+  assign counter_val_o = counter;
+
+  for (genvar i = 0; i < MaxNumCounters; i++) begin : g_counter
+    // Only elaborate flops that are needed from the given CounterWidth and NumCounters.
+    if (i < NumCounters) begin : g_counter_exists
+
+      logic [63:0] counter_upd;
+      logic [63:0] counter_load;
+      logic we;
+      logic [CounterWidth-1:0] counter_d;
+
+      // Update
+      always_comb begin
+
+        // Write
+        we = counter_we_i[i] | counterh_we_i[i];
+        counter_load[63:32] = counter[i][63:32];
+        counter_load[31:0]  = counter_val_i;
+        if (counterh_we_i[i]) begin
+          counter_load[63:32] = counter_val_i;
+          counter_load[31:0]  = counter[i][31:0];
+        end
+
+        // Increment
+        counter_upd = counter[i] + 64'h1;
+
+        // Next value logic
+        if (we) begin
+          counter_d = counter_load[CounterWidth-1:0];
+        end else if (counter_inc_i[i])begin
+          counter_d = counter_upd[CounterWidth-1:0];
+        end else begin
+          counter_d = counter[i][CounterWidth-1:0];
+        end
+      end
+
+`ifdef FPGA_XILINX
+      // Set DSP pragma for supported xilinx FPGAs
+      localparam dsp_pragma = CounterWidth < 49  ? "yes" : "no";
+      (* use_dsp = dsp_pragma *) logic [CounterWidth-1:0] counter_q;
+`else
+      logic [CounterWidth-1:0] counter_q;
+`endif
+
+      // Counter flop
+`ifdef FPGA_XILINX
+      // DSP output register requires synchronous reset.
+      always @(posedge clk_i) begin
+`else
+      always @(posedge clk_i or negedge rst_ni) begin
+`endif
+        if (!rst_ni) begin
+          counter_q <= '0;
+        end else begin
+          counter_q <= counter_d;
+        end
+      end
+
+      if (CounterWidth < 64) begin : g_counter_narrow
+        assign counter[i][CounterWidth-1:0] = counter_q;
+        assign counter[i][63:CounterWidth]  = '0;
+      end else begin : g_counter_full
+        assign counter[i] = counter_q;
+      end
+    end else begin : g_no_counter
+      assign counter[i] = '0;
+    end
+  end
+
+endmodule
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
index 67ab001..e9fce05 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
@@ -105,18 +105,18 @@
   // misa
   localparam logic [1:0] MXL = 2'd1; // M-XLEN: XLEN in M-Mode for RV32
   localparam logic [31:0] MISA_VALUE =
-      (0          <<  0)  // A - Atomic Instructions extension
-    | (1          <<  2)  // C - Compressed extension
-    | (0          <<  3)  // D - Double precision floating-point extension
-    | (32'(RV32E) <<  4)  // E - RV32E base ISA
-    | (0          <<  5)  // F - Single precision floating-point extension
-    | (1          <<  8)  // I - RV32I/64I/128I base ISA
-    | (32'(RV32M) << 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
-    | (0          << 23)  // X - Non-standard extensions present
-    | (32'(MXL)   << 30); // M-XLEN
+      (0           <<  0)  // A - Atomic Instructions extension
+    | (1           <<  2)  // C - Compressed extension
+    | (0           <<  3)  // D - Double precision floating-point extension
+    | (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
+    | (0           << 13)  // N - User level interrupts supported
+    | (0           << 18)  // S - Supervisor mode implemented
+    | (1           << 20)  // U - User mode implemented
+    | (0           << 23)  // X - Non-standard extensions present
+    | (32'(MXL)    << 30); // M-XLEN
 
   typedef struct packed {
     logic      mie;
@@ -183,7 +183,6 @@
   logic [MHPMCounterNum+3-1:0] mcountinhibit_d, mcountinhibit_q;
   logic                        mcountinhibit_we;
 
-  logic [63:0] mhpmcounter_d [32];
   // mhpmcounter flops are elaborated below providing only the precise number that is required based
   // on MHPMCounterNum/MHPMCounterWidth. This signal connects to the Q output of these flops
   // where they exist and is otherwise 0.
@@ -877,55 +876,51 @@
     end
   end
 
-  // update
-  always_comb begin : mhpmcounter_update
-    mhpmcounter_d = mhpmcounter;
+  // mcycle and minstret
+  ibex_counters #(
+    .MaxNumCounters(1),
+    .NumCounters(1),
+    .CounterWidth(64)
+  ) mcycle_counter_i (
+    .clk_i(clk_i),
+    .rst_ni(rst_ni),
+    .counter_inc_i(mhpmcounter_incr[0] & ~mcountinhibit[0]),
+    .counterh_we_i(mhpmcounterh_we[0]),
+    .counter_we_i(mhpmcounter_we[0]),
+    .counter_val_i(csr_wdata_int),
+    .counter_val_o(mhpmcounter[0:0])
+  );
 
-    for (int i=0; i<32; i++) begin : gen_mhpmcounter_update
+  ibex_counters #(
+    .MaxNumCounters(1),
+    .NumCounters(1),
+    .CounterWidth(64)
+  ) minstret_counter_i (
+    .clk_i(clk_i),
+    .rst_ni(rst_ni),
+    .counter_inc_i(mhpmcounter_incr[2] & ~mcountinhibit[2]),
+    .counterh_we_i(mhpmcounterh_we[2]),
+    .counter_we_i(mhpmcounter_we[2]),
+    .counter_val_i(csr_wdata_int),
+    .counter_val_o(mhpmcounter[2:2])
+  );
 
-      // increment
-      if (mhpmcounter_incr[i] & ~mcountinhibit[i]) begin
-        mhpmcounter_d[i] = mhpmcounter[i] + 64'h1;
-      end
+  // reserved:
+  assign mhpmcounter[1] = '0;
 
-      // write
-      if (mhpmcounter_we[i]) begin
-        mhpmcounter_d[i][31: 0] = csr_wdata_int;
-      end else if (mhpmcounterh_we[i]) begin
-        mhpmcounter_d[i][63:32] = csr_wdata_int;
-      end
-    end
-  end
-
-  // Performance monitor registers
-  // Only elaborate flops that are needed from the given MHPMCounterWidth and MHPMCounterNum
-  // parameters
-  for (genvar i = 0; i < 32; i++) begin : g_mhpmcounter
-    // First 3 counters (cycle, time, instret) must always be elaborated
-    if (i < 3 + MHPMCounterNum) begin : g_mhpmcounter_exists
-      // First 3 counters must be 64-bit the rest have parameterisable width
-      localparam int unsigned IMHPMCounterWidth = i < 3 ? 64 : MHPMCounterWidth;
-
-      logic [IMHPMCounterWidth-1:0] mhpmcounter_q;
-
-      always @(posedge clk_i or negedge rst_ni) begin
-        if(~rst_ni) begin
-          mhpmcounter_q <= '0;
-        end else begin
-          mhpmcounter_q <= mhpmcounter_d[i][IMHPMCounterWidth-1:0];
-        end
-      end
-
-      if (IMHPMCounterWidth < 64) begin : g_mhpmcounter_narrow
-        assign mhpmcounter[i][IMHPMCounterWidth-1:0] = mhpmcounter_q;
-        assign mhpmcounter[i][63:IMHPMCounterWidth]  = '0;
-      end else begin : g_mhpmcounter_full
-        assign mhpmcounter[i] = mhpmcounter_q;
-      end
-    end else begin : g_no_mhpmcounter
-      assign mhpmcounter[i] = '0;
-    end
-  end
+  ibex_counters #(
+    .MaxNumCounters(29),
+    .NumCounters(MHPMCounterNum),
+    .CounterWidth(MHPMCounterWidth)
+  ) mcounters_variable_i (
+    .clk_i(clk_i),
+    .rst_ni(rst_ni),
+    .counter_inc_i(mhpmcounter_incr[31:3] & ~mcountinhibit[31:3]),
+    .counterh_we_i(mhpmcounterh_we[31:3]),
+    .counter_we_i(mhpmcounter_we[31:3]),
+    .counter_val_i(csr_wdata_int),
+    .counter_val_o(mhpmcounter[3:31])
+  );
 
   if(MHPMCounterNum < 29) begin : g_mcountinhibit_reduced
     assign mcountinhibit = {{29-MHPMCounterNum{1'b1}}, mcountinhibit_q};
@@ -1025,7 +1020,7 @@
       CSR_OP_WRITE,
       CSR_OP_SET,
       CSR_OP_CLEAR
-      }, clk_i, !rst_ni)
-  `ASSERT_KNOWN(IbexCsrWdataIntKnown, csr_wdata_int, clk_i, !rst_ni)
+      })
+  `ASSERT_KNOWN(IbexCsrWdataIntKnown, csr_wdata_int)
 
 endmodule
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
index ae3cf86..40a5b7b 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
@@ -809,5 +809,5 @@
 
   // Selectors must be known/valid.
   `ASSERT(IbexRegImmAluOpKnown, (opcode == OPCODE_OP_IMM) |->
-      !$isunknown(instr[14:12]), clk_i, !rst_ni)
+      !$isunknown(instr[14:12]))
 endmodule // controller
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
index c470003..6928f54 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
@@ -9,9 +9,9 @@
  * Execution block: Hosts ALU and MUL/DIV unit
  */
 module ibex_ex_block #(
-    parameter bit    RV32M                    = 1,
-    parameter bit    BranchTargetALU          = 0,
-    parameter        MultiplierImplementation = "fast"
+    parameter bit RV32M                    = 1,
+    parameter bit BranchTargetALU          = 0,
+    parameter     MultiplierImplementation = "fast"
 ) (
     input  logic                  clk_i,
     input  logic                  rst_ni,
@@ -131,7 +131,29 @@
         .multdiv_result_o   ( multdiv_result        )
     );
   end else if (MultiplierImplementation == "fast") begin : gen_multdiv_fast
-    ibex_multdiv_fast multdiv_i (
+    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              ),
+        .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      ( alu_is_equal_result   ),
+        .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             ),
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
index 1839d59..2f15c7e 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
@@ -225,10 +225,10 @@
 
   // Must not push and pop simultaneously when FIFO full.
   `ASSERT(IbexFetchFifoPushPopFull,
-      (in_valid_i && pop_fifo) |-> (!valid_q[DEPTH-1] || clear_i), clk_i, !rst_ni)
+      (in_valid_i && pop_fifo) |-> (!valid_q[DEPTH-1] || clear_i))
 
   // Must not push to FIFO when full.
   `ASSERT(IbexFetchFifoPushFull,
-      (in_valid_i) |-> (!valid_q[DEPTH-1] || clear_i), clk_i, !rst_ni)
+      (in_valid_i) |-> (!valid_q[DEPTH-1] || clear_i))
 
 endmodule
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
index 56c8c5a..572ecaa 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
@@ -659,37 +659,35 @@
       IMM_B_U,
       IMM_B_J,
       IMM_B_INCR_PC,
-      IMM_B_INCR_ADDR
-      }, clk_i, !rst_ni)
+      IMM_B_INCR_ADDR})
   `ASSERT(IbexRegfileWdataSelValid, regfile_wdata_sel inside {
       RF_WD_LSU,
       RF_WD_EX,
-      RF_WD_CSR
-      }, clk_i, !rst_ni)
-  `ASSERT_KNOWN(IbexWbStateKnown, id_wb_fsm_cs, clk_i, !rst_ni)
+      RF_WD_CSR})
+  `ASSERT_KNOWN(IbexWbStateKnown, id_wb_fsm_cs)
 
   // Branch decision must be valid when jumping.
-  `ASSERT(IbexBranchDecisionValid, branch_in_dec |-> !$isunknown(branch_decision_i), clk_i, !rst_ni)
+  `ASSERT(IbexBranchDecisionValid, branch_in_dec |-> !$isunknown(branch_decision_i))
 
   // Instruction delivered to ID stage can not contain X.
   `ASSERT(IbexIdInstrKnown,
-      (instr_valid_i && !(illegal_c_insn_i || instr_fetch_err_i)) |-> !$isunknown(instr_rdata_i),
-      clk_i, !rst_ni)
+      (instr_valid_i && !(illegal_c_insn_i || instr_fetch_err_i)) |-> !$isunknown(instr_rdata_i))
 
   // Instruction delivered to ID stage can not contain X.
   `ASSERT(IbexIdInstrALUKnown,
-      (instr_valid_i && !(illegal_c_insn_i || instr_fetch_err_i)) |-> !$isunknown(instr_rdata_alu_i),
-      clk_i, !rst_ni)
+      (instr_valid_i && !(illegal_c_insn_i || instr_fetch_err_i)) |-> !$isunknown(instr_rdata_alu_i))
 
   // Multicycle enable signals must be unique.
   `ASSERT(IbexMulticycleEnableUnique,
-      $onehot0({data_req_dec, multdiv_en_dec, branch_in_dec, jump_in_dec}), clk_i, !rst_ni)
+      $onehot0({data_req_dec, multdiv_en_dec, branch_in_dec, jump_in_dec}))
 
   // Duplicated instruction flops must match
-  `ASSERT(IbexDuplicateInstrMatch, instr_valid_i |-> instr_rdata_i == instr_rdata_alu_i, clk_i, !rst_ni);
+  // === as DV environment can produce instructions with Xs in, so must use precise match that
+  // includes Xs
+  `ASSERT(IbexDuplicateInstrMatch, instr_valid_i |-> instr_rdata_i === instr_rdata_alu_i)
 
   `ifdef CHECK_MISALIGNED
-  `ASSERT(IbexMisalignedMemoryAccess, !lsu_addr_incr_req_i, clk_i, !rst_ni)
+  `ASSERT(IbexMisalignedMemoryAccess, !lsu_addr_incr_req_i)
   `endif
 
 endmodule
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
index 1f9b925..7510f9f 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
@@ -178,7 +178,6 @@
 
     fetch_ready      = 1'b0;
     branch_req       = 1'b0;
-    have_instr       = 1'b0;
 
     if (offset_in_init_q) begin
       // no valid instruction data for ID stage, assume aligned
@@ -189,8 +188,6 @@
     end else begin
       // an instruction is ready for ID stage
       if (fetch_valid) begin
-        have_instr = 1'b1;
-
         if (req_i && if_id_pipe_reg_we) begin
           fetch_ready      = 1'b1;
           offset_in_init_d = 1'b0;
@@ -200,14 +197,14 @@
 
     // take care of jumps and branches
     if (pc_set_i) begin
-      have_instr       = 1'b0;
-
       // switch to new PC from ID stage
       branch_req       = 1'b1;
       offset_in_init_d = 1'b0;
     end
   end
 
+  assign have_instr = fetch_valid & ~ (offset_in_init_q | pc_set_i);
+
   assign pc_if_o      = fetch_addr;
   assign if_busy_o    = prefetch_busy;
   assign perf_imiss_o = ~fetch_valid | branch_req;
@@ -268,25 +265,24 @@
   ////////////////
 
   // Selectors must be known/valid.
-  `ASSERT_KNOWN(IbexExcPcMuxKnown, exc_pc_mux_i, clk_i, !rst_ni)
+  `ASSERT_KNOWN(IbexExcPcMuxKnown, exc_pc_mux_i)
   `ASSERT(IbexPcMuxValid, pc_mux_i inside {
       PC_BOOT,
       PC_JUMP,
       PC_EXC,
       PC_ERET,
-      PC_DRET
-      }, clk_i, !rst_ni)
+      PC_DRET})
 
   // Boot address must be aligned to 256 bytes.
-  `ASSERT(IbexBootAddrUnaligned, boot_addr_i[7:0] == 8'h00, clk_i, !rst_ni)
+  `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, clk_i, !rst_ni)
+  `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), clk_i, !rst_ni)
+  `ASSERT(IbexInstrAddrUnknown, instr_req_o |-> !$isunknown(instr_addr_o))
 
   // Address must be word aligned when request is sent.
-  `ASSERT(IbexInstrAddrUnaligned, instr_req_o |-> (instr_addr_o[1:0] == 2'b00), clk_i, !rst_ni)
+  `ASSERT(IbexInstrAddrUnaligned, instr_req_o |-> (instr_addr_o[1:0] == 2'b00))
 
 endmodule
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv
index e9fd74b..33d9ede 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv
@@ -51,7 +51,11 @@
     output logic         load_err_o,
     output logic         store_err_o,
 
-    output logic         busy_o
+    output logic         busy_o,
+
+    // used for assertions only
+    input  logic         illegal_insn_id_i,    // illegal instruciton -> from ID/EX
+    input  logic         instr_valid_id_i      // valid instruction   -> from ID/EX
 );
 
   logic [31:0]  data_addr;
@@ -485,30 +489,35 @@
   // Assertions //
   ////////////////
 
+  logic unused_instr_valid_id;
+  logic unused_illegal_insn_id;
+
+  // Inputs only used for assertions
+  assign unused_instr_valid_id  = instr_valid_id_i;
+  assign unused_illegal_insn_id = illegal_insn_id_i;
+
   // Selectors must be known/valid.
-  `ASSERT_KNOWN(IbexDataTypeKnown, data_type_ex_i, clk_i, !rst_ni)
-  `ASSERT_KNOWN(IbexDataOffsetKnown, data_offset, clk_i, !rst_ni)
-  `ASSERT_KNOWN(IbexRDataOffsetQKnown, rdata_offset_q, clk_i, !rst_ni)
-  `ASSERT_KNOWN(IbexDataTypeQKnown, data_type_q, clk_i, !rst_ni)
+  `ASSERT(IbexDataTypeKnown, (instr_valid_id_i & ~illegal_insn_id_i) |-> !$isunknown(data_type_ex_i))
+  `ASSERT(IbexDataOffsetKnown, (instr_valid_id_i & ~illegal_insn_id_i) |-> !$isunknown(data_offset))
+  `ASSERT_KNOWN(IbexRDataOffsetQKnown, rdata_offset_q)
+  `ASSERT_KNOWN(IbexDataTypeQKnown, data_type_q)
   `ASSERT(IbexLsuStateValid, ls_fsm_cs inside {
       IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID,
-      WAIT_RVALID_DONE
-      }, clk_i, !rst_ni)
+      WAIT_RVALID_DONE})
 
   // There must not be an rvalid unless the FSM is handlling it.
   `ASSERT(IbexRvalidNotHandled, data_rvalid_i |-> (
       (ls_fsm_cs == WAIT_RVALID) ||
       (ls_fsm_cs == WAIT_RVALID_MIS) ||
-      (ls_fsm_cs == WAIT_RVALID_DONE)
-      ), clk_i, !rst_ni)
+      (ls_fsm_cs == WAIT_RVALID_DONE)))
 
   // Errors must only be sent together with rvalid.
-  `ASSERT(IbexDataErrWithoutRvalid, data_err_i |-> data_rvalid_i, clk_i, !rst_ni)
+  `ASSERT(IbexDataErrWithoutRvalid, data_err_i |-> data_rvalid_i)
 
   // Address must not contain X when request is sent.
-  `ASSERT(IbexDataAddrUnknown, data_req_o |-> !$isunknown(data_addr_o), clk_i, !rst_ni)
+  `ASSERT(IbexDataAddrUnknown, data_req_o |-> !$isunknown(data_addr_o))
 
   // Address must be word aligned when request is sent.
-  `ASSERT(IbexDataAddrUnaligned, data_req_o |-> (data_addr_o[1:0] == 2'b00), clk_i, !rst_ni)
+  `ASSERT(IbexDataAddrUnaligned, data_req_o |-> (data_addr_o[1:0] == 2'b00))
 
 endmodule
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
index 5fbbf09..326926d 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
@@ -14,7 +14,9 @@
 
 `include "prim_assert.sv"
 
-module ibex_multdiv_fast (
+module ibex_multdiv_fast #(
+    parameter bit SingleCycleMultiply = 0
+  ) (
     input  logic             clk_i,
     input  logic             rst_ni,
     input  logic             mult_en_i,
@@ -36,94 +38,305 @@
 
   import ibex_pkg::*;
 
-  logic [ 4:0] div_counter_q, div_counter_n;
-  typedef enum logic [1:0] {
-    ALBL, ALBH, AHBL, AHBH
-  } mult_fsm_e;
-  mult_fsm_e mult_state_q, mult_state_n;
-
-  typedef enum logic [2:0] {
-    MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
-  } md_fsm_e;
-  md_fsm_e md_state_q, md_state_n;
-
+  // Both multiplier variants
   logic signed [34:0] mac_res_signed;
   logic        [34:0] mac_res_ext;
-
-  logic [33:0] mac_res_q, mac_res_n, mac_res, op_remainder_n;
-  logic [15:0] mult_op_a;
-  logic [15:0] mult_op_b;
-  logic [33:0] accum;
+  logic        [33:0] accum;
   logic        sign_a, sign_b;
-  logic        div_sign_a, div_sign_b;
+  logic        mult_valid;
   logic        signed_mult;
+
+  // Flop used for intermediate value holding during div & mul calculation
+  logic [33:0] intermediate_val_q, intermediate_val_d;
+  // Results that become intermediate value depending on whether mul or div is being calculated
+  logic [33:0] mac_res_d, op_remainder_d;
+  // Raw output of MAC calculation
+  logic [33:0] mac_res;
+
+  // Divider signals
+  logic        div_sign_a, div_sign_b;
   logic        is_greater_equal;
   logic        div_change_sign, rem_change_sign;
   logic [31:0] one_shift;
   logic [31:0] op_denominator_q;
   logic [31:0] op_numerator_q;
   logic [31:0] op_quotient_q;
-  logic [31:0] op_denominator_n;
-  logic [31:0] op_numerator_n;
-  logic [31:0] op_quotient_n;
+  logic [31:0] op_denominator_d;
+  logic [31:0] op_numerator_d;
+  logic [31:0] op_quotient_d;
   logic [31:0] next_remainder;
   logic [32:0] next_quotient;
   logic [32:0] res_adder_h;
-  logic        mult_valid;
   logic        div_valid;
+  logic [ 4:0] div_counter_q, div_counter_d;
+  logic        multdiv_en;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin : proc_mult_state_q
+  typedef enum logic [2:0] {
+    MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
+  } md_fsm_e;
+  md_fsm_e md_state_q, md_state_d;
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      mult_state_q     <= ALBL;
-      mac_res_q        <= '0;
-      div_counter_q    <= '0;
-      md_state_q       <= MD_IDLE;
-      op_denominator_q <= '0;
-      op_numerator_q   <= '0;
-      op_quotient_q    <= '0;
-    end else begin
-
-      if (mult_en_i) begin
-        mult_state_q <= mult_state_n;
-      end
-
-      if (div_en_i) begin
-        div_counter_q    <= div_counter_n;
-        op_denominator_q <= op_denominator_n;
-        op_numerator_q   <= op_numerator_n;
-        op_quotient_q    <= op_quotient_n;
-        md_state_q       <= md_state_n;
-      end
-
-      unique case(1'b1)
-        mult_en_i:
-          mac_res_q <= mac_res_n;
-        div_en_i:
-          mac_res_q <= op_remainder_n;
-        default:
-          mac_res_q <= mac_res_q;
-       endcase
+      div_counter_q      <= '0;
+      md_state_q         <= MD_IDLE;
+      op_denominator_q   <= '0;
+      op_numerator_q     <= '0;
+      op_quotient_q      <= '0;
+    end else if (div_en_i) begin
+      div_counter_q    <= div_counter_d;
+      op_denominator_q <= op_denominator_d;
+      op_numerator_q   <= op_numerator_d;
+      op_quotient_q    <= op_quotient_d;
+      md_state_q       <= md_state_d;
     end
   end
 
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      intermediate_val_q <= '0;
+    end else if (multdiv_en) begin
+      intermediate_val_q <= intermediate_val_d;
+    end
+  end
+
+  assign multdiv_en = mult_en_i | div_en_i;
+
+  assign intermediate_val_d = div_en_i ? op_remainder_d : mac_res_d;
+
   assign signed_mult      = (signed_mode_i != 2'b00);
+  assign multdiv_result_o = div_en_i ? intermediate_val_q[31:0] : mac_res_d[31:0];
 
-  assign multdiv_result_o = div_en_i ? mac_res_q[31:0] : mac_res_n[31:0];
+  // 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
 
-  // The 2 MSBs of mac_res_ext (mac_res_ext[34:33]) are always equal since:
-  // 1. The 2 MSBs of the multiplicants are always equal, and
-  // 2. The 16 MSBs of the addend (accum[33:18]) are always equal.
-  // Thus, it is safe to ignore mac_res_ext[34].
-  assign mac_res_signed =
-      $signed({sign_a, mult_op_a}) * $signed({sign_b, mult_op_b}) + $signed(accum);
-  assign mac_res_ext    = $unsigned(mac_res_signed);
-  assign mac_res        = mac_res_ext[33:0];
+    typedef enum logic {
+      MULL, MULH
+    } mult_fsm_e;
+    mult_fsm_e mult_state_q, mult_state_d;
 
+    logic signed [33:0] mult1_res, mult2_res, mult3_res;
+    logic [15:0]        mult1_op_a, mult1_op_b;
+    logic [15:0]        mult2_op_a, mult2_op_b;
+    logic [15:0]        mult3_op_a, mult3_op_b;
+    logic               mult1_sign_a, mult1_sign_b;
+    logic               mult2_sign_a, mult2_sign_b;
+    logic               mult3_sign_a, mult3_sign_b;
+    logic [33:0]        summand1, summand2, summand3;
+
+    assign mult1_res = $signed({mult1_sign_a, mult1_op_a}) * $signed({mult1_sign_b, mult1_op_b});
+    assign mult2_res = $signed({mult2_sign_a, mult2_op_a}) * $signed({mult2_sign_b, mult2_op_b});
+    assign mult3_res = $signed({mult3_sign_a, mult3_op_a}) * $signed({mult3_sign_b, mult3_op_b});
+
+    assign mac_res_signed = $signed(summand1) + $signed(summand2) + $signed(summand3);
+
+    assign mac_res_ext    = $unsigned(mac_res_signed);
+    assign mac_res        = mac_res_ext[33:0];
+
+    assign sign_a = signed_mode_i[0] & op_a_i[31];
+    assign sign_b = signed_mode_i[1] & op_b_i[31];
+
+    // The first two multipliers are only used in state 1 (MULL). We can assign them statically.
+    // al*bl
+    assign mult1_sign_a = 1'b0;
+    assign mult1_sign_b = 1'b0;
+    assign mult1_op_a = op_a_i[`OP_L];
+    assign mult1_op_b = op_b_i[`OP_L];
+
+    // al*bh
+    assign mult2_sign_a = 1'b0;
+    assign mult2_sign_b = sign_b;
+    assign mult2_op_a = op_a_i[`OP_L];
+    assign mult2_op_b = op_b_i[`OP_H];
+
+    // used in MULH
+    assign accum[17:0] = intermediate_val_q[33:16];
+    assign accum[33:18] = {16{signed_mult & intermediate_val_q[33]}};
+
+    always_comb begin
+      // Default values == MULL
+
+      // ah*bl
+      mult3_sign_a = sign_a;
+      mult3_sign_b = 1'b0;
+      mult3_op_a = op_a_i[`OP_H];
+      mult3_op_b = op_b_i[`OP_L];
+
+      summand1 = {18'h0, mult1_res[`OP_H]};
+      summand2 = mult2_res;
+      summand3 = mult3_res;
+
+      // mac_res = A*B[47:16], mult1_res = A*B[15:0]
+      mac_res_d = {2'b0, mac_res[`OP_L], mult1_res[`OP_L]};
+      mult_valid = mult_en_i;
+      mult_state_d = MULL;
+
+      unique case (mult_state_q)
+
+        MULL: begin
+          if (operator_i != MD_OP_MULL) begin
+            mac_res_d = mac_res;
+            mult_valid = 1'b0;
+            mult_state_d = MULH;
+          end
+        end
+
+        MULH: begin
+          // ah*bh
+          mult3_sign_a = sign_a;
+          mult3_sign_b = sign_b;
+          mult3_op_a = op_a_i[`OP_H];
+          mult3_op_b = op_b_i[`OP_H];
+          mac_res_d = mac_res;
+
+          summand1 = '0;
+          summand2 = accum;
+          summand3 = mult3_res;
+
+          mult_state_d = MULL;
+          mult_valid = 1'b1;
+        end
+
+        default: begin
+          mult_state_d = MULL;
+        end
+
+      endcase // mult_state_q
+    end
+
+    always_ff @(posedge clk_i or negedge rst_ni) begin
+      if (!rst_ni) begin
+        mult_state_q <= MULL;
+      end else begin
+        if (mult_en_i) begin
+          mult_state_q <= mult_state_d;
+        end
+      end
+    end
+
+    // States must be knwon/valid.
+    `ASSERT_KNOWN(IbexMultStateKnown, mult_state_q)
+
+  // 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
+    logic [15:0] mult_op_a;
+    logic [15:0] mult_op_b;
+
+    typedef enum logic [1:0] {
+      ALBL, ALBH, AHBL, AHBH
+    } mult_fsm_e;
+    mult_fsm_e mult_state_q, mult_state_d;
+
+    // The 2 MSBs of mac_res_ext (mac_res_ext[34:33]) are always equal since:
+    // 1. The 2 MSBs of the multiplicants are always equal, and
+    // 2. The 16 MSBs of the addend (accum[33:18]) are always equal.
+    // Thus, it is safe to ignore mac_res_ext[34].
+    assign mac_res_signed =
+        $signed({sign_a, mult_op_a}) * $signed({sign_b, mult_op_b}) + $signed(accum);
+    assign mac_res_ext    = $unsigned(mac_res_signed);
+    assign mac_res        = mac_res_ext[33:0];
+
+    always_comb begin
+      mult_op_a    = op_a_i[`OP_L];
+      mult_op_b    = op_b_i[`OP_L];
+      sign_a       = 1'b0;
+      sign_b       = 1'b0;
+      accum        = intermediate_val_q;
+      mac_res_d    = mac_res;
+      mult_state_d = mult_state_q;
+      mult_valid   = 1'b0;
+
+      unique case (mult_state_q)
+
+        ALBL: begin
+          // al*bl
+          mult_op_a = op_a_i[`OP_L];
+          mult_op_b = op_b_i[`OP_L];
+          sign_a    = 1'b0;
+          sign_b    = 1'b0;
+          accum     = '0;
+          mac_res_d = mac_res;
+          mult_state_d = ALBH;
+        end
+
+        ALBH: begin
+          // al*bh<<16
+          mult_op_a = op_a_i[`OP_L];
+          mult_op_b = op_b_i[`OP_H];
+          sign_a    = 1'b0;
+          sign_b    = signed_mode_i[1] & op_b_i[31];
+          // result of AL*BL (in intermediate_val_q) always unsigned with no carry, so carries_q always 00
+          accum     = {18'b0, intermediate_val_q[31:16]};
+          if (operator_i == MD_OP_MULL) begin
+            mac_res_d = {2'b0, mac_res[`OP_L], intermediate_val_q[`OP_L]};
+          end else begin
+            // MD_OP_MULH
+            mac_res_d = mac_res;
+          end
+          mult_state_d = AHBL;
+        end
+
+        AHBL: begin
+          // ah*bl<<16
+          mult_op_a = op_a_i[`OP_H];
+          mult_op_b = op_b_i[`OP_L];
+          sign_a    = signed_mode_i[0] & op_a_i[31];
+          sign_b    = 1'b0;
+          if (operator_i == MD_OP_MULL) begin
+            accum        = {18'b0, intermediate_val_q[31:16]};
+            mac_res_d    = {2'b0, mac_res[15:0], intermediate_val_q[15:0]};
+            mult_valid   = 1'b1;
+            mult_state_d = ALBL;
+          end else begin
+            accum        = intermediate_val_q;
+            mac_res_d    = mac_res;
+            mult_state_d = AHBH;
+          end
+        end
+
+        AHBH: begin
+          // only MD_OP_MULH here
+          // ah*bh
+          mult_op_a = op_a_i[`OP_H];
+          mult_op_b = op_b_i[`OP_H];
+          sign_a    = signed_mode_i[0] & op_a_i[31];
+          sign_b    = signed_mode_i[1] & op_b_i[31];
+          accum[17: 0]  = intermediate_val_q[33:16];
+          accum[33:18]  = {16{signed_mult & intermediate_val_q[33]}};
+          // result of AH*BL is not signed only if signed_mode_i == 2'b00
+          mac_res_d    = mac_res;
+          mult_state_d = ALBL;
+          mult_valid   = 1'b1;
+        end
+        default: begin
+          mult_state_d = ALBL;
+        end
+      endcase // mult_state_q
+    end
+
+    always_ff @(posedge clk_i or negedge rst_ni) begin
+      if (!rst_ni) begin
+        mult_state_q <= ALBL;
+      end else begin
+        if (mult_en_i) begin
+          mult_state_q <= mult_state_d;
+        end
+      end
+    end
+
+    // States must be knwon/valid.
+    `ASSERT_KNOWN(IbexMultStateKnown, mult_state_q)
+
+  end // gen_multdiv_fast
+
+  // Divider
   assign res_adder_h    = alu_adder_ext_i[33:1];
 
-  assign next_remainder = is_greater_equal ? res_adder_h[31:0] : mac_res_q[31:0];
-  assign next_quotient  = is_greater_equal ? {1'b0,op_quotient_q} | {1'b0,one_shift} :
-                                             {1'b0,op_quotient_q};
+  assign next_remainder = is_greater_equal ? res_adder_h[31:0] : intermediate_val_q[31:0];
+  assign next_quotient  = is_greater_equal ? {1'b0, op_quotient_q} | {1'b0, one_shift} :
+                                             {1'b0, op_quotient_q};
 
   assign one_shift      = {31'b0, 1'b1} << div_counter_q;
 
@@ -131,10 +344,10 @@
   // Remainder - Divisor. If Remainder - Divisor >= 0, is_greater_equal is equal to 1,
   // the next Remainder is Remainder - Divisor contained in res_adder_h and the
   always_comb begin
-    if ((mac_res_q[31] ^ op_denominator_q[31]) == 1'b0) begin
+    if ((intermediate_val_q[31] ^ op_denominator_q[31]) == 1'b0) begin
       is_greater_equal = (res_adder_h[31] == 1'b0);
     end else begin
-      is_greater_equal = mac_res_q[31];
+      is_greater_equal = intermediate_val_q[31];
     end
   end
 
@@ -144,13 +357,13 @@
   assign rem_change_sign = div_sign_a;
 
 
-  always_comb begin : md_fsm
-    div_counter_n    = div_counter_q - 5'h1;
-    op_remainder_n   = mac_res_q;
-    op_quotient_n    = op_quotient_q;
-    md_state_n       = md_state_q;
-    op_numerator_n   = op_numerator_q;
-    op_denominator_n = op_denominator_q;
+  always_comb begin
+    div_counter_d    = div_counter_q - 5'h1;
+    op_remainder_d   = intermediate_val_q;
+    op_quotient_d    = op_quotient_q;
+    md_state_d       = md_state_q;
+    op_numerator_d   = op_numerator_q;
+    op_denominator_d = op_denominator_q;
     alu_operand_a_o  = {32'h0  , 1'b1};
     alu_operand_b_o  = {~op_b_i, 1'b1};
     div_valid        = 1'b0;
@@ -160,27 +373,27 @@
         if (operator_i == MD_OP_DIV) begin
           // Check if the Denominator is 0
           // quotient for division by 0
-          op_remainder_n = '1;
-          md_state_n     = equal_to_zero ? MD_FINISH : MD_ABS_A;
+          op_remainder_d = '1;
+          md_state_d     = equal_to_zero ? MD_FINISH : MD_ABS_A;
         end else begin
           // Check if the Denominator is 0
           // remainder for division by 0
-          op_remainder_n = {2'b0, op_a_i};
-          md_state_n     = equal_to_zero ? MD_FINISH : MD_ABS_A;
+          op_remainder_d = {2'b0, op_a_i};
+          md_state_d     = equal_to_zero ? MD_FINISH : MD_ABS_A;
         end
         // 0 - B = 0 iff B == 0
         alu_operand_a_o  = {32'h0  , 1'b1};
         alu_operand_b_o  = {~op_b_i, 1'b1};
-        div_counter_n    = 5'd31;
+        div_counter_d    = 5'd31;
       end
 
       MD_ABS_A: begin
         // quotient
-        op_quotient_n   = '0;
+        op_quotient_d   = '0;
         // A abs value
-        op_numerator_n  = div_sign_a ? alu_adder_i : op_a_i;
-        md_state_n      = MD_ABS_B;
-        div_counter_n   = 5'd31;
+        op_numerator_d  = div_sign_a ? alu_adder_i : op_a_i;
+        md_state_d      = MD_ABS_B;
+        div_counter_d   = 5'd31;
         // ABS(A) = 0 - A
         alu_operand_a_o = {32'h0  , 1'b1};
         alu_operand_b_o = {~op_a_i, 1'b1};
@@ -188,148 +401,68 @@
 
       MD_ABS_B: begin
         // remainder
-        op_remainder_n   = { 33'h0, op_numerator_q[31]};
+        op_remainder_d   = { 33'h0, op_numerator_q[31]};
         // B abs value
-        op_denominator_n = div_sign_b ? alu_adder_i : op_b_i;
-        md_state_n       = MD_COMP;
-        div_counter_n    = 5'd31;
+        op_denominator_d = div_sign_b ? alu_adder_i : op_b_i;
+        md_state_d       = MD_COMP;
+        div_counter_d    = 5'd31;
         // ABS(B) = 0 - B
         alu_operand_a_o  = {32'h0  , 1'b1};
         alu_operand_b_o  = {~op_b_i, 1'b1};
       end
 
       MD_COMP: begin
-        op_remainder_n  = {1'b0, next_remainder[31:0], op_numerator_q[div_counter_n]};
-        op_quotient_n   = next_quotient[31:0];
-        md_state_n      = (div_counter_q == 5'd1) ? MD_LAST : MD_COMP;
+        op_remainder_d  = {1'b0, next_remainder[31:0], op_numerator_q[div_counter_d]};
+        op_quotient_d   = next_quotient[31:0];
+        md_state_d      = (div_counter_q == 5'd1) ? MD_LAST : MD_COMP;
         // Division
-        alu_operand_a_o = {mac_res_q[31:0], 1'b1};         // it contains the remainder
-        alu_operand_b_o = {~op_denominator_q[31:0], 1'b1}; // -denominator two's compliment
+        alu_operand_a_o = {intermediate_val_q[31:0], 1'b1}; // it contains the remainder
+        alu_operand_b_o = {~op_denominator_q[31:0], 1'b1};  // -denominator two's compliment
       end
 
       MD_LAST: begin
         if (operator_i == MD_OP_DIV) begin
-          // this time we save the quotient in op_remainder_n (i.e. mac_res_q) since
+          // this time we save the quotient in op_remainder_d (i.e. intermediate_val_q) since
           // we do not need anymore the remainder
-          op_remainder_n = {1'b0, next_quotient};
+          op_remainder_d = {1'b0, next_quotient};
         end else begin
           // this time we do not save the quotient anymore since we need only the remainder
-          op_remainder_n = {2'b0, next_remainder[31:0]};
+          op_remainder_d = {2'b0, next_remainder[31:0]};
         end
         // Division
-        alu_operand_a_o  = {mac_res_q[31:0], 1'b1};         // it contains the remainder
-        alu_operand_b_o  = {~op_denominator_q[31:0], 1'b1}; // -denominator two's compliment
+        alu_operand_a_o  = {intermediate_val_q[31:0], 1'b1}; // it contains the remainder
+        alu_operand_b_o  = {~op_denominator_q[31:0], 1'b1};  // -denominator two's compliment
 
-        md_state_n = MD_CHANGE_SIGN;
+        md_state_d = MD_CHANGE_SIGN;
       end
 
       MD_CHANGE_SIGN: begin
-        md_state_n  = MD_FINISH;
+        md_state_d  = MD_FINISH;
         if (operator_i == MD_OP_DIV) begin
-          op_remainder_n = (div_change_sign) ? {2'h0,alu_adder_i} : mac_res_q;
+          op_remainder_d = (div_change_sign) ? {2'h0, alu_adder_i} : intermediate_val_q;
         end else begin
-          op_remainder_n = (rem_change_sign) ? {2'h0,alu_adder_i} : mac_res_q;
+          op_remainder_d = (rem_change_sign) ? {2'h0, alu_adder_i} : intermediate_val_q;
         end
         // ABS(Quotient) = 0 - Quotient (or Remainder)
         alu_operand_a_o  = {32'h0  , 1'b1};
-        alu_operand_b_o  = {~mac_res_q[31:0], 1'b1};
+        alu_operand_b_o  = {~intermediate_val_q[31:0], 1'b1};
       end
 
       MD_FINISH: begin
-        md_state_n = MD_IDLE;
+        md_state_d = MD_IDLE;
         div_valid   = 1'b1;
       end
 
       default: begin
-        md_state_n = MD_IDLE;
+        md_state_d = MD_IDLE;
       end
     endcase // md_state_q
   end
 
   assign valid_o = mult_valid | div_valid;
 
-  always_comb begin : mult_fsm
-    mult_op_a    = op_a_i[`OP_L];
-    mult_op_b    = op_b_i[`OP_L];
-    sign_a       = 1'b0;
-    sign_b       = 1'b0;
-    accum        = mac_res_q;
-    mac_res_n    = mac_res;
-    mult_state_n = mult_state_q;
-    mult_valid   = 1'b0;
-
-    unique case (mult_state_q)
-
-      ALBL: begin
-        // al*bl
-        mult_op_a = op_a_i[`OP_L];
-        mult_op_b = op_b_i[`OP_L];
-        sign_a    = 1'b0;
-        sign_b    = 1'b0;
-        accum     = '0;
-        mac_res_n = mac_res;
-        mult_state_n = ALBH;
-      end
-
-      ALBH: begin
-        // al*bh<<16
-        mult_op_a = op_a_i[`OP_L];
-        mult_op_b = op_b_i[`OP_H];
-        sign_a    = 1'b0;
-        sign_b    = signed_mode_i[1] & op_b_i[31];
-        // result of AL*BL (in mac_res_q) always unsigned with no carry, so carries_q always 00
-        accum     = {18'b0,mac_res_q[31:16]};
-        if (operator_i == MD_OP_MULL) begin
-          mac_res_n = {2'b0,mac_res[`OP_L],mac_res_q[`OP_L]};
-        end else begin
-          // MD_OP_MULH
-          mac_res_n = mac_res;
-        end
-        mult_state_n = AHBL;
-      end
-
-      AHBL: begin
-        // ah*bl<<16
-        mult_op_a = op_a_i[`OP_H];
-        mult_op_b = op_b_i[`OP_L];
-        sign_a    = signed_mode_i[0] & op_a_i[31];
-        sign_b    = 1'b0;
-        if (operator_i == MD_OP_MULL) begin
-          accum        = {18'b0,mac_res_q[31:16]};
-          mac_res_n    = {2'b0,mac_res[15:0],mac_res_q[15:0]};
-          mult_valid   = 1'b1;
-          mult_state_n = ALBL;
-        end else begin
-          accum        = mac_res_q;
-          mac_res_n    = mac_res;
-          mult_state_n = AHBH;
-        end
-      end
-
-      AHBH: begin
-        // only MD_OP_MULH here
-        // ah*bh
-        mult_op_a = op_a_i[`OP_H];
-        mult_op_b = op_b_i[`OP_H];
-        sign_a    = signed_mode_i[0] & op_a_i[31];
-        sign_b    = signed_mode_i[1] & op_b_i[31];
-        accum[17: 0]  = mac_res_q[33:16];
-        accum[33:18]  = {16{signed_mult & mac_res_q[33]}};
-        // result of AH*BL is not signed only if signed_mode_i == 2'b00
-        mac_res_n    = mac_res;
-        mult_state_n = ALBL;
-        mult_valid   = 1'b1;
-      end
-      default: begin
-        mult_state_n = ALBL;
-      end
-    endcase // mult_state_q
-  end
-
   // States must be knwon/valid.
   `ASSERT(IbexMultDivStateValid, md_state_q inside {
-      MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
-      }, clk_i, !rst_ni)
-  `ASSERT_KNOWN(IbexMultStateKnown, mult_state_q, clk_i, !rst_ni)
+      MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH})
 
 endmodule // ibex_mult
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv
index 95f17e4..0d80d90 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv
@@ -173,7 +173,7 @@
               accum_window_d = {       ~(op_a_ext[32]   &     op_b_i[0]),
                                          op_a_ext[31:0] & {32{op_b_i[0]}}  };
               op_b_shift_d   = op_b_ext >> 1;
-              md_state_d     = MD_COMP;
+              md_state_d     = !(op_b_ext >> 1) ? MD_LAST : MD_COMP;
             end
             MD_OP_MULH: begin
               op_a_shift_d   = op_a_ext;
@@ -221,19 +221,20 @@
               accum_window_d = res_adder_l;
               op_a_shift_d   = op_a_shift_q << 1;
               op_b_shift_d   = op_b_shift_q >> 1;
+              md_state_d     = !(op_b_shift_q >> 1) ? MD_LAST : MD_COMP;
             end
             MD_OP_MULH: begin
               accum_window_d = res_adder_h;
               op_a_shift_d   = op_a_shift_q;
               op_b_shift_d   = op_b_shift_q >> 1;
+              md_state_d     = (multdiv_state_q == 5'd1) ? MD_LAST : MD_COMP;
             end
             default: begin
               accum_window_d = {next_reminder[31:0], op_numerator_q[multdiv_state_m1]};
               op_a_shift_d   = next_quotient;
+              md_state_d     = (multdiv_state_q == 5'd1) ? MD_LAST : MD_COMP;
             end
           endcase
-
-          md_state_d = (multdiv_state_q == 5'd1) ? MD_LAST : MD_COMP;
         end
 
         MD_LAST: begin
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_tracer.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_tracer.sv
index 40eaa1e..625c5ad 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_tracer.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_tracer.sv
@@ -88,7 +88,7 @@
   localparam MEM = (1 << 3);
   logic [3:0] data_accessed;
 
-  function void printbuffer_dumpline();
+  function automatic void printbuffer_dumpline();
     string rvfi_insn_str;
 
     if (file_handle == 32'h0) begin
@@ -136,7 +136,7 @@
 
 
   // Format register address with "x" prefix, left-aligned to a fixed width of 3 characters.
-  function string reg_addr_to_str(input logic [4:0] addr);
+  function automatic string reg_addr_to_str(input logic [4:0] addr);
     if (addr < 10) begin
       return $sformatf(" x%0d", addr);
     end else begin
@@ -145,7 +145,7 @@
   endfunction
 
   // Get a CSR name for a CSR address.
-  function string get_csr_name(input logic [11:0] csr_addr);
+  function automatic string get_csr_name(input logic [11:0] csr_addr);
     unique case (csr_addr)
       12'd0: return "ustatus";
       12'd4: return "uie";
@@ -391,22 +391,22 @@
     endcase
   endfunction
 
-  function void decode_mnemonic(input string mnemonic);
+  function automatic void decode_mnemonic(input string mnemonic);
     decoded_str = mnemonic;
   endfunction
 
-  function void decode_r_insn(input string mnemonic);
+  function automatic void decode_r_insn(input string mnemonic);
     data_accessed = RS1 | RS2 | RD;
     decoded_str = $sformatf("%s\tx%0d,x%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr, rvfi_rs2_addr);
   endfunction
 
-  function void decode_i_insn(input string mnemonic);
+  function automatic void decode_i_insn(input string mnemonic);
     data_accessed = RS1 | RD;
     decoded_str = $sformatf("%s\tx%0d,x%0d,%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr,
                     $signed({{20 {rvfi_insn[31]}}, rvfi_insn[31:20]}));
   endfunction
 
-  function void decode_i_shift_insn(input string mnemonic);
+  function automatic void decode_i_shift_insn(input string mnemonic);
     // SLLI, SRLI, SRAI
     logic [4:0] shamt;
     shamt = {rvfi_insn[24:20]};
@@ -414,25 +414,25 @@
     decoded_str = $sformatf("%s\tx%0d,x%0d,0x%0x", mnemonic, rvfi_rd_addr, rvfi_rs1_addr, shamt);
   endfunction
 
-  function void decode_i_jalr_insn(input string mnemonic);
+  function automatic void decode_i_jalr_insn(input string mnemonic);
     // JALR
     data_accessed = RS1 | RD;
     decoded_str = $sformatf("%s\tx%0d,%0d(x%0d)", mnemonic, rvfi_rd_addr,
         $signed({{20 {rvfi_insn[31]}}, rvfi_insn[31:20]}), rvfi_rs1_addr);
   endfunction
 
-  function void decode_u_insn(input string mnemonic);
+  function automatic void decode_u_insn(input string mnemonic);
     data_accessed = RD;
     decoded_str = $sformatf("%s\tx%0d,0x%0x", mnemonic, rvfi_rd_addr, {rvfi_insn[31:12]});
   endfunction
 
-  function void decode_j_insn(input string mnemonic);
+  function automatic void decode_j_insn(input string mnemonic);
     // JAL
     data_accessed = RD;
     decoded_str = $sformatf("%s\tx%0d,%0x", mnemonic, rvfi_rd_addr, rvfi_pc_wdata);
   endfunction
 
-  function void decode_b_insn(input string mnemonic);
+  function automatic void decode_b_insn(input string mnemonic);
     logic [31:0] branch_target;
     logic [31:0] imm;
 
@@ -445,7 +445,7 @@
     decoded_str = $sformatf("%s\tx%0d,x%0d,%0x", mnemonic, rvfi_rs1_addr, rvfi_rs2_addr, branch_target);
   endfunction
 
-  function void decode_csr_insn(input string mnemonic);
+  function automatic void decode_csr_insn(input string mnemonic);
     logic [11:0] csr;
     string csr_name;
     csr = rvfi_insn[31:20];
@@ -461,7 +461,7 @@
     end
   endfunction
 
-  function void decode_cr_insn(input string mnemonic);
+  function automatic void decode_cr_insn(input string mnemonic);
     if (rvfi_rs2_addr == 5'b0) begin
       if (rvfi_insn[12] == 1'b1) begin
         // C.JALR
@@ -477,42 +477,42 @@
     end
   endfunction
 
-  function void decode_ci_cli_insn(input string mnemonic);
+  function automatic void decode_ci_cli_insn(input string mnemonic);
     logic [5:0] imm;
     imm = {rvfi_insn[12], rvfi_insn[6:2]};
     data_accessed = RD;
     decoded_str = $sformatf("%s\tx%0d,%0d", mnemonic, rvfi_rd_addr, $signed(imm));
   endfunction
 
-  function void decode_ci_caddi_insn(input string mnemonic);
+  function automatic void decode_ci_caddi_insn(input string mnemonic);
     logic [5:0] nzimm;
     nzimm = {rvfi_insn[12], rvfi_insn[6:2]};
     data_accessed = RS1 | RD;
     decoded_str = $sformatf("%s\tx%0d,%0d", mnemonic, rvfi_rd_addr, $signed(nzimm));
   endfunction
 
-  function void decode_ci_caddi16sp_insn(input string mnemonic);
+  function automatic void decode_ci_caddi16sp_insn(input string mnemonic);
     logic [9:0] nzimm;
     nzimm = {rvfi_insn[12], rvfi_insn[4:3], rvfi_insn[5], rvfi_insn[2], rvfi_insn[6], 4'b0};
     data_accessed = RS1 | RD;
     decoded_str = $sformatf("%s\tx%0d,%0d", mnemonic, rvfi_rd_addr, $signed(nzimm));
   endfunction
 
-  function void decode_ci_clui_insn(input string mnemonic);
+  function automatic void decode_ci_clui_insn(input string mnemonic);
     logic [5:0] nzimm;
     nzimm = {rvfi_insn[12], rvfi_insn[6:2]};
     data_accessed = RD;
     decoded_str = $sformatf("%s\tx%0d,0x%0x", mnemonic, rvfi_rd_addr, 20'($signed(nzimm)));
   endfunction
 
-  function void decode_ci_cslli_insn(input string mnemonic);
+  function automatic void decode_ci_cslli_insn(input string mnemonic);
     logic [5:0] shamt;
     shamt = {rvfi_insn[12], rvfi_insn[6:2]};
     data_accessed = RS1 | RD;
     decoded_str = $sformatf("%s\tx%0d,0x%0x", mnemonic, rvfi_rd_addr, shamt);
   endfunction
 
-  function void decode_ciw_insn(input string mnemonic);
+  function automatic void decode_ciw_insn(input string mnemonic);
     // C.ADDI4SPN
     logic [9:0] nzuimm;
     nzuimm = {rvfi_insn[10:7], rvfi_insn[12:11], rvfi_insn[5], rvfi_insn[6], 2'b00};
@@ -520,14 +520,14 @@
     decoded_str = $sformatf("%s\tx%0d,x2,%0d", mnemonic, rvfi_rd_addr, nzuimm);
   endfunction
 
-  function void decode_cb_sr_insn(input string mnemonic);
+  function automatic void decode_cb_sr_insn(input string mnemonic);
     logic [5:0] shamt;
     shamt = {rvfi_insn[12], rvfi_insn[6:2]};
     data_accessed = RS1 | RD;
     decoded_str = $sformatf("%s\tx%0d,0x%0x", mnemonic, rvfi_rs1_addr, shamt);
   endfunction
 
-  function void decode_cb_insn(input string mnemonic);
+  function automatic void decode_cb_insn(input string mnemonic);
     logic [7:0] imm;
     logic [31:0] jump_target;
     if (rvfi_insn[15:13] == 3'b110 || rvfi_insn[15:13] == 3'b111) begin
@@ -549,12 +549,12 @@
     end
   endfunction
 
-  function void decode_cs_insn(input string mnemonic);
+  function automatic void decode_cs_insn(input string mnemonic);
     data_accessed = RS1 | RS2 | RD; // RS1 == RD
     decoded_str = $sformatf("%s\tx%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs2_addr);
   endfunction
 
-  function void decode_cj_insn(input string mnemonic);
+  function automatic void decode_cj_insn(input string mnemonic);
     if (rvfi_insn[15:13] == 3'b001) begin
       // C.JAL
       data_accessed = RD;
@@ -562,7 +562,7 @@
     decoded_str = $sformatf("%s\t%0x", mnemonic, rvfi_pc_wdata);
   endfunction
 
-  function void decode_compressed_load_insn(input string mnemonic);
+  function automatic void decode_compressed_load_insn(input string mnemonic);
     logic [7:0] imm;
 
     if (rvfi_insn[1:0] == OPCODE_C0) begin
@@ -576,7 +576,7 @@
     decoded_str = $sformatf("%s\tx%0d,%0d(x%0d)", mnemonic, rvfi_rd_addr, imm, rvfi_rs1_addr);
   endfunction
 
-  function void decode_compressed_store_insn(input string mnemonic);
+  function automatic void decode_compressed_store_insn(input string mnemonic);
     logic [7:0] imm;
     if (rvfi_insn[1:0] == OPCODE_C0) begin
       // C.SW
@@ -589,7 +589,7 @@
     decoded_str = $sformatf("%s\tx%0d,%0d(x%0d)", mnemonic, rvfi_rs2_addr, imm, rvfi_rs1_addr);
   endfunction
 
-  function void decode_load_insn();
+  function automatic void decode_load_insn();
     string      mnemonic;
 
     /*
@@ -632,7 +632,7 @@
                     $signed({{20 {rvfi_insn[31]}}, rvfi_insn[31:20]}), rvfi_rs1_addr);
   endfunction
 
-  function void decode_store_insn();
+  function automatic void decode_store_insn();
     string    mnemonic;
 
     unique case (rvfi_insn[13:12])
@@ -655,7 +655,7 @@
     end
   endfunction
 
-  function string get_fence_description(logic [3:0] bits);
+  function automatic string get_fence_description(logic [3:0] bits);
     string desc = "";
     if (bits[3]) begin
       desc = {desc, "i"};
@@ -672,7 +672,7 @@
     return desc;
   endfunction
 
-  function void decode_fence();
+  function automatic void decode_fence();
     string predecessor;
     string successor;
     predecessor = get_fence_description(rvfi_insn[27:24]);
diff --git a/hw/vendor/lowrisc_ibex/shared/rtl/sim/simulator_ctrl.sv b/hw/vendor/lowrisc_ibex/shared/rtl/sim/simulator_ctrl.sv
index 555025e..81d03e2 100644
--- a/hw/vendor/lowrisc_ibex/shared/rtl/sim/simulator_ctrl.sv
+++ b/hw/vendor/lowrisc_ibex/shared/rtl/sim/simulator_ctrl.sv
@@ -10,7 +10,13 @@
  *
  * * 0x0 - CHAR_OUT_ADDR - [7:0] of write data output via output_char DPI call
  * and SimOutputManager (see dv/common/cpp/sim_output_manager.cc)
- * * 0x4 - SIM_CTRL_ADDR - Write 1 to bit 0 to halt sim
+ *
+ * * 0x8 - SIM_CTRL_ADDR - Write 1 to bit 0 to halt sim
+ *
+ * The slightly odd spacing is because we also use SIM_CTRL_ADDR when
+ * simulating simple_system code with Spike, which requires the address to be
+ * 64-bit aligned.
+ *
  */
 
 module simulator_ctrl #(
@@ -33,7 +39,7 @@
 );
 
   localparam CHAR_OUT_ADDR = 0;
-  localparam SIM_CTRL_ADDR = 1;
+  localparam SIM_CTRL_ADDR = 2;
 
   logic [7:0] ctrl_addr;
   logic [2:0] sim_finish = 3'b000;
diff --git a/hw/vendor/lowrisc_ibex/shared/rtl/timer.sv b/hw/vendor/lowrisc_ibex/shared/rtl/timer.sv
index f6b754f..871bd02 100644
--- a/hw/vendor/lowrisc_ibex/shared/rtl/timer.sv
+++ b/hw/vendor/lowrisc_ibex/shared/rtl/timer.sv
@@ -39,7 +39,7 @@
 
   logic                 timer_we;
   logic                 mtime_we, mtimeh_we;
-  logic                 mtimecmp_we, mtimcmph_we;
+  logic                 mtimecmp_we, mtimecmph_we;
   logic [DataWidth-1:0] mtime_wdata, mtimeh_wdata;
   logic [DataWidth-1:0] mtimecmp_wdata, mtimecmph_wdata;
   logic [TW-1:0]        mtime_q, mtime_d, mtime_inc;
diff --git a/hw/vendor/lowrisc_ibex/syn/syn_yosys.sh b/hw/vendor/lowrisc_ibex/syn/syn_yosys.sh
index 181e71a..08625d0 100755
--- a/hw/vendor/lowrisc_ibex/syn/syn_yosys.sh
+++ b/hw/vendor/lowrisc_ibex/syn/syn_yosys.sh
@@ -31,7 +31,7 @@
   sv2v \
     --define=SYNTHESIS \
     ../rtl/*_pkg.sv \
-    ../shared/rtl/prim_assert.sv \
+    -I../shared/rtl \
     $file \
     > $LR_SYNTH_OUT_DIR/generated/${module}.v
 
@@ -48,9 +48,10 @@
 # remove tracer (not needed for synthesis)
 rm -f $LR_SYNTH_OUT_DIR/generated/ibex_tracer.v
 
-# remove the latch-based register file (because we will use the
+# remove the FPGA & latch-based register file (because we will use the
 # flop-based one instead)
 rm -f $LR_SYNTH_OUT_DIR/generated/ibex_register_file_latch.v
+rm -f $LR_SYNTH_OUT_DIR/generated/ibex_register_file_fpga.v
 
 yosys -c ./tcl/yosys_run_synth.tcl | tee ./$LR_SYNTH_OUT_DIR/log/syn.log
 
diff --git a/hw/vendor/lowrisc_ibex/tool_requirements.py b/hw/vendor/lowrisc_ibex/tool_requirements.py
new file mode 100644
index 0000000..17a2bb0
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/tool_requirements.py
@@ -0,0 +1,9 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+# Version requirements for various tools. Checked by tooling (e.g. fusesoc),
+# and inserted into the Sphinx-generated documentation.
+__TOOL_REQUIREMENTS__ = {
+    'verilator': '4.028',
+}
diff --git a/hw/vendor/lowrisc_ibex/util/check_tool_requirements.py b/hw/vendor/lowrisc_ibex/util/check_tool_requirements.py
new file mode 100755
index 0000000..5a59d4c
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/util/check_tool_requirements.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python3
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+from distutils.version import StrictVersion
+import logging as log
+import os
+import subprocess
+import sys
+
+# Display INFO log messages and up.
+log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s")
+
+# Populate __TOOL_REQUIREMENTS__
+topsrcdir = os.path.join(os.path.dirname(__file__), '..')
+exec(open(os.path.join(topsrcdir, 'tool_requirements.py')).read())
+
+def get_verilator_version():
+    try:
+        # Note: "verilator" needs to be called through a shell and with all
+        # arguments in a string, as it doesn't have a shebang, but instead
+        # relies on perl magic to parse command line arguments.
+        version_str = subprocess.run('verilator --version', shell=True,
+                                     check=True, stdout=subprocess.PIPE,
+                                     stderr=subprocess.STDOUT,
+                                     universal_newlines=True)
+        return version_str.stdout.split(' ')[1].strip()
+
+    except subprocess.CalledProcessError as e:
+        log.error("Unable to call Verilator to check version: " + str(e))
+        log.error(e.stdout)
+        return None
+
+def check_version(tool_name, required_version, actual_version):
+    if required_version is None or actual_version is None:
+        return False
+
+    if StrictVersion(actual_version) < StrictVersion(required_version):
+        log.error("%s is too old: found version %s, need at least %s",
+                  tool_name, actual_version, required_version)
+        return False
+    else:
+        log.info("Found sufficiently recent version of %s (found %s, need %s)",
+                 tool_name, actual_version, required_version)
+        return True
+
+
+def main():
+    any_failed = False
+
+    if not check_version('verilator', __TOOL_REQUIREMENTS__['verilator'],
+                         get_verilator_version()):
+        any_failed = True
+
+    if any_failed:
+        log.error("Tool requirements not fulfilled. "
+                  "Please update the tools and retry.")
+        return 1
+    return 0
+
+if __name__ == "__main__":
+    sys.exit(main())
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 3ede25c..21ded15 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: f7e35d7939a27ae17b0481eb070e9a36ea335d1f
+    rev: 4583049cc2b3469ba9dea56b5e2d75809a89d8f3
   }
 }
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/README.md b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/README.md
index 5d12da4..d98e51d 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/README.md
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/README.md
@@ -62,9 +62,24 @@
 cov --help
 ```
 
+Use below command to install Verible, which is the tool to check Verilog style
+```bash
+verilog_style/build-verible.sh
+```
+
+This is the command to run Verilog style check. It's recommended to run and clean up
+all the style violations before submit a PR
+```bash
+verilog_style/run.sh
+```
+
 ## Document
 
-To understand how to setup and customize the generator, please check the full document under docs directory. You can use the makefile to generate the document. [HTML preview](https://htmlpreview.github.io/?https://github.com/google/riscv-dv/blob/master/docs/build/singlehtml/index.html#document-index)
+To understand how to setup and customize the generator, please check the full
+document under docs directory. You can use the makefile to generate the
+document. [HTML
+preview](https://htmlpreview.github.io/?https://github.com/google/riscv-dv/blob/master/docs/build/singlehtml/index.html#document-index).
+You can find the prebuilt document under docs/build/singlehtml/index.html
 
 ## External contributions and collaborations
 
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/configuration.rst b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/configuration.rst
index 3c4e481..398a0f4 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/configuration.rst
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/configuration.rst
@@ -110,63 +110,108 @@
 
 .. _YAML format: https://github.com/google/riscv-dv/blob/master/yaml/base_testlist.yaml
 
-.. note:: To automatically generate CSR tests without having to explicitly run the
-    script, include `riscv_csr_test` in the testlist as shown in the example YAML
-    file above.
+You can also add directed assembly/C test in the testlist
+
+.. code-block:: yaml
+
+    - test: riscv_single_c_test
+      description: >
+         single c test entry
+      iterations: 1
+      c_test: sample_c.c
+
+    - test: riscv_c_regression_test
+      description: >
+        Run all c tests under the given directory
+      iterations: 1
+      c_test: c_test_directory
+      gcc_opts:
+         # Some custom gcc options
+
+    - test: riscv_single_asm_test
+      description: >
+         single assembly test entry
+      iterations: 1
+      asm_test: sample_asm.S
+
+    - test: riscv_asm_regression_test
+      description: >
+        Run all assembly tests under the given directory
+      iterations: 1
+      asm_test: assembly_test_directory
+      gcc_opts:
+         # Some custom gcc options
+
 
 Runtime options of the generator
 --------------------------------
-+-----------------------------+---------------------------------------------------+---------+
-| Option                      | Description                                       | Default |
-+=============================+===================================================+=========+
-| num_of_tests                | Number of assembly tests to be generated          | 1       |
-+-----------------------------+---------------------------------------------------+---------+
-| num_of_sub_program          | Number of sub-program in one test                 | 5       |
-+-----------------------------+---------------------------------------------------+---------+
-| instr_cnt                   | Instruction count per test                        | 200     |
-+-----------------------------+---------------------------------------------------+---------+
-| enable_page_table_exception | Enable page table exception                       | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| enable_unaligned_load_store | Enable unaligned memory operations                | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| no_ebreak                   | Disable ebreak instruction                        | 1       |
-+-----------------------------+---------------------------------------------------+---------+
-| no_wfi                      | Disable WFI instruction                           | 1       |
-+-----------------------------+---------------------------------------------------+---------+
-| no_dret                     | Disable dret instruction                          | 1       |
-+-----------------------------+---------------------------------------------------+---------+
-| no_branch_jump              | Disable branch/jump instruction                   | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| no_load_store               | Disable load/store instruction                    | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| no_csr_instr                | Disable CSR instruction                           | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| no_fence                    | Disable fence instruction                         | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| illegal_instr_ratio         | Number of illegal instructions every 1000 instr   | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| hint_instr_ratio            | Number of HINT instructions every 1000 instr      | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| boot_mode                   | m:Machine mode, s:Supervisor mode, u:User mode    | m       |
-+-----------------------------+---------------------------------------------------+---------+
-| no_directed_instr           | Disable directed instruction stream               | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| require_signature_addr      | Set to 1 if test needs to talk to testbench       | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| signature_addr              | Write to this addr to send data to testbench      | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| enable_interrupt            | Enable MStatus.MIE, used in interrupt test        | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| gen_debug_section           | Disables randomized debug_rom section             | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| num_debug_sub_program       | Number of debug sub-programs in test              | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| enable_ebreak_in_debug_rom  | Generate ebreak instructions inside debug ROM     | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| set_dcsr_ebreak             | Randomly enable dcsr.ebreak(m/s/u)                | 0       |
-+-----------------------------+---------------------------------------------------+---------+
-| randomize_csr               | Fully randomize main CSRs (xSTATUS, xIE)          | 0       |
-+-----------------------------+---------------------------------------------------+---------+
++---------------------------------+---------------------------------------------------+---------+
+| Option                          | Description                                       | Default |
++=================================+===================================================+=========+
+| num_of_tests                    | Number of assembly tests to be generated          | 1       |
++---------------------------------+---------------------------------------------------+---------+
+| num_of_sub_program              | Number of sub-program in one test                 | 5       |
++---------------------------------+---------------------------------------------------+---------+
+| instr_cnt                       | Instruction count per test                        | 200     |
++---------------------------------+---------------------------------------------------+---------+
+| enable_page_table_exception     | Enable page table exception                       | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| enable_unaligned_load_store     | Enable unaligned memory operations                | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| no_ebreak                       | Disable ebreak instruction                        | 1       |
++---------------------------------+---------------------------------------------------+---------+
+| no_wfi                          | Disable WFI instruction                           | 1       |
++---------------------------------+---------------------------------------------------+---------+
+| set_mstatus_tw                  | Enable WFI to be treated as illegal instruction   | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| no_dret                         | Disable dret instruction                          | 1       |
++---------------------------------+---------------------------------------------------+---------+
+| no_branch_jump                  | Disable branch/jump instruction                   | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| no_csr_instr                    | Disable CSR instruction                           | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| enable_illegal_csr_instruction  | Enable illegal CSR instructions                   | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| enable_access_invalid_csr_level | Enable accesses to higher privileged CSRs         | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| enable_dummy_csr_write          | Enable some dummy CSR writes in setup routine     | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| enable_misaligned_instr         | Enable jumps to misaligned instruction addresses  | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| no_fence                        | Disable fence instruction                         | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| no_data_page                    | Disable data page generation                      | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| disable_compressed_instr        | Disable compressed instruction generation         | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| illegal_instr_ratio             | Number of illegal instructions every 1000 instr   | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| hint_instr_ratio                | Number of HINT instructions every 1000 instr      | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| boot_mode                       | m:Machine mode, s:Supervisor mode, u:User mode    | m       |
++---------------------------------+---------------------------------------------------+---------+
+| no_directed_instr               | Disable directed instruction stream               | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| require_signature_addr          | Set to 1 if test needs to talk to testbench       | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| signature_addr                  | Write to this addr to send data to testbench      | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| enable_interrupt                | Enable MStatus.MIE, used in interrupt test        | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| enable_timer_irq                | Enable xIE.xTIE, used to enable timer interrupts  | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| gen_debug_section               | Enables randomized debug_rom section              | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| num_debug_sub_program           | Number of debug sub-programs in test              | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| enable_ebreak_in_debug_rom      | Generate ebreak instructions inside debug ROM     | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| set_dcsr_ebreak                 | Randomly enable dcsr.ebreak(m/s/u)                | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| enable_debug_single_step        | Enable debug single stepping functionality        | 0       |
++---------------------------------+---------------------------------------------------+---------+
+| randomize_csr                   | Fully randomize main CSRs (xSTATUS, xIE)          | 0       |
++---------------------------------+---------------------------------------------------+---------+
 
 Setup Privileged CSR description (optional)
 -------------------------------------------
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/coverage_model.rst b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/coverage_model.rst
index 7a05c21..bcb085b 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/coverage_model.rst
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/coverage_model.rst
@@ -50,5 +50,5 @@
     # Split the run to process 5 CSV at a time, and run with LSF
     cov --dir out/spike_sim --lsf_cmd "bsub ....." -bz 5
 
-.. _riscv_core_setting.sv: https://github.com/google/riscv-dv/blob/master/setting/riscv_core_setting.sv
+.. _riscv_core_setting.sv: https://github.com/google/riscv-dv/blob/master/target/rv32imc/riscv_core_setting.sv
 
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/getting_started.rst b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/getting_started.rst
index a53a183..71f5f39 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/getting_started.rst
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/getting_started.rst
@@ -64,7 +64,7 @@
 one of below to run ISS simulation.
 
 1.  - `spike`_ setup
-    - Follow the `spike steps`_ to build spike
+    - Follow the instructions to build spike
     - Build spike with "--enable-commitlog"
     - Set environment variable SPIKE_PATH to the directory of the spike binary
 2.  - `riscv-ovpsim`_ setup
@@ -76,8 +76,7 @@
     - Follow the `sail-riscv steps`_ to install sail-riscv
     - Set environment variable SAIL_RISCV to the path of sail-riscv binary
 
-.. _spike: https://github.com/riscv/riscv-isa-sim#
-.. _spike steps: https://github.com/riscv/riscv-isa-sim#build-steps
+.. _spike: https://github.com/riscv/riscv-isa-sim
 .. _riscv-ovpsim: https://github.com/riscv/riscv-ovpsim
 .. _whisper: https://github.com/westerndigitalcorporation/swerv-ISS
 .. _sail-riscv: https://github.com/rems-project/sail-riscv
@@ -180,7 +179,7 @@
     run --test=riscv_rand_instr_test --iss=spike,sail
 
 Run directed assembly/C tests
----------------------------
+-----------------------------
 
 Sometimes it might be useful to run some hand-coded assembly/C tests to hit some
 corner cases::
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run.py
index 7fcdbfe..9e1a6af 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run.py
@@ -135,7 +135,7 @@
 
 
 def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir,
-               cmp_opts, output_dir, debug_cmd):
+               cmp_opts, output_dir, debug_cmd, lsf_cmd):
   """Compile the instruction generator
 
   Args:
@@ -147,6 +147,7 @@
     cmd_opts            : Compile options for the generator
     output_dir          : Output directory of the ELF files
     debug_cmd           : Produce the debug cmd log without running
+    lsf_cmd             : LSF command used to run the instruction generator
   """
   if (not((len(test_list) == 1) and (test_list[0]['test'] == 'riscv_csr_test'))):
     logging.info("Building RISC-V instruction generator")
@@ -159,9 +160,12 @@
         cmd = re.sub("<user_extension>", ext_dir, cmd)
       cmd = re.sub("<cwd>", cwd, cmd)
       cmd = re.sub("<cmp_opts>", cmp_opts, cmd)
-
-      logging.debug("Compile command: %s" % cmd)
-      run_cmd(cmd, debug_cmd = debug_cmd)
+      if lsf_cmd:
+        cmd = lsf_cmd + " " + cmd
+        run_parallel_cmd([cmd], debug_cmd = debug_cmd)
+      else:
+        logging.debug("Compile command: %s" % cmd)
+        run_cmd(cmd, debug_cmd = debug_cmd)
 
 
 def run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
@@ -296,7 +300,7 @@
   # Compile the instruction generator
   if not argv.so:
     do_compile(compile_cmd, test_list, argv.core_setting_dir, cwd, argv.user_extension_dir,
-               argv.cmp_opts, output_dir, argv.debug)
+               argv.cmp_opts, output_dir, argv.debug, argv.lsf_cmd)
   # Run the instruction generator
   if not argv.co:
     do_simulate(sim_cmd, test_list, cwd, argv.sim_opts, argv.seed_yaml, argv.seed, argv.csr_yaml,
@@ -534,8 +538,8 @@
     logging.error("No c test(*.c) found under %s" % c_test_dir)
 
 
-def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa,
-            setting_dir, timeout_s, debug_cmd):
+def iss_sim(test_list, output_dir, iss_list, iss_yaml, iss_opts,
+            isa, setting_dir, timeout_s, debug_cmd):
   """Run ISS simulation with the generated test program
 
   Args:
@@ -543,6 +547,7 @@
     output_dir  : Output directory of the ELF files
     iss_list    : List of instruction set simulators
     iss_yaml    : ISS configuration file in YAML format
+    iss_opts    : ISS command line options
     isa         : ISA variant passed to the ISS
     setting_dir : Generator setting directory
     timeout_s   : Timeout limit in seconds
@@ -562,6 +567,9 @@
           elf = prefix + ".o"
           log = ("%s/%s.%d.log" % (log_dir, test['test'], i))
           cmd = get_iss_cmd(base_cmd, elf, log)
+          if 'iss_opts' in test:
+            cmd += ' '
+            cmd += test['iss_opts']
           logging.info("Running %s sim: %s" % (iss, elf))
           if iss == "ovpsim":
             run_cmd(cmd, timeout_s, check_return_code=False, debug_cmd = debug_cmd)
@@ -687,6 +695,8 @@
                       help="Generator timeout limit in seconds")
   parser.add_argument("--end_signature_addr", type=str, default="0",
                       help="Address that privileged CSR test writes to at EOT")
+  parser.add_argument("--iss_opts", type=str, default="",
+                      help="Any ISS command line arguments")
   parser.add_argument("--iss_timeout", type=int, default=10,
                       help="ISS sim timeout limit in seconds")
   parser.add_argument("--iss_yaml", type=str, default="",
@@ -759,6 +769,9 @@
     if args.target == "rv32imc":
       args.mabi = "ilp32"
       args.isa  = "rv32imc"
+    elif args.target == "multi_harts":
+      args.mabi = "ilp32"
+      args.isa  = "rv32gc"
     elif args.target == "rv32i":
       args.mabi = "ilp32"
       args.isa  = "rv32i"
@@ -924,7 +937,7 @@
 
       # Run ISS simulation
       if args.steps == "all" or re.match(".*iss_sim.*", args.steps):
-        iss_sim(matched_list, output_dir, args.iss, args.iss_yaml,
+        iss_sim(matched_list, output_dir, args.iss, args.iss_yaml, args.iss_opts,
                 args.isa, args.core_setting_dir, args.iss_timeout, args.debug)
 
       # Compare ISS simulation result
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 bc1ca42..84c4fce 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
@@ -225,7 +225,7 @@
   test_file.write(f"\tli x1, {TEST_FAIL}\n")
   test_file.write(f"\tslli x1, x1, 8\n")
   test_file.write(f"\taddi x1, x1, {TEST_RESULT}\n")
-  test_file.write(f"\tli x2, {end_addr}\n")
+  test_file.write(f"\tli x2, 0x{end_addr}\n")
   test_file.write(f"\tsw x1, 0(x2)\n")
   test_file.write(f"\tj csr_fail\n")
 
@@ -244,7 +244,7 @@
   test_file.write(f"\tli x1, {TEST_PASS}\n")
   test_file.write(f"\tslli x1, x1, 8\n")
   test_file.write(f"\taddi x1, x1, {TEST_RESULT}\n")
-  test_file.write(f"\tli x2, {end_addr}\n")
+  test_file.write(f"\tli x2, 0x{end_addr}\n")
   test_file.write(f"\tsw x1, 0(x2)\n")
   test_file.write(f"\tj csr_pass\n")
 
@@ -318,28 +318,42 @@
       gen_csr_test_fail(csr_test_file, end_signature_addr)
 
 
-"""
-Define command line arguments.
-"""
-parser = argparse.ArgumentParser()
-parser.add_argument("--csr_file", type=str, default="yaml/csr_template.yaml",
-        help="The YAML file contating descriptions of all processor supported CSRs")
-parser.add_argument("--xlen", type=int, default=32,
-        help="Specify the ISA width, e.g. 32 or 64 or 128")
-parser.add_argument("--iterations", type=int, default=1,
-        help="Specify how many tests to be generated")
-parser.add_argument("--out", type=str, default="./",
-        help="Specify output directory")
-parser.add_argument("--end_signature_addr", type=str, default="0",
-        help="Address that should be written to at end of this test")
-args = parser.parse_args()
+def main():
+  """Main entry point of CSR test generation script.
+     Will set up a list of all supported CSR instructions,
+     and seed the RNG."""
+
+  # define command line arguments
+  parser = argparse.ArgumentParser()
+  parser.add_argument("--csr_file", type=str, default="yaml/csr_template.yaml",
+          help="The YAML file contating descriptions of all processor supported CSRs")
+  parser.add_argument("--xlen", type=int, default=32,
+          help="Specify the ISA width, e.g. 32 or 64 or 128")
+  parser.add_argument("--iterations", type=int, default=1,
+          help="Specify how many tests to be generated")
+  parser.add_argument("--out", type=str, default="./",
+          help="Specify output directory")
+  parser.add_argument("--end_signature_addr", type=str, default="0",
+          help="Address that should be written to at end of this test")
+  parser.add_argument("--seed", type=int, default=None,
+          help="""Value used to seed the random number generator. If no value is passed in,
+                  the RNG will be seeded from an internal source of randomness.""")
+  args = parser.parse_args()
+
+  """All supported CSR operations"""
+  csr_ops = ['csrrw', 'csrrs', 'csrrc', 'csrrwi', 'csrrsi', 'csrrci']
+
+  """
+  Seed the RNG.
+  If args.seed is None, seed will be drawn from some internal random source.
+  If args.seed is defined, this will be used to seed the RNG for user reproducibility.
+  """
+  random.seed(args.seed)
+
+  gen_csr_instr(get_csr_map(args.csr_file, args.xlen),
+                csr_ops, args.xlen, args.iterations, args.out,
+                args.end_signature_addr)
 
 
-"""
-A list containing all supported CSR instructions.
-"""
-csr_ops = ['csrrw', 'csrrs', 'csrrc', 'csrrwi', 'csrrsi', 'csrrci']
-
-gen_csr_instr(get_csr_map(args.csr_file, args.xlen),
-              csr_ops, args.xlen, args.iterations, args.out,
-              args.end_signature_addr)
+if __name__ == "__main__":
+  main()
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/dv_defines.svh b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/dv_defines.svh
index 205f5d3..07d3d1a 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/dv_defines.svh
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/dv_defines.svh
@@ -68,6 +68,18 @@
     `DV_CHECK_FATAL(std::randomize(VAR_), MSG_, ID_, with { WITH_C_ })
 `endif
 
+// Shorthand for common this.randomize(foo) + fatal check
+`ifndef DV_CHECK_MEMBER_RANDOMIZE_FATAL
+  `define DV_CHECK_MEMBER_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \
+    `DV_CHECK_FATAL(this.randomize(VAR_), MSG_, ID_)
+`endif
+
+// Shorthand for common this.randomize(foo) with { } + fatal check
+`ifndef DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL
+  `define DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(VAR_, C_, MSG_="Randomization failed!", ID_=`gfn) \
+    `DV_CHECK_FATAL(this.randomize(VAR_) with {C_}, MSG_, ID_)
+`endif
+
 // for vector processing
 `ifndef VECTOR_INCLUDE
   `define VECTOR_INCLUDE(VCE_INC) \
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_compressed_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_compressed_instr.sv
index 312b0b9..c91fd7c 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_compressed_instr.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_compressed_instr.sv
@@ -261,7 +261,7 @@
         binary = $sformatf("%4h", {get_func3(), imm[11], imm[4], imm[9:8],
                                    imm[10], imm[6], imm[7], imm[3:1], imm[5], get_c_opcode()});
       C_ADDI16SP:
-        binary = $sformatf("%4h", {get_func3(), imm[9], 5'b10,
+        binary = $sformatf("%4h", {get_func3(), imm[9], 5'b00010,
                                    imm[4], imm[6], imm[8:7], imm[5], get_c_opcode()});
       C_LUI:
         binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:0], get_c_opcode()});
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_instr.sv
index b305c9a..ce56488 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_instr.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/riscv_instr.sv
@@ -554,13 +554,13 @@
         else if(instr_name == ECALL)
           binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()});
         else if(instr_name inside {URET, SRET, MRET})
-          binary = $sformatf("%8h", {get_func7(), 5'b10, 13'b0, get_opcode()});
+          binary = $sformatf("%8h", {get_func7(), 5'b00010, 13'b0, get_opcode()});
         else if(instr_name inside {DRET})
           binary = $sformatf("%8h", {get_func7(), 5'b10010, 13'b0, get_opcode()});
         else if(instr_name == EBREAK)
-          binary = $sformatf("%8h", {get_func7(), 5'b01, 13'b0, get_opcode()});
+          binary = $sformatf("%8h", {get_func7(), 5'd1, 13'b0, get_opcode()});
         else if(instr_name == WFI)
-          binary = $sformatf("%8h", {get_func7(), 5'b101, 13'b0, get_opcode()});
+          binary = $sformatf("%8h", {get_func7(), 5'b00101, 13'b0, get_opcode()});
         else
           binary = $sformatf("%8h", {imm[11:0], rs1, get_func3(), rd, get_opcode()});
       end
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_amo_instr_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_amo_instr_lib.sv
index 9dda45d..8464aa5 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_amo_instr_lib.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_amo_instr_lib.sv
@@ -50,6 +50,21 @@
     super.new(name);
   endfunction
 
+  function void pre_randomize();
+    data_page = cfg.amo_region;
+    max_data_page_id = data_page.size();
+  endfunction
+
+  // Use "la" instruction to initialize the base regiseter
+  virtual function void add_rs1_init_la_instr(riscv_reg_t gpr, int id, int base = 0);
+    riscv_pseudo_instr la_instr;
+    la_instr = riscv_pseudo_instr::type_id::create("la_instr");
+    la_instr.pseudo_instr_name = LA;
+    la_instr.rd = gpr;
+    la_instr.imm_str = $sformatf("%0s+%0d", cfg.amo_region[id].name, base);
+    instr_list.push_front(la_instr);
+  endfunction
+
   function void post_randomize();
     gen_amo_instr();
     // rs1 cannot be modified by other instructions
@@ -85,8 +100,18 @@
   endfunction
 
   virtual function void gen_amo_instr();
-    lr_instr = riscv_instr::get_rand_instr(.include_instr({LR_W, LR_D}));
-    sc_instr = riscv_instr::get_rand_instr(.include_instr({SC_W, SC_D}));
+    riscv_instr_name_t allowed_lr_instr[];
+    riscv_instr_name_t allowed_sc_instr[];
+    if (RV32A inside {supported_isa}) begin
+      allowed_lr_instr = {LR_W};
+      allowed_sc_instr = {SC_W};
+    end
+    if (RV64A inside {supported_isa}) begin
+      allowed_lr_instr = {allowed_lr_instr, LR_D};
+      allowed_sc_instr = {allowed_sc_instr, SC_D};
+    end
+    lr_instr = riscv_instr::get_rand_instr(.include_instr({allowed_lr_instr}));
+    sc_instr = riscv_instr::get_rand_instr(.include_instr({allowed_sc_instr}));
     `DV_CHECK_RANDOMIZE_WITH_FATAL(lr_instr,
       rs1 == rs1_reg;
       if (reserved_rd.size() > 0) {
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
index 821ae8d..ae18ede 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
@@ -27,8 +27,8 @@
    riscv_instr_gen_config              cfg;
    riscv_data_page_gen                 data_page_gen;
    // User mode programs
-   riscv_instr_sequence                main_program;
-   riscv_instr_sequence                sub_program[];
+   riscv_instr_sequence                main_program[NUM_HARTS];
+   riscv_instr_sequence                sub_program[NUM_HARTS][];
    riscv_asm_program_gen               debug_rom;
    // Kernel programs
    // These programs are called in the interrupt/exception handling routine based on the privileged
@@ -47,6 +47,7 @@
    // Directed instruction ratio, occurance per 1000 instructions
    int unsigned                        directed_instr_stream_ratio[string];
    riscv_page_table_list#(SATP_MODE)   page_table_list;
+   int                                 hart;
 
   `uvm_object_utils(riscv_asm_program_gen)
 
@@ -60,120 +61,149 @@
 
   // This is the main function to generate all sections of the program.
   virtual function void gen_program();
-    string sub_program_name[$];
     instr_stream.delete();
     // Generate program header
     gen_program_header();
-    // Initialize general purpose registers
-    init_gpr();
-    if (!cfg.bare_program_mode) begin
-      setup_misa();
-      // Create all page tables
-      create_page_table();
-      // Setup privileged mode registers and enter target privileged mode
-      pre_enter_privileged_mode();
-    end
-    // Init section
-    gen_init_section();
-    // Generate sub program
-    gen_sub_program(sub_program, sub_program_name, cfg.num_of_sub_program);
-    // Generate main program
-    main_program = riscv_instr_sequence::type_id::create("main_program");
-    main_program.instr_cnt = cfg.main_program_instr_cnt;
-    main_program.is_debug_program = 0;
-    main_program.label_name = "_main";
-    generate_directed_instr_stream(.label("main"),
-                                   .original_instr_cnt(main_program.instr_cnt),
-                                   .min_insert_cnt(1),
-                                   .instr_stream(main_program.directed_instr));
-    main_program.cfg = cfg;
-    `DV_CHECK_RANDOMIZE_FATAL(main_program)
-    main_program.gen_instr(.is_main_program(1), .no_branch(cfg.no_branch_jump));
-    // Setup jump instruction among main program and sub programs
-    gen_callstack(main_program, sub_program, sub_program_name, cfg.num_of_sub_program);
-    `uvm_info(`gfn, "Generating callstack...done", UVM_LOW)
-    main_program.post_process_instr();
-    `uvm_info(`gfn, "Post-processing main program...done", UVM_LOW)
-    main_program.generate_instr_stream();
-    `uvm_info(`gfn, "Generating main program instruction stream...done", UVM_LOW)
-    instr_stream = {instr_stream, main_program.instr_string_list};
-    // Test done section
-    gen_test_done();
-    // Shuffle the sub programs and insert to the instruction stream
-    insert_sub_program(sub_program, instr_stream);
-    `uvm_info(`gfn, "Inserting sub-programs...done", UVM_LOW)
-    `uvm_info(`gfn, "Main/sub program generation...done", UVM_LOW)
-    // Program end
-    gen_program_end();
-    if (!cfg.bare_program_mode) begin
-      // Privileged mode switch routine
-      gen_privileged_mode_switch_routine();
-      // Generate debug rom section
-      if (riscv_instr_pkg::support_debug_mode) begin
-        gen_debug_rom();
+    for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
+      string sub_program_name[$];
+      instr_stream.push_back($sformatf("h%0d_start:", hart));
+      if (!cfg.bare_program_mode) begin
+        setup_misa();
+        // Create all page tables
+        create_page_table(hart);
+        // Setup privileged mode registers and enter target privileged mode
+        pre_enter_privileged_mode(hart);
       end
+      // Init section
+      gen_init_section(hart);
+      // If PMP is supported, we want to generate the associated trap handlers and the test_done
+      // section at the start of the program so we can allow access through the pmpcfg0 CSR
+      if (support_pmp) begin
+        gen_trap_handlers(hart);
+        // Ecall handler
+        gen_ecall_handler(hart);
+        // Instruction fault handler
+        gen_instr_fault_handler(hart);
+        // Load fault handler
+        gen_load_fault_handler(hart);
+        // Store fault handler
+        gen_store_fault_handler(hart);
+        gen_test_done();
+      end
+      // Generate sub program
+      gen_sub_program(hart, sub_program[hart], sub_program_name, cfg.num_of_sub_program);
+      // Generate main program
+      main_program[hart] = riscv_instr_sequence::type_id::create(get_label("main", hart));
+      main_program[hart].instr_cnt = cfg.main_program_instr_cnt;
+      main_program[hart].is_debug_program = 0;
+      main_program[hart].label_name = main_program[hart].get_name();
+      generate_directed_instr_stream(.hart(hart),
+                                     .label(main_program[hart].label_name),
+                                     .original_instr_cnt(main_program[hart].instr_cnt),
+                                     .min_insert_cnt(1),
+                                     .instr_stream(main_program[hart].directed_instr));
+      main_program[hart].cfg = cfg;
+      `DV_CHECK_RANDOMIZE_FATAL(main_program[hart])
+      main_program[hart].gen_instr(.is_main_program(1), .no_branch(cfg.no_branch_jump));
+      // Setup jump instruction among main program and sub programs
+      gen_callstack(main_program[hart], sub_program[hart], sub_program_name, cfg.num_of_sub_program);
+      `uvm_info(`gfn, "Generating callstack...done", UVM_LOW)
+      main_program[hart].post_process_instr();
+      `uvm_info(`gfn, "Post-processing main program...done", UVM_LOW)
+      main_program[hart].generate_instr_stream();
+      `uvm_info(`gfn, "Generating main program instruction stream...done", UVM_LOW)
+      instr_stream = {instr_stream, main_program[hart].instr_string_list};
+      // If PMP is supported, need to jump from end of main program to test_done section at the end
+      // of main_program, as the test_done will have moved to the beginning of the program
+      instr_stream = {instr_stream, $sformatf("%sj test_done", indent)};
+      // Test done section
+      // If PMP isn't supported, generate this in the normal location
+      if (hart == 0 & !support_pmp) begin
+        gen_test_done();
+      end
+      // Shuffle the sub programs and insert to the instruction stream
+      insert_sub_program(sub_program[hart], instr_stream);
+      `uvm_info(`gfn, "Inserting sub-programs...done", UVM_LOW)
+      `uvm_info(`gfn, "Main/sub program generation...done", UVM_LOW)
+      // Program end
+      gen_program_end(hart);
+      if (!cfg.bare_program_mode) begin
+        // Privileged mode switch routine
+        gen_privileged_mode_switch_routine(hart);
+        // Generate debug rom section
+        if (riscv_instr_pkg::support_debug_mode) begin
+          gen_debug_rom(hart);
+        end
+      end
+      gen_section({hart_prefix(hart), "instr_end"}, {"nop"});
     end
-    // Starting point of data section
-    gen_data_page_begin();
-    // Page table
-    if (!cfg.bare_program_mode) begin
-      gen_page_table_section();
-    end
-    if(!cfg.no_data_page) begin
-      // Kernel data section
-      gen_data_page();
-    end
-    gen_data_page_end();
-    // Stack section
-    gen_stack_section();
-    if (!cfg.bare_program_mode) begin
-      // Generate kernel program/data/stack section
-      gen_kernel_sections();
+    for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
+      // Starting point of data section
+      gen_data_page_begin(hart);
+      if(!cfg.no_data_page) begin
+        // User data section
+        gen_data_page(hart);
+        // AMO memory region
+        if ((hart == 0) && (RV32A inside {supported_isa})) begin
+          gen_data_page(hart, .amo(1));
+        end
+      end
+      // Stack section
+      gen_stack_section(hart);
+      if (!cfg.bare_program_mode) begin
+        // Generate kernel program/data/stack section
+        gen_kernel_sections(hart);
+      end
+      // Page table
+      if (!cfg.bare_program_mode) begin
+        gen_page_table_section(hart);
+      end
     end
   endfunction
 
   //---------------------------------------------------------------------------------------
   // Generate kernel program/data/stack sections
   //---------------------------------------------------------------------------------------
-  virtual function void gen_kernel_sections();
-    instr_stream.push_back("_kernel_instr_start: .align 12");
+  virtual function void gen_kernel_sections(int hart);
+    instr_stream.push_back(get_label("kernel_instr_start: .align 12", hart));
     instr_stream.push_back(".text");
     // Kernel programs
     if (cfg.virtual_addr_translation_on) begin
-      umode_program = riscv_instr_sequence::type_id::create("umode_program");
-      gen_kernel_program(umode_program);
-      smode_program = riscv_instr_sequence::type_id::create("smode_program");
-      gen_kernel_program(smode_program);
-      smode_lsu_program = riscv_instr_sequence::type_id::create("smode_lsu_program");
-      gen_kernel_program(smode_lsu_program);
+      umode_program = riscv_instr_sequence::type_id::create(get_label("umode_program", hart));
+      gen_kernel_program(hart, umode_program);
+      smode_program = riscv_instr_sequence::type_id::create(get_label("smode_program", hart));
+      gen_kernel_program(hart, smode_program);
+      smode_lsu_program = riscv_instr_sequence::type_id::create(
+                          get_label("smode_lsu_program", hart));
+      gen_kernel_program(hart, smode_lsu_program);
     end
     // All trap/interrupt handling is in the kernel region
     // Trap/interrupt delegation to user mode is not supported now
     // Trap handler
-    gen_all_trap_handler();
+    gen_all_trap_handler(hart);
     // Interrupt handling subroutine
     foreach(riscv_instr_pkg::supported_privileged_mode[i]) begin
-      gen_interrupt_handler_section(riscv_instr_pkg::supported_privileged_mode[i]);
+      gen_interrupt_handler_section(riscv_instr_pkg::supported_privileged_mode[i], hart);
     end
-    instr_stream.push_back("_kernel_instr_end: nop");
+    instr_stream.push_back(get_label("kernel_instr_end: nop", hart));
     // User stack and data pages may not be accessible when executing trap handling programs in
     // machine/supervisor mode. Generate separate kernel data/stack sections to solve it.
     if (cfg.virtual_addr_translation_on) begin
       // Kernel data pages
-      instr_stream.push_back("_kernel_data_start: .align 12");
+      instr_stream.push_back(get_label("kernel_data_start: .align 12", hart));
       if(!cfg.no_data_page) begin
         // Data section
-        gen_data_page(1'b1);
+        gen_data_page(hart, 1'b1);
       end
-      gen_data_page_end();
     end
     // Kernel stack section
-    gen_kernel_stack_section();
+    gen_kernel_stack_section(hart);
   endfunction
 
-  virtual function void gen_kernel_program(riscv_instr_sequence seq);
+  virtual function void gen_kernel_program(int hart, riscv_instr_sequence seq);
     seq.instr_cnt = cfg.kernel_program_instr_cnt;
-    generate_directed_instr_stream(.label(seq.get_name()),
+    generate_directed_instr_stream(.hart(hart),
+                                   .label(seq.get_name()),
                                    .original_instr_cnt(seq.instr_cnt),
                                    .min_insert_cnt(0),
                                    .instr_stream(seq.directed_instr),
@@ -192,7 +222,8 @@
   // Generate any subprograms and set up the callstack
   //---------------------------------------------------------------------------------------
 
-  virtual function void gen_sub_program(ref riscv_instr_sequence sub_program[],
+  virtual function void gen_sub_program(int hart,
+                                        ref riscv_instr_sequence sub_program[],
                                         ref string sub_program_name[$],
                                         input int num_sub_program,
                                         bit is_debug = 1'b0,
@@ -200,15 +231,17 @@
     if(num_sub_program > 0) begin
       sub_program = new[num_sub_program];
       foreach(sub_program[i]) begin
-        sub_program[i] = riscv_instr_sequence::type_id::create($sformatf("%s_%0d",prefix,i+1));
-        `uvm_info(`gfn, $sformatf("sub program name: %s", prefix), UVM_LOW)
+        sub_program[i] = riscv_instr_sequence::type_id::create(
+                         get_label($sformatf("%s_%0d", prefix, i + 1), hart));
+        `uvm_info(`gfn, $sformatf("sub program name: %s", sub_program[i].get_name()), UVM_LOW)
         sub_program[i].is_debug_program = is_debug;
         if (is_debug) begin
           sub_program[i].instr_cnt = cfg.debug_sub_program_instr_cnt[i];
         end else begin
           sub_program[i].instr_cnt = cfg.sub_program_instr_cnt[i];
         end
-        generate_directed_instr_stream(.label(sub_program[i].get_name()),
+        generate_directed_instr_stream(.hart(hart),
+                                       .label(sub_program[i].get_name()),
                                        .original_instr_cnt(sub_program[i].instr_cnt),
                                        .min_insert_cnt(0),
                                        .instr_stream(sub_program[i].directed_instr));
@@ -267,74 +300,96 @@
   //---------------------------------------------------------------------------------------
 
   virtual function void gen_program_header();
+    string str[$];
     instr_stream.push_back(".include \"user_define.h\"");
     instr_stream.push_back(".globl _start");
     instr_stream.push_back(".section .text");
     if (cfg.disable_compressed_instr) begin
       instr_stream.push_back(".option norvc;");
     end
-    instr_stream.push_back("_start:");
+    str = {"csrr x5, mhartid"};
+    for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
+      str = {str, $sformatf("li x6, %0d", hart),
+                  $sformatf("beq x5, x6, %0df", hart)};
+    end
+    gen_section("_start", str);
+    for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
+      instr_stream.push_back($sformatf("%0d: j h%0d_start", hart, hart));
+    end
   endfunction
 
-  virtual function void gen_program_end();
-    // Use write_tohost to terminate spike simulation
-    gen_section("write_tohost", {"sw gp, tohost, t5"});
-    gen_section("_exit", {"j write_tohost"});
+  virtual function void gen_program_end(int hart);
+    if (hart == 0) begin
+      // Use write_tohost to terminate spike simulation
+      gen_section("write_tohost", {"sw gp, tohost, t5"});
+      gen_section("_exit", {"j write_tohost"});
+    end
   endfunction
 
-  virtual function void gen_data_page_begin();
-    instr_stream.push_back(".data");
-    instr_stream.push_back(".pushsection .tohost,\"aw\",@progbits;");
-    instr_stream.push_back(".align 6; .global tohost; tohost: .dword 0;");
-    instr_stream.push_back(".align 6; .global fromhost; fromhost: .dword 0;");
-    instr_stream.push_back(".popsection;");
+  virtual function void gen_data_page_begin(int hart);
+    instr_stream.push_back(".section .data");
+    if (hart == 0) begin
+      instr_stream.push_back(".align 6; .global tohost; tohost: .dword 0;");
+      instr_stream.push_back(".align 6; .global fromhost; fromhost: .dword 0;");
+    end
   endfunction
 
-  virtual function void gen_data_page(bit is_kernel = 1'b0);
+  virtual function void gen_data_page(int hart, bit is_kernel = 1'b0, bit amo = 0);
     string data_page;
     data_page_gen = riscv_data_page_gen::type_id::create("data_page_gen");
     data_page_gen.cfg = cfg;
-    data_page_gen.gen_data_page(cfg.data_page_pattern, is_kernel);
+    data_page_gen.gen_data_page(hart, cfg.data_page_pattern, is_kernel, amo);
     instr_stream = {instr_stream, data_page_gen.data_page_str};
   endfunction
 
-  virtual function void gen_data_page_end();
-    instr_stream.push_back(".align 4;");
-  endfunction
-
   // Generate the user stack section
-  virtual function void gen_stack_section();
-    instr_stream.push_back(".pushsection .user_stack,\"aw\",@progbits;");
+  virtual function void gen_stack_section(int hart);
+    if (cfg.use_push_data_section) begin
+      instr_stream.push_back($sformatf(".pushsection .%0suser_stack,\"aw\",@progbits;",
+                             hart_prefix(hart)));
+    end
     instr_stream.push_back(".align 12");
-    instr_stream.push_back("_user_stack_start:");
+    instr_stream.push_back(get_label("user_stack_start:", hart));
     instr_stream.push_back($sformatf(".rept %0d", cfg.stack_len - 1));
     instr_stream.push_back($sformatf(".%0dbyte 0x0", XLEN/8));
     instr_stream.push_back(".endr");
-    instr_stream.push_back("_user_stack_end:");
+    instr_stream.push_back(get_label("user_stack_end:", hart));
     instr_stream.push_back($sformatf(".%0dbyte 0x0", XLEN/8));
-    instr_stream.push_back(".popsection;");
+    if (cfg.use_push_data_section) begin
+      instr_stream.push_back(".popsection;");
+    end
   endfunction
 
   // The kernal stack is used to save user program context before executing exception handling
-  virtual function void gen_kernel_stack_section();
-    instr_stream.push_back(".pushsection .kernel_stack,\"aw\",@progbits;");
+  virtual function void gen_kernel_stack_section(int hart);
+    if (cfg.use_push_data_section) begin
+      instr_stream.push_back($sformatf(".pushsection .%0skernel_stack,\"aw\",@progbits;",
+                             hart_prefix(hart)));
+    end
     instr_stream.push_back(".align 12");
-    instr_stream.push_back("_kernel_stack_start:");
+    instr_stream.push_back(get_label("kernel_stack_start:", hart));
     instr_stream.push_back($sformatf(".rept %0d", cfg.kernel_stack_len - 1));
     instr_stream.push_back($sformatf(".%0dbyte 0x0", XLEN/8));
     instr_stream.push_back(".endr");
-    instr_stream.push_back("_kernel_stack_end:");
+    instr_stream.push_back(get_label("kernel_stack_end:", hart));
     instr_stream.push_back($sformatf(".%0dbyte 0x0", XLEN/8));
-    instr_stream.push_back(".popsection;");
+    if (cfg.use_push_data_section) begin
+      instr_stream.push_back(".popsection;");
+    end
   endfunction
 
-  virtual function void gen_init_section();
+  virtual function void gen_init_section(int hart);
     string str;
-    str = format_string("_init:", LABEL_STR_LEN);
+    str = format_string(get_label("init:", hart), LABEL_STR_LEN);
     instr_stream.push_back(str);
+    init_gpr();
     // Init stack pointer to point to the end of the user stack
-    str = {indent, $sformatf("la x%0d, _user_stack_end", cfg.sp)};
+    str = {indent, $sformatf("la x%0d, %0suser_stack_end", cfg.sp, hart_prefix(hart))};
     instr_stream.push_back(str);
+    if (support_pmp) begin
+      str = {indent, "j main"};
+      instr_stream.push_back(str);
+    end
     if (cfg.enable_floating_point) begin
       init_floating_point_gpr();
     end
@@ -431,6 +486,7 @@
     bit [DATA_WIDTH-1:0] reg_val;
     // Init general purpose registers with random values
     for(int i = 0; i < 32; i++) begin
+      if (i inside {cfg.sp, cfg.tp}) continue;
       `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(reg_val,
         reg_val dist {
           'h0                         :/ 1,
@@ -515,26 +571,29 @@
   // Privileged mode entering routine
   //---------------------------------------------------------------------------------------
 
-  virtual function void pre_enter_privileged_mode();
+  virtual function void pre_enter_privileged_mode(int hart);
     string instr[];
     // Setup kerenal stack pointer
-    gen_section("kernel_sp", {$sformatf("la x%0d, _kernel_stack_end", cfg.tp)});
+    gen_section(get_label("kernel_sp", hart),
+               {$sformatf("la x%0d, %0skernel_stack_end", cfg.tp, hart_prefix(hart))});
     // Setup interrupt and exception delegation
     if(!cfg.no_delegation && (cfg.init_privileged_mode != MACHINE_MODE)) begin
-      gen_delegation();
+      gen_delegation(hart);
     end
     // Setup trap vector register
-    trap_vector_init();
+    trap_vector_init(hart);
+    // Setup PMP CSRs
+    setup_pmp(hart);
     // Initialize PTE (link page table based on their real physical address)
     if(cfg.virtual_addr_translation_on) begin
       page_table_list.process_page_table(instr);
-      gen_section("process_pt", instr);
+      gen_section(get_label("process_pt", hart), instr);
     end
     // Setup mepc register, jump to init entry
-    setup_epc();
+    setup_epc(hart);
   endfunction
 
-  virtual function void gen_privileged_mode_switch_routine();
+  virtual function void gen_privileged_mode_switch_routine(int hart);
     privil_seq = riscv_privileged_common_seq::type_id::create("privil_seq");
     foreach(riscv_instr_pkg::supported_privileged_mode[i]) begin
       string instr[$];
@@ -545,6 +604,7 @@
                       riscv_instr_pkg::supported_privileged_mode[i].name()), UVM_LOW)
       // Enter privileged mode
       privil_seq.cfg = cfg;
+      privil_seq.hart = hart;
       `DV_CHECK_RANDOMIZE_FATAL(privil_seq)
       privil_seq.enter_privileged_mode(riscv_instr_pkg::supported_privileged_mode[i], instr);
       if (cfg.require_signature_addr) begin
@@ -553,11 +613,14 @@
         // is complete, for any initial state analysis
         case(riscv_instr_pkg::supported_privileged_mode[i])
           SUPERVISOR_MODE: begin
-            gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR), .csr(SSTATUS));
-            gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR), .csr(SIE));
+            gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR),
+                                    .csr(SSTATUS));
+            gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR),
+                                    .csr(SIE));
           end
           USER_MODE: begin
-            gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR), .csr(USTATUS));
+            gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR),
+                                    .csr(USTATUS));
             gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR), .csr(UIE));
           end
         endcase
@@ -572,10 +635,10 @@
   endfunction
 
   // Setup EPC before entering target privileged mode
-  virtual function void setup_epc();
+  virtual function void setup_epc(int hart);
     string instr[];
     string mode_name;
-    instr = {$sformatf("la x%0d, _init", cfg.gpr[0])};
+    instr = {$sformatf("la x%0d, %0sinit", cfg.gpr[0], hart_prefix(hart))};
     if(cfg.virtual_addr_translation_on) begin
       // For supervisor and user mode, use virtual address instead of physical address.
       // Virtual address starts from address 0x0, here only the lower 12 bits are kept
@@ -587,9 +650,19 @@
     mode_name = cfg.init_privileged_mode.name();
     instr = {instr,
              $sformatf("csrw mepc, x%0d", cfg.gpr[0]),
-             $sformatf("j init_%0s", mode_name.tolower())
+             $sformatf("j %0sinit_%0s", hart_prefix(hart), mode_name.tolower())
             };
-    gen_section("mepc_setup", instr);
+    gen_section(get_label("mepc_setup", hart), instr);
+  endfunction
+
+  // Setup PMP CSR configuration
+  virtual function void setup_pmp(int hart);
+    string instr[$];
+    if (riscv_instr_pkg::support_pmp) begin
+      cfg.pmp_cfg.setup_pmp();
+      cfg.pmp_cfg.gen_pmp_instr(instr, cfg.scratch_reg);
+      gen_section(get_label("pmp_setup", hart), instr);
+    end
   endfunction
 
   //---------------------------------------------------------------------------------------
@@ -598,18 +671,19 @@
 
   // Interrupt and exception delegation setting.
   // The lower level exception and interrupt can be delegated to higher level handler.
-  virtual function void gen_delegation();
-    gen_delegation_instr(MEDELEG, MIDELEG,
+  virtual function void gen_delegation(int hart);
+    gen_delegation_instr(hart, MEDELEG, MIDELEG,
                          cfg.m_mode_exception_delegation,
                          cfg.m_mode_interrupt_delegation);
     if(riscv_instr_pkg::support_umode_trap) begin
-      gen_delegation_instr(SEDELEG, SIDELEG,
+      gen_delegation_instr(hart, SEDELEG, SIDELEG,
                            cfg.s_mode_exception_delegation,
                            cfg.s_mode_interrupt_delegation);
     end
   endfunction
 
-  virtual function void gen_delegation_instr(privileged_reg_t edeleg,
+  virtual function void gen_delegation_instr(int hart,
+                                             privileged_reg_t edeleg,
                                              privileged_reg_t ideleg,
                                              bit edeleg_enable[exception_cause_t],
                                              bit ideleg_enable[interrupt_cause_t]);
@@ -636,11 +710,11 @@
              $sformatf("csrw 0x%0x, x%0d # %0s", ideleg, cfg.gpr[0], ideleg.name())};
     section_name = edeleg.name();
     section_name = section_name.tolower();
-    gen_section($sformatf("%0s_setup", section_name), instr);
+    gen_section(get_label($sformatf("%0s_setup", section_name), hart), instr);
   endfunction
 
   // Setup trap vector - MTVEC, STVEC, UTVEC
-  virtual function void trap_vector_init();
+  virtual function void trap_vector_init(int hart);
     string instr[];
     privileged_reg_t trap_vec_reg;
     string tvec_name;
@@ -655,7 +729,8 @@
           !riscv_instr_pkg::support_umode_trap) continue;
       if (riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
       tvec_name = trap_vec_reg.name();
-      instr = {instr, $sformatf("la x%0d, %0s_handler", cfg.gpr[0], tvec_name.tolower())};
+      instr = {instr, $sformatf("la x%0d, %0s%0s_handler",
+                                cfg.gpr[0], hart_prefix(hart), tvec_name.tolower())};
       if (SATP_MODE != BARE && riscv_instr_pkg::supported_privileged_mode[i] != MACHINE_MODE) begin
         // For supervisor and user mode, use virtual address instead of physical address.
         // Virtual address starts from address 0x0, here only the lower 20 bits are kept
@@ -668,7 +743,7 @@
       instr = {instr, $sformatf("csrw 0x%0x, x%0d # %0s",
                                  trap_vec_reg, cfg.gpr[0], trap_vec_reg.name())};
     end
-    gen_section("trap_vec_init", instr);
+    gen_section(get_label("trap_vec_init", hart), instr);
   endfunction
 
   //---------------------------------------------------------------------------------------
@@ -676,33 +751,24 @@
   //---------------------------------------------------------------------------------------
 
   // Trap handling routine
-  virtual function void gen_all_trap_handler();
+  virtual function void gen_all_trap_handler(int hart);
     string instr[$];
-    foreach(riscv_instr_pkg::supported_privileged_mode[i]) begin
-      if(riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
-      case(riscv_instr_pkg::supported_privileged_mode[i])
-        MACHINE_MODE:
-          gen_trap_handler_section("m", MCAUSE, MTVEC, MTVAL, MEPC, MSCRATCH, MSTATUS, MIE, MIP);
-        SUPERVISOR_MODE:
-          gen_trap_handler_section("s", SCAUSE, STVEC, STVAL, SEPC, SSCRATCH, SSTATUS, SIE, SIP);
-        USER_MODE:
-          if(riscv_instr_pkg::support_umode_trap) begin
-            gen_trap_handler_section("u", UCAUSE, UTVEC, UTVAL, UEPC, USCRATCH, USTATUS, UIE, UIP);
-          end
-      endcase
+    // If PMP isn't supported, generate the relevant trap handler sections as per usual
+    if (!support_pmp) begin
+      gen_trap_handlers(hart);
+      // Ecall handler
+      gen_ecall_handler(hart);
+      // Instruction fault handler
+      gen_instr_fault_handler(hart);
+      // Load fault handler
+      gen_load_fault_handler(hart);
+      // Store fault handler
+      gen_store_fault_handler(hart);
     end
     // Ebreak handler
-    gen_ebreak_handler();
-    // Ecall handler
-    gen_ecall_handler();
+    gen_ebreak_handler(hart);
     // Illegal instruction handler
-    gen_illegal_instr_handler();
-    // Instruction fault handler
-    gen_instr_fault_handler();
-    // Load fault handler
-    gen_load_fault_handler();
-    // Store fault handler
-    gen_store_fault_handler();
+    gen_illegal_instr_handler(hart);
     // Generate page table fault handling routine
     // Page table fault is always handled in machine mode, as virtual address translation may be
     // broken when page fault happens.
@@ -712,44 +778,65 @@
     end else begin
       instr.push_back("nop");
     end
-    gen_section("pt_fault_handler", instr);
+    gen_section(get_label("pt_fault_handler", hart), instr);
+  endfunction
+
+  virtual function void gen_trap_handlers(int hart);
+    foreach(riscv_instr_pkg::supported_privileged_mode[i]) begin
+      if(riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
+      case(riscv_instr_pkg::supported_privileged_mode[i])
+        MACHINE_MODE:
+          gen_trap_handler_section(hart, "m", MCAUSE, MTVEC, MTVAL,
+                                   MEPC, MSCRATCH, MSTATUS, MIE, MIP);
+        SUPERVISOR_MODE:
+          gen_trap_handler_section(hart, "s", SCAUSE, STVEC, STVAL,
+                                   SEPC, SSCRATCH, SSTATUS, SIE, SIP);
+        USER_MODE:
+          if(riscv_instr_pkg::support_umode_trap) begin
+            gen_trap_handler_section(hart, "u", UCAUSE, UTVEC, UTVAL,
+                                     UEPC, USCRATCH, USTATUS, UIE, UIP);
+          end
+      endcase
+    end
   endfunction
 
   // Generate the interrupt and trap handler for different privileged mode.
   // The trap handler checks the xCAUSE to determine the type of the exception and jumps to
   // corresponding exeception handling routine.
-  virtual function void gen_trap_handler_section(string mode,
-                                            privileged_reg_t cause, privileged_reg_t tvec,
-                                            privileged_reg_t tval, privileged_reg_t epc,
-                                            privileged_reg_t scratch, privileged_reg_t status,
-                                            privileged_reg_t ie, privileged_reg_t ip);
+  virtual function void gen_trap_handler_section(int hart,
+                                                 string mode,
+                                                 privileged_reg_t cause, privileged_reg_t tvec,
+                                                 privileged_reg_t tval, privileged_reg_t epc,
+                                                 privileged_reg_t scratch, privileged_reg_t status,
+                                                 privileged_reg_t ie, privileged_reg_t ip);
     bit is_interrupt = 'b1;
     string tvec_name;
     string instr[$];
     if (cfg.mtvec_mode == VECTORED) begin
-      gen_interrupt_vector_table(mode, status, cause, ie, ip, scratch, instr);
+      gen_interrupt_vector_table(hart, mode, status, cause, ie, ip, scratch, instr);
     end else begin
       // Push user mode GPR to kernel stack before executing exception handling, this is to avoid
       // exception handling routine modify user program state unexpectedly
       push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
-      // Checking xStatus can be optional if ISS (like spike) has different implementation of certain
-      // fields compared with the RTL processor.
+      // Checking xStatus can be optional if ISS (like spike) has different implementation of
+      // certain fields compared with the RTL processor.
       if (cfg.check_xstatus) begin
         instr = {instr, $sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], status, status.name())};
       end
       instr = {instr,
                // Use scratch CSR to save a GPR value
-               // Check if the exception is caused by an interrupt, if yes, jump to interrupt handler
-               // Interrupt is indicated by xCause[XLEN-1]
+               // Check if the exception is caused by an interrupt, if yes, jump to interrupt
+               // handler Interrupt is indicated by xCause[XLEN-1]
                $sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause.name()),
                $sformatf("srli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], XLEN-1),
-               $sformatf("bne x%0d, x0, %0smode_intr_handler", cfg.gpr[0], mode)};
+               $sformatf("bne x%0d, x0, %0s%0smode_intr_handler",
+                         cfg.gpr[0], hart_prefix(hart), mode)};
     end
     // The trap handler will occupy one 4KB page, it will be allocated one entry in the page table
     // with a specific privileged mode.
     instr_stream.push_back(".align 12");
     tvec_name = tvec.name();
-    gen_section($sformatf("%0s_handler", tvec_name.tolower()), instr);
+    gen_section(get_label($sformatf("%0s_handler", tvec_name.tolower()), hart), instr);
     // Exception handler
     instr = {};
     if (cfg.mtvec_mode == VECTORED) begin
@@ -764,39 +851,51 @@
              $sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause.name()),
              // Breakpoint
              $sformatf("li x%0d, 0x%0x # BREAKPOINT", cfg.gpr[1], BREAKPOINT),
-             $sformatf("beq x%0d, x%0d, ebreak_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0sebreak_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              // Check if it's an ECALL exception. Jump to ECALL exception handler
              $sformatf("li x%0d, 0x%0x # ECALL_UMODE", cfg.gpr[1], ECALL_UMODE),
-             $sformatf("beq x%0d, x%0d, ecall_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0secall_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              $sformatf("li x%0d, 0x%0x # ECALL_SMODE", cfg.gpr[1], ECALL_SMODE),
-             $sformatf("beq x%0d, x%0d, ecall_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0secall_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              $sformatf("li x%0d, 0x%0x # ECALL_MMODE", cfg.gpr[1], ECALL_MMODE),
-             $sformatf("beq x%0d, x%0d, ecall_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0secall_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              // Page table fault or access fault conditions
              $sformatf("li x%0d, 0x%0x", cfg.gpr[1], INSTRUCTION_ACCESS_FAULT),
-             $sformatf("beq x%0d, x%0d, instr_fault_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0sinstr_fault_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              $sformatf("li x%0d, 0x%0x", cfg.gpr[1], LOAD_ACCESS_FAULT),
-             $sformatf("beq x%0d, x%0d, load_fault_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0sload_fault_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              $sformatf("li x%0d, 0x%0x", cfg.gpr[1], STORE_AMO_ACCESS_FAULT),
-             $sformatf("beq x%0d, x%0d, store_fault_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0sstore_fault_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              $sformatf("li x%0d, 0x%0x", cfg.gpr[1], INSTRUCTION_PAGE_FAULT),
-             $sformatf("beq x%0d, x%0d, pt_fault_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0spt_fault_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              $sformatf("li x%0d, 0x%0x", cfg.gpr[1], LOAD_PAGE_FAULT),
-             $sformatf("beq x%0d, x%0d, pt_fault_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0spt_fault_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              $sformatf("li x%0d, 0x%0x", cfg.gpr[1], STORE_AMO_PAGE_FAULT),
-             $sformatf("beq x%0d, x%0d, pt_fault_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0spt_fault_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              // Illegal instruction exception
              $sformatf("li x%0d, 0x%0x # ILLEGAL_INSTRUCTION", cfg.gpr[1], ILLEGAL_INSTRUCTION),
-             $sformatf("beq x%0d, x%0d, illegal_instr_handler", cfg.gpr[0], cfg.gpr[1]),
+             $sformatf("beq x%0d, x%0d, %0sillegal_instr_handler",
+                       cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
              // Skip checking tval for illegal instruction as it's implementation specific
              $sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[1], tval, tval.name()),
              "1: jal x1, test_done "
            };
-    gen_section($sformatf("%0smode_exception_handler", mode), instr);
+    gen_section(get_label($sformatf("%0smode_exception_handler", mode), hart), instr);
   endfunction
 
   // Generate for interrupt vector table
-  virtual function void gen_interrupt_vector_table(string           mode,
+  virtual function void gen_interrupt_vector_table(int              hart,
+                                                   string           mode,
                                                    privileged_reg_t status,
                                                    privileged_reg_t cause,
                                                    privileged_reg_t ie,
@@ -810,10 +909,10 @@
     // ambiguity does not arise in practice, since user-mode software interrupts are either
     // disabled or delegated
     instr = {instr, ".option norvc;",
-                    $sformatf("j %0smode_exception_handler", mode)};
+                    $sformatf("j %0s%0smode_exception_handler", hart_prefix(hart), mode)};
     // Redirect the interrupt to the corresponding interrupt handler
     for (int i = 1; i < max_interrupt_vector_num; i++) begin
-      instr.push_back($sformatf("j %0smode_intr_vector_%0d", mode, i));
+      instr.push_back($sformatf("j %0s%0smode_intr_vector_%0d", hart_prefix(hart), mode, i));
     end
     if (!cfg.disable_compressed_instr) begin
       instr = {instr, ".option rvc;"};
@@ -821,7 +920,8 @@
     for (int i = 1; i < max_interrupt_vector_num; i++) begin
       string intr_handler[$];
       push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, intr_handler);
-      gen_signature_handshake(.instr(intr_handler), .signature_type(CORE_STATUS), .core_status(HANDLING_IRQ));
+      gen_signature_handshake(.instr(intr_handler), .signature_type(CORE_STATUS),
+                              .core_status(HANDLING_IRQ));
       intr_handler = {intr_handler,
                       $sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause.name()),
                       // Terminate the test if xCause[31] != 0 (indicating exception)
@@ -833,18 +933,18 @@
       gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(ip));
       // Jump to commmon interrupt handling routine
       intr_handler = {intr_handler,
-                      $sformatf("j %0smode_intr_handler", mode),
+                      $sformatf("j %0s%0smode_intr_handler", hart_prefix(hart), mode),
                       "1: j test_done"};
-      gen_section($sformatf("%0smode_intr_vector_%0d", mode, i), intr_handler);
+      gen_section(get_label($sformatf("%0smode_intr_vector_%0d", mode, i), hart), intr_handler);
     end
   endfunction
 
   // ECALL trap handler
   // It does some clean up like dump GPRs before communicating with host to terminate the test.
   // User can extend this function if some custom clean up routine is needed.
-  virtual function void gen_ecall_handler();
+  virtual function void gen_ecall_handler(int hart);
     string str;
-    str = format_string("ecall_handler:", LABEL_STR_LEN);
+    str = format_string(get_label("ecall_handler:", hart), LABEL_STR_LEN);
     instr_stream.push_back(str);
     dump_perf_stats();
     gen_register_dump();
@@ -861,7 +961,7 @@
   // TODO: Support random operations in debug mode
   // TODO: Support ebreak exception delegation
   // TODO: handshake the correct Xcause CSR based on delegation privil. mode
-  virtual function void gen_ebreak_handler();
+  virtual function void gen_ebreak_handler(int hart);
     string instr[$];
     gen_signature_handshake(instr, CORE_STATUS, EBREAK_EXCEPTION);
     gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
@@ -872,7 +972,7 @@
     };
     pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
     instr.push_back("mret");
-    gen_section("ebreak_handler", instr);
+    gen_section(get_label("ebreak_handler", hart), instr);
   endfunction
 
   // Illegal instruction handler
@@ -882,7 +982,7 @@
   // 4 and resumes execution. The way that the illegal instruction is injected guarantees that
   // PC + 4 is a valid instruction boundary.
   // TODO: handshake the corret Xcause CSR based on delegation setup
-  virtual function void gen_illegal_instr_handler();
+  virtual function void gen_illegal_instr_handler(int hart);
     string instr[$];
     gen_signature_handshake(instr, CORE_STATUS, ILLEGAL_INSTR_EXCEPTION);
     gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
@@ -893,37 +993,37 @@
     };
     pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
     instr.push_back("mret");
-    gen_section("illegal_instr_handler", instr);
+    gen_section(get_label("illegal_instr_handler", hart), instr);
   endfunction
 
   // TODO: handshake correct csr based on delegation
-  virtual function void gen_instr_fault_handler();
+  virtual function void gen_instr_fault_handler(int hart);
     string instr[$];
     gen_signature_handshake(instr, CORE_STATUS, INSTR_FAULT_EXCEPTION);
     gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
     pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
     instr.push_back("mret");
-    gen_section("instr_fault_handler", instr);
+    gen_section(get_label("instr_fault_handler", hart), instr);
   endfunction
 
   // TODO: handshake correct csr based on delegation
-  virtual function void gen_load_fault_handler();
+  virtual function void gen_load_fault_handler(int hart);
     string instr[$];
     gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
     gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
     pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
     instr.push_back("mret");
-    gen_section("load_fault_handler", instr);
+    gen_section(get_label("load_fault_handler", hart), instr);
   endfunction
 
   // TODO: handshake correct csr based on delegation
-  virtual function void gen_store_fault_handler();
+  virtual function void gen_store_fault_handler(int hart);
     string instr[$];
     gen_signature_handshake(instr, CORE_STATUS, STORE_FAULT_EXCEPTION);
     gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
     pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
     instr.push_back("mret");
-    gen_section("store_fault_handler", instr);
+    gen_section(get_label("store_fault_handler", hart), instr);
   endfunction
 
   //---------------------------------------------------------------------------------------
@@ -934,7 +1034,7 @@
   // The page is created based on the address translation mode - SV32, SV39, SV48
   // Right now only the lowest level 4KB page table is configured as leaf page table entry (PTE),
   // all the other super pages are link PTE.
-  virtual function void create_page_table();
+  virtual function void create_page_table(int hart);
     string instr[];
     if(cfg.virtual_addr_translation_on) begin
       page_table_list = riscv_page_table_list#(SATP_MODE)::
@@ -953,15 +1053,20 @@
 
   // Generate the page table section of the program
   // The page table is generated as a group of continuous 4KB data sections.
-  virtual function void gen_page_table_section();
+  virtual function void gen_page_table_section(int hart);
     string page_table_section[$];
     if(page_table_list != null) begin
-      instr_stream.push_back(".pushsection .page_table,\"aw\",@progbits;");
+      if (cfg.use_push_data_section) begin
+        instr_stream.push_back($sformatf(".pushsection .%0spage_table,\"aw\",@progbits;",
+                                         hart_prefix(hart)));
+      end
       foreach(page_table_list.page_table[i]) begin
         page_table_list.page_table[i].gen_page_table_section(page_table_section);
         instr_stream = {instr_stream, page_table_section};
       end
-      instr_stream.push_back(".popsection;");
+      if (cfg.use_push_data_section) begin
+        instr_stream.push_back(".popsection;");
+      end
     end
   endfunction
 
@@ -976,7 +1081,7 @@
   endfunction
 
   // Interrupt handler routine
-  virtual function void gen_interrupt_handler_section(privileged_mode_t mode);
+  virtual function void gen_interrupt_handler_section(privileged_mode_t mode, int hart);
     string mode_prefix;
     string ls_unit;
     privileged_reg_t status, ip, ie, scratch;
@@ -1047,7 +1152,8 @@
     };
     // The interrupt handler will use one 4KB page
     instr_stream.push_back(".align 12");
-    gen_section($sformatf("%0smode_intr_handler", mode_prefix), interrupt_handler_instr);
+    gen_section(get_label($sformatf("%0smode_intr_handler", mode_prefix), hart),
+                interrupt_handler_instr);
   endfunction
 
   //---------------------------------------------------------------------------------------
@@ -1181,7 +1287,8 @@
 
   virtual function void add_directed_instr_stream(string name, int unsigned ratio);
     directed_instr_stream_ratio[name] = ratio;
-    `uvm_info(`gfn, $sformatf("Adding directed instruction stream:%0s ratio:%0d/1000", name, ratio), UVM_LOW)
+    `uvm_info(`gfn, $sformatf("Adding directed instruction stream:%0s ratio:%0d/1000", name, ratio),
+              UVM_LOW)
   endfunction
 
   virtual function void get_directed_instr_stream();
@@ -1210,7 +1317,8 @@
   endfunction
 
   // Generate directed instruction stream based on the ratio setting
-  virtual function void generate_directed_instr_stream(input string label,
+  virtual function void generate_directed_instr_stream(input int hart,
+                                                       input string label,
                                                        input int unsigned original_instr_cnt,
                                                        input int unsigned min_insert_cnt = 0,
                                                        input bit kernel_mode = 0,
@@ -1245,6 +1353,7 @@
         end
         if($cast(new_instr_stream, object_h)) begin
           new_instr_stream.cfg = cfg;
+          new_instr_stream.hart = hart;
           new_instr_stream.label = $sformatf("%0s_%0d", label, idx);
           new_instr_stream.kernel_mode = kernel_mode;
           `DV_CHECK_RANDOMIZE_FATAL(new_instr_stream)
@@ -1262,10 +1371,11 @@
   // Generate the debug ROM, and any related programs
   //---------------------------------------------------------------------------------------
 
-  virtual function void gen_debug_rom();
+  virtual function void gen_debug_rom(int hart);
     `uvm_info(`gfn, "Creating debug ROM", UVM_LOW)
     debug_rom = riscv_asm_program_gen::type_id::create("debug_rom", , {"uvm_test_top", ".", `gfn});
     debug_rom.cfg = cfg;
+    debug_rom.hart = hart;
     debug_rom.gen_program();
     instr_stream = {instr_stream, debug_rom.instr_stream};
   endfunction
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_data_page_gen.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_data_page_gen.sv
index e80ab35..e79d8cc 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_data_page_gen.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_data_page_gen.sv
@@ -23,7 +23,7 @@
 
   riscv_instr_gen_config  cfg;
   string                  data_page_str[$];
-  mem_region_t          mem_region_setting[$];
+  mem_region_t            mem_region_setting[$];
 
   `uvm_object_utils(riscv_data_page_gen)
 
@@ -50,7 +50,10 @@
   endfunction
 
   // Generate data pages for all memory regions
-  function void gen_data_page(data_pattern_t pattern, bit is_kernel = 1'b0);
+  function void gen_data_page(int hart_id,
+                              data_pattern_t pattern,
+                              bit is_kernel = 1'b0,
+                              bit amo = 0);
     string tmp_str;
     bit [7:0] tmp_data[];
     int page_cnt;
@@ -58,23 +61,30 @@
     data_page_str = {};
     if (is_kernel) begin
       mem_region_setting = cfg.s_mem_region;
+    end else if (amo) begin
+      mem_region_setting = cfg.amo_region;
     end else begin
       mem_region_setting = cfg.mem_region;
     end
-    if (is_kernel) begin
-      // All kernel data pages in the same section
-      data_page_str.push_back(".pushsection .kernel_data,\"aw\",@progbits;");
-    end
     foreach (mem_region_setting[i]) begin
       `uvm_info(`gfn, $sformatf("Generate data section: %0s size:0x%0x  xwr:0x%0x]",
                                 mem_region_setting[i].name,
                                 mem_region_setting[i].size_in_bytes,
                                 mem_region_setting[i].xwr), UVM_LOW)
-      if (!is_kernel) begin
-        data_page_str.push_back($sformatf(".pushsection .%0s,\"aw\",@progbits;",
-                                          mem_region_setting[i].name));
+      if (amo) begin
+        if (cfg.use_push_data_section) begin
+          data_page_str.push_back($sformatf(".pushsection .%0s,\"aw\",@progbits;",
+                                            mem_region_setting[i].name));
+        end
+        data_page_str.push_back($sformatf("%0s:", mem_region_setting[i].name));
+      end else begin
+        if (cfg.use_push_data_section) begin
+          data_page_str.push_back($sformatf(".pushsection .%0s,\"aw\",@progbits;",
+                                            {hart_prefix(hart_id), mem_region_setting[i].name}));
+        end
+        data_page_str.push_back($sformatf("%0s:",
+                                          {hart_prefix(hart_id), mem_region_setting[i].name}));
       end
-      data_page_str.push_back($sformatf("%0s:", mem_region_setting[i].name));
       page_size = mem_region_setting[i].size_in_bytes;
       for(int i = 0; i < page_size; i+= 32) begin
         if (page_size-i >= 32) begin
@@ -85,13 +95,10 @@
         tmp_str = format_string($sformatf(".word %0s", format_data(tmp_data)), LABEL_STR_LEN);
         data_page_str.push_back(tmp_str);
       end
-      if (!is_kernel) begin
+      if (cfg.use_push_data_section) begin
         data_page_str.push_back(".popsection;");
       end
     end
-    if (is_kernel) begin
-      data_page_str.push_back(".popsection;");
-    end
   endfunction
 
 endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_debug_rom_gen.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_debug_rom_gen.sv
index d409aef..6e6ba85 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_debug_rom_gen.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_debug_rom_gen.sv
@@ -27,6 +27,7 @@
   string debug_end[$];
   string str[$];
   string dret;
+  int hart;
 
   `uvm_object_utils(riscv_debug_rom_gen)
 
@@ -45,7 +46,7 @@
       // If the debug section should not be generated, we just populate it
       // with a dret instruction.
       debug_main = {dret};
-      gen_section("debug_rom", debug_main);
+      gen_section($sformatf("%0sdebug_rom", hart_prefix(hart)), debug_main);
     end else begin
       if (cfg.enable_ebreak_in_debug_rom) begin
         gen_ebreak_header();
@@ -80,21 +81,21 @@
         gen_increment_ebreak_counter();
       end
       format_section(debug_main);
-      gen_sub_program(sub_program, sub_program_name,
+      gen_sub_program(hart, sub_program[hart], sub_program_name,
                       cfg.num_debug_sub_program, 1'b1, "debug_sub");
-      main_program = riscv_instr_sequence::type_id::create("debug_program");
-      main_program.instr_cnt = cfg.debug_program_instr_cnt;
-      main_program.is_debug_program = 1;
-      main_program.cfg = cfg;
-      `DV_CHECK_RANDOMIZE_FATAL(main_program)
-      main_program.gen_instr(.is_main_program(1'b1), .no_branch(cfg.no_branch_jump));
-      gen_callstack(main_program, sub_program, sub_program_name,
+      main_program[hart] = riscv_instr_sequence::type_id::create("debug_program");
+      main_program[hart].instr_cnt = cfg.debug_program_instr_cnt;
+      main_program[hart].is_debug_program = 1;
+      main_program[hart].cfg = cfg;
+      `DV_CHECK_RANDOMIZE_FATAL(main_program[hart])
+      main_program[hart].gen_instr(.is_main_program(1'b1), .no_branch(cfg.no_branch_jump));
+      gen_callstack(main_program[hart], sub_program[hart], sub_program_name,
                     cfg.num_debug_sub_program);
-      main_program.post_process_instr();
-      main_program.generate_instr_stream(.no_label(1'b1));
-      insert_sub_program(sub_program, debug_main);
-      debug_main = {debug_main, main_program.instr_string_list};
-      gen_section("debug_rom", debug_main);
+      main_program[hart].post_process_instr();
+      main_program[hart].generate_instr_stream(.no_label(1'b1));
+      insert_sub_program(sub_program[hart], debug_main);
+      debug_main = {debug_main, main_program[hart].instr_string_list};
+      gen_section($sformatf("%0sdebug_rom", hart_prefix(hart)), debug_main);
       if (cfg.enable_ebreak_in_debug_rom) begin
         gen_ebreak_footer();
       end
@@ -105,7 +106,7 @@
       end
       //format_section(debug_end);
       debug_end = {debug_end, dret};
-      gen_section("debug_end", debug_end);
+      gen_section($sformatf("%0sdebug_end", hart_prefix(hart)), debug_end);
     end
     gen_debug_exception_handler();
   endfunction
@@ -114,7 +115,7 @@
   // TODO(udinator) - remains empty for now, only a DRET
   virtual function void gen_debug_exception_handler();
     str = {"dret"};
-    gen_section("debug_exception", str);
+    gen_section($sformatf("%0sdebug_exception", hart_prefix(hart)), str);
   endfunction
 
   //-------------------------------------------------------------------------------------
@@ -130,7 +131,7 @@
     str = {$sformatf("csrw 0x%0x, x%0d", DSCRATCH1, cfg.scratch_reg),
            $sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH0),
            $sformatf("beq x%0d, x0, 1f", cfg.scratch_reg),
-           $sformatf("j debug_end"),
+           $sformatf("j %0sdebug_end", hart_prefix(hart)),
            $sformatf("1: csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
     debug_main = {debug_main, str};
   endfunction
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv
index 5351973..64984ff 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv
@@ -65,9 +65,11 @@
     la_instr.pseudo_instr_name = LA;
     la_instr.rd = gpr;
     if(kernel_mode) begin
-      la_instr.imm_str = $sformatf("%s+%0d", cfg.s_mem_region[id].name, base);
+      la_instr.imm_str = $sformatf("%0s%s+%0d",
+                                   hart_prefix(hart), cfg.s_mem_region[id].name, base);
     end else begin
-      la_instr.imm_str = $sformatf("%s+%0d", cfg.mem_region[id].name, base);
+      la_instr.imm_str = $sformatf("%0s%s+%0d",
+                                   hart_prefix(hart), cfg.mem_region[id].name, base);
     end
     instr_list.push_front(la_instr);
   endfunction
@@ -184,8 +186,10 @@
       instr_list[i].atomic = 1'b1;
     end
     jump.has_label = 1'b1;
-    jump.label = $sformatf("j_%0s_%0s_%0d", label, target_program_label, idx);
-    branch.imm_str = jump.label;
+    jump.label = "1";
+    jump.comment = $sformatf("%s jump %0s -> %0s",
+                             hart_prefix(hart), label, target_program_label);
+    branch.imm_str = "1f";
     branch.comment = "branch to jump instr";
     branch.branch_assigned = 1'b1;
   endfunction
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_illegal_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_illegal_instr.sv
index 40afff0..fe5be8c 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_illegal_instr.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_illegal_instr.sv
@@ -320,12 +320,12 @@
   constraint illegal_func7_c {
     if (!compressed) {
       if (exception == kIllegalFunc7) {
-        !(func7 inside {7'b0, 7'b0100000, 7'b1});
-        if (opcode == 7'b001001) { // SLLI, SRLI, SRAI
-          !(func7[6:1] inside {6'b0, 6'b010000});
+        !(func7 inside {7'd0, 7'b0100000, 7'd1});
+        if (opcode == 7'b0001001) { // SLLI, SRLI, SRAI
+          !(func7[6:1] inside {6'd0, 6'b010000});
         }
       } else {
-        func7 inside {7'b0, 7'b0100000, 7'b1};
+        func7 inside {7'd0, 7'b0100000, 7'd1};
       }
     }
   }
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv
index 2777337..703a966 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv
@@ -73,7 +73,8 @@
       mem_addr = rs1_value + imm;
       unaligned_mem_access = is_unaligned_mem_access();
       if (unaligned_mem_access) begin
-        `uvm_info(`gfn, $sformatf("Unaligned: %0s, mem_addr:%0x", instr_name.name(), mem_addr), UVM_HIGH)
+        `uvm_info(`gfn, $sformatf("Unaligned: %0s, mem_addr:%0x", instr_name.name(), mem_addr),
+                  UVM_HIGH)
       end
     end
     if (category == LOGICAL) begin
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv
index 021b23c..907fbc0 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv
@@ -91,6 +91,9 @@
   // Vector extension setting
   rand riscv_vector_cfg  vector_cfg;
 
+  // PMP configuration settings
+  rand riscv_pmp_cfg pmp_cfg;
+
   //-----------------------------------------------------------------------------
   //  User space memory region and stack setting
   //-----------------------------------------------------------------------------
@@ -103,6 +106,11 @@
     '{name:"region_4", size_in_bytes: 4096,      xwr: 3'b111}
   };
 
+  // Dedicated shared memory region for multi-harts atomic operations
+  mem_region_t amo_region[$] = '{
+    '{name:"amo_0",    size_in_bytes: 64,        xwr: 3'b111}
+  };
+
   // Stack section word length
   int stack_len = 5000;
 
@@ -145,6 +153,12 @@
   bit                    enable_unaligned_load_store;
   int                    illegal_instr_ratio;
   int                    hint_instr_ratio;
+  // Number of harts to be simulated, must be <= NUM_HARTS
+  int                    num_of_harts = NUM_HARTS;
+  // Use SP as stack pointer
+  bit                    fix_sp;
+  // Use push/pop section for data pages
+  bit                    use_push_data_section = 0;
   // Directed boot privileged mode, u, m, s
   string                 boot_mode_opts;
   int                    enable_page_table_exception;
@@ -225,7 +239,6 @@
   int                    dist_control_mode;
   int unsigned           category_dist[riscv_instr_category_t];
 
-  uvm_cmdline_processor  inst;
 
   constraint default_c {
     sub_program_instr_cnt.size() == num_of_sub_program;
@@ -241,8 +254,8 @@
       enable_sfence == 1'b1;
       (init_privileged_mode != SUPERVISOR_MODE) || (mstatus_tvm == 1'b1);
     } else {
-      (init_privileged_mode != SUPERVISOR_MODE || !riscv_instr_pkg::support_sfence || mstatus_tvm || no_fence)
-                                                     -> (enable_sfence == 1'b0);
+      (init_privileged_mode != SUPERVISOR_MODE || !riscv_instr_pkg::support_sfence || mstatus_tvm
+          || no_fence) -> (enable_sfence == 1'b0);
     }
   }
 
@@ -299,6 +312,11 @@
     // This is default disabled at setup phase. It can be enabled in the exception and interrupt
     // handling routine
     mstatus_mprv == 1'b0;
+    if (SATP_MODE == BARE) {
+      mstatus_mxr == 0;
+      mstatus_sum == 0;
+      mstatus_tvm == 0;
+    }
   }
 
   // Exception delegation setting
@@ -354,6 +372,9 @@
   }
 
   constraint sp_tp_c {
+    if (fix_sp) {
+      sp == SP;
+    }
     sp != tp;
     !(sp inside {GP, RA, ZERO});
     !(tp inside {GP, RA, ZERO});
@@ -372,8 +393,11 @@
     unique {gpr};
   }
 
-  constraint addr_translaction_c {
+  constraint addr_translaction_rnd_order_c {
     solve init_privileged_mode before virtual_addr_translation_on;
+  }
+  
+  constraint addr_translaction_c {
     if ((init_privileged_mode != MACHINE_MODE) && (SATP_MODE != BARE)) {
       virtual_addr_translation_on == 1'b1;
     } else {
@@ -415,6 +439,7 @@
     `uvm_field_int(no_dret, UVM_DEFAULT)
     `uvm_field_int(no_fence, UVM_DEFAULT)
     `uvm_field_int(no_wfi, UVM_DEFAULT)
+    `uvm_field_int(fix_sp, UVM_DEFAULT)
     `uvm_field_int(enable_unaligned_load_store, UVM_DEFAULT)
     `uvm_field_int(illegal_instr_ratio, UVM_DEFAULT)
     `uvm_field_int(hint_instr_ratio, UVM_DEFAULT)
@@ -436,6 +461,7 @@
     `uvm_field_int(support_supervisor_mode, UVM_DEFAULT)
     `uvm_field_int(disable_compressed_instr, UVM_DEFAULT)
     `uvm_field_int(signature_addr, UVM_DEFAULT)
+    `uvm_field_int(num_of_harts, UVM_DEFAULT)
     `uvm_field_int(require_signature_addr, UVM_DEFAULT)
     `uvm_field_int(gen_debug_section, UVM_DEFAULT)
     `uvm_field_int(enable_ebreak_in_debug_rom, UVM_DEFAULT)
@@ -448,6 +474,7 @@
     `uvm_field_int(max_directed_instr_stream_seq, UVM_DEFAULT)
     `uvm_field_int(enable_floating_point, UVM_DEFAULT)
     `uvm_field_int(enable_vector_extension, UVM_DEFAULT)
+    `uvm_field_int(use_push_data_section, UVM_DEFAULT)
   `uvm_object_utils_end
 
   function new (string name = "");
@@ -468,6 +495,8 @@
     get_bool_arg_value("+no_branch_jump=", no_branch_jump);
     get_bool_arg_value("+no_load_store=", no_load_store);
     get_bool_arg_value("+no_csr_instr=", no_csr_instr);
+    get_bool_arg_value("+fix_sp=", fix_sp);
+    get_bool_arg_value("+use_push_data_section=", use_push_data_section);
     get_bool_arg_value("+enable_illegal_csr_instruction=", enable_illegal_csr_instruction);
     get_bool_arg_value("+enable_access_invalid_csr_level=", enable_access_invalid_csr_level);
     get_bool_arg_value("+enable_misaligned_instr=", enable_misaligned_instr);
@@ -479,6 +508,7 @@
     get_bool_arg_value("+no_delegation=", no_delegation);
     get_int_arg_value("+illegal_instr_ratio=", illegal_instr_ratio);
     get_int_arg_value("+hint_instr_ratio=", hint_instr_ratio);
+    get_int_arg_value("+num_of_harts=", num_of_harts);
     get_bool_arg_value("+enable_unaligned_load_store=", enable_unaligned_load_store);
     get_bool_arg_value("+force_m_delegation=", force_m_delegation);
     get_bool_arg_value("+force_s_delegation=", force_s_delegation);
@@ -508,6 +538,7 @@
                   $sformatf("Illegal boot mode option - %0s", boot_mode_opts))
       endcase
       init_privileged_mode.rand_mode(0);
+      addr_translaction_rnd_order_c.constraint_mode(0);
     end
     `uvm_info(`gfn, $sformatf("riscv_instr_pkg::supported_privileged_mode = %0d",
                    riscv_instr_pkg::supported_privileged_mode.size()), UVM_LOW)
@@ -533,6 +564,8 @@
       disable_compressed_instr = 1;
     end
     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);
     setup_instr_distribution();
     get_invalid_priv_lvl_csr();
   endfunction
@@ -629,7 +662,8 @@
     end
   endfunction
 
-  // Populate invalid_priv_mode_csrs with the main implemented CSRs for each supported privilege mode
+  // Populate invalid_priv_mode_csrs with the main implemented CSRs for each supported privilege
+  // mode
   // TODO(udi) - include performance/pmp/trigger CSRs?
   virtual function void get_invalid_priv_lvl_csr();
     string invalid_lvl[$];
@@ -660,28 +694,4 @@
     end
   endfunction
 
-  // Get an integer argument from comand line
-  function void get_int_arg_value(string cmdline_str, ref int val);
-    string s;
-    if(inst.get_arg_value(cmdline_str, s)) begin
-      val = s.atoi();
-    end
-  endfunction
-
-  // Get a bool argument from comand line
-  function void get_bool_arg_value(string cmdline_str, ref bit val);
-    string s;
-    if(inst.get_arg_value(cmdline_str, s)) begin
-      val = s.atobin();
-    end
-  endfunction
-
-  // Get a hex argument from command line
-  function void get_hex_arg_value(string cmdline_str, ref int val);
-    string s;
-    if(inst.get_arg_value(cmdline_str, s)) begin
-      val = s.atohex();
-    end
-  endfunction
-
 endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_pkg.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_pkg.sv
index 9b06e94..3a06a71 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_pkg.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_pkg.sv
@@ -26,6 +26,8 @@
 
   `define include_file(f) `include `"f`"
 
+  uvm_cmdline_processor  inst;
+
   // Data section setting
   typedef struct {
     string         name;
@@ -500,7 +502,7 @@
   } riscv_instr_name_t;
 
   // Maximum virtual address bits used by the program
-  parameter MAX_USED_VADDR_BITS = 30;
+  parameter int MAX_USED_VADDR_BITS = 30;
 
   typedef enum bit [4:0] {
     ZERO = 5'b00000,
@@ -929,6 +931,41 @@
 
   `include "riscv_core_setting.sv"
 
+  // PMP address matching mode
+  typedef enum bit [1:0] {
+    OFF   = 2'b00,
+    TOR   = 2'b01,
+    NA4   = 2'b10,
+    NAPOT = 2'b11
+  } pmp_addr_mode_t;
+
+  // PMP configuration register layout
+  // This configuration struct includes the pmp address for simplicity
+  // TODO (udinator) allow a full 34 bit address for rv32?
+  typedef struct{
+    rand bit                   l;
+    bit [1:0]                  zero;
+    rand pmp_addr_mode_t       a;
+    rand bit                   x;
+    rand bit                   w;
+    rand bit                   r;
+    // RV32: addr is the top 32 bits of a 34 bit PMP address
+    // RV64: addr is the top 54 bits of a 56 bit PMP address
+    rand bit [XLEN - 1 : 0]    addr;
+  } pmp_cfg_reg_t;
+
+  function automatic string hart_prefix(int hart = 0);
+    if (NUM_HARTS <= 1) begin
+      return "";
+    end else begin
+      return $sformatf("h%0d_", hart);
+    end
+  endfunction : hart_prefix
+
+  function automatic string get_label(string label, int hart = 0);
+    return {hart_prefix(hart), label};
+  endfunction : get_label
+
   typedef struct packed {
     bit ill;
     bit [XLEN-2:7] reserved;
@@ -953,19 +990,19 @@
   parameter bit [XLEN - 1 : 0] SUM_BIT_MASK  = 'h1 << 18;
   parameter bit [XLEN - 1 : 0] MPP_BIT_MASK  = 'h3 << 11;
 
-  parameter IMM25_WIDTH = 25;
-  parameter IMM12_WIDTH = 12;
-  parameter INSTR_WIDTH = 32;
-  parameter DATA_WIDTH  = 32;
+  parameter int IMM25_WIDTH = 25;
+  parameter int IMM12_WIDTH = 12;
+  parameter int INSTR_WIDTH = 32;
+  parameter int DATA_WIDTH  = 32;
 
   // Parameters for output assembly program formatting
-  parameter MAX_INSTR_STR_LEN = 11;
-  parameter LABEL_STR_LEN     = 18;
+  parameter int MAX_INSTR_STR_LEN = 11;
+  parameter int LABEL_STR_LEN     = 18;
 
   // Parameter for program generation
-  parameter MAX_CALLSTACK_DEPTH = 20;
-  parameter MAX_SUB_PROGRAM_CNT = 20;
-  parameter MAX_CALL_PER_FUNC   = 5;
+  parameter int MAX_CALLSTACK_DEPTH = 20;
+  parameter int MAX_SUB_PROGRAM_CNT = 20;
+  parameter int MAX_CALL_PER_FUNC   = 5;
 
   string indent = {LABEL_STR_LEN{" "}};
 
@@ -1032,7 +1069,8 @@
         instr.push_back($sformatf("csrr x%0d, 0x%0x // MSTATUS", tp, status));
         instr.push_back($sformatf("srli x%0d, x%0d, 11", tp, tp));  // Move MPP to bit 0
         instr.push_back($sformatf("andi x%0d, x%0d, 0x3", tp, tp)); // keep the MPP bits
-        instr.push_back($sformatf("xori x%0d, x%0d, 0x3", tp, tp)); // Check if MPP equals to M-mode('b11)
+        // Check if MPP equals to M-mode('b11)
+        instr.push_back($sformatf("xori x%0d, x%0d, 0x3", tp, tp));
         instr.push_back($sformatf("bnez x%0d, 1f", tp));      // Use physical address for kernel SP
         // Use virtual address for stack pointer
         instr.push_back($sformatf("slli x%0d, x%0d, %0d", sp, sp, XLEN - MAX_USED_VADDR_BITS));
@@ -1069,6 +1107,30 @@
     end
   endfunction
 
+  // Get an integer argument from comand line
+  function automatic void get_int_arg_value(string cmdline_str, ref int val);
+    string s;
+    if(inst.get_arg_value(cmdline_str, s)) begin
+      val = s.atoi();
+    end
+  endfunction
+
+  // Get a bool argument from comand line
+  function automatic void get_bool_arg_value(string cmdline_str, ref bit val);
+    string s;
+    if(inst.get_arg_value(cmdline_str, s)) begin
+      val = s.atobin();
+    end
+  endfunction
+
+  // Get a hex argument from command line
+  function automatic void get_hex_arg_value(string cmdline_str, ref int val);
+    string s;
+    if(inst.get_arg_value(cmdline_str, s)) begin
+      val = s.atohex();
+    end
+  endfunction
+
   riscv_reg_t all_gpr[] = {ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0,
                            A1, A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6,
                            S7, S8, S9, S10, S11, T3, T4, T5, T6};
@@ -1081,6 +1143,7 @@
   };
 
   `include "riscv_vector_cfg.sv"
+  `include "riscv_pmp_cfg.sv"
   typedef class riscv_instr;
   `include "riscv_instr_gen_config.sv"
   `include "isa/riscv_instr.sv"
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_stream.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_stream.sv
index 473e8d8..ab72deb 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_stream.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_stream.sv
@@ -28,6 +28,7 @@
   // Some additional reserved registers that should not be used as rd register
   // by this instruction stream
   riscv_reg_t           reserved_rd[];
+  int                   hart;
 
   `uvm_object_utils(riscv_instr_stream)
   `uvm_object_new
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv
index c710051..235178a 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv
@@ -39,8 +39,11 @@
 
   `uvm_object_utils(riscv_load_store_base_instr_stream)
 
-  constraint sp_c {
+  constraint sp_rnd_order_c {
     solve use_sp_as_rs1 before rs1_reg;
+  }
+  
+  constraint sp_c {
     use_sp_as_rs1 dist {1 := 1, 0 := 2};
     if (use_sp_as_rs1) {
       rs1_reg == SP;
@@ -97,6 +100,7 @@
     if (SP inside {cfg.reserved_regs, reserved_rd}) begin
       use_sp_as_rs1 = 0;
       use_sp_as_rs1.rand_mode(0);
+      sp_rnd_order_c.constraint_mode(0);
     end
   endfunction
 
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_entry.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_entry.sv
index 5027f88..dfb00f4 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_entry.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_entry.sv
@@ -23,16 +23,16 @@
 class riscv_page_table_entry#(satp_mode_t MODE = SV39) extends uvm_object;
 
   // Note that only SV32, SV39, SV48 are supported
-  parameter PPN0_WIDTH  = (MODE == SV32) ? 10 : 9;
-  parameter PPN1_WIDTH  = (MODE == SV32) ? 12 : 9;
-  parameter PPN2_WIDTH  = (MODE == SV39) ? 26 : ((MODE == SV48) ? 9 : 1);
-  parameter PPN3_WIDTH  = (MODE == SV48) ? 9  : 1;
-  parameter RSVD_WIDTH  = (MODE == SV32) ? 1  : 10;
-  parameter VPN_WIDTH   = (MODE == SV32) ? 10 : 9;
+  parameter int PPN0_WIDTH  = (MODE == SV32) ? 10 : 9;
+  parameter int PPN1_WIDTH  = (MODE == SV32) ? 12 : 9;
+  parameter int PPN2_WIDTH  = (MODE == SV39) ? 26 : ((MODE == SV48) ? 9 : 1);
+  parameter int PPN3_WIDTH  = (MODE == SV48) ? 9  : 1;
+  parameter int RSVD_WIDTH  = (MODE == SV32) ? 1  : 10;
+  parameter int VPN_WIDTH   = (MODE == SV32) ? 10 : 9;
   // Spare bits in virtual address = XLEN - used virtual address bits
-  parameter VADDR_SPARE = (MODE == SV32) ? 0  : (MODE == SV39) ? 25 : 16;
+  parameter int VADDR_SPARE = (MODE == SV32) ? 0  : (MODE == SV39) ? 25 : 16;
   // Virtual address bit width
-  parameter VADDR_WIDTH = (MODE == SV32) ? 31 : (MODE == SV39) ? 38 : 48;
+  parameter int VADDR_WIDTH = (MODE == SV32) ? 31 : (MODE == SV39) ? 38 : 48;
 
   rand bit                    v;     // PTE is valid
   rand pte_permission_t       xwr;   // PTE execute-write-read permission
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_list.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_list.sv
index f17f16f..d05bffd 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_list.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_page_table_list.sv
@@ -27,11 +27,11 @@
 
 class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
 
-  localparam PTE_SIZE   = XLEN / 8;
-  localparam PTE_CNT    = 4096 / PTE_SIZE;
-  localparam PAGE_LEVEL = (MODE == SV32) ? 2 : ((MODE == SV39) ? 3 : 4);
-  localparam LINK_PTE_PER_TABLE = 2;
-  localparam SUPER_LEAF_PTE_PER_TABLE = 2;
+  localparam int PteSize   = XLEN / 8;
+  localparam int PteCnt    = 4096 / PteSize;
+  localparam int PageLevel = (MODE == SV32) ? 2 : ((MODE == SV39) ? 3 : 4);
+  localparam int LinkPtePerTable = 2;
+  localparam int SuperLeafPtePerTable = 2;
 
   satp_mode_t mode = MODE;
 
@@ -92,7 +92,7 @@
     exception_cfg = riscv_page_table_exception_cfg::type_id::create("exception_cfg");
     valid_leaf_pte = riscv_page_table_entry#(MODE)::type_id::create("valid_leaf_pte");
     valid_link_pte = riscv_page_table_entry#(MODE)::type_id::create("valid_link_pte");
-    valid_data_leaf_pte = riscv_page_table_entry#(MODE)::type_id::create("valid_link_pte");
+    valid_data_leaf_pte = riscv_page_table_entry#(MODE)::type_id::create("valid_data_leaf_pte");
     illegal_pte = riscv_page_table_entry#(MODE)::type_id::create("illegal_pte");
   endfunction
 
@@ -101,8 +101,8 @@
   // higher level page table, only PTE[0] and PTE[1] is non-leaf PTE, all other PTEs are leaf
   // PTE. All leaf PTE should have PPN map to the real physical address of the instruction
   // or data. For non-leaf PTE, the PPN should map to the physical address of the next PTE.
-  // Take SV39 for example: (PTE_SIZE = 8B)
-  // Table size is 4KB, PTE_SIZE=8B, entry count = 4K/8 = 512
+  // Take SV39 for example: (PteSize = 8B)
+  // Table size is 4KB, PteSize=8B, entry count = 4K/8 = 512
   // Level 2: Root table, 2 entries, PTE[0] and PTE[1] is non-leaf PTE, PTE[2] is leaf PTE, all
   //          other PTEs are invalid, totalling 1 page table with 3 PTEs at this level.
   // Level 1: Two page tables, map to PTE[0] and PTE[1] of the root table.
@@ -130,10 +130,10 @@
       foreach(page_table[i].pte[j]) begin
         if(page_table[i].level > 0) begin
           // Superpage
-          if (j < LINK_PTE_PER_TABLE) begin
+          if (j < LinkPtePerTable) begin
             // First few super pages are link PTE to the next level
             $cast(page_table[i].pte[j], valid_link_pte.clone());
-          end else if (j < SUPER_LEAF_PTE_PER_TABLE + LINK_PTE_PER_TABLE) begin
+          end else if (j < SuperLeafPtePerTable + LinkPtePerTable) begin
             // Non-link superpage table entry
             $cast(page_table[i].pte[j], valid_leaf_pte.clone());
           end else begin
@@ -354,7 +354,7 @@
     // Fix kernel leaf PTE
     instr.push_back("fix_kernel_leaf_pte:");
     // - Load the starting virtual address of the kernel space
-    instr.push_back($sformatf("la x%0d, _kernel_instr_start", tmp_reg));
+    instr.push_back($sformatf("la x%0d, kernel_instr_start", tmp_reg));
     // TODO: Fix kernel instruction/data pages separatedly
     instr.push_back($sformatf("slli x%0d, x%0d, %0d", tmp_reg, tmp_reg,
                     XLEN - MAX_USED_VADDR_BITS));
@@ -405,9 +405,9 @@
   endfunction
 
   virtual function void default_page_table_setting();
-    num_of_page_table = new[PAGE_LEVEL];
+    num_of_page_table = new[PageLevel];
     foreach(num_of_page_table[i]) begin
-      num_of_page_table[i] = LINK_PTE_PER_TABLE ** (PAGE_LEVEL - i - 1);
+      num_of_page_table[i] = LinkPtePerTable ** (PageLevel - i - 1);
     end
   endfunction
 
@@ -415,7 +415,7 @@
     page_table = new[num_of_page_table.sum()];
     foreach(page_table[i]) begin
       page_table[i] = riscv_page_table#(MODE)::type_id::create($sformatf("page_table_%0d",i));
-      page_table[i].init_page_table(PTE_CNT);
+      page_table[i].init_page_table(PteCnt);
       page_table[i].table_id = i;
       page_table[i].level = get_level(i);
     end
@@ -441,8 +441,8 @@
       instr = {instr, $sformatf("la x%0d, page_table_%0d+2048 # Process PT_%0d",
                                 cfg.gpr[1], i, i)};
       foreach(page_table[i].pte[j]) begin
-        if(j >= SUPER_LEAF_PTE_PER_TABLE) continue;
-        pte_addr_offset = (j * PTE_SIZE) - 2048;
+        if(j >= SuperLeafPtePerTable) continue;
+        pte_addr_offset = (j * PteSize) - 2048;
         `uvm_info(`gfn, $sformatf("Processing PT_%0d_PTE_%0d, v = %0d, level = %0d",
                         i, j, page_table[i].pte[j].v, page_table[i].level), UVM_LOW)
         if(page_table[i].pte[j].xwr == NEXT_LEVEL_PAGE) begin
@@ -471,8 +471,8 @@
     if (cfg.support_supervisor_mode) begin
       instr = {instr,
                // Process kernel instruction pages
-               $sformatf("la x%0d, _kernel_instr_start", cfg.gpr[0]),
-               $sformatf("la x%0d, _kernel_instr_end", cfg.gpr[1]),
+               $sformatf("la x%0d, kernel_instr_start", cfg.gpr[0]),
+               $sformatf("la x%0d, kernel_instr_end", cfg.gpr[1]),
                // Get the VPN of the physical address
                $sformatf("slli x%0d, x%0d, %0d",
                          cfg.gpr[0], cfg.gpr[0], XLEN - MAX_USED_VADDR_BITS),
@@ -501,7 +501,7 @@
                // If not the end of the kernel space, process the next PTE
                $sformatf("ble x%0d, x%0d, 1b", cfg.gpr[0], cfg.gpr[1]),
                // Process kernel data pages
-               $sformatf("la x%0d, _kernel_data_start", cfg.gpr[0]),
+               $sformatf("la x%0d, kernel_data_start", cfg.gpr[0]),
                // Get the VPN of the physical address
                $sformatf("slli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0],
                          XLEN - MAX_USED_VADDR_BITS),
@@ -531,14 +531,14 @@
   // If you want to create custom page table topology, override the below tasks to specify the
   // level and parent of each table.
   virtual function int get_level(int table_id);
-    for(int level = PAGE_LEVEL - 1; level >= 0; level--) begin
+    for(int level = PageLevel - 1; level >= 0; level--) begin
       if(table_id < num_of_page_table[level]) return level;
       table_id -= num_of_page_table[level];
     end
   endfunction
 
   virtual function int get_child_table_id(int table_id, int pte_id);
-    return table_id * LINK_PTE_PER_TABLE + pte_id + 1;
+    return table_id * LinkPtePerTable + pte_id + 1;
   endfunction
 
 endclass
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
new file mode 100644
index 0000000..8abf685
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+class riscv_pmp_cfg extends uvm_object;
+
+  // default to a single PMP region
+  rand int pmp_num_regions = 1;
+  // default to granularity of 0 (4 bytes grain)
+  int pmp_granularity = 0;
+  // enable bit for pmp randomization
+  bit pmp_randomize = 0;
+  // pmp CSR configurations
+  rand pmp_cfg_reg_t pmp_cfg[];
+  // PMP maximum address - used to set defaults
+  // TODO(udinator) - make this address configurable?
+  bit [XLEN - 1 : 0] pmp_max_address = {XLEN{1'b1}};
+
+  // used to parse addr_mode configuration from cmdline
+  typedef uvm_enum_wrapper#(pmp_addr_mode_t) addr_mode_wrapper;
+  pmp_addr_mode_t addr_mode;
+
+  `uvm_object_utils_begin(riscv_pmp_cfg)
+    `uvm_field_int(pmp_num_regions, UVM_DEFAULT)
+    `uvm_field_int(pmp_granularity, UVM_DEFAULT)
+  `uvm_object_utils_end
+
+  // constraints
+  constraint sanity_c {
+    pmp_num_regions inside {[1 : 16]};
+    pmp_granularity inside {[0 : XLEN + 3]};
+  }
+
+  // TODO(udinator) more address constraints?
+  // TODO(udinator) move to posts_randomize() if lower performance
+  constraint xwr_c {
+    foreach (pmp_cfg[i]) {
+      !(pmp_cfg[i].w && !pmp_cfg[i].r);
+    }
+  }
+
+  constraint grain_addr_mode_c {
+    foreach (pmp_cfg[i]) {
+      (pmp_granularity >= 1) -> (pmp_cfg[i].a != NA4);
+    }
+  }
+
+  function new(string name = "");
+    string s;
+    super.new(name);
+    inst = uvm_cmdline_processor::get_inst();
+    get_bool_arg_value("+pmp_randomize=", pmp_randomize);
+    get_int_arg_value("+pmp_granularity=", pmp_granularity);
+    get_int_arg_value("+pmp_num_regions=", pmp_num_regions);
+    pmp_cfg = new[pmp_num_regions];
+    // As per privileged spec, the top 10 bits of a rv64 PMP address are all 0.
+    if (XLEN == 64) begin
+      pmp_max_address[XLEN - 1 : XLEN - 11] = 10'b0;
+    end
+    if (!pmp_randomize) begin
+      set_defaults();
+      setup_pmp();
+    end
+  endfunction
+
+  // This will only get called if pmp_randomize is set, in which case we apply command line
+  // arguments after randomization
+  function void post_randomize();
+    setup_pmp();
+  endfunction
+
+  function void set_defaults();
+    foreach(pmp_cfg[i]) begin
+      pmp_cfg[i].l    = 1'b0;
+      pmp_cfg[i].a    = TOR;
+      pmp_cfg[i].x    = 1'b1;
+      pmp_cfg[i].w    = 1'b1;
+      pmp_cfg[i].r    = 1'b1;
+      pmp_cfg[i].addr = assign_default_addr(pmp_num_regions, i + 1);
+    end
+  endfunction
+
+  // Helper function to break down
+  function bit [XLEN - 1 : 0] assign_default_addr(int num_regions, int index);
+    return pmp_max_address / num_regions * index;
+  endfunction
+
+  function void setup_pmp();
+    string arg_name;
+    string pmp_region;
+    foreach (pmp_cfg[i]) begin
+      arg_name = $sformatf("+pmp_region_%0d=", i);
+      if (inst.get_arg_value(arg_name, pmp_region)) begin
+        parse_pmp_config(pmp_region, pmp_cfg[i]);
+        `uvm_info(`gfn, $sformatf("Configured pmp_cfg[%0d] from command line: %p",
+                                  i, pmp_cfg[i]), UVM_LOW)
+      end
+    end
+  endfunction
+
+  function void parse_pmp_config(string pmp_region, output pmp_cfg_reg_t pmp_cfg_reg);
+    string fields[$];
+    string field_vals[$];
+    string field_type;
+    string field_val;
+    uvm_split_string(pmp_region, ",", fields);
+    foreach (fields[i]) begin
+      uvm_split_string(fields[i], ":", field_vals);
+      field_type = field_vals.pop_front();
+      field_val = field_vals.pop_front();
+      case (field_type)
+        "L": begin
+          pmp_cfg_reg.l = field_val.atobin();
+        end
+        "A": begin
+          `DV_CHECK(addr_mode_wrapper::from_name(field_val, addr_mode))
+          pmp_cfg_reg.a = addr_mode;
+        end
+        "X": begin
+          pmp_cfg_reg.x = field_val.atobin();
+        end
+        "W": begin
+          pmp_cfg_reg.w = field_val.atobin();
+        end
+        "R": begin
+          pmp_cfg_reg.r = field_val.atobin();
+        end
+        "ADDR": begin
+          // Don't have to convert address to "PMP format" here,
+          // since it must be masked off in hardware
+          pmp_cfg_reg.addr = format_addr(field_val.atohex());
+        end
+        default: begin
+          `uvm_fatal(`gfn, $sformatf("%s, Invalid PMP configuration field name!", field_val))
+        end
+      endcase
+    end
+  endfunction
+
+  function bit [XLEN - 1 : 0] format_addr(bit [XLEN - 1 : 0] addr);
+    // For all ISAs, pmpaddr CSRs do not include the bottom two bits of the input address
+    bit [XLEN - 1 : 0] shifted_addr;
+    shifted_addr = addr >> 2; case (XLEN)
+      // RV32 - pmpaddr is bits [33:2] of the whole 34 bit address
+      // Return the input address right-shifted by 2 bits
+      32: begin
+        return shifted_addr;
+      end
+      // RV64 - pmpaddr is bits [55:2] of the whole 56 bit address, prepended by 10'b0
+      // Return {10'b0, shifted_addr[53:0]}
+      64: begin
+        return {10'b0, shifted_addr[XLEN - 11 : 0]};
+      end
+    endcase
+  endfunction
+
+  // TODO(udinator) - implement function to return hardware masked pmpaddr "representation"
+  function bit [XLEN - 1 : 0] convert_addr2pmp(bit [XLEN - 1 : 0] addr);
+    `uvm_info(`gfn, "Placeholder function, need to implement", UVM_LOW)
+  endfunction
+
+  // This function parses the pmp_cfg[] array to generate the actual instructions to set up
+  // the PMP CSR registers.
+  // Since either 4 (in rv32) or 8 (in rv64) PMP configuration registers fit into one physical
+  // CSR, this function waits until it has reached this maximum to write to the physical CSR to
+  // save some extraneous instructions from being performed.
+  function void gen_pmp_instr(ref string instr[$], riscv_reg_t scratch_reg);
+    int cfg_per_csr = XLEN / 4;
+    bit [XLEN - 1 : 0] pmp_word;
+    bit [XLEN - 1 : 0] cfg_bitmask;
+    bit [7 : 0] cfg_byte;
+    riscv_instr_pkg::privileged_reg_t base_pmp_addr = PMPADDR0;
+    riscv_instr_pkg::privileged_reg_t base_pmpcfg_addr = PMPCFG0;
+    int pmp_id;
+    foreach (pmp_cfg[i]) begin
+      // TODO(udinator) condense this calculations if possible
+      pmp_id = i / cfg_per_csr;
+      cfg_byte = {pmp_cfg[i].l, pmp_cfg[i].zero, pmp_cfg[i].a,
+                  pmp_cfg[i].x, pmp_cfg[i].w, pmp_cfg[i].r};
+      `uvm_info(`gfn, $sformatf("cfg_byte: 0x%0x", cfg_byte), UVM_DEBUG)
+      cfg_bitmask = cfg_byte << ((i % cfg_per_csr) * 8);
+      `uvm_info(`gfn, $sformatf("cfg_bitmask: 0x%0x", cfg_bitmask), UVM_DEBUG)
+      pmp_word = pmp_word | cfg_bitmask;
+      `uvm_info(`gfn, $sformatf("pmp_word: 0x%0x", pmp_word), UVM_DEBUG)
+      cfg_bitmask = 0;
+      `uvm_info(`gfn, $sformatf("pmp_addr: 0x%0x", pmp_cfg[i].addr), UVM_DEBUG)
+      instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg, pmp_cfg[i].addr));
+      instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmp_addr + i, scratch_reg));
+      // short circuit if end of list
+      if (i == pmp_cfg.size() - 1) begin
+        instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg, pmp_word));
+        instr.push_back($sformatf("csrw 0x%0x, x%0d",
+                                  base_pmpcfg_addr + pmp_id,
+                                  scratch_reg));
+        return;
+      end else if ((i + 1) % cfg_per_csr == 0) begin
+        // if we've filled up pmp_word, write to the corresponding CSR
+        instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg, pmp_word));
+        instr.push_back($sformatf("csrw 0x%0x, x%0d",
+                                  base_pmpcfg_addr + pmp_id,
+                                  scratch_reg));
+        pmp_word = 0;
+      end
+    end
+  endfunction
+
+endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_privileged_common_seq.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_privileged_common_seq.sv
index 0970da0..4dc3f2c 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_privileged_common_seq.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_privileged_common_seq.sv
@@ -18,6 +18,7 @@
 class riscv_privileged_common_seq extends uvm_sequence;
 
   riscv_instr_gen_config  cfg;
+  int                     hart;
   riscv_privil_reg        mstatus;
   riscv_privil_reg        mie;
   riscv_privil_reg        sstatus;
@@ -33,7 +34,8 @@
 
   virtual function void enter_privileged_mode(input privileged_mode_t mode,
                                               output string instrs[$]);
-    string label = format_string({"init_", mode.name(), ":"}, LABEL_STR_LEN);
+    string label = format_string({$sformatf("%0sinit_%0s:",
+                                 hart_prefix(hart), mode.name())}, LABEL_STR_LEN);
     string ret_instr[] = {"mret"};
     riscv_privil_reg regs[$];
     label = label.tolower();
@@ -69,10 +71,16 @@
     mstatus.set_field("TW", cfg.set_mstatus_tw);
     mstatus.set_field("FS", cfg.mstatus_fs);
     mstatus.set_field("VS", cfg.mstatus_vs);
-    if(XLEN==64) begin
-      mstatus.set_field("UXL", 2'b10);
+    if (!(SUPERVISOR_MODE inside {supported_privileged_mode}) && (XLEN != 32)) begin
+      mstatus.set_field("SXL", 2'b00);
+    end else if (XLEN == 64) begin
       mstatus.set_field("SXL", 2'b10);
     end
+    if (!(USER_MODE inside {supported_privileged_mode}) && (XLEN != 32)) begin
+      mstatus.set_field("UXL", 2'b00);
+    end else if (XLEN == 64) begin
+      mstatus.set_field("UXL", 2'b10);
+    end
     mstatus.set_field("XS", 0);
     mstatus.set_field("SD", 0);
     mstatus.set_field("UIE", 0);
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/ml/riscvOVPsim.ic b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/ml/riscvOVPsim.ic
index 8712e05..b1cadaa 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/ml/riscvOVPsim.ic
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/ml/riscvOVPsim.ic
@@ -17,3 +17,6 @@
 --override riscvOVPsim/cpu/time_undefined=T
 --override riscvOVPsim/cpu/reset_address=0x80000000
 --override riscvOVPsim/cpu/simulateexceptions=T
+--override riscvOVPsim/cpu/defaultsemihost=F
+--override riscvOVPsim/cpu/wfi_is_nop=T
+--exitonsymbol _exit
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/ml/riscv_core_setting.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/ml/riscv_core_setting.sv
index 425351c..18cf13c 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/ml/riscv_core_setting.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/ml/riscv_core_setting.sv
@@ -39,6 +39,9 @@
 // supported
 int max_interrupt_vector_num = 16;
 
+// Physical memory protection support
+bit support_pmp = 0;
+
 // Debug mode support
 bit support_debug_mode = 0;
 
@@ -57,6 +60,8 @@
 parameter int ELEN = 64;
 parameter int SLEN = 64;
 
+// Number of harts
+parameter int NUM_HARTS = 1;
 // ----------------------------------------------------------------------------
 // Previleged CSR implementation
 // ----------------------------------------------------------------------------
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/multi_harts/riscvOVPsim.ic b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/multi_harts/riscvOVPsim.ic
new file mode 100644
index 0000000..36e0eea
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/multi_harts/riscvOVPsim.ic
@@ -0,0 +1,22 @@
+# riscOVPsim configuration file converted from YAML
+--variant RV32I
+--override riscvOVPsim/cpu/add_Extensions=MCA
+--override riscvOVPsim/cpu/misa_MXL=1
+--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
+--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
+--override riscvOVPsim/cpu/unaligned=T
+--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
+--override riscvOVPsim/cpu/user_version=2.3
+--override riscvOVPsim/cpu/priv_version=1.11
+--override riscvOVPsim/cpu/mvendorid=0
+--override riscvOVPsim/cpu/marchid=0
+--override riscvOVPsim/cpu/mimpid=0
+--override riscvOVPsim/cpu/mhartid=0
+--override riscvOVPsim/cpu/cycle_undefined=F
+--override riscvOVPsim/cpu/instret_undefined=F
+--override riscvOVPsim/cpu/time_undefined=T
+--override riscvOVPsim/cpu/reset_address=0x80000000
+--override riscvOVPsim/cpu/simulateexceptions=T
+--override riscvOVPsim/cpu/defaultsemihost=F
+--override riscvOVPsim/cpu/wfi_is_nop=T
+--exitonsymbol _exit
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/multi_harts/riscv_core_setting.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/multi_harts/riscv_core_setting.sv
new file mode 100644
index 0000000..9e6e966
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/multi_harts/riscv_core_setting.sv
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//-----------------------------------------------------------------------------
+// Processor feature configuration
+//-----------------------------------------------------------------------------
+// XLEN
+parameter int XLEN = 32;
+
+// Parameter for SATP mode, set to BARE if address translation is not supported
+parameter satp_mode_t SATP_MODE = BARE;
+
+// Supported Privileged mode
+privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE};
+
+// Unsupported instructions
+riscv_instr_name_t unsupported_instr[];
+
+// ISA supported by the processor
+riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C, RV32A};
+
+// Interrupt mode support
+mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};
+
+// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
+// supported
+int max_interrupt_vector_num = 16;
+
+// Physical memory protection support
+bit support_pmp = 0;
+
+// Debug mode support
+bit support_debug_mode = 0;
+
+// Support delegate trap to user mode
+bit support_umode_trap = 0;
+
+// Support sfence.vma instruction
+bit support_sfence = 0;
+
+// Support unaligned load/store
+bit support_unaligned_load_store = 1'b1;
+
+// Parameter for vector extension
+parameter int VECTOR_EXTENSION_ENABLE = 0;
+parameter int VLEN = 512;
+parameter int ELEN = 64;
+parameter int SLEN = 64;
+
+// Number of harts
+parameter int NUM_HARTS = 2;
+
+// ----------------------------------------------------------------------------
+// Previleged CSR implementation
+// ----------------------------------------------------------------------------
+
+// Implemented previlieged CSR list
+`ifdef DSIM
+privileged_reg_t implemented_csr[] = {
+`else
+parameter privileged_reg_t implemented_csr[] = {
+`endif
+    // Machine mode mode CSR
+    MVENDORID,  // Vendor ID
+    MARCHID,    // Architecture ID
+    MIMPID,     // Implementation ID
+    MHARTID,    // Hardware thread ID
+    MSTATUS,    // Machine status
+    MISA,       // ISA and extensions
+    MIE,        // Machine interrupt-enable register
+    MTVEC,      // Machine trap-handler base address
+    MCOUNTEREN, // Machine counter enable
+    MSCRATCH,   // Scratch register for machine trap handlers
+    MEPC,       // Machine exception program counter
+    MCAUSE,     // Machine trap cause
+    MTVAL,      // Machine bad address or instruction
+    MIP         // Machine interrupt pending
+};
+
+// ----------------------------------------------------------------------------
+// Supported interrupt/exception setting, used for functional coverage
+// ----------------------------------------------------------------------------
+
+`ifdef DSIM
+interrupt_cause_t implemented_interrupt[] = {
+`else
+parameter interrupt_cause_t implemented_interrupt[] = {
+`endif
+    M_SOFTWARE_INTR,
+    M_TIMER_INTR,
+    M_EXTERNAL_INTR
+};
+
+`ifdef DSIM
+exception_cause_t implemented_exception[] = {
+`else
+parameter exception_cause_t implemented_exception[] = {
+`endif
+    INSTRUCTION_ACCESS_FAULT,
+    ILLEGAL_INSTRUCTION,
+    BREAKPOINT,
+    LOAD_ADDRESS_MISALIGNED,
+    LOAD_ACCESS_FAULT,
+    ECALL_MMODE
+};
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/multi_harts/testlist.yaml b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/multi_harts/testlist.yaml
new file mode 100644
index 0000000..c491ae7
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/multi_harts/testlist.yaml
@@ -0,0 +1,79 @@
+# Copyright Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# ================================================================================
+#                  Regression test list format
+# --------------------------------------------------------------------------------
+# test            : Assembly test name
+# description     : Description of this test
+# gen_opts        : Instruction generator options
+# iterations      : Number of iterations of this test
+# no_iss          : Enable/disable ISS simulator (Optional)
+# gen_test        : Test name used by the instruction generator
+# asm_tests       : Path to directed, hand-coded assembly test file or directory
+# rtl_test        : RTL simulation test name
+# cmp_opts        : Compile options passed to the instruction generator
+# sim_opts        : Simulation options passed to the instruction generator
+# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional)
+# compare_opts    : Options for the RTL & ISS trace comparison
+# gcc_opts        : gcc compile options
+# --------------------------------------------------------------------------------
+
+- import: <riscv_dv_root>/yaml/base_testlist.yaml
+
+
+- test: riscv_non_compressed_instr_test
+  description: >
+    Random instruction test without compressed instructions
+  iterations: 1
+  gen_test: riscv_rand_instr_test
+  gen_opts: >
+    +disable_compressed_instr=1
+  rtl_test: core_base_test
+
+
+- test: riscv_hint_instr_test
+  description: >
+    HINT instruction test, verify the processor can detect HINT instruction
+    treat it as NOP. No illegal instruction exception is expected
+  iterations: 2
+  gen_test: riscv_rand_instr_test
+  gen_opts: >
+    +hint_instr_ratio=5
+  rtl_test: core_base_test
+
+
+- test: riscv_amo_test
+  description: >
+    RISC-V atomic instruction extension test
+  iterations: 2
+  gen_test: riscv_rand_instr_test
+  gen_opts: >
+    +instr_cnt=5000
+    +num_of_sub_program=5
+    +directed_instr_0=riscv_lr_sc_instr_stream,10
+    +directed_instr_1=riscv_amo_instr_stream,10
+  rtl_test: core_base_test
+
+
+- test: riscv_single_hart_test
+  description: >
+    single hart random test
+  iterations: 2
+  gen_test: riscv_rand_instr_test
+  gen_opts: >
+    +instr_cnt=6000
+    +num_of_harts=1
+  rtl_test: core_base_test
+
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32i/riscvOVPsim.ic b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32i/riscvOVPsim.ic
index 4281a3c..64bc56b 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32i/riscvOVPsim.ic
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32i/riscvOVPsim.ic
@@ -16,3 +16,6 @@
 --override riscvOVPsim/cpu/time_undefined=T
 --override riscvOVPsim/cpu/reset_address=0x80000000
 --override riscvOVPsim/cpu/simulateexceptions=T
+--override riscvOVPsim/cpu/defaultsemihost=F
+--override riscvOVPsim/cpu/wfi_is_nop=T
+--exitonsymbol _exit
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32i/riscv_core_setting.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32i/riscv_core_setting.sv
index bd7ae9b..8f4a977 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32i/riscv_core_setting.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32i/riscv_core_setting.sv
@@ -39,6 +39,9 @@
 // supported
 int max_interrupt_vector_num = 16;
 
+// Physical memory protection support
+bit support_pmp = 0;
+
 // Debug mode support
 bit support_debug_mode = 0;
 
@@ -57,6 +60,8 @@
 parameter int ELEN = 64;
 parameter int SLEN = 64;
 
+// Number of harts
+parameter int NUM_HARTS = 1;
 // ----------------------------------------------------------------------------
 // Previleged CSR implementation
 // ----------------------------------------------------------------------------
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/riscvOVPsim.ic b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/riscvOVPsim.ic
index c7e9d0a..43c8b8c 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/riscvOVPsim.ic
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/riscvOVPsim.ic
@@ -17,3 +17,6 @@
 --override riscvOVPsim/cpu/time_undefined=T
 --override riscvOVPsim/cpu/reset_address=0x80000000
 --override riscvOVPsim/cpu/simulateexceptions=T
+--override riscvOVPsim/cpu/defaultsemihost=F
+--override riscvOVPsim/cpu/wfi_is_nop=T
+--exitonsymbol _exit
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/riscv_core_setting.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/riscv_core_setting.sv
index a373e50..9926318 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/riscv_core_setting.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/riscv_core_setting.sv
@@ -39,6 +39,9 @@
 // supported
 int max_interrupt_vector_num = 16;
 
+// Physical memory protection support
+bit support_pmp = 0;
+
 // Debug mode support
 bit support_debug_mode = 0;
 
@@ -57,6 +60,9 @@
 parameter int ELEN = 64;
 parameter int SLEN = 64;
 
+// Number of harts
+parameter int NUM_HARTS = 1;
+
 // ----------------------------------------------------------------------------
 // Previleged CSR implementation
 // ----------------------------------------------------------------------------
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/testlist.yaml b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/testlist.yaml
index 0aa7f53..78d64fc 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/testlist.yaml
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv32imc/testlist.yaml
@@ -53,3 +53,14 @@
     +hint_instr_ratio=5
   rtl_test: core_base_test
 
+- test: riscv_pmp_test
+  description: >
+    Provide some PMP configuration parameters, and setup PMP CSRs appropriately
+  iterations: 2
+  gen_test: riscv_rand_instr_test
+  gen_opts: >
+    +pmp_randomize=0
+    +pmp_num_regions=1
+    +pmp_granularity=1
+    +pmp_region_0=L:0,A:TOR,X:1,W:1,R:1,ADDR:FFFFFFFF
+  rtl_test: core_base_test
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gc/riscvOVPsim.ic b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gc/riscvOVPsim.ic
index efe857b..fdf7448 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gc/riscvOVPsim.ic
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gc/riscvOVPsim.ic
@@ -16,3 +16,6 @@
 --override riscvOVPsim/cpu/time_undefined=T
 --override riscvOVPsim/cpu/reset_address=0x80000000
 --override riscvOVPsim/cpu/simulateexceptions=T
+--override riscvOVPsim/cpu/defaultsemihost=F
+--override riscvOVPsim/cpu/wfi_is_nop=T
+--exitonsymbol _exit
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gc/riscv_core_setting.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gc/riscv_core_setting.sv
index 15ea4c6..7e7ba60 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gc/riscv_core_setting.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gc/riscv_core_setting.sv
@@ -39,6 +39,9 @@
 // supported
 int max_interrupt_vector_num = 16;
 
+// Physical memory protection support
+bit support_pmp = 0;
+
 // Debug mode support
 bit support_debug_mode = 0;
 
@@ -57,6 +60,9 @@
 parameter int ELEN = 64;
 parameter int SLEN = 64;
 
+// Number of harts
+parameter int NUM_HARTS = 1;
+
 // ----------------------------------------------------------------------------
 // Previleged CSR implementation
 // ----------------------------------------------------------------------------
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gcv/riscvOVPsim.ic b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gcv/riscvOVPsim.ic
index 32e3d75..fdb0914 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gcv/riscvOVPsim.ic
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gcv/riscvOVPsim.ic
@@ -17,3 +17,6 @@
 --override riscvOVPsim/cpu/time_undefined=T
 --override riscvOVPsim/cpu/reset_address=0x80000000
 --override riscvOVPsim/cpu/simulateexceptions=T
+--override riscvOVPsim/cpu/defaultsemihost=F
+--override riscvOVPsim/cpu/wfi_is_nop=T
+--exitonsymbol _exit
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gcv/riscv_core_setting.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gcv/riscv_core_setting.sv
index 94c99fb..df86af5 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gcv/riscv_core_setting.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64gcv/riscv_core_setting.sv
@@ -39,6 +39,9 @@
 // supported
 int max_interrupt_vector_num = 16;
 
+// Physical memory protection support
+bit support_pmp = 0;
+
 // Debug mode support
 bit support_debug_mode = 0;
 
@@ -57,6 +60,8 @@
 parameter int ELEN = 64;
 parameter int SLEN = 64;
 
+// Number of harts
+parameter int NUM_HARTS = 1;
 // ----------------------------------------------------------------------------
 // Previleged CSR implementation
 // ----------------------------------------------------------------------------
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64imc/riscvOVPsim.ic b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64imc/riscvOVPsim.ic
index 8712e05..b1cadaa 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64imc/riscvOVPsim.ic
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64imc/riscvOVPsim.ic
@@ -17,3 +17,6 @@
 --override riscvOVPsim/cpu/time_undefined=T
 --override riscvOVPsim/cpu/reset_address=0x80000000
 --override riscvOVPsim/cpu/simulateexceptions=T
+--override riscvOVPsim/cpu/defaultsemihost=F
+--override riscvOVPsim/cpu/wfi_is_nop=T
+--exitonsymbol _exit
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64imc/riscv_core_setting.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64imc/riscv_core_setting.sv
index 1803e98..5ce7e0e 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64imc/riscv_core_setting.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/target/rv64imc/riscv_core_setting.sv
@@ -39,6 +39,9 @@
 // supported
 int max_interrupt_vector_num = 16;
 
+// Physical memory protection support
+bit support_pmp = 0;
+
 // Debug mode support
 bit support_debug_mode = 0;
 
@@ -57,6 +60,9 @@
 parameter int ELEN = 64;
 parameter int SLEN = 64;
 
+// Number of harts
+parameter int NUM_HARTS = 1;
+
 // ----------------------------------------------------------------------------
 // Previleged CSR implementation
 // ----------------------------------------------------------------------------
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv
index 9f35d55..36ed566 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv
@@ -52,7 +52,9 @@
     cfg.init_privileged_mode = MACHINE_MODE;
     cfg.init_privileged_mode.rand_mode(0);
     cfg.enable_unaligned_load_store = 1'b1;
+    cfg.addr_translaction_rnd_order_c.constraint_mode(0);
     `DV_CHECK_RANDOMIZE_FATAL(cfg)
+	cfg.addr_translaction_rnd_order_c.constraint_mode(1);
     `uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
                     cfg.sprint()), UVM_LOW)
   endfunction
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/verilog_style/build-verible.sh b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/verilog_style/build-verible.sh
new file mode 100755
index 0000000..f4d3a6a
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/verilog_style/build-verible.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+#
+# Copyright 2019 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+VERIBLE_VERSION=03c7102ab8ed63037159f479ce17b3487401f082
+INSTALL_DIR=/tools/verible
+
+# this requires the bazel build system and GCC7
+# see https://docs.bazel.build/versions/master/install-ubuntu.html
+
+echo "checking whether bazel is installed..."
+if which bazel; then
+  echo "OK"
+else
+  echo "bazel is not installed. installing bazel..."
+  sudo apt install curl -y
+  curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
+  echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" \
+    | sudo tee /etc/apt/sources.list.d/bazel.list
+  sudo apt update && sudo apt install bazel -y
+fi
+
+# upgrade to GCC7
+# TODO: check whether we need to maintain the default symlinks here
+# for gcc -> GCC-5* such that other tools still work.
+echo "checking whether GCC7 is installed..."
+if which gcc-7; then
+  echo "OK"
+else
+  echo "Error: GCC7 is not installed. Exit and Verible isn't installed"
+  exit 0
+fi
+
+# get verible and install under /tools/verible
+# note: you may add $INSTALL_DIR to the PATH, but it is not
+# required for the run scripts to work.
+echo "Installing Verible ($VERIBLE_VERSION)..."
+
+mkdir -p build && cd build
+git clone https://github.com/google/verible.git
+cd verible
+git pull origin master
+git checkout $VERIBLE_VERSION
+
+bazel build --cxxopt='-std=c++17' //...
+bazel test --cxxopt='-std=c++17' //...
+
+sudo mkdir -p $INSTALL_DIR
+
+sudo install bazel-bin/verilog/tools/syntax/verilog_syntax $INSTALL_DIR
+sudo install bazel-bin/verilog/tools/formatter/verilog_format $INSTALL_DIR
+sudo install bazel-bin/verilog/tools/lint/verilog_lint $INSTALL_DIR
+
+echo "done"
+
+
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/verilog_style/exclude_filelist.f b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/verilog_style/exclude_filelist.f
new file mode 100644
index 0000000..ac20326
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/verilog_style/exclude_filelist.f
@@ -0,0 +1,10 @@
+# Current Verible can not support some syntax used in following files. List them here to exclude
+# from Verilog style check
+# tool does not support macro very well. Issue at github.com/google/verible/issues/102
+riscv_instr_cover_group.sv
+riscv_instr_pkg.sv
+# tool does not support included file very well. Issue at github.com/google/verible/issues/178
+riscv_custom_instr_enum.sv
+# tool bug. Issue at github.com/google/verible/issues/172
+riscv_instr_stream.sv
+riscv_reg.sv
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/verilog_style/run.sh b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/verilog_style/run.sh
new file mode 100755
index 0000000..f67a5f9
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/verilog_style/run.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Copyright 2019 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+find src/ -type f \( -name "*.sv" -o -name "*.svh" \) \
+  | grep -vFf ./verilog_style/exclude_filelist.f \
+  | xargs /tools/verible/verilog_lint --rules=-macro-name-style
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/iss.yaml b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/iss.yaml
index 4a59629..344ef79 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/iss.yaml
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/iss.yaml
@@ -23,7 +23,6 @@
     <path_var>/riscvOVPsim.exe
     --controlfile <cfg_path>/riscvOVPsim.ic
     --objfilenoentry <elf>
-    --override riscvOVPsim/cpu/PMP_registers=0
     --override riscvOVPsim/cpu/simulateexceptions=T
     --trace --tracechange --traceshowicount --tracemode --traceregs
     --finishafter 1000000
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/simulator.yaml b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/simulator.yaml
index d0a214b..d926809 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/simulator.yaml
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/simulator.yaml
@@ -20,6 +20,7 @@
               +incdir+<user_extension>
              -f <cwd>/files.f -full64
              -l <out>/compile.log
+             -LDFLAGS '-Wl,--no-as-needed'
              -Mdir=<out>/vcs_simv.csrc
              -o <out>/vcs_simv <cmp_opts> <cov_opts> "
     cov_opts: >
@@ -42,7 +43,7 @@
               -l <out>/compile.log <cmp_opts>"
   sim:
     cmd: >
-      irun -R <sim_opts> -svseed <seed>
+      irun -R <sim_opts> -svseed <seed> -svrnc rand_struct
 
 - tool: questa
   compile:
@@ -78,6 +79,7 @@
                 +incdir+$UVM_HOME/src
                 $UVM_HOME/src/uvm_pkg.sv
                 +define+DSIM
+                -suppress EnumMustBePositive
                 +incdir+<setting>
                 +incdir+<user_extension>
                 -f <cwd>/files.f