Update lowrisc_ibex to lowRISC/ibex@3f0b730
Update code from upstream repository
https://github.com/lowRISC/ibex.git to revision
3f0b730d57ee415abd2526fc283d3d16c6632d6b
* [doc] Riviera-PRO instructions for Simple System (Greg Chadwick)
* [rtl] Decouple `mip` and `mie` CSRs (Pirmin Vogel)
* Extend riscv-compliance description (Tobias Wölfel)
* Fix incdirs of src_files.yml (dalance)
* [verilator] Fix ELF loading (Luís Marques)
* Fix FPGA part number for Arty A7-100T (Stephano Cetola)
* Ignore all interrupts in NMI mode, clarify interrupt documentation
(Pirmin Vogel)
* [rtl] Comment and naming tweaks (Greg Chadwick)
* [rtl] Timing fix for pc_mux_o in ibex_controller (Greg Chadwick)
* [rtl] Add multdiv_sel signal to decode (Greg Chadwick)
* [rtl] Replicate instruction flops to reduce fanout (Greg Chadwick)
* [RTL] Added seperate ALU for branch target (Greg Chadwick)
* [dv] Fix a missed Riviera compile warning (lowRISC/ibex#576)
(udinator)
* [DV] Add support for Riviera (Daniel Mlynek)
* Work around Riviera 2019.10 issue (Daniel Mlynek)
* [DV] Use const instead of parameter (Daniel Mlynek)
* [examples] Add Dual-Port Memory to Simple System (ganoam)
* Update google_riscv-dv to google/riscv-dv@f7e35d7 (lowRISC/ibex#573)
(udinator)
* Riviera compile warnings (lowRISC/ibex#572) (udinator)
* Verilator: Remove unused waivers (Philipp Wagner)
* Include assert macros when they are used (Daniel Mlynek)
* Simple System: Correctly tie-off unused signals (Daniel Mlynek)
* Specify boot address in decimal (Daniel Mlynek)
* FPGA example: add support for the Arty A7-35 (Stefan Tauner)
* sw-led: do not hardcode CC in makefile (Stefan Tauner)
* [DV] Test debug requests during interrupt handler execution
(lowRISC/ibex#565) (udinator)
* [DV] Test nested interrupts (lowRISC/ibex#560) (udinator)
* Update google_riscv-dv to google/riscv-dv@a655f34 (lowRISC/ibex#564)
(udinator)
* Improve wording in README of simple system (Philipp Wagner)
* [syn] Feed ABC faster clock for better results (Greg Chadwick)
* [rtl] Fix Typo in FPGA Register File (ganoam)
* [DV] Add test to assert interrupts during debug execution
(lowRISC/ibex#524) (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 12dc793..7b8f16a 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: 80067b077c5241a59e9f0724d5c226ff7c919467
+ rev: 3f0b730d57ee415abd2526fc283d3d16c6632d6b
}
}
diff --git a/hw/vendor/lowrisc_ibex/Makefile b/hw/vendor/lowrisc_ibex/Makefile
index c7c480c..1d928a0 100644
--- a/hw/vendor/lowrisc_ibex/Makefile
+++ b/hw/vendor/lowrisc_ibex/Makefile
@@ -7,7 +7,7 @@
@echo "or how to set-up the different environments."
# Use a parallel run (make -j N) for a faster build
-build-all: build-riscv-compliance build-simple-system build-arty \
+build-all: build-riscv-compliance build-simple-system build-arty-100 \
build-csr-test
@@ -46,9 +46,10 @@
--raminit=$(simple-system-program)
-# Arty A7 100T
-# Use the following targets:
-# - "build-arty"
+# Arty A7 FPGA example
+# Use the following targets (depending on your hardware):
+# - "build-arty-35"
+# - "build-arty-100"
# - "program-arty"
arty-sw-program = examples/sw/led/led.vmem
sw-led: $(arty-sw-program)
@@ -57,13 +58,20 @@
$(arty-sw-program):
cd examples/sw/led && $(MAKE)
-build-arty: sw-led
+.PHONY: build-arty-35
+build-arty-35: sw-led
fusesoc --cores-root=. run --target=synth --setup --build \
- lowrisc:ibex:top_artya7_100
+ lowrisc:ibex:top_artya7 --part xc7a35ticsg324-1L
+
+.PHONY: build-arty-100
+build-arty-100: sw-led
+ fusesoc --cores-root=. run --target=synth --setup --build \
+ lowrisc:ibex:top_artya7 --part xc7a100tcsg324-1
.PHONY: program-arty
program-arty:
- fusesoc --cores-root=. pgm lowrisc:ibex:top_artya7_100
+ fusesoc --cores-root=. run --target=synth --run \
+ lowrisc:ibex:top_artya7
# Lint check
diff --git a/hw/vendor/lowrisc_ibex/doc/exception_interrupts.rst b/hw/vendor/lowrisc_ibex/doc/exception_interrupts.rst
index c4b53dd..567c149 100644
--- a/hw/vendor/lowrisc_ibex/doc/exception_interrupts.rst
+++ b/hw/vendor/lowrisc_ibex/doc/exception_interrupts.rst
@@ -5,8 +5,10 @@
Ibex implements trap handling for interrupts and exceptions according to the RISC-V Privileged Specification, version 1.11.
+When entering an interrupt/exception handler, the core sets the ``mepc`` CSR to the current program counter and saves ``mstatus``.MIE to ``mstatus``.MPIE.
All exceptions cause the core to jump to the base address of the vector table in the ``mtvec`` CSR.
Interrupts are handled in vectored mode, i.e., the core jumps to the base address plus four times the interrupt ID.
+Upon executing an MRET instruction, the core jumps to the program counter previously saved in the ``mepc`` CSR and restores ``mstatus``.MPIE to ``mstatus``.MIE.
The base address of the vector table is initialized to the boot address (must be aligned to 256 bytes, i.e., its least significant byte must be 0x00) when the core is booting.
The base address can be changed after bootup by writing to the ``mtvec`` CSR.
@@ -47,10 +49,13 @@
To enable interrupts, both the global interrupt enable (MIE) bit in the ``mstatus`` CSR and the corresponding individual interrupt enable bit in the ``mie`` CSR need to be set.
For more information, see the :ref:`cs-registers` documentation.
-If multiple interrupts are pending, the highest priority is given to the interrupt with the highest ID.
+If multiple interrupts are pending, they are handled in the priority order defined by the RISC-V Privileged Specification, version 1.11 (see Machine Interrupt Registers, Section 3.1.9).
+The highest priority is given to the interrupt with the highest ID, except for timer interrupts, which have the lowest priority.
The NMI is enabled independent of the values in the ``mstatus`` and ``mie`` CSRs, and it is not visible through the ``mip`` CSR.
It has interrupt ID 31, i.e., it has the highest priority of all interrupts and the core jumps to the trap-handler base address (in ``mtvec``) plus 0x7C to handle the NMI.
+When handling the NMI, all interrupts including the NMI are ignored.
+Nested NMIs are not supported.
All interrupt lines are level-sensitive.
It is assumed that the interrupt handler signals completion of the handling routine to the interrupt source, e.g., through a memory-mapped register, which then deasserts the corresponding interrupt line.
@@ -94,13 +99,51 @@
The illegal instruction exception, instruction access fault, LSU error exceptions and ECALL instruction exceptions cannot be disabled and are always active.
-Handling
---------
+Nested Interrupt/Exception Handling
+-----------------------------------
-Ibex does support nested interrupt/exception handling.
-Exceptions inside interrupt/exception handlers cause another exception.
-However, exceptions during the critical part of your exception handlers, i.e. before having saved the ``mepc`` and ``mstatus``, will cause those CSRs to be overwritten.
-Interrupts during interrupt/exception handlers are thus disabled by default, but can be explicitly enabled if desired.
+Ibex does support nested interrupt/exception handling in software.
+The hardware automatically disables interrupts upon entering an interrupt/exception handler.
+Otherwise, interrupts/exceptions during the critical part of the handler, i.e. before software has saved the ``mepc`` and ``mstatus`` CSRs, would cause those CSRs to be overwritten.
+If desired, software can explicitly enable interrupts by setting ``mstatus``.MIE to 1'b1 from within the handler.
+However, software should only do this after saving ``mepc`` and ``mstatus``.
+There is no limit on the maximum number of nested interrupts.
+Note that, after enabling interrupts by setting ``mstatus``.MIE to 1'b1, the current handler will be interrupted also by lower priority interrupts.
+To allow higher priority interrupts only, the handler must configure ``mie`` accordingly.
-When entering an interrupt/exception handler, the core sets ``mepc`` to the current program counter and saves ``mstatus``.MIE to ``mstatus``.MPIE.
-Upon executing an MRET instruction, the core jumps to the program counter saved in the ``mepc`` CSR and restores ``mstatus``.MPIE to ``mstatus``.MIE.
+The following pseudo-code snippet visualizes how to perform nested interrupt handling in software.
+
+.. code-block:: c
+ :linenos:
+
+ isr_handle_nested_interrupts(id) {
+ // Save mpec and mstatus to stack
+ mepc_bak = mepc;
+ mstatus_bak = mstatus;
+
+ // Save mie to stack (optional)
+ mie_bak = mie;
+
+ // Keep lower-priority interrupts disabled (optional)
+ mie = ~((1 << (id + 1)) - 1);
+
+ // Re-enable interrupts
+ mstatus.MIE = 1;
+
+ // Handle interrupt
+ // This code block can be interrupted by other interrupts.
+ // ...
+
+ // Restore mstatus (this disables interrupts) and mepc
+ mstatus = mstatus_bak;
+ mepc = mepc_bak;
+
+ // Restore mie (optional)
+ mie = mie_bak;
+ }
+
+Nesting of interrupts/exceptions in hardware is not supported.
+The purpose of the nonstandard ``mstack`` CSRs in Ibex is only to support recoverable NMIs.
+These CSRs are not accessible by software.
+While handling an NMI, all interrupts are ignored independent of ``mstatus``.MIE.
+Nested NMIs are not supported.
diff --git a/hw/vendor/lowrisc_ibex/doc/integration.rst b/hw/vendor/lowrisc_ibex/doc/integration.rst
index 387298c..1270ca0 100644
--- a/hw/vendor/lowrisc_ibex/doc/integration.rst
+++ b/hw/vendor/lowrisc_ibex/doc/integration.rst
@@ -87,6 +87,9 @@
+------------------------------+-------------+------------+-----------------------------------------------------------------+
| ``RV32M`` | bit | 1 | M(ultiply) extension enable |
+------------------------------+-------------+------------+-----------------------------------------------------------------+
+| ``BranchTargetALU`` | bit | 0 | *EXPERIMENTAL* - Enables branch target ALU removing a stall |
+| | | | cycle from taken branches |
++------------------------------+-------------+------------+-----------------------------------------------------------------+
| ``MultiplierImplementation`` | string | "fast" | Multiplicator type, "slow", or "fast" |
+------------------------------+-------------+------------+-----------------------------------------------------------------+
| ``DbgTriggerEn`` | bit | 0 | Enable debug trigger support (one trigger only) |
@@ -96,6 +99,8 @@
| ``DmExceptionAddr`` | int | 0x1A110808 | Address to jump to when an exception occurs while in Debug Mode |
+------------------------------+-------------+------------+-----------------------------------------------------------------+
+Any parameter marked *EXPERIMENTAL* when enabled is not verified to the same standard as the rest of the Ibex core.
+
Interfaces
----------
diff --git a/hw/vendor/lowrisc_ibex/doc/pipeline_details.rst b/hw/vendor/lowrisc_ibex/doc/pipeline_details.rst
index 2c86043..753daed 100644
--- a/hw/vendor/lowrisc_ibex/doc/pipeline_details.rst
+++ b/hw/vendor/lowrisc_ibex/doc/pipeline_details.rst
@@ -67,13 +67,17 @@
+-----------------------+-----------------------+-------------------------------------------------------------+
| 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 |
-| | | is used to calculate the branch condition. The following |
-| | | cycle the ALU is used again to calculate the branch target |
+| | 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. |
+| | | 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 |
diff --git a/hw/vendor/lowrisc_ibex/dv/cs_registers/tb/tb_cs_registers.sv b/hw/vendor/lowrisc_ibex/dv/cs_registers/tb/tb_cs_registers.sv
index d93b8a3..ea2893f 100644
--- a/hw/vendor/lowrisc_ibex/dv/cs_registers/tb/tb_cs_registers.sv
+++ b/hw/vendor/lowrisc_ibex/dv/cs_registers/tb/tb_cs_registers.sv
@@ -45,12 +45,9 @@
logic irq_timer_i;
logic irq_external_i;
logic [14:0] irq_fast_i;
- logic irq_pending_o; // interupt request pending
logic nmi_mode_i; // core is handling an NMI
- logic csr_msip_o; // software interrupt pending
- logic csr_mtip_o; // timer interrupt pending
- logic csr_meip_o; // external interrupt pending
- logic [14:0] csr_mfip_o; // fast interrupt pending
+ logic irq_pending_o; // interupt request pending
+ ibex_pkg::irqs_t irqs_o;
logic csr_mstatus_mie_o;
logic [31:0] csr_mepc_o;
diff --git a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/README.md b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/README.md
index c369a6e..747f814 100644
--- a/hw/vendor/lowrisc_ibex/dv/riscv_compliance/README.md
+++ b/hw/vendor/lowrisc_ibex/dv/riscv_compliance/README.md
@@ -66,7 +66,8 @@
export RISCV_TARGET=ibex
# Note: rv32imc does not include the I and M extension tests
- make RISCV_ISA=rv32i && make RISCV_ISA=rv32im && make RISCV_ISA=rv32imc
+ make RISCV_ISA=rv32i && make RISCV_ISA=rv32im && make RISCV_ISA=rv32imc && \
+ make RISCV_ISA=rv32Zicsr && make RISCV_ISA=rv32Zifencei
```
Compliance test suite system
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 a3a3974..f8120ee 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
@@ -29,6 +29,11 @@
paramtype: vlogparam
default: 0
description: Enable the E ISA extension (reduced register set) [0/1]
+ BranchTargetALU:
+ datatype: int
+ paramtype: vlogparam
+ default: 0
+ description: Enables seperate branch target ALU (increasing branch performance EXPERIMENTAL) [0/1]
targets:
sim:
@@ -38,6 +43,7 @@
parameters:
- RV32M
- RV32E
+ - BranchTargetALU
toplevel: ibex_riscv_compliance
tools:
verilator:
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 fc3facf..1a3c557 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,8 +15,9 @@
input IO_RST_N
);
- parameter bit RV32E = 0;
- parameter bit RV32M = 1;
+ parameter bit RV32E = 0;
+ parameter bit RV32M = 1;
+ parameter bit BranchTargetALU = 0;
logic clk_sys, rst_sys_n;
@@ -104,7 +105,8 @@
.DmHaltAddr(32'h00000000),
.DmExceptionAddr(32'h00000000),
.RV32E(RV32E),
- .RV32M(RV32M)
+ .RV32M(RV32M),
+ .BranchTargetALU(BranchTargetALU)
) u_core (
.clk_i (clk_sys),
.rst_ni (rst_sys_n),
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_cfg.sv b/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_cfg.sv
index 06f9985..4152230 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_cfg.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/env/core_ibex_env_cfg.sv
@@ -6,6 +6,7 @@
bit enable_irq_single_seq;
bit enable_irq_multiple_seq;
+ bit enable_nested_irq;
bit enable_debug_seq;
bit[31:0] max_interval;
bit require_signature_addr;
@@ -15,6 +16,7 @@
`uvm_object_utils_begin(core_ibex_env_cfg)
`uvm_field_int(enable_irq_single_seq, UVM_DEFAULT)
`uvm_field_int(enable_irq_multiple_seq, UVM_DEFAULT)
+ `uvm_field_int(enable_nested_irq, UVM_DEFAULT)
`uvm_field_int(enable_debug_seq, UVM_DEFAULT)
`uvm_field_int(max_interval, UVM_DEFAULT)
`uvm_field_int(require_signature_addr, UVM_DEFAULT)
@@ -25,6 +27,7 @@
super.new(name);
void'($value$plusargs("enable_irq_single_seq=%0d", enable_irq_single_seq));
void'($value$plusargs("enable_irq_multiple_seq=%0d", enable_irq_multiple_seq));
+ void'($value$plusargs("enable_nested_irq=%0d", enable_nested_irq));
void'($value$plusargs("enable_debug_seq=%0d", enable_debug_seq));
void'($value$plusargs("max_interval=%0d", max_interval));
void'($value$plusargs("require_signature_addr=%0d", require_signature_addr));
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f b/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f
index 55a8090..56b5e46 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/ibex_dv.f
@@ -2,9 +2,12 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-+define+BOOT_ADDR=32'h8000_0000
+// 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
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/riscv_core_setting.sv b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/riscv_core_setting.sv
index fe9377d..174d19f 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/riscv_core_setting.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/riscv_core_setting.sv
@@ -80,7 +80,7 @@
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
-parameter privileged_reg_t implemented_csr[] = {
+const privileged_reg_t implemented_csr[] = {
// Machine mode mode CSR
MVENDORID, // Vendor ID
MARCHID, // Architecture ID
@@ -151,14 +151,12 @@
// --------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// --------------------------------------------------------------------------
-
-parameter interrupt_cause_t implemented_interrupt[] = {
+const interrupt_cause_t implemented_interrupt[] = {
M_SOFTWARE_INTR,
M_TIMER_INTR,
M_EXTERNAL_INTR
};
-
-parameter exception_cause_t implemented_exception[] = {
+const exception_cause_t implemented_exception[] = {
INSTRUCTION_ACCESS_FAULT,
ILLEGAL_INSTRUCTION,
BREAKPOINT,
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml
index f3fed04..85fe687 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/riscv_dv_extension/testlist.yaml
@@ -280,6 +280,7 @@
+require_signature_addr=1
+gen_debug_section=1
+randomize_csr=1
+ +no_csr_instr=1
+enable_dummy_csr_write=1
+boot_mode=m
rtl_test: core_ibex_debug_csr_test
@@ -289,6 +290,46 @@
compare_opts:
compare_final_value_only: 1
+- test: riscv_irq_in_debug_mode_test
+ description: >
+ Send interrupts while the core is executing in debug mode, should ignore everything
+ iterations: 10
+ gen_test: riscv_rand_instr_test
+ gen_opts: >
+ +require_signature_addr=1
+ +gen_debug_section=1
+ +enable_interrupt=1
+ +randomize_csr=1
+ +no_csr_instr=1
+ +no_fence=1
+ rtl_test: core_ibex_irq_in_debug_test
+ sim_opts: >
+ +require_signature_addr=1
+ +enable_debug_seq=1
+ +enable_irq_multiple_seq=1
+ compare_opts:
+ compare_final_value_only: 1
+
+- test: riscv_debug_in_irq_test
+ description: >
+ Send debug stimulus while core is in an interrupt handler
+ iterations: 10
+ gen_test: riscv_rand_instr_test
+ gen_opts: >
+ +require_signature_addr=1
+ +gen_debug_section=1
+ +enable_interrupt=1
+ +randomize_csr=1
+ no_csr_instr=1
+ +no_fence=1
+ rtl_test: core_ibex_debug_in_irq_test
+ sim_opts: >
+ +require_signature_addr=1
+ +enable_debug_seq=1
+ +enable_irq_multiple_seq=1
+ compare_opts:
+ compare_final_value_only: 1
+
- test: riscv_single_interrupt_test
description: >
Random instruction test with complete interrupt handling
@@ -323,6 +364,26 @@
compare_opts:
compare_final_value_only: 1
+- test: riscv_nested_interrupt_test
+ description: >
+ Assert interrupt, and then assert another interrupt during the first irq_handler routine
+ iterations: 10
+ gen_test: riscv_rand_instr_test
+ gen_opts: >
+ +instr_cnt=10000
+ +require_signature_addr=1
+ +enable_interrupt=1
+ +enable_nested_interrupt=1
+ +randomize_csr=1
+ +no_csr_instr=1
+ rtl_test: core_ibex_nested_irq_test
+ sim_opts: >
+ +require_signature_addr=1
+ +enable_irq_multiple_seq=1
+ +enable_nested_irq=1
+ compare_opts:
+ compare_final_value_only: 1
+
- test: riscv_interrupt_wfi_test
description: >
Inject interrupts after a encountering wfi instructions.
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_seq_lib.sv b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_seq_lib.sv
index 165d158..c016129 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_seq_lib.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_seq_lib.sv
@@ -70,12 +70,13 @@
`uvm_object_utils(irq_raise_seq)
`uvm_object_new
+ bit no_nmi;
virtual task send_req();
irq_seq_item irq;
irq = irq_seq_item::type_id::create($sformatf("irq_raise_single[%0d]", iteration_cnt));
start_item(irq);
- `DV_CHECK_RANDOMIZE_WITH_FATAL(irq, num_of_interrupt > 1;)
+ `DV_CHECK_RANDOMIZE_WITH_FATAL(irq, num_of_interrupt > 1; irq_nm == ~no_nmi;)
finish_item(irq);
get_response(irq);
endtask
@@ -86,12 +87,13 @@
`uvm_object_utils(irq_raise_single_seq)
`uvm_object_new
+ bit no_nmi;
virtual task send_req();
irq_seq_item irq;
irq = irq_seq_item::type_id::create($sformatf("irq_raise_single[%0d]", iteration_cnt));
start_item(irq);
- `DV_CHECK_RANDOMIZE_WITH_FATAL(irq, num_of_interrupt == 1;)
+ `DV_CHECK_RANDOMIZE_WITH_FATAL(irq, num_of_interrupt == 1; irq_nm == ~no_nmi;)
finish_item(irq);
get_response(irq);
endtask
@@ -119,8 +121,7 @@
// Simple debug sequence
// debug_req is just a single bit sideband signal, use the interface to drive it directly
-class debug_seq extends core_base_seq;
-
+class debug_seq extends core_base_seq#(irq_seq_item);
virtual core_ibex_dut_probe_if dut_vif;
`uvm_object_utils(debug_seq)
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_lib.sv b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_lib.sv
index 9841507..c800a9d 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_lib.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_test_lib.sv
@@ -84,53 +84,37 @@
num_instr_ret[31:0] = signature_data;
wait_for_csr_write(CSR_MINSTRETH);
num_instr_ret[63:32] = signature_data;
- // mhpmcounter3
- wait_for_csr_write(12'hB03);
+ wait_for_csr_write(CSR_MHPMCOUNTER3);
num_cycles_lsu[31:0] = signature_data;
- // mhpmcounter4
- wait_for_csr_write(12'hB04);
+ wait_for_csr_write(CSR_MHPMCOUNTER4);
num_cycles_if[31:0] = signature_data;
- // mhpmcounter5
- wait_for_csr_write(12'hB05);
+ wait_for_csr_write(CSR_MHPMCOUNTER5);
num_loads[31:0] = signature_data;
- // mhpmcounter6
- wait_for_csr_write(12'hB06);
+ wait_for_csr_write(CSR_MHPMCOUNTER6);
num_stores[31:0] = signature_data;
- // mhpmcounter7
- wait_for_csr_write(12'hB07);
+ wait_for_csr_write(CSR_MHPMCOUNTER7);
num_jumps[31:0] = signature_data;
- // mhpmcounter8
- wait_for_csr_write(12'hB08);
+ wait_for_csr_write(CSR_MHPMCOUNTER8);
num_branches[31:0] = signature_data;
- // mhpmcounter9
- wait_for_csr_write(12'hB09);
+ wait_for_csr_write(CSR_MHPMCOUNTER9);
num_branches_taken[31:0] = signature_data;
- // mhpmcounter10
- wait_for_csr_write(12'hB0A);
+ wait_for_csr_write(CSR_MHPMCOUNTER10);
num_instr_ret_c[31:0] = signature_data;
- // mhpmcounterh3
- wait_for_csr_write(12'hB83);
+ wait_for_csr_write(CSR_MHPMCOUNTER3H);
num_cycles_lsu[63:32] = signature_data;
- // mhpmcounterh4
- wait_for_csr_write(12'hB84);
+ wait_for_csr_write(CSR_MHPMCOUNTER4H);
num_cycles_if[63:32] = signature_data;
- // mhpmcounterh5
- wait_for_csr_write(12'hB85);
+ wait_for_csr_write(CSR_MHPMCOUNTER5H);
num_loads[63:32] = signature_data;
- // mhpmcounterh6
- wait_for_csr_write(12'hB86);
+ wait_for_csr_write(CSR_MHPMCOUNTER6H);
num_stores[63:32] = signature_data;
- // mhpmcounterh7
- wait_for_csr_write(12'hB87);
+ wait_for_csr_write(CSR_MHPMCOUNTER7H);
num_jumps[63:32] = signature_data;
- // mhpmcounterh8
- wait_for_csr_write(12'hB88);
+ wait_for_csr_write(CSR_MHPMCOUNTER8H);
num_branches[63:32] = signature_data;
- // mhpmcounterh9
- wait_for_csr_write(12'hB89);
+ wait_for_csr_write(CSR_MHPMCOUNTER9H);
num_branches_taken[63:32] = signature_data;
- // mhpmcounterh10
- wait_for_csr_write(12'hB8A);
+ wait_for_csr_write(CSR_MHPMCOUNTER10H);
num_instr_ret_c[63:32] = signature_data;
`uvm_info(`gfn, $sformatf("NUM_CYCLES: 0x%0x", num_cycles), UVM_LOW)
`uvm_info(`gfn, $sformatf("NUM_INSTR_RET: 0x%0x", num_instr_ret), UVM_LOW)
@@ -154,6 +138,7 @@
bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] core_init_mstatus;
bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] core_init_mie;
+ priv_lvl_e init_operating_mode;
priv_lvl_e operating_mode;
bit [$clog2(irq_agent_pkg::DATA_WIDTH)-1:0] irq_id;
irq_seq_item irq_txn;
@@ -162,6 +147,7 @@
bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] mcause;
bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] mip;
bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] mie;
+ bit in_nested_trap;
virtual task send_stimulus();
fork
@@ -186,7 +172,7 @@
end
begin
if (cfg.enable_debug_seq) begin
- send_debug_stimulus();
+ stress_debug();
end
end
join_none
@@ -194,27 +180,35 @@
join_none
endtask
+ function priv_lvl_e select_mode();
+ if (in_nested_trap) return operating_mode;
+ else return init_operating_mode;
+ endfunction
+
virtual task wait_for_core_setup();
wait_for_csr_write(CSR_MSTATUS, 1000);
core_init_mstatus = signature_data;
// capture the initial privilege mode ibex will boot into
- operating_mode = core_init_mstatus[12:11];
+ init_operating_mode = priv_lvl_e'(core_init_mstatus[12:11]);
wait_for_csr_write(CSR_MIE, 500);
core_init_mie = signature_data;
check_next_core_status(INITIALIZED, "Core initialization handshake failure", 500);
endtask
- virtual task send_irq_stimulus();
+ virtual task send_irq_stimulus_start(input bit no_nmi,
+ output bit ret_val);
bit irq_valid;
// send the interrupt
- if (cfg.enable_irq_single_seq) vseq.start_irq_raise_single_seq();
- else if (cfg.enable_irq_multiple_seq) vseq.start_irq_raise_seq();
+ if (cfg.enable_irq_single_seq) vseq.start_irq_raise_single_seq(no_nmi);
+ else if (cfg.enable_irq_multiple_seq) vseq.start_irq_raise_seq(no_nmi);
irq_collected_port.get(irq_txn);
irq = {irq_txn.irq_nm, irq_txn.irq_fast, 4'b0, irq_txn.irq_external, 3'b0,
irq_txn.irq_timer, 3'b0, irq_txn.irq_software, 3'b0};
+ `uvm_info(`gfn, $sformatf("irq: 0x%0x", irq), UVM_LOW)
// Get the bit position of the highest priority interrupt - ibex will only handle this one if
// there are multiple irqs asserted at once.
irq_valid = get_max_valid_irq_id(irq);
+ `uvm_info(`gfn, $sformatf("irq_id: 0x%0x", irq_id), UVM_LOW)
// If the interrupt is maskable, and the corresponding bit in MIE is not set, skip the next
// checks, as it means the interrupt in question is not enabled by Ibex, and drop the interrupt
// lines to avoid locking up the simulation.
@@ -224,15 +218,16 @@
irq = {irq_txn.irq_nm, irq_txn.irq_fast, 4'b0, irq_txn.irq_external, 3'b0,
irq_txn.irq_timer, 3'b0, irq_txn.irq_software, 3'b0};
`DV_CHECK_EQ_FATAL(irq, 0, "Interrupt lines have not been dropped")
+ ret_val = irq_valid;
return;
end
- `uvm_info(`gfn, $sformatf("irq: 0b%0b", irq), UVM_LOW)
check_next_core_status(HANDLING_IRQ, "Core did not jump to vectored interrupt handler", 750);
check_priv_mode(PRIV_LVL_M);
+ operating_mode = dut_vif.priv_mode;
// check mstatus
wait_for_csr_write(CSR_MSTATUS, 500);
mstatus = signature_data;
- `DV_CHECK_EQ_FATAL(mstatus[12:11], operating_mode, "Incorrect privilege mode")
+ `DV_CHECK_EQ_FATAL(mstatus[12:11], select_mode(), "Incorrect mstatus.mpp")
`DV_CHECK_EQ_FATAL(mstatus[7], 1'b1, "mstatus.mpie was not set to 1'b1 after entering handler")
`DV_CHECK_EQ_FATAL(mstatus[3], 1'b0, "mstatus.mie was not set to 1'b0 after entering handler")
// check mcause against the interrupt id
@@ -254,18 +249,32 @@
`DV_CHECK_EQ_FATAL(mip[irq_id], 1'b1,
$sformatf("mip[%0d] is not set, but core responded to corresponding interrupt", irq_id))
end
+ ret_val = irq_valid;
+ return;
+ endtask
+
+ virtual task send_irq_stimulus_end();
// As Ibex interrupts are level sensitive, core must write to memory mapped address to
// indicate that irq stimulus be dropped
check_next_core_status(FINISHED_IRQ, "Core did not signal end of interrupt properly", 300);
// Will receive irq_seq_item indicating that lines have been dropped
vseq.start_irq_drop_seq();
- irq_collected_port.get(irq_txn);
- irq = {irq_txn.irq_nm, irq_txn.irq_fast, 4'b0, irq_txn.irq_external, 3'b0,
- irq_txn.irq_timer, 3'b0, irq_txn.irq_software, 3'b0};
- `DV_CHECK_EQ_FATAL(irq, 0, "Interrupt lines have not been dropped")
+ // Want to skip this .get() call on the second MRET of nested interrupt scenarios
+ if (!(cfg.enable_nested_irq && !in_nested_trap)) begin
+ irq_collected_port.get(irq_txn);
+ irq = {irq_txn.irq_nm, irq_txn.irq_fast, 4'b0, irq_txn.irq_external, 3'b0,
+ irq_txn.irq_timer, 3'b0, irq_txn.irq_software, 3'b0};
+ `DV_CHECK_EQ_FATAL(irq, 0, "Interrupt lines have not been dropped")
+ end
wait_ret("mret", 1000);
endtask
+ virtual task send_irq_stimulus(bit no_nmi = 1'b0);
+ bit ret_val;
+ send_irq_stimulus_start(no_nmi, ret_val);
+ if (ret_val) send_irq_stimulus_end();
+ endtask
+
function int get_max_valid_irq_id(bit [irq_agent_pkg::DATA_WIDTH-1:0] irq);
int i;
// Ibex implementation of MIE does not mask NM interrupts, so need to check this separately
@@ -288,6 +297,7 @@
bit[ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] mcause;
wait_for_csr_write(CSR_MCAUSE, 1000);
mcause = signature_data;
+ `uvm_info(`gfn, $sformatf("mcause: 0x%0x", mcause), UVM_LOW)
`DV_CHECK_EQ_FATAL(mcause[ibex_mem_intf_agent_pkg::DATA_WIDTH-1], irq_or_exc,
$sformatf("mcause.interrupt is not set to 0x%0x", irq_or_exc))
`DV_CHECK_EQ_FATAL(mcause[ibex_mem_intf_agent_pkg::DATA_WIDTH-2:0], cause,
@@ -297,7 +307,7 @@
// Basic debug stimulus check for Ibex for debug stimulus stress tests: check that Ibex enters
// debug mode properly after stimulus is sent and then check that a dret is encountered signifying
// the end of debug mode.
- virtual task send_debug_stimulus();
+ virtual task stress_debug();
fork
begin
vseq.start_debug_stress_seq();
@@ -328,7 +338,7 @@
`uvm_fatal(`gfn, $sformatf("Invalid xRET instruction %0s", ret))
end
endcase
- wait (dut_vif.priv_mode === operating_mode);
+ wait (dut_vif.priv_mode === select_mode());
end
begin : ret_timeout
clk_vif.wait_clks(timeout);
@@ -372,7 +382,7 @@
end
begin
if (cfg.enable_debug_seq) begin
- send_debug_stimulus();
+ stress_debug();
end
end
join_none
@@ -407,6 +417,17 @@
// Checker functions/tasks that might be commonly used
//------------------------------------------------------
+ // Send a single debug request and perform all relevant checks
+ virtual task send_debug_stimulus(priv_lvl_e mode, string debug_status_err_msg);
+ vseq.start_debug_single_seq();
+ check_next_core_status(IN_DEBUG_MODE, debug_status_err_msg, 1000);
+ check_priv_mode(PRIV_LVL_M);
+ wait_for_csr_write(CSR_DCSR, 500);
+ check_dcsr_prv(mode);
+ check_dcsr_cause(DBG_CAUSE_HALTREQ);
+ wait_ret("dret", 5000);
+ endtask
+
// Illegal instruction checker
virtual task check_illegal_insn(string exception_msg);
check_next_core_status(HANDLING_EXCEPTION, "Core did not jump to vectored exception handler", 1000);
@@ -484,6 +505,104 @@
endclass
+// Tests irqs asserted in debug mode
+class core_ibex_irq_in_debug_test extends core_ibex_directed_test;
+
+ `uvm_component_utils(core_ibex_irq_in_debug_test)
+ `uvm_component_new
+
+ virtual task check_stimulus();
+ bit detected_irq = 1'b0;
+ forever begin
+ // Drive core into debug mode
+ vseq.start_debug_single_seq();
+ check_next_core_status(IN_DEBUG_MODE, "Core did not enter debug mode properly", 1000);
+ check_priv_mode(PRIV_LVL_M);
+ wait_for_csr_write(CSR_DCSR, 500);
+ check_dcsr_prv(operating_mode);
+ check_dcsr_cause(DBG_CAUSE_HALTREQ);
+ clk_vif.wait_clks($urandom_range(50, 100));
+ // Raise interrupts while the core is in debug mode
+ vseq.start_irq_raise_seq();
+ fork
+ begin : wait_irq
+ wait_for_core_status(HANDLING_IRQ);
+ `uvm_fatal(`gfn, "Core is handling interrupt detected in debug mode")
+ end
+ begin
+ clk_vif.wait_clks(500);
+ disable wait_irq;
+ end
+ join
+ vseq.start_irq_drop_seq();
+ wait_ret("dret", 5000);
+ clk_vif.wait_clks($urandom_range(250, 500));
+ end
+ endtask
+
+endclass
+
+// Tests debug mode asserted during irq handler
+class core_ibex_debug_in_irq_test extends core_ibex_directed_test;
+
+ `uvm_component_utils(core_ibex_debug_in_irq_test)
+ `uvm_component_new
+
+ virtual task check_stimulus();
+ // send first part of irq/checking routine
+ // then assert basic debug stimulus
+ // check that core enters and exits debug mode correctly
+ // then finish interrupt handling routine
+ bit valid_irq;
+ forever begin
+ send_irq_stimulus_start(1'b0, valid_irq);
+ if (valid_irq) begin
+ fork
+ begin
+ send_debug_stimulus(operating_mode, "Core did not enter debug mode from interrupt handler");
+ end
+ begin
+ wait(dut_vif.dret == 1'b1);
+ send_irq_stimulus_end();
+ end
+ join
+ end
+ clk_vif.wait_clks($urandom_range(250, 500));
+ end
+ endtask
+
+endclass
+
+// Nested interrupt test class (with multiple interrupts)
+class core_ibex_nested_irq_test extends core_ibex_directed_test;
+
+ `uvm_component_utils(core_ibex_nested_irq_test)
+ `uvm_component_new
+
+ virtual task check_stimulus();
+ bit valid_irq;
+ bit valid_nested_irq;
+ int unsigned initial_irq_delay;
+ forever begin
+ send_irq_stimulus_start(1'b1, valid_irq);
+ if (valid_irq) begin
+ initial_irq_delay = vseq.irq_raise_seq_h.max_delay;
+ vseq.irq_raise_seq_h.max_delay = 0;
+ // Send nested interrupt after the checks of the first interrupt have finished
+ in_nested_trap = 1'b1;
+ // wait until we are setting mstatus.mie to 1'b1 to send the next set of interrupts
+ wait(csr_vif.csr_access === 1'b1 && csr_vif.csr_addr === CSR_MSTATUS &&
+ csr_vif.csr_op != CSR_OP_READ);
+ send_irq_stimulus(1'b0);
+ vseq.irq_raise_seq_h.max_delay = initial_irq_delay;
+ in_nested_trap = 1'b0;
+ send_irq_stimulus_end();
+ end
+ end
+ endtask
+
+endclass
+
// Debug WFI test class
class core_ibex_debug_wfi_test extends core_ibex_directed_test;
@@ -495,20 +614,7 @@
wait (dut_vif.wfi === 1'b1);
wait (dut_vif.core_sleep === 1'b1);
clk_vif.wait_clks($urandom_range(100));
- vseq.start_debug_single_seq();
- // After assserting this signal, core should wake up and jump into debug mode from WFI state
- // - next handshake should be a notification that the core is now in debug mode
- check_next_core_status(IN_DEBUG_MODE, "Core did not jump into debug mode from WFI state",
- 1000);
- check_priv_mode(PRIV_LVL_M);
- // We don't want to trigger debug stimulus for any WFI instructions encountered inside the
- // debug rom - those should act as NOP instructions - so we wait until hitting the end of the
- // debug rom.
- // We also want to check that dcsr.cause has been set correctly
- wait_for_csr_write(CSR_DCSR, 500);
- check_dcsr_prv(operating_mode);
- check_dcsr_cause(DBG_CAUSE_HALTREQ);
- wait_ret("dret", 5000);
+ send_debug_stimulus(init_operating_mode, "Core did not jump into debug mode from WFI state");
end
endtask
@@ -525,25 +631,11 @@
// wait for a dummy write to mstatus in init code
wait(csr_vif.csr_access === 1'b1 && csr_vif.csr_addr === CSR_MSTATUS &&
csr_vif.csr_op != CSR_OP_READ);
- vseq.start_debug_single_seq();
- check_next_core_status(IN_DEBUG_MODE, "Core did not jump into debug mode from WFI state",
- 1000);
- check_priv_mode(PRIV_LVL_M);
- wait_for_csr_write(CSR_DCSR, 500);
- check_dcsr_prv(operating_mode);
- check_dcsr_cause(DBG_CAUSE_HALTREQ);
- wait_ret("dret", 5000);
+ send_debug_stimulus(init_operating_mode, "Core did not trap to debug mode upon debug stimulus");
// wait for a dummy write to mie in the init code
wait(csr_vif.csr_access === 1'b1 && csr_vif.csr_addr === CSR_MIE &&
csr_vif.csr_op != CSR_OP_READ);
- vseq.start_debug_single_seq();
- check_next_core_status(IN_DEBUG_MODE, "Core did not jump into debug mode from WFI state",
- 1000);
- check_priv_mode(PRIV_LVL_M);
- wait_for_csr_write(CSR_DCSR, 500);
- check_dcsr_prv(operating_mode);
- check_dcsr_cause(DBG_CAUSE_HALTREQ);
- wait_ret("dret", 5000);
+ send_debug_stimulus(init_operating_mode, "Core did not trap to debug mode upon debug stimulus");
endtask
endclass
@@ -579,7 +671,7 @@
// capture the first write of dcsr
check_priv_mode(PRIV_LVL_M);
wait_for_csr_write(CSR_DCSR, 500);
- check_dcsr_prv(operating_mode);
+ check_dcsr_prv(init_operating_mode);
dcsr = signature_data;
// We also want to check that dcsr.cause has been set correctly
check_dcsr_cause(DBG_CAUSE_HALTREQ);
@@ -616,7 +708,7 @@
// Read dcsr and verify the appropriate ebreak(m/s/u) bit has been set based on the prv field,
// as well as the cause field
wait_for_csr_write(CSR_DCSR, 500);
- check_dcsr_prv(operating_mode);
+ check_dcsr_prv(init_operating_mode);
check_dcsr_ebreak();
check_dcsr_cause(DBG_CAUSE_HALTREQ);
wait_ret("dret", 5000);
@@ -627,7 +719,7 @@
check_priv_mode(PRIV_LVL_M);
// Read dcsr and verify the appropriate ebreak(m/s/u) bit has been set based on the prv field
wait_for_csr_write(CSR_DCSR, 500);
- check_dcsr_prv(operating_mode);
+ check_dcsr_prv(init_operating_mode);
check_dcsr_ebreak();
check_dcsr_cause(DBG_CAUSE_EBREAK);
wait_ret("dret", 5000);
@@ -656,7 +748,7 @@
wait_for_csr_write(CSR_DSCRATCH0, 500);
next_counter = signature_data;
wait_for_csr_write(CSR_DCSR, 1000);
- check_dcsr_prv(operating_mode);
+ check_dcsr_prv(init_operating_mode);
check_dcsr_cause(DBG_CAUSE_HALTREQ);
`DV_CHECK_EQ_FATAL(signature_data[2], 1'b1, "dcsr.step is not set")
wait_ret("dret", 5000);
@@ -677,7 +769,7 @@
wait_for_csr_write(CSR_DSCRATCH0, 500);
next_counter = signature_data;
wait_for_csr_write(CSR_DCSR, 500);
- check_dcsr_prv(operating_mode);
+ check_dcsr_prv(init_operating_mode);
check_dcsr_cause(DBG_CAUSE_STEP);
if (counter === 0) begin
`DV_CHECK_EQ_FATAL(signature_data[2], 1'b0, "dcsr.step is set")
@@ -741,7 +833,7 @@
check_priv_mode(PRIV_LVL_M);
// Next write of CORE_STATUS will be the load/store fault type
wait_for_mem_txn(cfg.signature_addr, CORE_STATUS);
- mem_status = signature_data_q.pop_front();
+ mem_status = core_status_t'(signature_data_q.pop_front());
if (mem_status == LOAD_FAULT_EXCEPTION) begin
exc_type = EXC_CAUSE_LOAD_ACCESS_FAULT;
end else if (mem_status == STORE_FAULT_EXCEPTION) begin
@@ -817,7 +909,7 @@
// Wait for a CSR access
wait (csr_vif.csr_access == 1'b1);
check_illegal_insn($sformatf("Core did not treat access to CSR 0x%0x from %0s as illegal",
- csr_vif.csr_addr, operating_mode));
+ csr_vif.csr_addr, init_operating_mode));
end
endtask
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_vseq.sv b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_vseq.sv
index d8d9134..951bf3d 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_vseq.sv
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/tests/core_ibex_vseq.sv
@@ -45,7 +45,7 @@
irq_drop_seq_h = irq_drop_seq::type_id::create("irq_drop_seq_h");
irq_drop_seq_h.num_of_iterations = 1;
irq_drop_seq_h.max_interval = 1;
- irq_drop_seq_h.max_delay = 1;
+ irq_drop_seq_h.max_delay = 0;
irq_drop_seq_h.interval = 0;
end
if (cfg.enable_debug_seq) begin
@@ -93,11 +93,13 @@
debug_seq_single_h.start(null);
endtask
- virtual task start_irq_raise_single_seq();
+ virtual task start_irq_raise_single_seq(bit no_nmi = 1'b0);
+ irq_raise_single_seq_h.no_nmi = no_nmi;
irq_raise_single_seq_h.start(p_sequencer.irq_seqr);
endtask
- virtual task start_irq_raise_seq();
+ virtual task start_irq_raise_seq(bit no_nmi = 1'b0);
+ irq_raise_seq_h.no_nmi = no_nmi;
irq_raise_seq_h.start(p_sequencer.irq_seqr);
endtask
diff --git a/hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml b/hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml
index fcfdf50..ff30d68 100644
--- a/hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml
+++ b/hw/vendor/lowrisc_ibex/dv/uvm/yaml/rtl_simulation.yaml
@@ -88,3 +88,19 @@
-covbaserun test
wave_opts: >
-input <cwd>/ius.tcl
+
+- tool: riviera
+ env_var: ALDEC_PATH
+ compile:
+ cmd:
+ - "vlib <out>/work"
+ - "vlog -work <out>/work
+ +incdir+<ALDEC_PATH>/vlib/uvm-1.2/src
+ -l uvm_1_2
+ -f ibex_dv.f"
+
+ sim:
+ cmd: >
+ vsim -c <sim_opts> <cov_opts> -lib <out>/work +access +r+w -l <out>/logfile.log -do "run -all; endsim; quit -force" +ibex_tracer_file_base="trace_core"
+ cov_opts: >
+ -acdb_file <out>/cov.acdb
diff --git a/hw/vendor/lowrisc_ibex/dv/verilator/memutil/cpp/verilator_memutil.cc b/hw/vendor/lowrisc_ibex/dv/verilator/memutil/cpp/verilator_memutil.cc
index 5f17763..4ea506e 100644
--- a/hw/vendor/lowrisc_ibex/dv/verilator/memutil/cpp/verilator_memutil.cc
+++ b/hw/vendor/lowrisc_ibex/dv/verilator/memutil/cpp/verilator_memutil.cc
@@ -422,7 +422,7 @@
retcode = false;
goto ret;
}
- for (int i = 0; i < len_bytes / 4; ++i) {
+ for (int i = 0; i < (len_bytes + 3) / 4; ++i) {
if (!simutil_verilator_set_mem(i, (svLogicVecVal *)&buf[4 * i])) {
std::cerr << "ERROR: Could not set memory byte: " << i * 4 << "/"
<< len_bytes << "" << std::endl;
diff --git a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/README.md b/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/README.md
deleted file mode 100644
index eb0e1f1..0000000
--- a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/README.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# Ibex RISC-V Core SoC Example
-
-Please see [examples](https://ibex-core.readthedocs.io/en/latest/examples.html "Ibex User Manual") for a description of this example.
-
-## Requirements
-
-### Tools
-
- - RV32 compiler
- - srecord
- - `fusesoc` and its dependencies
- - Xilinx Vivado
-
-## Build
-
-### Software
-
-First the software must be built. Go into `examples/sw/led` and call:
-
-```
-make CC=/path/to/RISC-V-compiler
-```
-
-The path to the RV32 compiler `/path/to/RISC-V-compiler` depends on the environment.
-For example, it can be `riscv32-unknown-elf-gcc` if the binary is available through the `PATH` environment or `/opt/riscv/bin/riscv-none-embed-gcc` if a specific path is used.
-
-This should produce a `led.vmem` file which is used in the synthesises to update the SRAM storage.
-
-### Hardware
-
-Run the following command at the top level to build the hardware.
-
-```
-fusesoc --cores-root=. run --target=synth --setup --build lowrisc:ibex:top_artya7_100
-```
-
-This will create a directory `build` which contains the output files, including
-the bitstream.
-
-## Program
-
-After the board is connected to the computer it can be programmed with:
-
-```
-fusesoc --cores-root=. pgm lowrisc:ibex:top_artya7_100
-```
-
-LED1/LED3 and LED0/LED2 should alternately be on after the FPGA programming is finished.
diff --git a/hw/vendor/lowrisc_ibex/examples/fpga/artya7/README.md b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/README.md
new file mode 100644
index 0000000..ccd5a4f
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/README.md
@@ -0,0 +1,72 @@
+# Ibex RISC-V Core SoC Example
+
+Please see [examples](https://ibex-core.readthedocs.io/en/latest/examples.html "Ibex User Manual") for a description of this example.
+
+## Requirements
+
+### Tools
+
+ - RV32 compiler
+ - srecord
+ - `fusesoc` and its dependencies
+ - Xilinx Vivado
+
+### Hardware
+
+ - Either a Digilent Arty A7-35 oder A7-100 board
+
+## Build
+
+The easiest way to build and execute this example is to call the following make goals from the root directory.
+
+Use the following for the Arty A7-35
+
+```
+make build-arty-35 program-arty
+```
+
+and for the Arty A7-100
+
+```
+make build-arty-100 program-arty
+```
+
+### Software
+
+First the software must be built. Go into `examples/sw/led` and call:
+
+```
+make CC=/path/to/RISC-V-compiler
+```
+
+The setting of `CC` is only required if `riscv32-unknown-elf-gcc` is not available through the `PATH` environment variable.
+The path to the RV32 compiler `/path/to/RISC-V-compiler` depends on the environment.
+For example, it can be for example `/opt/riscv/bin/riscv-none-embed-gcc` if the whole path is required or simply the name of the executable if it is available through the `PATH` environment variable.
+
+This should produce a `led.vmem` file which is used in the synthesis to update the SRAM storage.
+
+### Hardware
+
+Run either of the following commands at the top level to build the respective hardware.
+Both variants of the Arty A7 are supported and can be selected via the `--parts` parameter.
+
+```
+fusesoc --cores-root=. run --target=synth --setup --build lowrisc:ibex:top_artya7 --part xc7a35ticsg324-1L
+```
+
+```
+fusesoc --cores-root=. run --target=synth --setup --build lowrisc:ibex:top_artya7 --part xc7a100tcsg324-1
+```
+
+This will create a directory `build` which contains the output files, including
+the bitstream.
+
+## Program
+
+After the board is connected to the computer it can be programmed with:
+
+```
+fusesoc --cores-root=. run --target=synth --run lowrisc:ibex:top_artya7
+```
+
+LED1/LED3 and LED0/LED2 should alternately be on after the FPGA programming is finished.
diff --git a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/data/pins_artya7.xdc b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/data/pins_artya7.xdc
similarity index 100%
rename from hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/data/pins_artya7.xdc
rename to hw/vendor/lowrisc_ibex/examples/fpga/artya7/data/pins_artya7.xdc
diff --git a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/top_artya7_100.sv b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/rtl/top_artya7.sv
similarity index 98%
rename from hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/top_artya7_100.sv
rename to hw/vendor/lowrisc_ibex/examples/fpga/artya7/rtl/top_artya7.sv
index a822144..2722719 100644
--- a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/rtl/top_artya7_100.sv
+++ b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/rtl/top_artya7.sv
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-module top_artya7_100 (
+module top_artya7 (
input IO_CLK,
input IO_RST_N,
output [3:0] LED
diff --git a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/top_artya7_100.core b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/top_artya7.core
similarity index 83%
rename from hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/top_artya7_100.core
rename to hw/vendor/lowrisc_ibex/examples/fpga/artya7/top_artya7.core
index ad86832..632f068 100644
--- a/hw/vendor/lowrisc_ibex/examples/fpga/artya7-100/top_artya7_100.core
+++ b/hw/vendor/lowrisc_ibex/examples/fpga/artya7/top_artya7.core
@@ -2,15 +2,15 @@
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
-name: "lowrisc:ibex:top_artya7_100:0.1"
-description: "Ibex example toplevel for the Arty A7-100 board"
+name: "lowrisc:ibex:top_artya7:0.1"
+description: "Ibex example toplevel for Arty A7 boards (both, -35 and -100)"
filesets:
files_rtl_artya7:
depend:
- lowrisc:ibex:ibex_core
- lowrisc:ibex:fpga_xilinx_shared
files:
- - rtl/top_artya7_100.sv
+ - rtl/top_artya7.sv
file_type: systemVerilogSource
files_constraints:
@@ -37,9 +37,9 @@
filesets:
- files_rtl_artya7
- files_constraints
- toplevel: top_artya7_100
+ toplevel: top_artya7
parameters:
- SRAM_INIT_FILE
tools:
vivado:
- part: "xc7a100tcsg324-1" # Arty A7-100
+ 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 98a16f3..fc6be03 100644
--- a/hw/vendor/lowrisc_ibex/examples/simple_system/README.md
+++ b/hw/vendor/lowrisc_ibex/examples/simple_system/README.md
@@ -15,7 +15,7 @@
Note Linux package managers may have Verilator but often a very old version
that is not suitable. It is recommended Verilator is built from source.
* [FuseSoC](https://github.com/olofk/fusesoc)
-* RISC-V Compiler Toolchain - lowRISC provides a pre-built GCC based toolchain
+* RISC-V Compiler Toolchain - lowRISC provides a pre-built GCC based toolchain
<https://github.com/lowRISC/lowrisc-toolchains/releases>
## Building Simulation
@@ -29,7 +29,7 @@
## Building Software
-Simple System related software can be found in examples/sw/simple_system
+Simple System related software can be found in `examples/sw/simple_system`.
To build the hello world example, from the Ibex reposistory root run:
@@ -38,14 +38,14 @@
```
This should create the file
-examples/sw/simple_system/hello_test/hello_test.vmem which is the memory
-initialisation file used to run the hello_test program
+`examples/sw/simple_system/hello_test/hello_test.vmem` which is the memory
+initialisation file used to run the `hello_test` program.
-To build new software make a copy of the hello_test directory named as desired.
+To build new software make a copy of the `hello_test` directory named as desired.
Look inside the Makefile for further instructions.
If using a toolchain other than the lowRISC pre-built one
-examples/sw/simple_system/common/common.mk may need altering to point to the
+`examples/sw/simple_system/common/common.mk` may need altering to point to the
correct compiler binaries.
## Running the Simulator
@@ -53,15 +53,16 @@
Having built the simulator and software, from the Ibex repository root run:
```
-./build/lowrisc_ibex_ibex_simple_system_0/sim-verilator/Vibex_simple_system [-t] --raminit=<sw_vmem_file>
+./build/lowrisc_ibex_ibex_simple_system_0/sim-verilator/Vibex_simple_system [-t] --meminit=ram,<sw_vmem_file>
```
-`<sw_vmem_file>` should be a path to a vmem file built as described above, use
-./examples/sw/simple_system/hello_test/hello_test.vmem to run the hello_test
+`<sw_vmem_file>` should be a path to a Verilog memory (vmem) file, or an ELF
+file built as described above. Use
+`./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
+If using the `hello_test` binary the simulator will halt itself, outputting some
simulation statistics:
```
@@ -88,9 +89,9 @@
The simulator produces several output files
-* ibex_simple_system.log - The ASCII output written via the output peripheral
-* ibex_simple_system_pcount.csv - A csv of the performance counters
-* trace_core_00000000.log - An instruction trace of execution
+* `ibex_simple_system.log` - The ASCII output written via the output peripheral
+* `ibex_simple_system_pcount.csv` - A csv of the performance counters
+* `trace_core_00000000.log` - An instruction trace of execution
## Simulating with Synopsys VCS
@@ -101,7 +102,7 @@
```
`<sw_vmem_file>` should be a path to a vmem file built as described above, use
-./examples/sw/simple_system/hello_test/hello_test.vmem to run the hello_test
+`./examples/sw/simple_system/hello_test/hello_test.vmem` to run the `hello_test`
binary.
To run the simulator:
@@ -112,15 +113,27 @@
Pass `-gui` to use the DVE GUI.
+## Simulating with Riviera-PRO
+
+To build and run Simple System run:
+
+```
+fusesoc --cores-root=. run --target=sim --tool=rivierapro lowrisc:ibex:ibex_simple_system --RV32M=1 --RV32E=0 --SRAM_INIT_FILE=<sw_vmem_file>
+```
+
+`<sw_vmem_file>` should be a path to a vmem file built as described above, use
+`./examples/sw/simple_system/hello_test/hello_test.vmem` to run the `hello_test`
+binary.
+
## System Memory Map
| 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 |
-| 0x30000 | RISCV timer mtime register |
-| 0x30004 | RISCV timer mtimeh register |
-| 0x30008 | RISCV timer mtimecmp register |
-| 0x3000C | RISCV timer mtimecmph register |
+| 0x30000 | RISC-V timer `mtime` register |
+| 0x30004 | RISC-V timer `mtimeh` register |
+| 0x30008 | RISC-V timer `mtimecmp` register |
+| 0x3000C | RISC-V timer `mtimecmph` register |
| 0x100000 – 0x1FFFFF | 1 MB memory for instruction and data. Execution starts at 0x100080, exception handler base is 0x100000 |
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 efeff92..0d3e636 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
@@ -32,6 +32,11 @@
datatype: str
paramtype: vlogdefine
description: Path to a vmem file to initialize the RAM with
+ BranchTargetALU:
+ datatype: int
+ paramtype: vlogparam
+ default: 0
+ description: Enables seperate branch target ALU (increasing branch performance EXPERIMENTAL) [0/1]
targets:
sim:
@@ -41,6 +46,7 @@
parameters:
- RV32M
- RV32E
+ - BranchTargetALU
- SRAM_INIT_FILE
toplevel: ibex_simple_system
tools:
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 4db796e..aa71e6f 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,14 +18,14 @@
input IO_RST_N
);
- parameter bit RV32E = 0;
- parameter bit RV32M = 1;
+ parameter bit RV32E = 0;
+ parameter bit RV32M = 1;
+ parameter bit BranchTargetALU = 0;
logic clk_sys = 1'b0, rst_sys_n;
typedef enum {
- CoreD,
- CoreI
+ CoreD
} bus_host_e;
typedef enum {
@@ -35,7 +35,7 @@
} bus_device_e;
localparam NrDevices = 3;
- localparam NrHosts = 2;
+ localparam NrHosts = 1;
// interrupts
logic timer_irq;
@@ -71,6 +71,16 @@
assign cfg_device_addr_base[Timer] = 32'h30000;
assign cfg_device_addr_mask[Timer] = ~32'h3FF; // 1 kB
+ // Instruction fetch signals
+ logic instr_req;
+ logic instr_gnt;
+ logic instr_rvalid;
+ logic [31:0] instr_addr;
+ logic [31:0] instr_rdata;
+ logic instr_err;
+
+ assign instr_gnt = instr_req;
+ assign instr_err = '0;
`ifdef VERILATOR
assign clk_sys = IO_CLK;
@@ -78,7 +88,6 @@
`else
initial begin
rst_sys_n = 1'b0;
- device_err = '{default:1'b0};
#8
rst_sys_n = 1'b1;
end
@@ -88,6 +97,10 @@
end
`endif
+ // Tie-off unused error signals
+ assign device_err[Ram] = 1'b0;
+ assign device_err[SimCtrl] = 1'b0;
+
bus #(
.NrDevices (NrDevices),
.NrHosts (NrHosts ),
@@ -120,16 +133,13 @@
.cfg_device_addr_mask
);
- assign host_we[CoreI] = 1'b0;
- assign host_be[CoreI] = 4'b1111;
- assign host_wdata[CoreI] = 32'b0;
-
ibex_core_tracing #(
.MHPMCounterNum(29),
.DmHaltAddr(32'h00100000),
.DmExceptionAddr(32'h00100000),
.RV32E(RV32E),
- .RV32M(RV32M)
+ .RV32M(RV32M),
+ .BranchTargetALU(BranchTargetALU)
) u_core (
.clk_i (clk_sys),
.rst_ni (rst_sys_n),
@@ -140,12 +150,12 @@
// First instruction executed is at 0x0 + 0x80
.boot_addr_i (32'h00100000),
- .instr_req_o (host_req[CoreI]),
- .instr_gnt_i (host_gnt[CoreI]),
- .instr_rvalid_i (host_rvalid[CoreI]),
- .instr_addr_o (host_addr[CoreI]),
- .instr_rdata_i (host_rdata[CoreI]),
- .instr_err_i (host_err[CoreI]),
+ .instr_req_o (instr_req),
+ .instr_gnt_i (instr_gnt),
+ .instr_rvalid_i (instr_rvalid),
+ .instr_addr_o (instr_addr),
+ .instr_rdata_i (instr_rdata),
+ .instr_err_i (instr_err),
.data_req_o (host_req[CoreD]),
.data_gnt_i (host_gnt[CoreD]),
@@ -170,18 +180,27 @@
);
// SRAM block for instruction and data storage
- ram_1p #(
+ ram_2p #(
.Depth(1024*1024/4)
) u_ram (
- .clk_i (clk_sys),
- .rst_ni (rst_sys_n),
- .req_i (device_req[Ram]),
- .we_i (device_we[Ram]),
- .be_i (device_be[Ram]),
- .addr_i (device_addr[Ram]),
- .wdata_i (device_wdata[Ram]),
- .rvalid_o (device_rvalid[Ram]),
- .rdata_o (device_rdata[Ram])
+ .clk_i (clk_sys),
+ .rst_ni (rst_sys_n),
+
+ .a_req_i (device_req[Ram]),
+ .a_we_i (device_we[Ram]),
+ .a_be_i (device_be[Ram]),
+ .a_addr_i (device_addr[Ram]),
+ .a_wdata_i (device_wdata[Ram]),
+ .a_rvalid_o (device_rvalid[Ram]),
+ .a_rdata_o (device_rdata[Ram]),
+
+ .b_req_i (instr_req),
+ .b_we_i (1'b0),
+ .b_be_i (4'b0),
+ .b_addr_i (instr_addr),
+ .b_wdata_i (32'b0),
+ .b_rvalid_o (instr_rvalid),
+ .b_rdata_o (instr_rdata)
);
simulator_ctrl #(
diff --git a/hw/vendor/lowrisc_ibex/examples/sw/led/Makefile b/hw/vendor/lowrisc_ibex/examples/sw/led/Makefile
index 5b264c5..bfd5472 100644
--- a/hw/vendor/lowrisc_ibex/examples/sw/led/Makefile
+++ b/hw/vendor/lowrisc_ibex/examples/sw/led/Makefile
@@ -10,7 +10,7 @@
# ARCH = rv32im # to disable compressed instructions
SRCS = $(PROGRAM).c
-CC = /tools/riscv/bin/riscv32-unknown-elf-gcc
+CC = riscv32-unknown-elf-gcc
OBJCOPY ?= $(subst gcc,objcopy,$(wordlist 1,1,$(CC)))
OBJDUMP ?= $(subst gcc,objdump,$(wordlist 1,1,$(CC)))
diff --git a/hw/vendor/lowrisc_ibex/ibex_core.core b/hw/vendor/lowrisc_ibex/ibex_core.core
index 0bada04..4d71538 100644
--- a/hw/vendor/lowrisc_ibex/ibex_core.core
+++ b/hw/vendor/lowrisc_ibex/ibex_core.core
@@ -63,6 +63,12 @@
description: "Multiplier implementation. Valid values: fast, slow"
default: fast
+ BranchTargetALU:
+ datatype: int
+ paramtype: vlogparam
+ default: 0
+ description: "Enables seperate branch target ALU (increasing branch performance EXPERIMENTAL) [0/1]"
+
targets:
default:
filesets:
diff --git a/hw/vendor/lowrisc_ibex/ibex_core_tracing.core b/hw/vendor/lowrisc_ibex/ibex_core_tracing.core
index 7b8f4af..9de7f13 100644
--- a/hw/vendor/lowrisc_ibex/ibex_core_tracing.core
+++ b/hw/vendor/lowrisc_ibex/ibex_core_tracing.core
@@ -46,6 +46,12 @@
description: "Multiplier implementation. Valid values: fast, slow"
default: fast
+ BranchTargetALU:
+ datatype: int
+ paramtype: vlogparam
+ default: 0
+ description: "Enables seperate branch target ALU (increasing branch performance EXPERIMENTAL) [0/1]"
+
targets:
diff --git a/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt b/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
index 3ff0b2b..7be67c3 100644
--- a/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
+++ b/hw/vendor/lowrisc_ibex/lint/verilator_waiver.vlt
@@ -19,13 +19,9 @@
lint_off -msg DECLFILENAME -file "*/rtl/ibex_register_file_latch.sv"
lint_off -msg DECLFILENAME -file "*/rtl/ibex_register_file_fpga.sv"
-// Bits of signal are not used: boot_addr_i[7:0]
-// Boot address is 256B aligned, cleaner to pass all bits in
-lint_off -msg UNUSED -file "*/rtl/ibex_if_stage.sv" -lines 40
-
// 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 80
+lint_off -msg UNUSED -file "*/rtl/ibex_if_stage.sv" -lines 85
// Bits of signal are not used: shift_right_result_ext[32]
// cleaner to write all bits even if not all are used
@@ -33,15 +29,15 @@
// 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 23
+lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 26
// 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 48
+lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 51
// 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 68
+lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 71
// Signal is not used: test_en_i
// testability signal
@@ -50,18 +46,22 @@
// Signal is not used: clk_i
// leaving clk and reset connected in-case we want to add assertions
-lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 15
-lint_off -msg UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -lines 14
-lint_off -msg UNUSED -file "*/rtl/ibex_decoder.sv" -lines 21
+lint_off -msg UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -lines 17
+lint_off -msg UNUSED -file "*/rtl/ibex_decoder.sv" -lines 25
// Signal is not used: rst_ni
// leaving clk and reset connected in-case we want to add assertions
-lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 16
-lint_off -msg UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -lines 15
-lint_off -msg UNUSED -file "*/rtl/ibex_decoder.sv" -lines 22
+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 167
+lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 158
+
+// 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
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_alu.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_alu.sv
index cb57889..a7bf21a 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_alu.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_alu.sv
@@ -14,7 +14,7 @@
input logic [32:0] multdiv_operand_a_i,
input logic [32:0] multdiv_operand_b_i,
- input logic multdiv_en_i,
+ input logic multdiv_sel_i,
output logic [31:0] adder_result_o,
output logic [33:0] adder_result_ext_o,
@@ -59,11 +59,11 @@
end
// prepare operand a
- assign adder_in_a = multdiv_en_i ? multdiv_operand_a_i : {operand_a_i,1'b1};
+ assign adder_in_a = multdiv_sel_i ? multdiv_operand_a_i : {operand_a_i,1'b1};
// prepare operand b
assign operand_b_neg = {operand_b_i,1'b0} ^ {33{adder_op_b_negate}};
- assign adder_in_b = multdiv_en_i ? multdiv_operand_b_i : operand_b_neg ;
+ assign adder_in_b = multdiv_sel_i ? multdiv_operand_b_i : operand_b_neg ;
// actual adder
assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b);
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv
index 52c3a54..442b579 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv
@@ -10,6 +10,9 @@
* This module is fully combinatorial, clock and reset are used for
* assertions only.
*/
+
+`include "prim_assert.sv"
+
module ibex_compressed_decoder (
input logic clk_i,
input logic rst_ni,
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
index e1172c6..aee4f55 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_controller.sv
@@ -6,6 +6,9 @@
/**
* Main controller of the processor
*/
+
+`include "prim_assert.sv"
+
module ibex_controller (
input logic clk_i,
input logic rst_ni,
@@ -53,11 +56,9 @@
// interrupt signals
input logic csr_mstatus_mie_i, // M-mode interrupt enable bit
- input logic csr_msip_i, // software interrupt pending
- input logic csr_mtip_i, // timer interrupt pending
- input logic csr_meip_i, // external interrupt pending
- input logic [14:0] csr_mfip_i, // fast interrupt pending
input logic irq_pending_i, // interrupt request pending
+ input ibex_pkg::irqs_t irqs_i, // interrupt requests qualified with
+ // mie CSR
input logic irq_nm_i, // non-maskeable interrupt
output logic nmi_mode_o, // core executing NMI handler
@@ -121,7 +122,7 @@
logic handle_irq;
logic [3:0] mfip_id;
- logic unused_csr_mtip;
+ logic unused_irq_timer;
logic ecall_insn;
logic mret_insn;
@@ -209,31 +210,34 @@
priv_mode_i == PRIV_LVL_U ? debug_ebreaku_i :
1'b0;
- // interrupts including NMI are ignored while in debug mode [Debug Spec v0.13.2, p.39]
- assign handle_irq = ~debug_mode_q &
- ((irq_nm_i & ~nmi_mode_q) | (irq_pending_i & csr_mstatus_mie_i));
+ // Interrupts including NMI are ignored,
+ // - while in debug mode [Debug Spec v0.13.2, p.39],
+ // - while in NMI mode (nested NMIs are not supported, NMI has highest priority and
+ // cannot be interrupted by regular interrupts).
+ assign handle_irq = ~debug_mode_q & ~nmi_mode_q &
+ (irq_nm_i | (irq_pending_i & csr_mstatus_mie_i));
// generate ID of fast interrupts, highest priority to highest ID
always_comb begin : gen_mfip_id
- if (csr_mfip_i[14]) mfip_id = 4'd14;
- else if (csr_mfip_i[13]) mfip_id = 4'd13;
- else if (csr_mfip_i[12]) mfip_id = 4'd12;
- else if (csr_mfip_i[11]) mfip_id = 4'd11;
- else if (csr_mfip_i[10]) mfip_id = 4'd10;
- else if (csr_mfip_i[ 9]) mfip_id = 4'd9;
- else if (csr_mfip_i[ 8]) mfip_id = 4'd8;
- else if (csr_mfip_i[ 7]) mfip_id = 4'd7;
- else if (csr_mfip_i[ 6]) mfip_id = 4'd6;
- else if (csr_mfip_i[ 5]) mfip_id = 4'd5;
- else if (csr_mfip_i[ 5]) mfip_id = 4'd5;
- else if (csr_mfip_i[ 4]) mfip_id = 4'd4;
- else if (csr_mfip_i[ 3]) mfip_id = 4'd3;
- else if (csr_mfip_i[ 2]) mfip_id = 4'd2;
- else if (csr_mfip_i[ 1]) mfip_id = 4'd1;
- else mfip_id = 4'd0;
+ if (irqs_i.irq_fast[14]) mfip_id = 4'd14;
+ else if (irqs_i.irq_fast[13]) mfip_id = 4'd13;
+ else if (irqs_i.irq_fast[12]) mfip_id = 4'd12;
+ else if (irqs_i.irq_fast[11]) mfip_id = 4'd11;
+ else if (irqs_i.irq_fast[10]) mfip_id = 4'd10;
+ else if (irqs_i.irq_fast[ 9]) mfip_id = 4'd9;
+ else if (irqs_i.irq_fast[ 8]) mfip_id = 4'd8;
+ else if (irqs_i.irq_fast[ 7]) mfip_id = 4'd7;
+ else if (irqs_i.irq_fast[ 6]) mfip_id = 4'd6;
+ else if (irqs_i.irq_fast[ 5]) mfip_id = 4'd5;
+ else if (irqs_i.irq_fast[ 5]) mfip_id = 4'd5;
+ else if (irqs_i.irq_fast[ 4]) mfip_id = 4'd4;
+ else if (irqs_i.irq_fast[ 3]) mfip_id = 4'd3;
+ else if (irqs_i.irq_fast[ 2]) mfip_id = 4'd2;
+ else if (irqs_i.irq_fast[ 1]) mfip_id = 4'd1;
+ else mfip_id = 4'd0;
end
- assign unused_csr_mtip = csr_mtip_i;
+ assign unused_irq_timer = irqs_i.irq_timer;
/////////////////////
// Core controller //
@@ -250,6 +254,10 @@
csr_save_cause_o = 1'b0;
csr_mtval_o = '0;
+ // The values of pc_mux and exc_pc_mux are only relevant if pc_set is set. Some of the states
+ // below always set pc_mux and exc_pc_mux but only set pc_set if certain conditions are met.
+ // This avoid having to factor those conditions into the pc_mux and exc_pc_mux select signals
+ // helping timing.
pc_mux_o = PC_BOOT;
pc_set_o = 1'b0;
@@ -347,6 +355,11 @@
// 2. debug requests
// 3. interrupt requests
+ // Set PC mux for branch and jump here to ease timing. Value is only relevant if pc_set_o is
+ // also set. Setting the mux value here avoids factoring in special_req and instr_valid_i
+ // which helps timing.
+ pc_mux_o = PC_JUMP;
+
if (instr_valid_i) begin
// get ready for special instructions, exceptions, pipeline flushes
@@ -358,7 +371,6 @@
halt_if = 1'b1;
// set PC in IF stage to branch or jump target
end else if (branch_set_i || jump_set_i) begin
- pc_mux_o = PC_JUMP;
pc_set_o = 1'b1;
perf_tbranch_o = branch_set_i;
@@ -391,10 +403,11 @@
end // DECODE
IRQ_TAKEN: begin
+ pc_mux_o = PC_EXC;
+ exc_pc_mux_o = EXC_PC_IRQ;
+
if (handle_irq) begin
- pc_mux_o = PC_EXC;
pc_set_o = 1'b1;
- exc_pc_mux_o = EXC_PC_IRQ;
csr_save_if_o = 1'b1;
csr_save_cause_o = 1'b1;
@@ -403,17 +416,17 @@
if (irq_nm_i && !nmi_mode_q) begin
exc_cause_o = EXC_CAUSE_IRQ_NM;
nmi_mode_d = 1'b1; // enter NMI mode
- end else if (csr_mfip_i != 15'b0) begin
+ end else if (irqs_i.irq_fast != 15'b0) begin
// generate exception cause ID from fast interrupt ID:
// - first bit distinguishes interrupts from exceptions,
// - second bit adds 16 to fast interrupt ID
// for example EXC_CAUSE_IRQ_FAST_0 = {1'b1, 5'd16}
exc_cause_o = exc_cause_e'({2'b11, mfip_id});
- end else if (csr_meip_i) begin
+ end else if (irqs_i.irq_external) begin
exc_cause_o = EXC_CAUSE_IRQ_EXTERNAL_M;
- end else if (csr_msip_i) begin
+ end else if (irqs_i.irq_software) begin
exc_cause_o = EXC_CAUSE_IRQ_SOFTWARE_M;
- end else begin // csr_mtip_i
+ end else begin // irqs_i.irq_timer
exc_cause_o = EXC_CAUSE_IRQ_TIMER_M;
end
end
@@ -422,13 +435,14 @@
end
DBG_TAKEN_IF: begin
+ pc_mux_o = PC_EXC;
+ exc_pc_mux_o = EXC_PC_DBD;
+
// enter debug mode and save PC in IF to dpc
// jump to debug exception handler in debug memory
if (debug_single_step_i || debug_req_i || trigger_match_i) begin
flush_id = 1'b1;
- pc_mux_o = PC_EXC;
pc_set_o = 1'b1;
- exc_pc_mux_o = EXC_PC_DBD;
csr_save_if_o = 1'b1;
debug_csr_save_o = 1'b1;
@@ -486,6 +500,9 @@
flush_id = 1'b1;
ctrl_fsm_ns = DECODE;
+ // As pc_mux and exc_pc_mux can take various values in this state they aren't set early
+ // here.
+
// exceptions: set exception PC, save PC and exception cause
// exc_req_lsu is high for one clock cycle only (in DECODE)
if (exc_req_q || store_err_q || load_err_q) begin
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
index f136bdd..7291d2b 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_core.sv
@@ -18,6 +18,7 @@
parameter int unsigned MHPMCounterWidth = 40,
parameter bit RV32E = 1'b0,
parameter bit RV32M = 1'b1,
+ parameter bit BranchTargetALU = 1'b0,
parameter MultiplierImplementation = "fast",
parameter bit DbgTriggerEn = 1'b0,
parameter int unsigned DmHaltAddr = 32'h1A110800,
@@ -100,6 +101,8 @@
logic instr_valid_id;
logic instr_new_id;
logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage
+ logic [31:0] instr_rdata_alu_id; // Instruction sampled inside IF stage (replicated to ease
+ // fan-out)
logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage
logic instr_is_compressed_id;
logic instr_fetch_err; // Bus error on instr fetch
@@ -135,12 +138,16 @@
logic [31:0] alu_operand_a_ex;
logic [31:0] alu_operand_b_ex;
+ jt_mux_sel_e jt_mux_sel_ex;
+ logic [11:0] bt_operand_imm_ex;
+
logic [31:0] alu_adder_result_ex; // Used to forward computed address to LSU
logic [31:0] regfile_wdata_ex;
// Multiplier Control
logic mult_en_ex;
logic div_en_ex;
+ logic multdiv_sel_ex;
md_op_e multdiv_operator_ex;
logic [1:0] multdiv_signed_mode_ex;
logic [31:0] multdiv_operand_a_ex;
@@ -177,10 +184,7 @@
// Interrupts
logic irq_pending;
logic nmi_mode;
- logic csr_msip;
- logic csr_mtip;
- logic csr_meip;
- logic [14:0] csr_mfip;
+ irqs_t irqs;
logic csr_mstatus_mie;
logic [31:0] csr_mepc, csr_depc;
@@ -318,6 +322,7 @@
.instr_valid_id_o ( instr_valid_id ),
.instr_new_id_o ( instr_new_id ),
.instr_rdata_id_o ( instr_rdata_id ),
+ .instr_rdata_alu_id_o ( instr_rdata_alu_id ),
.instr_rdata_c_id_o ( instr_rdata_c_id ),
.instr_is_compressed_id_o ( instr_is_compressed_id ),
.instr_fetch_err_o ( instr_fetch_err ),
@@ -356,8 +361,9 @@
//////////////
ibex_id_stage #(
- .RV32E ( RV32E ),
- .RV32M ( RV32M )
+ .RV32E ( RV32E ),
+ .RV32M ( RV32M ),
+ .BranchTargetALU ( BranchTargetALU )
) id_stage_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
@@ -373,6 +379,7 @@
.instr_valid_i ( instr_valid_id ),
.instr_new_i ( instr_new_id ),
.instr_rdata_i ( instr_rdata_id ),
+ .instr_rdata_alu_i ( instr_rdata_alu_id ),
.instr_rdata_c_i ( instr_rdata_c_id ),
.instr_is_compressed_i ( instr_is_compressed_id ),
@@ -401,8 +408,12 @@
.alu_operand_a_ex_o ( alu_operand_a_ex ),
.alu_operand_b_ex_o ( alu_operand_b_ex ),
+ .jt_mux_sel_ex_o ( jt_mux_sel_ex ),
+ .bt_operand_imm_o ( bt_operand_imm_ex ),
+
.mult_en_ex_o ( mult_en_ex ),
.div_en_ex_o ( div_en_ex ),
+ .multdiv_sel_ex_o ( multdiv_sel_ex ),
.multdiv_operator_ex_o ( multdiv_operator_ex ),
.multdiv_signed_mode_ex_o ( multdiv_signed_mode_ex ),
.multdiv_operand_a_ex_o ( multdiv_operand_a_ex ),
@@ -436,11 +447,8 @@
// Interrupt Signals
.csr_mstatus_mie_i ( csr_mstatus_mie ),
- .csr_msip_i ( csr_msip ),
- .csr_mtip_i ( csr_mtip ),
- .csr_meip_i ( csr_meip ),
- .csr_mfip_i ( csr_mfip ),
.irq_pending_i ( irq_pending ),
+ .irqs_i ( irqs ),
.irq_nm_i ( irq_nm_i ),
.nmi_mode_o ( nmi_mode ),
@@ -482,6 +490,7 @@
ibex_ex_block #(
.RV32M ( RV32M ),
+ .BranchTargetALU ( BranchTargetALU ),
.MultiplierImplementation ( MultiplierImplementation )
) ex_block_i (
.clk_i ( clk ),
@@ -492,10 +501,16 @@
.alu_operand_a_i ( alu_operand_a_ex ),
.alu_operand_b_i ( alu_operand_b_ex ),
+ // Branch target ALU signal from ID stage
+ .jt_mux_sel_i ( jt_mux_sel_ex ),
+ .bt_operand_imm_i ( bt_operand_imm_ex ),
+ .pc_id_i ( pc_id ),
+
// Multipler/Divider signal from ID stage
.multdiv_operator_i ( multdiv_operator_ex ),
.mult_en_i ( mult_en_ex ),
.div_en_i ( div_en_ex ),
+ .multdiv_sel_i ( multdiv_sel_ex ),
.multdiv_signed_mode_i ( multdiv_signed_mode_ex ),
.multdiv_operand_a_i ( multdiv_operand_a_ex ),
.multdiv_operand_b_i ( multdiv_operand_b_ex ),
@@ -605,12 +620,9 @@
.irq_timer_i ( irq_timer_i ),
.irq_external_i ( irq_external_i ),
.irq_fast_i ( irq_fast_i ),
- .irq_pending_o ( irq_pending ),
.nmi_mode_i ( nmi_mode ),
- .csr_msip_o ( csr_msip ),
- .csr_mtip_o ( csr_mtip ),
- .csr_meip_o ( csr_meip ),
- .csr_mfip_o ( csr_mfip ),
+ .irq_pending_o ( irq_pending ),
+ .irqs_o ( irqs ),
.csr_mstatus_mie_o ( csr_mstatus_mie ),
.csr_mstatus_tw_o ( csr_mstatus_tw ),
.csr_mepc_o ( csr_mepc ),
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv
index 2eb40cc..b4ba19d 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_core_tracing.sv
@@ -14,6 +14,7 @@
parameter int unsigned MHPMCounterWidth = 40,
parameter bit RV32E = 1'b0,
parameter bit RV32M = 1'b1,
+ parameter bit BranchTargetALU = 1'b0,
parameter MultiplierImplementation = "fast",
parameter bit DbgTriggerEn = 1'b0,
parameter int unsigned DmHaltAddr = 32'h1A110800,
@@ -99,6 +100,7 @@
.MHPMCounterWidth ( MHPMCounterWidth ),
.RV32E ( RV32E ),
.RV32M ( RV32M ),
+ .BranchTargetALU ( BranchTargetALU ),
.DbgTriggerEn ( DbgTriggerEn ),
.MultiplierImplementation ( MultiplierImplementation ),
.DmHaltAddr ( DmHaltAddr ),
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
index 2f6f476..67ab001 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv
@@ -9,6 +9,9 @@
* Control and Status Registers (CSRs) following the RISC-V Privileged
* Specification, draft version 1.11
*/
+
+`include "prim_assert.sv"
+
module ibex_cs_registers #(
parameter bit DbgTriggerEn = 0,
parameter int unsigned MHPMCounterNum = 8,
@@ -49,12 +52,9 @@
input logic irq_timer_i,
input logic irq_external_i,
input logic [14:0] irq_fast_i,
- output logic irq_pending_o, // interupt request pending
input logic nmi_mode_i,
- output logic csr_msip_o, // software interrupt pending
- output logic csr_mtip_o, // timer interrupt pending
- output logic csr_meip_o, // external interrupt pending
- output logic [14:0] csr_mfip_o, // fast interrupt pending
+ output logic irq_pending_o, // interrupt request pending
+ output ibex_pkg::irqs_t irqs_o, // interrupt requests qualified with mie
output logic csr_mstatus_mie_o,
output logic [31:0] csr_mepc_o,
@@ -131,15 +131,6 @@
priv_lvl_e mpp;
} StatusStk_t;
- // struct for mip/mie CSRs
- typedef struct packed {
- logic irq_software;
- logic irq_timer;
- logic irq_external;
- logic [14:0] irq_fast; // 15 fast interrupts,
- // one interrupt is reserved for NMI (not visible through mip/mie)
- } Interrupts_t;
-
typedef struct packed {
x_debug_ver_e xdebugver;
logic [11:0] zero2;
@@ -164,13 +155,13 @@
// CSRs
priv_lvl_e priv_lvl_q, priv_lvl_d;
Status_t mstatus_q, mstatus_d;
- Interrupts_t mie_q, mie_d;
+ irqs_t mie_q, mie_d;
logic [31:0] mscratch_q, mscratch_d;
logic [31:0] mepc_q, mepc_d;
logic [5:0] mcause_q, mcause_d;
logic [31:0] mtval_q, mtval_d;
logic [31:0] mtvec_q, mtvec_d;
- Interrupts_t mip;
+ irqs_t mip;
Dcsr_t dcsr_q, dcsr_d;
logic [31:0] depc_q, depc_d;
logic [31:0] dscratch0_q, dscratch0_d;
@@ -239,10 +230,10 @@
assign illegal_csr_insn_o = csr_access_i & (illegal_csr | illegal_csr_write | illegal_csr_priv);
// mip CSR is purely combinational - must be able to re-enable the clock upon WFI
- assign mip.irq_software = irq_software_i & mie_q.irq_software;
- assign mip.irq_timer = irq_timer_i & mie_q.irq_timer;
- assign mip.irq_external = irq_external_i & mie_q.irq_external;
- assign mip.irq_fast = irq_fast_i & mie_q.irq_fast;
+ assign mip.irq_software = irq_software_i;
+ assign mip.irq_timer = irq_timer_i;
+ assign mip.irq_external = irq_external_i;
+ assign mip.irq_fast = irq_fast_i;
// read logic
always_comb begin
@@ -629,11 +620,6 @@
assign csr_rdata_o = csr_rdata_int;
// directly output some registers
- assign csr_msip_o = mip.irq_software;
- assign csr_mtip_o = mip.irq_timer;
- assign csr_meip_o = mip.irq_external;
- assign csr_mfip_o = mip.irq_fast;
-
assign csr_mepc_o = mepc_q;
assign csr_depc_o = depc_q;
assign csr_mtvec_o = mtvec_q;
@@ -644,7 +630,10 @@
assign debug_ebreakm_o = dcsr_q.ebreakm;
assign debug_ebreaku_o = dcsr_q.ebreaku;
- assign irq_pending_o = csr_msip_o | csr_mtip_o | csr_meip_o | (|csr_mfip_o);
+ // Qualify incoming interrupt requests in mip CSR with mie CSR for controller and to re-enable
+ // clock upon WFI (must be purely combinational).
+ assign irqs_o = mip & mie_q;
+ assign irq_pending_o = |irqs_o;
// actual registers
always_ff @(posedge clk_i or negedge rst_ni) begin
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
index f28017c..ae3cf86 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv
@@ -14,9 +14,13 @@
* This module is fully combinatorial, clock and reset are used for
* assertions only.
*/
+
+`include "prim_assert.sv"
+
module ibex_decoder #(
- parameter bit RV32E = 0,
- parameter bit RV32M = 1
+ parameter bit RV32E = 0,
+ parameter bit RV32M = 1,
+ parameter bit BranchTargetALU = 0
) (
input logic clk_i,
input logic rst_ni,
@@ -34,17 +38,21 @@
// from IF-ID pipeline register
input logic instr_new_i, // instruction read is new
input logic [31:0] instr_rdata_i, // instruction read from memory/cache
+ input logic [31:0] instr_rdata_alu_i, // instruction read from memory/cache
+ // replicated to ease fan-out)
+
input logic illegal_c_insn_i, // compressed instruction decode failed
// immediates
- output ibex_pkg::imm_a_sel_e imm_a_mux_sel_o, // immediate selection for operand a
- output ibex_pkg::imm_b_sel_e imm_b_mux_sel_o, // immediate selection for operand b
- output logic [31:0] imm_i_type_o,
- output logic [31:0] imm_s_type_o,
- output logic [31:0] imm_b_type_o,
- output logic [31:0] imm_u_type_o,
- output logic [31:0] imm_j_type_o,
- output logic [31:0] zimm_rs1_type_o,
+ output ibex_pkg::imm_a_sel_e imm_a_mux_sel_o, // immediate selection for operand a
+ output ibex_pkg::imm_b_sel_e imm_b_mux_sel_o, // immediate selection for operand b
+ output ibex_pkg::jt_mux_sel_e jt_mux_sel_o, // jump target selection
+ output logic [31:0] imm_i_type_o,
+ output logic [31:0] imm_s_type_o,
+ output logic [31:0] imm_b_type_o,
+ output logic [31:0] imm_u_type_o,
+ output logic [31:0] imm_j_type_o,
+ output logic [31:0] zimm_rs1_type_o,
// register file
output ibex_pkg::rf_wd_sel_e regfile_wdata_sel_o, // RF write data selection
@@ -64,6 +72,8 @@
output logic mult_en_o, // perform integer multiplication
output logic div_en_o, // perform integer division or
// remainder
+ output logic multdiv_sel_o,
+
output ibex_pkg::md_op_e multdiv_operator_o,
output logic [1:0] multdiv_signed_mode_o,
@@ -93,12 +103,18 @@
logic regfile_we;
logic [31:0] instr;
+ logic [31:0] instr_alu;
csr_op_e csr_op;
opcode_e opcode;
+ opcode_e opcode_alu;
- assign instr = instr_rdata_i;
+ // To help timing the flops containing the current instruction are replicated to reduce fan-out.
+ // instr_alu is used to determine the ALU control logic and associated operand/imm select signals
+ // as the ALU is often on the more critical timing paths. instr is used for everything else.
+ assign instr = instr_rdata_i;
+ assign instr_alu = instr_rdata_alu_i;
//////////////////////////////////////
// Register and immediate selection //
@@ -180,12 +196,6 @@
jump_in_dec_o = 1'b0;
jump_set_o = 1'b0;
branch_in_dec_o = 1'b0;
- alu_operator_o = ALU_SLTU;
- alu_op_a_mux_sel_o = OP_A_IMM;
- alu_op_b_mux_sel_o = OP_B_IMM;
-
- imm_a_mux_sel_o = IMM_A_ZERO;
- imm_b_mux_sel_o = IMM_B_I;
mult_en_o = 1'b0;
div_en_o = 1'b0;
@@ -221,40 +231,26 @@
OPCODE_JAL: begin // Jump and Link
jump_in_dec_o = 1'b1;
+
if (instr_new_i) begin
// Calculate jump target
- alu_op_a_mux_sel_o = OP_A_CURRPC;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_b_mux_sel_o = IMM_B_J;
- alu_operator_o = ALU_ADD;
regfile_we = 1'b0;
jump_set_o = 1'b1;
end else begin
// Calculate and store PC+4
- alu_op_a_mux_sel_o = OP_A_CURRPC;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_b_mux_sel_o = IMM_B_INCR_PC;
- alu_operator_o = ALU_ADD;
regfile_we = 1'b1;
end
end
OPCODE_JALR: begin // Jump and Link Register
jump_in_dec_o = 1'b1;
+
if (instr_new_i) begin
// Calculate jump target
- alu_op_a_mux_sel_o = OP_A_REG_A;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_b_mux_sel_o = IMM_B_I;
- alu_operator_o = ALU_ADD;
regfile_we = 1'b0;
jump_set_o = 1'b1;
end else begin
// Calculate and store PC+4
- alu_op_a_mux_sel_o = OP_A_CURRPC;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_b_mux_sel_o = IMM_B_INCR_PC;
- alu_operator_o = ALU_ADD;
regfile_we = 1'b1;
end
if (instr[14:12] != 3'b0) begin
@@ -266,26 +262,14 @@
branch_in_dec_o = 1'b1;
// Check branch condition selection
unique case (instr[14:12])
- 3'b000: alu_operator_o = ALU_EQ;
- 3'b001: alu_operator_o = ALU_NE;
- 3'b100: alu_operator_o = ALU_LT;
- 3'b101: alu_operator_o = ALU_GE;
- 3'b110: alu_operator_o = ALU_LTU;
- 3'b111: alu_operator_o = ALU_GEU;
- default: illegal_insn = 1'b1;
+ 3'b000,
+ 3'b001,
+ 3'b100,
+ 3'b101,
+ 3'b110,
+ 3'b111: illegal_insn = 1'b0;
+ default: illegal_insn = 1'b1;
endcase
- if (instr_new_i) begin
- // Evaluate branch condition
- alu_op_a_mux_sel_o = OP_A_REG_A;
- alu_op_b_mux_sel_o = OP_B_REG_B;
- end else begin
- // Calculate jump target in EX
- alu_op_a_mux_sel_o = OP_A_CURRPC;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_b_mux_sel_o = IMM_B_B;
- alu_operator_o = ALU_ADD;
- regfile_we = 1'b0;
- end
end
////////////////
@@ -293,18 +277,10 @@
////////////////
OPCODE_STORE: begin
- alu_op_a_mux_sel_o = OP_A_REG_A;
- alu_op_b_mux_sel_o = OP_B_REG_B;
data_req_o = 1'b1;
data_we_o = 1'b1;
- alu_operator_o = ALU_ADD;
- if (!instr[14]) begin
- // offset from immediate
- imm_b_mux_sel_o = IMM_B_S;
- alu_op_b_mux_sel_o = OP_B_IMM;
- end else begin
- // Register offset is illegal since no register c available
+ if (instr[14]) begin
illegal_insn = 1'b1;
end
@@ -318,17 +294,11 @@
end
OPCODE_LOAD: begin
- alu_op_a_mux_sel_o = OP_A_REG_A;
data_req_o = 1'b1;
regfile_wdata_sel_o = RF_WD_LSU;
regfile_we = 1'b1;
data_type_o = 2'b00;
- // offset from immediate
- alu_operator_o = ALU_ADD;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_b_mux_sel_o = IMM_B_I;
-
// sign/zero extension
data_sign_extension_o = ~instr[14];
@@ -353,38 +323,25 @@
/////////
OPCODE_LUI: begin // Load Upper Immediate
- alu_op_a_mux_sel_o = OP_A_IMM;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_a_mux_sel_o = IMM_A_ZERO;
- imm_b_mux_sel_o = IMM_B_U;
- alu_operator_o = ALU_ADD;
regfile_we = 1'b1;
end
OPCODE_AUIPC: begin // Add Upper Immediate to PC
- alu_op_a_mux_sel_o = OP_A_CURRPC;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_b_mux_sel_o = IMM_B_U;
- alu_operator_o = ALU_ADD;
regfile_we = 1'b1;
end
OPCODE_OP_IMM: begin // Register-Immediate ALU Operations
- alu_op_a_mux_sel_o = OP_A_REG_A;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_b_mux_sel_o = IMM_B_I;
regfile_we = 1'b1;
unique case (instr[14:12])
- 3'b000: alu_operator_o = ALU_ADD; // Add Immediate
- 3'b010: alu_operator_o = ALU_SLT; // Set to one if Lower Than Immediate
- 3'b011: alu_operator_o = ALU_SLTU; // Set to one if Lower Than Immediate Unsigned
- 3'b100: alu_operator_o = ALU_XOR; // Exclusive Or with Immediate
- 3'b110: alu_operator_o = ALU_OR; // Or with Immediate
- 3'b111: alu_operator_o = ALU_AND; // And with Immediate
+ 3'b000,
+ 3'b010,
+ 3'b011,
+ 3'b100,
+ 3'b110,
+ 3'b111: illegal_insn = 1'b0;
3'b001: begin
- alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
if (instr[31:25] != 7'b0) begin
illegal_insn = 1'b1;
end
@@ -392,23 +349,21 @@
3'b101: begin
if (instr[31:25] == 7'b0) begin
- alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate
+ illegal_insn = 1'b0;
end else if (instr[31:25] == 7'b010_0000) begin
- alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate
+ illegal_insn = 1'b0;
end else begin
illegal_insn = 1'b1;
end
end
default: begin
- alu_operator_o = ALU_SLTU;
+ illegal_insn = 1'b1;
end
endcase
end
OPCODE_OP: begin // Register-Register ALU operation
- alu_op_a_mux_sel_o = OP_A_REG_A;
- alu_op_b_mux_sel_o = OP_B_REG_B;
regfile_we = 1'b1;
if (instr[31]) begin
@@ -416,69 +371,61 @@
end else begin
unique case ({instr[30:25], instr[14:12]})
// RV32I ALU operations
- {6'b00_0000, 3'b000}: alu_operator_o = ALU_ADD; // Add
- {6'b10_0000, 3'b000}: alu_operator_o = ALU_SUB; // Sub
- {6'b00_0000, 3'b010}: alu_operator_o = ALU_SLT; // Set Lower Than
- {6'b00_0000, 3'b011}: alu_operator_o = ALU_SLTU; // Set Lower Than Unsigned
- {6'b00_0000, 3'b100}: alu_operator_o = ALU_XOR; // Xor
- {6'b00_0000, 3'b110}: alu_operator_o = ALU_OR; // Or
- {6'b00_0000, 3'b111}: alu_operator_o = ALU_AND; // And
- {6'b00_0000, 3'b001}: alu_operator_o = ALU_SLL; // Shift Left Logical
- {6'b00_0000, 3'b101}: alu_operator_o = ALU_SRL; // Shift Right Logical
- {6'b10_0000, 3'b101}: alu_operator_o = ALU_SRA; // Shift Right Arithmetic
+ {6'b00_0000, 3'b000},
+ {6'b10_0000, 3'b000},
+ {6'b00_0000, 3'b010},
+ {6'b00_0000, 3'b011},
+ {6'b00_0000, 3'b100},
+ {6'b00_0000, 3'b110},
+ {6'b00_0000, 3'b111},
+ {6'b00_0000, 3'b001},
+ {6'b00_0000, 3'b101},
+ {6'b10_0000, 3'b101}: illegal_insn = 1'b0;
// supported RV32M instructions
{6'b00_0001, 3'b000}: begin // mul
- alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULL;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b001}: begin // mulh
- alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b010}: begin // mulhsu
- alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b01;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b011}: begin // mulhu
- alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b100}: begin // div
- alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_DIV;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b101}: begin // divu
- alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_DIV;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b110}: begin // rem
- alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_REM;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b111}: begin // remu
- alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_REM;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
@@ -501,9 +448,6 @@
// FENCE.I will flush the IF stage and prefetch buffer but nothing else.
unique case (instr[14:12])
3'b000: begin
- alu_operator_o = ALU_ADD; // nop
- alu_op_a_mux_sel_o = OP_A_REG_A;
- alu_op_b_mux_sel_o = OP_B_IMM;
regfile_we = 1'b0;
end
3'b001: begin
@@ -512,10 +456,6 @@
// requests will be ignored).
jump_in_dec_o = 1'b1;
- alu_op_a_mux_sel_o = OP_A_CURRPC;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_b_mux_sel_o = IMM_B_INCR_PC;
- alu_operator_o = ALU_ADD;
regfile_we = 1'b0;
if (instr_new_i) begin
@@ -531,8 +471,6 @@
OPCODE_SYSTEM: begin
if (instr[14:12] == 3'b000) begin
// non CSR related SYSTEM instructions
- alu_op_a_mux_sel_o = OP_A_REG_A;
- alu_op_b_mux_sel_o = OP_B_IMM;
unique case (instr[31:20])
12'h000: // ECALL
// environment (system) call
@@ -564,16 +502,6 @@
csr_access_o = 1'b1;
regfile_wdata_sel_o = RF_WD_CSR;
regfile_we = 1'b1;
- alu_op_b_mux_sel_o = OP_B_IMM;
- imm_a_mux_sel_o = IMM_A_Z;
- imm_b_mux_sel_o = IMM_B_I; // CSR address is encoded in I imm
-
- if (instr[14]) begin
- // rs1 field is used as immediate
- alu_op_a_mux_sel_o = OP_A_IMM;
- end else begin
- alu_op_a_mux_sel_o = OP_A_REG_A;
- end
unique case (instr[13:12])
2'b01: csr_op = CSR_OP_WRITE;
@@ -614,6 +542,260 @@
end
end
+ /////////////////////////////
+ // Decoder for ALU control //
+ /////////////////////////////
+
+ always_comb begin
+ alu_operator_o = ALU_SLTU;
+ alu_op_a_mux_sel_o = OP_A_IMM;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+
+ imm_a_mux_sel_o = IMM_A_ZERO;
+ imm_b_mux_sel_o = IMM_B_I;
+
+ jt_mux_sel_o = JT_ALU;
+
+ multdiv_sel_o = 1'b0;
+
+ opcode_alu = opcode_e'(instr_alu[6:0]);
+
+ unique case (opcode_alu)
+
+ ///////////
+ // Jumps //
+ ///////////
+
+ OPCODE_JAL: begin // Jump and Link
+ if (BranchTargetALU) begin
+ jt_mux_sel_o = JT_ALU;
+ end
+
+ if (instr_new_i) begin
+ // Calculate jump target
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMM_B_J;
+ alu_operator_o = ALU_ADD;
+ end else begin
+ // Calculate and store PC+4
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMM_B_INCR_PC;
+ alu_operator_o = ALU_ADD;
+ end
+ end
+
+ OPCODE_JALR: begin // Jump and Link Register
+ if (BranchTargetALU) begin
+ jt_mux_sel_o = JT_ALU;
+ end
+
+ if (instr_new_i) begin
+ // Calculate jump target
+ alu_op_a_mux_sel_o = OP_A_REG_A;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMM_B_I;
+ alu_operator_o = ALU_ADD;
+ end else begin
+ // Calculate and store PC+4
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMM_B_INCR_PC;
+ alu_operator_o = ALU_ADD;
+ end
+ end
+
+ OPCODE_BRANCH: begin // Branch
+ // Check branch condition selection
+ unique case (instr_alu[14:12])
+ 3'b000: alu_operator_o = ALU_EQ;
+ 3'b001: alu_operator_o = ALU_NE;
+ 3'b100: alu_operator_o = ALU_LT;
+ 3'b101: alu_operator_o = ALU_GE;
+ 3'b110: alu_operator_o = ALU_LTU;
+ 3'b111: alu_operator_o = ALU_GEU;
+ default: ;
+ endcase
+
+ if (BranchTargetALU) begin
+ // With branch target ALU the main ALU evaluates the branch condition and the branch
+ // target ALU calculates the target (which is controlled in a seperate block below)
+ alu_op_a_mux_sel_o = OP_A_REG_A;
+ alu_op_b_mux_sel_o = OP_B_REG_B;
+ jt_mux_sel_o = JT_BT_ALU;
+ end else begin
+ // Without branch target ALU, a branch is a two-stage operation using the Main ALU in both
+ // stages
+ if (instr_new_i) begin
+ // First evaluate the branch condition
+ alu_op_a_mux_sel_o = OP_A_REG_A;
+ alu_op_b_mux_sel_o = OP_B_REG_B;
+ end else begin
+ // Then calculate jump target
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMM_B_B;
+ alu_operator_o = ALU_ADD;
+ end
+ end
+ end
+
+ ////////////////
+ // Load/store //
+ ////////////////
+
+ OPCODE_STORE: begin
+ alu_op_a_mux_sel_o = OP_A_REG_A;
+ alu_op_b_mux_sel_o = OP_B_REG_B;
+ alu_operator_o = ALU_ADD;
+
+ if (!instr_alu[14]) begin
+ // offset from immediate
+ imm_b_mux_sel_o = IMM_B_S;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ end
+ end
+
+ OPCODE_LOAD: begin
+ alu_op_a_mux_sel_o = OP_A_REG_A;
+
+ // offset from immediate
+ alu_operator_o = ALU_ADD;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMM_B_I;
+ end
+
+ /////////
+ // ALU //
+ /////////
+
+ OPCODE_LUI: begin // Load Upper Immediate
+ alu_op_a_mux_sel_o = OP_A_IMM;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_a_mux_sel_o = IMM_A_ZERO;
+ imm_b_mux_sel_o = IMM_B_U;
+ alu_operator_o = ALU_ADD;
+ end
+
+ OPCODE_AUIPC: begin // Add Upper Immediate to PC
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMM_B_U;
+ alu_operator_o = ALU_ADD;
+ end
+
+ OPCODE_OP_IMM: begin // Register-Immediate ALU Operations
+ alu_op_a_mux_sel_o = OP_A_REG_A;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMM_B_I;
+
+ unique case (instr_alu[14:12])
+ 3'b000: alu_operator_o = ALU_ADD; // Add Immediate
+ 3'b010: alu_operator_o = ALU_SLT; // Set to one if Lower Than Immediate
+ 3'b011: alu_operator_o = ALU_SLTU; // Set to one if Lower Than Immediate Unsigned
+ 3'b100: alu_operator_o = ALU_XOR; // Exclusive Or with Immediate
+ 3'b110: alu_operator_o = ALU_OR; // Or with Immediate
+ 3'b111: alu_operator_o = ALU_AND; // And with Immediate
+
+ 3'b001: begin
+ alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
+ end
+
+ 3'b101: begin
+ if (instr_alu[31:25] == 7'b0) begin
+ alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate
+ end else if (instr_alu[31:25] == 7'b010_0000) begin
+ alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate
+ end
+ end
+
+ default: ;
+ endcase
+ end
+
+ OPCODE_OP: begin // Register-Register ALU operation
+ alu_op_a_mux_sel_o = OP_A_REG_A;
+ alu_op_b_mux_sel_o = OP_B_REG_B;
+
+ unique case ({instr_alu[30:25], instr_alu[14:12]})
+ // RV32I ALU operations
+ {6'b00_0000, 3'b000}: alu_operator_o = ALU_ADD; // Add
+ {6'b10_0000, 3'b000}: alu_operator_o = ALU_SUB; // Sub
+ {6'b00_0000, 3'b010}: alu_operator_o = ALU_SLT; // Set Lower Than
+ {6'b00_0000, 3'b011}: alu_operator_o = ALU_SLTU; // Set Lower Than Unsigned
+ {6'b00_0000, 3'b100}: alu_operator_o = ALU_XOR; // Xor
+ {6'b00_0000, 3'b110}: alu_operator_o = ALU_OR; // Or
+ {6'b00_0000, 3'b111}: alu_operator_o = ALU_AND; // And
+ {6'b00_0000, 3'b001}: alu_operator_o = ALU_SLL; // Shift Left Logical
+ {6'b00_0000, 3'b101}: alu_operator_o = ALU_SRL; // Shift Right Logical
+ {6'b10_0000, 3'b101}: alu_operator_o = ALU_SRA; // Shift Right Arithmetic
+
+ // supported RV32M instructions, all use the same ALU operation
+ {6'b00_0001, 3'b000}, // mul
+ {6'b00_0001, 3'b001}, // mulh
+ {6'b00_0001, 3'b010}, // mulhsu
+ {6'b00_0001, 3'b011}, // mulhu
+ {6'b00_0001, 3'b100}, // div
+ {6'b00_0001, 3'b101}, // divu
+ {6'b00_0001, 3'b110}, // rem
+ {6'b00_0001, 3'b111}: begin // remu
+ multdiv_sel_o = 1'b1;
+ alu_operator_o = ALU_ADD;
+ end
+
+ default: ;
+ endcase
+ end
+
+ /////////////
+ // Special //
+ /////////////
+
+ OPCODE_MISC_MEM: begin
+ // For now, treat the FENCE (funct3 == 000) instruction as a NOP. This may not be correct
+ // in a system with caches and should be revisited.
+ // FENCE.I will flush the IF stage and prefetch buffer but nothing else.
+ unique case (instr_alu[14:12])
+ 3'b000: begin
+ alu_operator_o = ALU_ADD; // nop
+ alu_op_a_mux_sel_o = OP_A_REG_A;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ end
+ 3'b001: begin
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMM_B_INCR_PC;
+ alu_operator_o = ALU_ADD;
+ end
+ default: ;
+ endcase
+ end
+
+ OPCODE_SYSTEM: begin
+ if (instr_alu[14:12] == 3'b000) begin
+ // non CSR related SYSTEM instructions
+ alu_op_a_mux_sel_o = OP_A_REG_A;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ end else begin
+ // instruction to read/modify CSR
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_a_mux_sel_o = IMM_A_Z;
+ imm_b_mux_sel_o = IMM_B_I; // CSR address is encoded in I imm
+
+ if (instr_alu[14]) begin
+ // rs1 field is used as immediate
+ alu_op_a_mux_sel_o = OP_A_IMM;
+ end else begin
+ alu_op_a_mux_sel_o = OP_A_REG_A;
+ end
+ end
+
+ end
+ default: ;
+ endcase
+ end
+
// make sure instructions accessing non-available registers in RV32E cause illegal
// instruction exceptions
assign illegal_insn_o = illegal_insn | illegal_reg_rv32e;
@@ -628,5 +810,4 @@
// Selectors must be known/valid.
`ASSERT(IbexRegImmAluOpKnown, (opcode == OPCODE_OP_IMM) |->
!$isunknown(instr[14:12]), clk_i, !rst_ni)
-
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 71b4e9a..c470003 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_ex_block.sv
@@ -10,31 +10,39 @@
*/
module ibex_ex_block #(
parameter bit RV32M = 1,
+ parameter bit BranchTargetALU = 0,
parameter MultiplierImplementation = "fast"
) (
- input logic clk_i,
- input logic rst_ni,
+ input logic clk_i,
+ input logic rst_ni,
// ALU
- input ibex_pkg::alu_op_e alu_operator_i,
- input logic [31:0] alu_operand_a_i,
- input logic [31:0] alu_operand_b_i,
+ input ibex_pkg::alu_op_e alu_operator_i,
+ input logic [31:0] alu_operand_a_i,
+ input logic [31:0] alu_operand_b_i,
+
+ // Branch Target ALU
+ // All of these signals are unusued when BranchTargetALU == 0
+ input ibex_pkg::jt_mux_sel_e jt_mux_sel_i,
+ input logic [11:0] bt_operand_imm_i,
+ input logic [31:0] pc_id_i,
// Multiplier/Divider
- input ibex_pkg::md_op_e multdiv_operator_i,
- input logic mult_en_i,
- input logic div_en_i,
- input logic [1:0] multdiv_signed_mode_i,
- input logic [31:0] multdiv_operand_a_i,
- input logic [31:0] multdiv_operand_b_i,
+ input ibex_pkg::md_op_e multdiv_operator_i,
+ input logic mult_en_i,
+ input logic div_en_i,
+ input logic multdiv_sel_i,
+ input logic [1:0] multdiv_signed_mode_i,
+ input logic [31:0] multdiv_operand_a_i,
+ input logic [31:0] multdiv_operand_b_i,
// Outputs
- output logic [31:0] alu_adder_result_ex_o, // to LSU
- output logic [31:0] regfile_wdata_ex_o,
- output logic [31:0] jump_target_o, // to IF
- output logic branch_decision_o, // to ID
+ output logic [31:0] alu_adder_result_ex_o, // to LSU
+ output logic [31:0] regfile_wdata_ex_o,
+ output logic [31:0] jump_target_o, // to IF
+ output logic branch_decision_o, // to ID
- output logic ex_valid_o // EX has valid output
+ output logic ex_valid_o // EX has valid output
);
import ibex_pkg::*;
@@ -44,7 +52,7 @@
logic [32:0] multdiv_alu_operand_b, multdiv_alu_operand_a;
logic [33:0] alu_adder_result_ext;
logic alu_cmp_result, alu_is_equal_result;
- logic multdiv_valid, multdiv_en_sel;
+ logic multdiv_valid;
logic multdiv_en;
/*
@@ -53,10 +61,8 @@
from the multdiv_i module are eliminated
*/
if (RV32M) begin : gen_multdiv_m
- assign multdiv_en_sel = MultiplierImplementation == "fast" ? div_en_i : mult_en_i | div_en_i;
assign multdiv_en = mult_en_i | div_en_i;
end else begin : gen_multdiv_no_m
- assign multdiv_en_sel = 1'b0;
assign multdiv_en = 1'b0;
end
@@ -64,7 +70,25 @@
// branch handling
assign branch_decision_o = alu_cmp_result;
- assign jump_target_o = alu_adder_result_ex_o;
+
+ if (BranchTargetALU) begin : g_branch_target_alu
+ logic [32:0] bt_alu_result;
+
+ assign bt_alu_result = {{19{bt_operand_imm_i[11]}}, bt_operand_imm_i, 1'b0} + pc_id_i;
+
+ assign jump_target_o = (jt_mux_sel_i == JT_ALU) ? alu_adder_result_ex_o : bt_alu_result[31:0];
+ end else begin : g_no_branch_target_alu
+ // Unused jt_mux_sel_i/bt_operand_imm_i/pc_id_i signals causes lint errors, this avoids them
+ ibex_pkg::jt_mux_sel_e unused_jt_mux_sel;
+ logic [11:0] unused_bt_operand_imm;
+ logic [31:0] unused_pc_id;
+
+ assign unused_jt_mux_sel = jt_mux_sel_i;
+ assign unused_bt_operand_imm = bt_operand_imm_i;
+ assign unused_pc_id = pc_id_i;
+
+ assign jump_target_o = alu_adder_result_ex_o;
+ end
/////////
// ALU //
@@ -76,7 +100,7 @@
.operand_b_i ( alu_operand_b_i ),
.multdiv_operand_a_i ( multdiv_alu_operand_a ),
.multdiv_operand_b_i ( multdiv_alu_operand_b ),
- .multdiv_en_i ( multdiv_en_sel ),
+ .multdiv_sel_i ( multdiv_sel_i ),
.adder_result_o ( alu_adder_result_ex_o ),
.adder_result_ext_o ( alu_adder_result_ext ),
.result_o ( alu_result ),
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
index dacfe05..1839d59 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv
@@ -9,6 +9,9 @@
* input port: send address and data to the FIFO
* clear_i clears the FIFO for the following cycle, including any new request
*/
+
+`include "prim_assert.sv"
+
module ibex_fetch_fifo #(
parameter int unsigned NUM_REQS = 2
) (
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
index c06028f..56c8c5a 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv
@@ -13,9 +13,13 @@
* Decode stage of the core. It decodes the instructions and hosts the register
* file.
*/
+
+`include "prim_assert.sv"
+
module ibex_id_stage #(
- parameter bit RV32E = 0,
- parameter bit RV32M = 1
+ parameter bit RV32E = 0,
+ parameter bit RV32M = 1,
+ parameter bit BranchTargetALU = 0
) (
input logic clk_i,
input logic rst_ni,
@@ -30,6 +34,7 @@
input logic instr_valid_i,
input logic instr_new_i,
input logic [31:0] instr_rdata_i, // from IF-ID pipeline registers
+ input logic [31:0] instr_rdata_alu_i, // from IF-ID pipeline registers
input logic [15:0] instr_rdata_c_i, // from IF-ID pipeline registers
input logic instr_is_compressed_i,
output logic instr_req_o,
@@ -58,9 +63,14 @@
output logic [31:0] alu_operand_a_ex_o,
output logic [31:0] alu_operand_b_ex_o,
+ // Branch target ALU
+ output ibex_pkg::jt_mux_sel_e jt_mux_sel_ex_o,
+ output logic [11:0] bt_operand_imm_o,
+
// MUL, DIV
output logic mult_en_ex_o,
output logic div_en_ex_o,
+ output logic multdiv_sel_ex_o,
output ibex_pkg::md_op_e multdiv_operator_ex_o,
output logic [1:0] multdiv_signed_mode_ex_o,
output logic [31:0] multdiv_operand_a_ex_o,
@@ -91,11 +101,8 @@
// Interrupt signals
input logic csr_mstatus_mie_i,
- input logic csr_msip_i,
- input logic csr_mtip_i,
- input logic csr_meip_i,
- input logic [14:0] csr_mfip_i,
input logic irq_pending_i,
+ input ibex_pkg::irqs_t irqs_i,
input logic irq_nm_i,
output logic nmi_mode_o,
@@ -146,7 +153,7 @@
logic wfi_insn_dec;
logic branch_in_dec;
- logic branch_set_n, branch_set_q;
+ logic branch_set, branch_set_d;
logic jump_in_dec;
logic jump_set;
@@ -194,6 +201,7 @@
// Multiplier Control
logic mult_en_id, mult_en_dec; // use integer multiplier
logic div_en_id, div_en_dec; // use integer division or reminder
+ logic multdiv_sel_dec;
logic multdiv_en_dec;
md_op_e multdiv_operator;
logic [1:0] multdiv_signed_mode;
@@ -314,8 +322,9 @@
/////////////
ibex_decoder #(
- .RV32E ( RV32E ),
- .RV32M ( RV32M )
+ .RV32E ( RV32E ),
+ .RV32M ( RV32M ),
+ .BranchTargetALU ( BranchTargetALU )
) decoder_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@@ -332,11 +341,13 @@
// from IF-ID pipeline register
.instr_new_i ( instr_new_i ),
.instr_rdata_i ( instr_rdata_i ),
+ .instr_rdata_alu_i ( instr_rdata_alu_i ),
.illegal_c_insn_i ( illegal_c_insn_i ),
// immediates
.imm_a_mux_sel_o ( imm_a_mux_sel ),
.imm_b_mux_sel_o ( imm_b_mux_sel_dec ),
+ .jt_mux_sel_o ( jt_mux_sel_ex_o ),
.imm_i_type_o ( imm_i_type ),
.imm_s_type_o ( imm_s_type ),
@@ -361,6 +372,7 @@
// MULT & DIV
.mult_en_o ( mult_en_dec ),
.div_en_o ( div_en_dec ),
+ .multdiv_sel_o ( multdiv_sel_dec ),
.multdiv_operator_o ( multdiv_operator ),
.multdiv_signed_mode_o ( multdiv_signed_mode ),
@@ -427,16 +439,13 @@
.store_err_i ( lsu_store_err_i ),
// jump/branch control
- .branch_set_i ( branch_set_q ),
+ .branch_set_i ( branch_set ),
.jump_set_i ( jump_set ),
// interrupt signals
.csr_mstatus_mie_i ( csr_mstatus_mie_i ),
- .csr_msip_i ( csr_msip_i ),
- .csr_mtip_i ( csr_mtip_i ),
- .csr_meip_i ( csr_meip_i ),
- .csr_mfip_i ( csr_mfip_i ),
.irq_pending_i ( irq_pending_i ),
+ .irqs_i ( irqs_i ),
.irq_nm_i ( irq_nm_i ),
.nmi_mode_o ( nmi_mode_o ),
@@ -503,8 +512,17 @@
assign alu_operand_a_ex_o = alu_operand_a;
assign alu_operand_b_ex_o = alu_operand_b;
+ if (BranchTargetALU) begin : g_bt_operand_imm
+ // Branch target ALU sign-extends and inserts bottom 0 bit so only want the
+ // 'raw' B-type immediate bits.
+ assign bt_operand_imm_o = imm_b_type[12:1];
+ end else begin : g_no_bt_operand_imm
+ assign bt_operand_imm_o = '0;
+ end
+
assign mult_en_ex_o = mult_en_id;
assign div_en_ex_o = div_en_id;
+ assign multdiv_sel_ex_o = multdiv_sel_dec;
assign multdiv_operator_ex_o = multdiv_operator;
assign multdiv_signed_mode_ex_o = multdiv_signed_mode;
@@ -518,14 +536,32 @@
// ID-EX/WB Pipeline Register //
////////////////////////////////
+ if (BranchTargetALU) begin : g_branch_set_direct
+ // Branch set fed straight to controller with branch target ALU
+ // (condition pass/fail used same cycle as generated instruction request)
+ assign branch_set = branch_set_d;
+ end else begin : g_branch_set_flopped
+ // Branch set flopped without branch target ALU
+ // (condition pass/fail used next cycle where branch target is calculated)
+ logic branch_set_q;
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ branch_set_q <= 1'b0;
+ end else begin
+ branch_set_q <= branch_set_d;
+ end
+ end
+
+ assign branch_set = branch_set_q;
+ end
+
always_ff @(posedge clk_i or negedge rst_ni) begin : id_wb_pipeline_reg
if (!rst_ni) begin
id_wb_fsm_cs <= IDLE;
- branch_set_q <= 1'b0;
instr_multicycle_done_q <= 1'b0;
end else begin
id_wb_fsm_cs <= id_wb_fsm_ns;
- branch_set_q <= branch_set_n;
instr_multicycle_done_q <= instr_multicycle_done_n;
end
end
@@ -542,7 +578,7 @@
stall_multdiv = 1'b0;
stall_jump = 1'b0;
stall_branch = 1'b0;
- branch_set_n = 1'b0;
+ branch_set_d = 1'b0;
perf_branch_o = 1'b0;
instr_ret_o = 1'b0;
@@ -570,7 +606,7 @@
id_wb_fsm_ns = branch_decision_i ? WAIT_MULTICYCLE : IDLE;
stall_branch = branch_decision_i;
instr_multicycle_done_n = ~branch_decision_i;
- branch_set_n = branch_decision_i;
+ branch_set_d = branch_decision_i;
perf_branch_o = 1'b1;
instr_ret_o = ~branch_decision_i;
end
@@ -640,10 +676,18 @@
(instr_valid_i && !(illegal_c_insn_i || instr_fetch_err_i)) |-> !$isunknown(instr_rdata_i),
clk_i, !rst_ni)
+ // 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)
+
// 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)
+ // Duplicated instruction flops must match
+ `ASSERT(IbexDuplicateInstrMatch, instr_valid_i |-> instr_rdata_i == instr_rdata_alu_i, clk_i, !rst_ni);
+
`ifdef CHECK_MISALIGNED
`ASSERT(IbexMisalignedMemoryAccess, !lsu_addr_incr_req_i, clk_i, !rst_ni)
`endif
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
index 07c5f92..1f9b925 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv
@@ -9,6 +9,9 @@
* Instruction fetch unit: Selection of the next PC, and buffering (sampling) of
* the read instruction.
*/
+
+`include "prim_assert.sv"
+
module ibex_if_stage #(
parameter int unsigned DmHaltAddr = 32'h1A110800,
parameter int unsigned DmExceptionAddr = 32'h1A110808
@@ -32,6 +35,8 @@
output logic instr_valid_id_o, // instr in IF-ID is valid
output logic instr_new_id_o, // instr in IF-ID is new
output logic [31:0] instr_rdata_id_o, // instr for ID stage
+ output logic [31:0] instr_rdata_alu_id_o, // replicated instr for ID stage
+ // to reduce fan-out
output logic [15:0] instr_rdata_c_id_o, // compressed instr for ID stage
// (mtval), meaningful only if
// instr_is_compressed_id_o = 1'b1
@@ -234,6 +239,7 @@
instr_new_id_o <= 1'b0;
instr_valid_id_o <= 1'b0;
instr_rdata_id_o <= '0;
+ instr_rdata_alu_id_o <= '0;
instr_fetch_err_o <= '0;
instr_rdata_c_id_o <= '0;
instr_is_compressed_id_o <= 1'b0;
@@ -244,6 +250,8 @@
if (if_id_pipe_reg_we) begin
instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed;
+ // To reduce fan-out and help timing from the instr_rdata_id flops they are replicated.
+ instr_rdata_alu_id_o <= instr_decompressed;
instr_fetch_err_o <= fetch_err;
instr_rdata_c_id_o <= fetch_rdata[15:0];
instr_is_compressed_id_o <= instr_is_compressed_int;
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 a1f2e44..e9fd74b 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv
@@ -9,6 +9,9 @@
* Load Store Unit, used to eliminate multiple access during processor stalls,
* and to align bytes and halfwords.
*/
+
+`include "prim_assert.sv"
+
module ibex_load_store_unit (
input logic clk_i,
input logic rst_ni,
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
index 6f18d12..5fbbf09 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_fast.sv
@@ -11,6 +11,9 @@
*
* 16x16 kernel multiplier and Long Division
*/
+
+`include "prim_assert.sv"
+
module ibex_multdiv_fast (
input logic clk_i,
input logic rst_ni,
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv
index e5cf71c..95f17e4 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_multdiv_slow.sv
@@ -8,6 +8,9 @@
*
* Baugh-Wooley multiplier and Long Division
*/
+
+`include "prim_assert.sv"
+
module ibex_multdiv_slow (
input logic clk_i,
input logic rst_ni,
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv
index f3d1101..15faa54 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_pkg.sv
@@ -132,6 +132,12 @@
IMM_B_INCR_ADDR
} imm_b_sel_e;
+// Only used when BranchTargetALU == 1
+typedef enum logic {
+ JT_ALU, // Jump target from main ALU
+ JT_BT_ALU // Jump target from specialised branch ALU
+} jt_mux_sel_e;
+
// Regfile write data selection
typedef enum logic [1:0] {
RF_WD_LSU,
@@ -160,6 +166,15 @@
EXC_PC_DBG_EXC // Exception while in debug mode
} exc_pc_sel_e;
+// Interrupt requests
+typedef struct packed {
+ logic irq_software;
+ logic irq_timer;
+ logic irq_external;
+ logic [14:0] irq_fast; // 15 fast interrupts,
+ // one interrupt is reserved for NMI (not visible through mip/mie)
+} irqs_t;
+
// Exception cause
typedef enum logic [5:0] {
EXC_CAUSE_IRQ_SOFTWARE_M = {1'b1, 5'd03},
diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_fpga.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_fpga.sv
index 3ced5d8..13ba74a 100644
--- a/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_fpga.sv
+++ b/hw/vendor/lowrisc_ibex/rtl/ibex_register_file_fpga.sv
@@ -43,7 +43,7 @@
assign rdata_a_o = (raddr_a_i == '0) ? '0 : mem[raddr_a_i];
// async_read b
- assign rdata_b_o = (raddr_b_i == '0) ? '0 : mem[baddr_b_i];
+ assign rdata_b_o = (raddr_b_i == '0) ? '0 : mem[raddr_b_i];
// we select
assign we = (waddr_a_i == '0) ? 1'b0 : we_a_i;
diff --git a/hw/vendor/lowrisc_ibex/shared/prim_assert.core b/hw/vendor/lowrisc_ibex/shared/prim_assert.core
deleted file mode 100644
index 5ded010..0000000
--- a/hw/vendor/lowrisc_ibex/shared/prim_assert.core
+++ /dev/null
@@ -1,17 +0,0 @@
-CAPI=2:
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-
-name: "lowrisc:prim:assert:0.1"
-description: "Assertion primitives"
-filesets:
- files_rtl:
- files:
- - rtl/prim_assert.sv
- file_type: systemVerilogSource
-
-targets:
- default:
- filesets:
- - files_rtl
diff --git a/hw/vendor/lowrisc_ibex/shared/rtl/bus.sv b/hw/vendor/lowrisc_ibex/shared/rtl/bus.sv
index 188a2b8..d25abb3 100644
--- a/hw/vendor/lowrisc_ibex/shared/rtl/bus.sv
+++ b/hw/vendor/lowrisc_ibex/shared/rtl/bus.sv
@@ -51,14 +51,17 @@
input [AddressWidth-1:0] cfg_device_addr_mask [NrDevices]
);
- logic [$clog2(NrHosts)-1:0] host_sel_req, host_sel_resp;
- logic [$clog2(NrDevices)-1:0] device_sel_req, device_sel_resp;
+ localparam int unsigned NumBitsHostSel = NrHosts > 1 ? $clog2(NrHosts) : 1;
+ localparam int unsigned NumBitsDeviceSel = NrDevices > 1 ? $clog2(NrDevices) : 1;
+
+ logic [NumBitsHostSel-1:0] host_sel_req, host_sel_resp;
+ logic [NumBitsDeviceSel-1:0] device_sel_req, device_sel_resp;
// Master select prio arbiter
always_comb begin
for (integer host = NrHosts - 1; host >= 0; host = host - 1) begin
if (host_req_i[host]) begin
- host_sel_req = $clog2(NrHosts)'(host);
+ host_sel_req = NumBitsHostSel'(host);
end
end
end
@@ -68,7 +71,7 @@
for (integer device = 0; device < NrDevices; device = device + 1) begin
if ((host_addr_i[host_sel_req] & cfg_device_addr_mask[device])
== cfg_device_addr_base[device]) begin
- device_sel_req = $clog2(NrDevices)'(device);
+ device_sel_req = NumBitsDeviceSel'(device);
end
end
end
@@ -86,7 +89,7 @@
always_comb begin
for (integer device = 0; device < NrDevices; device = device + 1) begin
- if ($clog2(NrDevices)'(device) == device_sel_req) begin
+ if (NumBitsDeviceSel'(device) == device_sel_req) begin
device_req_o[device] = host_req_i[host_sel_req];
device_we_o[device] = host_we_i[host_sel_req];
device_addr_o[device] = host_addr_i[host_sel_req];
@@ -105,8 +108,7 @@
always_comb begin
for (integer host = 0; host < NrHosts; host = host + 1) begin
host_gnt_o[host] = 1'b0;
-
- if ($clog2(NrHosts)'(host) == host_sel_resp) begin
+ if (NumBitsHostSel'(host) == host_sel_resp) begin
host_rvalid_o[host] = device_rvalid_i[device_sel_resp];
host_err_o[host] = device_err_i[device_sel_resp];
host_rdata_o[host] = device_rdata_i[device_sel_resp];
diff --git a/hw/vendor/lowrisc_ibex/shared/rtl/prim_assert.sv b/hw/vendor/lowrisc_ibex/shared/rtl/prim_assert.sv
deleted file mode 100644
index 8234d61..0000000
--- a/hw/vendor/lowrisc_ibex/shared/rtl/prim_assert.sv
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-// Macros and helper code for using assertions.
-// - Provides default clk and rst options to simplify code
-// - Provides boiler plate template for common assertions
-
-`ifdef UVM
- // report assertion error with UVM if compiled
- package assert_rpt_pkg;
- import uvm_pkg::*;
- `include "uvm_macros.svh"
- function void assert_rpt(string msg);
- `uvm_error("ASSERT FAILED", msg)
- endfunction
- endpackage
-`endif
-
-///////////////////
-// Helper macros //
-///////////////////
-
-// local helper macro to reduce code clutter. undefined at the end of this file
-`ifndef VERILATOR
-`ifndef SYNTHESIS
-`define INC_ASSERT
-`endif
-`endif
-
-// Converts an arbitrary block of code into a Verilog string
-`define PRIM_STRINGIFY(__x) `"__x`"
-
- // ASSERT_RPT is available to change the reporting mechanism when an assert fails
-`define ASSERT_RPT(__name, __msg) \
-`ifdef UVM \
- assert_rpt_pkg::assert_rpt($sformatf("[%m] %s: %s (%s:%0d)", \
- __name, __msg, `__FILE__, `__LINE__)); \
-`else \
- $error("[ASSERT FAILED] [%m] %s: %s", __name, __msg); \
-`endif
-
-///////////////////////////////////////
-// Simple assertion and cover macros //
-///////////////////////////////////////
-
-// Immediate assertion
-// Note that immediate assertions are sensitive to simulation glitches.
-`define ASSERT_I(__name, __prop) \
-`ifdef INC_ASSERT \
- __name: assert (__prop) \
- else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
-`endif
-
-// Assertion in initial block. Can be used for things like parameter checking.
-`define ASSERT_INIT(__name, __prop) \
-`ifdef INC_ASSERT \
- initial \
- __name: assert (__prop) \
- else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
-`endif
-
-// Assertion in final block. Can be used for things like queues being empty
-// at end of sim, all credits returned at end of sim, state machines in idle
-// at end of sim.
-`define ASSERT_FINAL(__name, __prop) \
-`ifdef INC_ASSERT \
- final \
- __name: assert (__prop || $test$plusargs("disable_assert_final_checks")) \
- else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
-`endif
-
-// Assert a concurrent property directly.
-// It can be called as a module (or interface) body item.
-`define ASSERT(__name, __prop, __clk, __rst) \
-`ifdef INC_ASSERT \
- __name: assert property (@(posedge __clk) disable iff (__rst !== '0) (__prop)) \
- else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
-`endif
-// Note: Above we use (__rst !== '0) in the disable iff statements instead of
-// (__rst == '1). This properly disables the assertion in cases when reset is X at
-// the beginning of a simulation. For that case, (reset == '1) does not disable the
-// assertion.
-
-// Assert a concurrent property NEVER happens
-`define ASSERT_NEVER(__name, __prop, __clk, __rst) \
-`ifdef INC_ASSERT \
- __name: assert property (@(posedge __clk) disable iff (__rst !== '0) not (__prop)) \
- else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
-`endif
-
-// Assert that signal has a known value (each bit is either '0' or '1') after reset.
-// It can be called as a module (or interface) body item.
-`define ASSERT_KNOWN(__name, __sig, __clk, __rst) \
-`ifdef INC_ASSERT \
- `ASSERT(__name, !$isunknown(__sig), __clk, __rst) \
-`endif
-
-// Cover a concurrent property
-`define COVER(__name, __prop, __clk, __rst) \
-`ifdef INC_ASSERT \
- __name: cover property (@(posedge __clk) disable iff (__rst !== '0) (__prop)); \
-`endif
-
-//////////////////////////////
-// Complex assertion macros //
-//////////////////////////////
-
-// Assert that signal is an active-high pulse with pulse length of 1 clock cycle
-`define ASSERT_PULSE(__name, __sig, __clk, __rst) \
-`ifdef INC_ASSERT \
- `ASSERT(__name, $rose(__sig) |=> !(__sig), __clk, __rst) \
-`endif
-
-// Assert that valid is known after reset and data is known when valid == 1
-`define ASSERT_VALID_DATA(__name, __valid, __dat, __clk, __rst) \
-`ifdef INC_ASSERT \
- `ASSERT_KNOWN(__name``KnownValid, __valid, __clk, __rst) \
- `ASSERT_NEVER(__name``KnownData, (__valid) && $isunknown(__dat), __clk, __rst) \
-`endif
-
-// Same as ASSERT_VALID_DATA, but also assert that ready is known after reset
-`define ASSERT_VALID_READY_DATA(__name, __valid, __ready, __dat, __clk, __rst) \
-`ifdef INC_ASSERT \
- `ASSERT_KNOWN(__name``KnownValid, __valid, __clk, __rst) \
- `ASSERT_KNOWN(__name``KnownReady, __ready, __clk, __rst) \
- `ASSERT_NEVER(__name``KnownData, (__valid) && $isunknown(__dat), __clk, __rst) \
-`endif
-
-///////////////////////
-// Assumption macros //
-///////////////////////
-
-// Assume a concurrent property
-`define ASSUME(__name, __prop, __clk, __rst) \
-`ifdef INC_ASSERT \
- __name: assume property (@(posedge __clk) disable iff (__rst !== '0) (__prop)) \
- else begin `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) end \
-`endif
-
-// Assume an immediate property
-`define ASSUME_I(__name, __prop) \
-`ifdef INC_ASSERT \
- __name: assume (__prop) \
- else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
-`endif
-
-//////////////////////////////////
-// For formal verification only //
-//////////////////////////////////
-
-// Note that the existing set of ASSERT macros specified above shall be used for FPV,
-// thereby ensuring that the assertions are evaluated during DV simulations as well.
-
-// ASSUME_FPV
-// Assume a concurrent property during formal verification only.
-`define ASSUME_FPV(__name, __prop, __clk, __rst) \
-`ifdef FPV_ON \
- `ASSUME(__name, __prop, __clk, __rst) \
-`endif
-
-// ASSUME_I_FPV
-// Assume a concurrent property during formal verification only.
-`define ASSUME_I_FPV(__name, __prop) \
-`ifdef FPV_ON \
- `ASSUME_I(__name, __prop) \
-`endif
-
-// COVER_FPV
-// Cover a concurrent property during formal verification
-`define COVER_FPV(__name, __prop, __clk, __rst) \
-`ifdef FPV_ON \
- `COVER(__name, __prop, __clk, __rst) \
-`endif
diff --git a/hw/vendor/lowrisc_ibex/shared/rtl/ram_2p.sv b/hw/vendor/lowrisc_ibex/shared/rtl/ram_2p.sv
new file mode 100644
index 0000000..d583fb4
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/shared/rtl/ram_2p.sv
@@ -0,0 +1,125 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+/**
+ * Dual-port RAM with 1 cycle read/write delay, 32 bit words.
+ *
+ * The two ports are in Read-First Mode: when reading from and writing to the same address
+ * simultaneously, the old content is returned, before the new content is written. New content
+ * is made available to both ports with one cycle delay.
+ *
+ * Simultaneous write operations by both ports to the same address are to be avoided: The data
+ * written to memory is not determined.
+ */
+module ram_2p #(
+ parameter int Depth = 128
+) (
+ input clk_i,
+ input rst_ni,
+
+ input a_req_i,
+ input a_we_i,
+ input [ 3:0] a_be_i,
+ input [31:0] a_addr_i,
+ input [31:0] a_wdata_i,
+ output logic a_rvalid_o,
+ output logic [31:0] a_rdata_o,
+
+ input b_req_i,
+ input b_we_i,
+ input [ 3:0] b_be_i,
+ input [31:0] b_addr_i,
+ input [31:0] b_wdata_i,
+ output logic b_rvalid_o,
+ output logic [31:0] b_rdata_o
+);
+
+ localparam int Aw = $clog2(Depth);
+
+ logic [31:0] mem [Depth];
+
+ logic [Aw-1:0] a_addr_idx;
+ assign a_addr_idx = a_addr_i[Aw-1+2:2];
+ logic [31-Aw:0] unused_a_addr_parts;
+ assign unused_a_addr_parts = {a_addr_i[31:Aw+2], a_addr_i[1:0]};
+
+ logic [Aw-1:0] b_addr_idx;
+ assign b_addr_idx = b_addr_i[Aw-1+2:2];
+ logic [31-Aw:0] unused_b_addr_parts;
+ assign unused_b_addr_parts = {b_addr_i[31:Aw+2], b_addr_i[1:0]};
+
+ always @(posedge clk_i) begin
+ if (a_req_i) begin
+ if (a_we_i) begin
+ for (int i = 0; i < 4; i = i + 1) begin
+ if (a_be_i[i] == 1'b1) begin
+ mem[a_addr_idx][i*8 +: 8] <= a_wdata_i[i*8 +: 8];
+ end
+ end
+ end
+ a_rdata_o <= mem[a_addr_idx];
+ end
+ end
+
+ always @(posedge clk_i) begin
+ if (b_req_i) begin
+ if (b_we_i) begin
+ for (int i = 0; i < 4; i = i + 1) begin
+ if (b_be_i[i] == 1'b1) begin
+ mem[b_addr_idx][i*8 +: 8] <= b_wdata_i[i*8 +: 8];
+ end
+ end
+ end
+ b_rdata_o <= mem[b_addr_idx];
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ a_rvalid_o <= '0;
+ end else begin
+ a_rvalid_o <= a_req_i;
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ b_rvalid_o <= '0;
+ end else begin
+ b_rvalid_o <= b_req_i;
+ end
+ end
+
+ `ifdef VERILATOR
+ // Task for loading 'mem' with SystemVerilog system task $readmemh()
+ export "DPI-C" task simutil_verilator_memload;
+ // Function for setting a specific 32 bit element in |mem|
+ // Returns 1 (true) for success, 0 (false) for errors.
+ export "DPI-C" function simutil_verilator_set_mem;
+
+ task simutil_verilator_memload;
+ input string file;
+ $readmemh(file, mem);
+ endtask
+
+ // TODO: Allow 'val' to have other widths than 32 bit
+ function int simutil_verilator_set_mem(input int index,
+ input logic[31:0] val);
+ if (index >= Depth) begin
+ return 0;
+ end
+
+ mem[index] = val;
+ return 1;
+ endfunction
+ `endif
+
+ `ifdef SRAM_INIT_FILE
+ localparam MEM_FILE = `"`SRAM_INIT_FILE`";
+ initial begin
+ $display("Initializing SRAM from %s", MEM_FILE);
+ $readmemh(MEM_FILE, mem);
+ end
+ `endif
+endmodule
diff --git a/hw/vendor/lowrisc_ibex/shared/rtl/timer.sv b/hw/vendor/lowrisc_ibex/shared/rtl/timer.sv
index c4f9fca..f6b754f 100644
--- a/hw/vendor/lowrisc_ibex/shared/rtl/timer.sv
+++ b/hw/vendor/lowrisc_ibex/shared/rtl/timer.sv
@@ -3,6 +3,9 @@
// SPDX-License-Identifier: Apache-2.0
// Example memory mapped timer
+
+`include "prim_assert.sv"
+
module timer #(
// Bus data width (must be 32)
parameter int unsigned DataWidth = 32,
diff --git a/hw/vendor/lowrisc_ibex/shared/sim_shared.core b/hw/vendor/lowrisc_ibex/shared/sim_shared.core
index 42fea45..02ff4d4 100644
--- a/hw/vendor/lowrisc_ibex/shared/sim_shared.core
+++ b/hw/vendor/lowrisc_ibex/shared/sim_shared.core
@@ -11,6 +11,7 @@
files:
- ./rtl/prim_clock_gating.sv
- ./rtl/ram_1p.sv
+ - ./rtl/ram_2p.sv
- ./rtl/bus.sv
- ./rtl/sim/simulator_ctrl.sv
- ./rtl/timer.sv
diff --git a/hw/vendor/lowrisc_ibex/src_files.yml b/hw/vendor/lowrisc_ibex/src_files.yml
index 67513ea..ed49434 100644
--- a/hw/vendor/lowrisc_ibex/src_files.yml
+++ b/hw/vendor/lowrisc_ibex/src_files.yml
@@ -1,6 +1,7 @@
ibex:
incdirs: [
rtl,
+ shared/rtl,
]
files: [
rtl/ibex_pkg.sv,
diff --git a/hw/vendor/lowrisc_ibex/syn/ibex_core_lr_synth_conf.tcl b/hw/vendor/lowrisc_ibex/syn/ibex_core_lr_synth_conf.tcl
index 4d799d8..f3f8622 100644
--- a/hw/vendor/lowrisc_ibex/syn/ibex_core_lr_synth_conf.tcl
+++ b/hw/vendor/lowrisc_ibex/syn/ibex_core_lr_synth_conf.tcl
@@ -51,6 +51,12 @@
set lr_synth_rst_input rst_ni
# clock period in ps, this gives a 250 MHz clock. using the nangate45 library
-# Ibex can meet this on reg2reg paths but sees some failures on the IO paths
+# Ibex can happily meet this on all paths with the lr_synth_abc_clk_uprate
+# setting below. With a lower uprate timing may not be met.
set lr_synth_clk_period 4000.0
+# Amount to subtract from clk period to give the clock period passed to ABC in
+# the synth flow. ABC maps the design to the standard cell library and
+# optimises paths for timing, better results are obtained by giving it a faster
+# clock period so it optimises more.
+set lr_synth_abc_clk_uprate 2000.0
diff --git a/hw/vendor/lowrisc_ibex/syn/tcl/lr_synth_flow_var_setup.tcl b/hw/vendor/lowrisc_ibex/syn/tcl/lr_synth_flow_var_setup.tcl
index b78f35d..0ae986a 100644
--- a/hw/vendor/lowrisc_ibex/syn/tcl/lr_synth_flow_var_setup.tcl
+++ b/hw/vendor/lowrisc_ibex/syn/tcl/lr_synth_flow_var_setup.tcl
@@ -13,6 +13,7 @@
set_flow_var rpt_out "./${lr_synth_out_dir}/reports" "Report output directory"
set_flow_bool_var flatten 1 "flatten"
set_flow_bool_var timing_run 0 "timing run"
+set_flow_bool_var ibex_branch_target_alu 0 "Enable branch target ALU in Ibex"
source $lr_synth_config_file
@@ -43,6 +44,11 @@
set_flow_var sta_paths_per_group 100 "STA paths reported per group"
set_flow_var sta_overall_paths 1000 "STA paths reported in overall report"
puts "clock period: $lr_synth_clk_period ps"
+
+ if { $lr_synth_abc_clk_uprate > $lr_synth_clk_period } {
+ puts "WARNING: abc_clk_uprate must be less than clk_period otherwise ABC will be given a negative clk period"
+ }
+
}
puts "================================================="
diff --git a/hw/vendor/lowrisc_ibex/syn/tcl/yosys_run_synth.tcl b/hw/vendor/lowrisc_ibex/syn/tcl/yosys_run_synth.tcl
index 9d5f055..fcece96 100644
--- a/hw/vendor/lowrisc_ibex/syn/tcl/yosys_run_synth.tcl
+++ b/hw/vendor/lowrisc_ibex/syn/tcl/yosys_run_synth.tcl
@@ -14,7 +14,12 @@
write_sdc_out $lr_synth_sdc_file_in $lr_synth_sdc_file_out
}
-yosys "read -sv ./rtl/prim_clock_gating.v $lr_synth_out_dir/generated/*.v"
+yosys "read_verilog -sv ./rtl/prim_clock_gating.v $lr_synth_out_dir/generated/*.v"
+
+if { $lr_synth_ibex_branch_target_alu } {
+ yosys "chparam -set BranchTargetALU 1 ibex_core"
+}
+
yosys "synth $flatten_opt -top $lr_synth_top_module"
yosys "opt -purge"
@@ -23,8 +28,10 @@
yosys "dfflibmap -liberty $lr_synth_cell_library_path"
yosys "opt"
+set yosys_abc_clk_period [expr $lr_synth_clk_period - $lr_synth_abc_clk_uprate]
+
if { $lr_synth_timing_run } {
- yosys "abc -liberty $lr_synth_cell_library_path -constr $lr_synth_sdc_file_out -D $lr_synth_clk_period"
+ yosys "abc -liberty $lr_synth_cell_library_path -constr $lr_synth_sdc_file_out -D $yosys_abc_clk_period"
} else {
yosys "abc -liberty $lr_synth_cell_library_path"
}
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 d5f652d..3ede25c 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: d23da3862f95954e6374aaec787e0fb0c1878a16
+ rev: f7e35d7939a27ae17b0481eb070e9a36ea335d1f
}
}
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 4de7872..5d12da4 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/README.md
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/README.md
@@ -16,20 +16,9 @@
- Supports mixing directed instructions with random instruction stream
- Debug mode support, with fully randomized debug ROM
- Instruction generation coverage model
-- Communication of information to any integrated SV testbench
-- Co-simulation with multiple ISS : spike, riscv-ovpsim
-
-A CSR test generation script written in Python is also provided, to generate a
-directed test suite that stresses all CSR instructions on all of the CSRs that
-the core implements.
-
-## External contributions and collaborations
-
-This repository is still under active development. We hope the RISC-V processor
-verification platform development to be a collaborative effort of the RISC-V
-community. Free feel to submit issues, feature requests, pull requests through
-Github. You can also send your private collaboration request to [riscv_dv_dev@google.com](riscv_dv_dev@google.com).
-Please refer to CONTRIBUTING.md for license related questions.
+- Handshake communication with testbench
+- Support handcoded assembly test
+- Co-simulation with multiple ISS : spike, riscv-ovpsim, whisper, sail-riscv
## Getting Started
@@ -73,533 +62,18 @@
cov --help
```
-### Setup RISCV-GCC compiler toolchain
+## Document
-- Install [riscv-gcc](https://github.com/riscv/riscv-gcc) toolchain
-- Set environment variable RISCV_GCC to the RISC-V gcc executable
- executable. (example: <install_dir>/bin/riscv32-unknown-elf-gcc)
-- Set environment variable RISCV_OBJCOPY to RISC-v objcopy executable
- executable. (example: <install_dir>/bin/riscv32-unknown-elf-objcopy)
+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)
-```bash
-# Sample .bashrc setup
-export RISCV_TOOLCHAIN=<riscv_gcc_install_path>
-export RISCV_GCC="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-gcc"
-export RISCV_OBJCOPY="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-objcopy"
-```
+## External contributions and collaborations
-### Setup ISS (instruction set simulator)
-
-Currently three ISS are supported, the default ISS is spike. You can install any
-one of below to run ISS simulation.
-
-- [spike](https://github.com/riscv/riscv-isa-sim#) setup
- - Follow the [steps](https://github.com/riscv/riscv-isa-sim#build-steps) to build spike
- - Build spike with "--enable-commitlog"
- - Set environment variable SPIKE_PATH to the directory of the spike binary
-- [riscv-ovpsim](https://github.com/riscv/riscv-ovpsim) setup
- - Download the riscv-ovpsim binary
- - Set environment variable OVPSIM_PATH to the directory of the ovpsim binary
-- [whisper(swerv-ISS)](https://github.com/westerndigitalcorporation/swerv-ISS) setup
- - Follow the instruction to install the ISS, and set WHISPER_ISS to the
- whisper binary
-- [sail-riscv](https://github.com/rems-project/sail-riscv) setup
- - Follow the [steps](https://github.com/rems-project/sail-riscv/blob/master/README.md) to install sail-riscv
- - Set environment variable SAIL_RISCV to the path of sail-riscv binary
-
-```bash
-export SPIKE_PATH=$RISCV_TOOLCHAIN/bin
-export SAIL_RISCV="xx/xxx/ocaml_emulator"
-export OVPSIM_PATH=/xx/xxx/riscv-ovpsim/bin/Linux64
-export WHISPER_ISS="xx/xxx/swerv-ISS/build-Linux/whisper"
-```
-
-## Running the generator
-
-A simple script "run.py" is provided for you to run a single test or a regression.
-
-You can use --help to get the complete command reference:
-
-```bash
-run --help
-```
-
-Here is the command to run a single test:
-
-```bash
-run --test=riscv_arithmetic_basic_test
-```
-You can specify the simulator by "-simulator" option
-
-```bash
-run --test riscv_arithmetic_basic_test --simulator ius
-run --test riscv_arithmetic_basic_test --simulator vcs
-run --test riscv_arithmetic_basic_test --simulator questa
-run --test riscv_arithmetic_basic_test --simulator dsim
-run --test riscv_arithmetic_basic_test --simulator qrun
-```
-The complete test list can be found in [yaml/base_testlist.yaml](https://github.com/google/riscv-dv/blob/master/yaml/base_testlist.yaml). To run a full
-regression, simply use below command
-
-```bash
-run
-```
-
-You can also run multiple generator jobs in parallel through LSF
-
-```bash
-run --lsf_cmd="bsub -Is"
-```
-
-Here's a few more examples of the run command:
-
-```bash
-# Run a single test 10 times
-run --test riscv_arithmetic_basic_test --iterations 10
-
-# Run multiple tests
-run --test riscv_arithmetic_basic_test,riscv_rand_instr_test
-
-# Run a test with verbose logging
-run --test riscv_arithmetic_basic_test --verbose
-
-# Run a test with a specified seed
-run --test riscv_arithmetic_basic_test --seed 123
-
-# Skip the generation, run ISS simulation with previously generated program
-run --test riscv_arithmetic_basic_test --steps iss_sim
-
-# Run the generator only, do not compile and simluation with ISS
-run --test riscv_arithmetic_basic_test --steps gen
-
-# Compile the generator only, do not simulate
-run --test riscv_arithmetic_basic_test --co
-
-....
-```
-
-### Run ISS simulation
-
-You can use -iss to run with different ISS.
-
-```bash
-# Run ISS with spike
-run --test riscv_arithmetic_basic_test --iss spike
-
-# Run ISS with riscv-ovpsim
-run --test riscv_rand_instr_test --iss ovpsim
-
-# Run ISS with whisper (swerv-ISS)
-run --test riscv_rand_instr_test --iss whisper
-
-# Run ISS with sail-riscv
-run --test riscv_rand_instr_test --iss sail
-```
-
-To run with ISS simulation for RV32IMC, you can specify ISA and ABI from command
-line like this:
-
-```bash
-# Run a full regression with RV32IMC
-run --isa rv32imc --mabi ilp32
-```
-
-We have added a flow to run ISS simulation with both spike and riscv-ovpsim,
-the instruction trace from these runs will be cross compared. This could greatly
-speed up your development of new test without the need to simulate against a
-real RISC-V processor.
-
-```bash
-run --test=riscv_rand_instr_test --iss=spike,ovpsim
-run --test=riscv_rand_instr_test --iss=ovpsim,whisper
-run --test=riscv_rand_instr_test --iss=spike,sail
-```
-### Run directed assembly tests
-
-Sometimes it might be useful to run some hand-coded assembly tests to hit some
-corner cases:
-
-```bash
-# Run a single/multiple assembly test
-run --asm_tests asm_test_path1/asm_test1.S,asm_test_path2/asm_test2.S
-
-# Run regression with all assembly tests(*.S) under a given directory
-run --asm_tests asm_test_path1,asm_test_path2
-
-# Run mix between the assembly test and assembly tests under a directory
-run --asm_tests asm_test_path1/asm_test1.S,asm_test_path2
-```
-
-You could also use this approach to integrate the assembly tests
-from other sources to riscv-dv flow.
-
-## Configuration
-
-### Configure the generator to match your processor features
-
-The default configuration of the instruction generator is **RV32IMC** (machine
-mode only). A few pre-defined configurations can be found under "target" directory,
-you can run with these targets if it matches your processor specification.
-
-```bash
-run # Default target rv32imc
-run --target rv32i # rv32i, machine mode only
-run --target rv32imc # rv32imc, machine mode only
-run --target rv64imc # rv64imc, machine mode only
-run --target rv64gc # rv64gc, SV39, M/S/U mode
-```
-
-If you want to have a custom setting for your processor, you can make a copy of
-existing target directory as the template, and modify riscv_core_setting.sv to
-match your processor capability.
-
-```verilog
-// Bit width of RISC-V GPR
-parameter int XLEN = 64;
-
-// Parameter for SATP mode, set to BARE if address translation is not supported
-parameter satp_mode_t SATP_MODE = SV39;
-
-// Supported Privileged mode
-privileged_mode_t supported_privileged_mode[] = {USER_MODE,
- SUPERVISOR_MODE,
- MACHINE_MODE};
-
-// Unsupported instructions
-riscv_instr_name_t unsupported_instr[] = {};
-
-// ISA supported by the processor
-riscv_instr_group_t supported_isa[] = {RV32I, RV32M, RV64I, RV64M};
-
-...
-```
-
-You can then run the generator with "--custom_target <target_dir>"
-
-```bash
-# You need to manually specify isa and mabi for your custom target
-run --custom_target <target_dir> --isa <isa> --mabi <mabi>
-...
-```
-
-### Setup the memory map
-
-Here's a few cases that you might want to allocate the instruction and data
-sections to match the actual memory map
-- The processor has internal memories, and you want to test load/store from
- various internal/externel memory regions
-- The processor implments the PMP feature, and you want to configure the memory
- map to match PMP setting.
-- Virtual address translation is implmented and you want to test load/store from
- sparse memory locations to verify data TLB replacement logic.
-
-You can configure the memory map in [riscv_instr_gen_config.sv](https://github.com/google/riscv-dv/blob/master/src/riscv_instr_gen_config.sv)
-
-```verilog
- mem_region_t mem_region[$] = '{
- '{name:"region_0", size_in_bytes: 4096, xwr: 3'b111},
- '{name:"region_1", size_in_bytes: 4096 * 4, xwr: 3'b111},
- '{name:"region_2", size_in_bytes: 4096 * 2, xwr: 3'b111},
- '{name:"region_3", size_in_bytes: 512, xwr: 3'b111},
- '{name:"region_4", size_in_bytes: 4096, xwr: 3'b111}
- };
-```
-
-Each memory region belongs to a separate section in the generated assembly
-program. You can modify the link script to link each section to the target
-memory location. Please avoid setting a large memory range as it could takes a
-long time to randomly initializing the memory. You can break down a large memory
-region to a few representative small regions which covers all the boundary
-conditions for the load/store testing.
-
-### Setup regression test list
-
-[Test list in YAML format](https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml)
-
-```yaml
-# test : Assembly test name
-# description : Description of this test
-# gen_opts : Instruction generator options
-# iterations : Number of iterations of this test
-# no_iss : Enable/disable ISS simulation (Optional)
-# gen_test : Test name used by the instruction generator
-# 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 log comparison (Optional)
-# compare_opts : Options for the RTL & ISS trace comparison
-
-- test: riscv_arithmetic_basic_test
- description: >
- Arithmetic instruction test, no load/store/branch instructions
- gen_opts: >
- +instr_cnt=10000
- +num_of_sub_program=0
- +no_fence=1
- +no_data_page=1'b1
- +no_branch_jump=1'b1
- +boot_mode=m
- iterations: 2
- gen_test: riscv_instr_base_test
- rtl_test: core_base_test
-
-- test: riscv_csr_test
- description: >
- Stress CSR accesses on all implemented CSRs
- iterations: 2
- no_iss: 1
- rtl_test: core_base_test
- no_post_compare: 1
-
-- test: riscv_directed_asm_test
- description: >
- Hand-coded assembly test to test corner case
- iterations: 1
- asm_tests: <asm_test_dir_path or asm_test_file path>
- rtl_test: core_base_test
-
-```
-
-Note: To automatically generate CSR stress tests without having to explicitly run the
-script, include a test entry `riscv_csr_test` in the testlist as shown in the
-example YAML file above.
-
-
-The generation flow now supports inclusion of handcoded assembly tests into the
-overall regression. To do this, simply create a YAML entry in the appropriate
-testlist as shown above in `riscv_directed_asm_test`, using the `asm_tests`
-field to point to the location of the assembly test file or directory.
-The run flow will then locate these file(s) and include them into the overall
-regression run. These directed test targets can also be run individually from
-the python script, as shown below:
-
-```bash
-
-# Run directed assembly test 10 times
-python3 run.py --test riscv_directed_asm_test --iterations 10
-
-```
-
-Note: when using the `asm_tests` field to specify some directed/handcoded
-assembly tests to the flow, make sure that the `gen_test` field is not defined,
-as this will cause the flow to throw an error.
-
-
-### 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 |
-
-
-### Setup Privileged CSR description (optional)
-
-This YAML description file of all CSRs is only required for the privileged CSR
-test. All other standard tests do not use this description.
-
-[CSR descriptions in YAML
-format](https://github.com/google/riscv-dv/blob/master/yaml/csr_template.yaml)
-
-```yaml
-- csr: CSR_NAME
- description: >
- BRIEF_DESCRIPTION
- address: 0x###
- privilege_mode: MODE (D/M/S/H/U)
- rv32:
- - MSB_FIELD_NAME:
- - description: >
- BRIEF_DESCRIPTION
- - type: TYPE (WPRI/WLRL/WARL/R)
- - reset_val: RESET_VAL
- - msb: MSB_POS
- - lsb: LSB_POS
- - ...
- - ...
- - LSB_FIELD_NAME:
- - description: ...
- - type: ...
- - ...
- rv64:
- - MSB_FIELD_NAME:
- - description: >
- BRIEF_DESCRIPTION
- - type: TYPE (WPRI/WLRL/WARL/R)
- - reset_val: RESET_VAL
- - msb: MSB_POS
- - lsb: LSB_POS
- - ...
- - ...
- - LSB_FIELD_NAME:
- - description: ...
- - type: ...
- - ...
-```
-
-To specify what ISA width should be generated in the test, simply include the
-matching rv32/rv64/rv128 entry and fill in the appropriate CSR field entries.
-
-### Privileged CSR Test Generation (optional)
-
-The CSR generation script is located at
-[scripts/gen_csr_test.py](https://github.com/google/riscv-dv/blob/master/scripts/gen_csr_test.py).
-The CSR test code that this script generates will execute every CSR instruction
-on every processor implemented CSR, writing values to the CSR and then using a
-prediction function to calculate a reference value that will be written into
-another GPR. The reference value will then be compared to the value actually
-stored in the CSR to determine whether to jump to the failure condition or
-continue executing, allowing it to be completely self checking. This script has
-been integrated with run.py. If you want to run it separately, you can get the
-command reference with --help:
-
-```bash
-python3 scripts/gen_csr_test.py --help
-```
-
-### Adding new instruction stream and test
-
-Please refer to src/src/riscv_load_store_instr_lib.sv for an example on how to
-add a new instruction stream.
-After the new instruction stream is created, you can use a runtime option to mix
-it with random instructions
-
-```bash
-//+directed_instr_n=instr_sequence_name,frequency(number of insertions per 1000 instructions)
-+directed_instr_5=riscv_multi_page_load_store_instr_stream,4
-
-// An alternative command line options for directed instruction stream
-+stream_name_0=riscv_multi_page_load_store_instr_stream
-+stream_freq_0=4
-```
-
-## Integrate a new ISS
-
-You can add a new entry in [iss.yaml](https://github.com/google/riscv-dv/blob/master/yaml/iss.yaml)
-
-```yaml
-- iss: new_iss_name
- path_var: ISS_PATH
- cmd: >
- <path_var>/iss_executable --isa=<variant> -l <elf>
-```
-
-Simulate with the new ISS
-
-```bash
-run --test riscv_arithmetic_basic_test --iss new_iss_name
-```
-
-## End-to-end RTL and ISS co-simulation flow
-
-We have collaborated with LowRISC to apply this flow for [IBEX RISC-V core
-verification](https://github.com/lowRISC/ibex/blob/master/doc/verification.rst). You can use
-it as a reference to setup end-to-end co-simulation flow.
-This repo is still under active development, this is the recommended approach to
-customize the instruction generator while keeping the effort of merging
-upstream changes to a minimum.
-- Do not modify the upstream classes directly. When possible, extend from
- the upstream classses and implement your own functionalities.
-- Add your extensions under user_extension directory, and add the files to
- user_extension/user_extension.svh. If you prefer to put your extensions in a
- different directory, you can use "-ext <user_extension_path>" to override the
- user extension path.
-- Create a new target directory and customize the setting and testlist
-- Run the generator with `--custom_target <target_dir> --isa <isa> --mabi <mabi>`
-- Use command line type override to use your extended classes.
- `--sim_opts="+uvm_set_type_override=<upstream_class>,<extended_class>"`
-- If extending `riscv_asm_program_gen` class is desired, must use this command
- line override:
- `--sim_opts="+uvm_set_inst_override=riscv_asm_program_gen,<extended
- class>,'uvm_test_top.asm_gen'"`
-
-You can refer to [riscv-dv extension for ibex](https://github.com/lowRISC/ibex/blob/master/dv/uvm/Makefile#L68) for a working example.
-
-We have plan to open-source the end-to-end environments of other advanced RISC-V
-processors. Stay tuned!
-
-## Handshaking Mechanism
-
-This mechanism allows the generator to generate small, directed sequences of
-instructions that write critical information to a specified address in memory,
-that the testbench monitors for write accesses to.
-This allows for more in-depth verification of scenarios that involve external
-stimulus to the core, such as interrupts and debug requests.
-
-For more information, detailed documentation of this mechanism can be found in
-[HANDSHAKE.md](./HANDSHAKE.md).
-
-## Functional coverage (work in progress)
-
-This flow extracts functional coverage information from the
-instruction trace generated by ISS. It's independent of the instruction generation
-flow and does not require a tracer implementation in the RTL. You can use this
-flow as long as your program can be run with an ISS supported in this flow. The
-flow parses the instruction trace log and converts it to a CSV trace format. After
-that, a SV test is run to process the CSV trace files and sample functional
-coverage from there.
-
-The functional covergroup is defined in [riscv_instr_cover_group.sv](https://github.com/google/riscv-dv/blob/master/src/riscv_instr_cover_group.sv). It includes below major categories:
-- Cover all operands for each instruction
-- Hazard conditions
-- Corner cases like overflow, underflow, divide by zero
-- Aligned/unaligned load/store
-- Positive/negative immediate value
-- Forward/backward branches, branch hit history
-- Hint instruction
-- Illegal instruction
-- All compressed and non-compressed opcode
-- Access to all implemened privileged CSR
-- Exception and interrupt
-
-The functional covergroup is still under active development. Please feel free to
-add anything you are interested or file a bug for any feature request.
-
-Before start, please check the you have modified [riscv_core_setting.sv](https://github.com/google/riscv-dv/blob/master/setting/riscv_core_setting.sv) to reflect your processor capabilities. The covergroup is selectively instantiated based on this setting so that you don't need to deal with excluding unrelated coverpoints later. You also need to get the Spike ISS or riscvOVPsim ISS (riscv-ovpsim) setup before running this flow.
-
-
-```bash
-# Process spike simulation log and collect functional coverage
-cov --dir out/spike_sim
-
-# Get the command reference
-cov --help
-
-# Run the coverage flow with predefined targets
-cov --dir out/spike_sim --target rv32imc
-```
-
-The coverage sampling from the CSV could be time consuming if you have a large
-number of log to process. You can split them to small batches and run with LSF
-in parallel.
+This repository is still under active development. We hope the RISC-V processor
+verification platform development to be a collaborative effort of the RISC-V
+community. Free feel to submit issues, feature requests, pull requests through
+Github. You can also send your private collaboration request to [riscv_dv_dev@google.com](riscv_dv_dev@google.com).
+Please refer to CONTRIBUTING.md for license related questions.
-```
-# Split the run to process 5 CSV at a time, and run with LSF
-cov --dir out/spike_sim --lsf_cmd "bsub ....." -bz 5
-```
## Supporting model
Please file an issue under this repository for any bug report / integration
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/cov.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/cov.py
index ab44e1e..b49178b 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/cov.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/cov.py
@@ -53,7 +53,7 @@
build_cmd += (" --custom_target %s" % argv.custom_target)
if argv.stop_on_first_error:
build_cmd += (" --stop_on_first_error")
- run_cmd(build_cmd)
+ run_cmd(build_cmd, debug_cmd = argv.debug)
def sim_cov(out, cfg, cwd, opts_vec, opts_cov, csv_list):
"""Simulation the coverage collection
@@ -101,7 +101,7 @@
sim_cmd += (" --log_suffix _%d" % file_idx)
if argv.lsf_cmd == "":
logging.info("Processing batch %0d/%0d" % (file_idx+1, batch_cnt))
- run_cmd(sim_cmd)
+ run_cmd(sim_cmd, debug_cmd = argv.debug)
else:
sim_cmd += (" --lsf_cmd \"%s\"" % argv.lsf_cmd)
sim_cmd_list.append(sim_cmd)
@@ -127,8 +127,9 @@
sys.exit(RET_FAIL)
logging.info("Processing trace log under %s" % argv.dir)
if not os.path.isdir(argv.dir) or not os.listdir(argv.dir):
- logging.error("Cannot find %s directory, or it is empty", argv.dir)
- sys.exit(RET_FAIL)
+ if not argv.debug:
+ logging.error("Cannot find %s directory, or it is empty", argv.dir)
+ sys.exit(RET_FAIL)
if argv.core:
"""
If functional coverage is being collected from an RTL core implementation,
@@ -239,6 +240,8 @@
help="Controlling coverage coverpoints")
parser.add_argument("--exp", action="store_true", default=False,
help="Run generator with experimental features")
+ parser.add_argument("-d", "--debug", type=str, default="",
+ help="Generate debug command log file")
return parser
def load_config(args, cwd):
@@ -250,6 +253,8 @@
Returns:
Loaded configuration dictionary.
"""
+ if args.debug:
+ args.debug = open(args.debug, "w")
if args.verbose:
args.opts += "-v"
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/make.bat b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/make.bat
index 6247f7e..2f8439d 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/make.bat
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/make.bat
@@ -9,6 +9,7 @@
)
set SOURCEDIR=source
set BUILDDIR=build
+set SPHINXOPTS="-html_theme classic"
if "%1" == "" goto help
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/appendix.rst b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/appendix.rst
new file mode 100644
index 0000000..6d6028e
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/appendix.rst
@@ -0,0 +1,49 @@
+Appendix
+========
+
+Trace CSV format
+----------------
+
+A standard CSV format is defined for the instruction execution trace. It's used for co-simulation result comparison and functional coverage collection.
+
+.. image:: trace_csv.png
+
+**The CSV format includes the following fields:**
+
+- pc : Program counter (instruction memory address)
+- instr: Instruction name
+- gpr: General purpose register updated by the instruction (rd, fd, vd etc.)
+
+ - Format: <GPR name>:<Value>
+ - GPR can be any integer/floating point/vector register
+ - If more than one general purpose registers are updated, separate them with semicolon
+- csr: Privileged CSR updated by the instruction
+
+ - The same format as the GPR field
+- binary: Instruction binary
+- instr_str: Instruction in assmebly format
+- operand: Instruction operands
+- pad: Unused
+
+**Here's a sample of the CSV trace file:**
+
+.. code-block:: verilog
+
+ pc,instr,gpr,csr,binary,mode,instr_str,operand,pad
+ ffffffff8000000c,c.addi,ra:daab700e,,000000b9,3,"c.addi ra, 14","ra,14",
+ ffffffff8000000e,lui,sp:ff8e6000,,ff8e6137,3,"lui sp, 0xff8e6","sp,0xff8e6",
+ ffffffff80000012,addi,sp:ff8e6541,,54110113,3,"addi sp, sp, 1345","sp,sp,1345",
+ ffffffff80000016,c.li,gp:00000000,,00004181,3,"c.li gp, 0","gp,0",
+ ffffffff80000018,lui,tp:80000000,,80000237,3,"lui tp, 0x80000","tp,0x80000",
+ ffffffff8000001c,lui,t0:f999d000,,f999d2b7,3,"lui t0, 0xf999d","t0,0xf999d",
+ ffffffff80000020,addi,t0:f999cbf0,,bf028293,3,"addi t0, t0, -1040","t0,t0,-1040",
+ ffffffff80000024,lui,t1:0416b000,,0416b337,3,"lui t1, 0x416b","t1,0x416b",
+ ffffffff80000028,addi,t1:0416b6ee,,6ee30313,3,"addi t1, t1, 1774","t1,t1,1774",
+ ffffffff8000002c,lui,t2:e6420000,,e64203b7,3,"lui t2, 0xe6420","t2,0xe6420",
+ ...
+
+To integrate a new ISS or processor with the co-simualtion or coverage flow, user must implement a
+python script to convert the custom trace log format to this CSV format. You can find a sample
+script `here`_.
+
+.. _here: https://github.com/google/riscv-dv/blob/master/scripts/spike_log_to_trace_csv.py
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/conf.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/conf.py
index ec91d3e..f271167 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/conf.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/conf.py
@@ -14,6 +14,7 @@
# import sys
# sys.path.insert(0, os.path.abspath('.'))
from pallets_sphinx_themes import ProjectLink
+import sphinx_rtd_theme
# -- Project information -----------------------------------------------------
@@ -35,6 +36,7 @@
"sphinxcontrib.log_cabinet",
"sphinx_issues",
"rst2pdf.pdfbuilder",
+ 'sphinx_rtd_theme',
]
# Add any paths that contain templates here, relative to this directory.
@@ -51,20 +53,20 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
-html_theme = "jinja"
-html_theme_options = {"index_sidebar_logo": False}
-
-html_context = {
- "project_links": [
- ProjectLink("Source Code", "https://github.com/google/riscv-dv.git"),
- ProjectLink("Issue Tracker", "https://github.com/google/riscv-dv/issues"),
- ]
-}
-
-html_sidebars = {
- "index": ["project.html", "localtoc.html", "searchbox.html"],
- "**": ["localtoc.html", "relations.html", "searchbox.html"],
-}
+html_theme = "sphinx_rtd_theme"
+#html_theme_options = {"index_sidebar_logo": False}
+#
+#html_context = {
+# "project_links": [
+# ProjectLink("Source Code", "https://github.com/google/riscv-dv.git"),
+# ProjectLink("Issue Tracker", "https://github.com/google/riscv-dv/issues"),
+# ]
+#}
+#
+#html_sidebars = {
+# "index": ["project.html", "localtoc.html", "searchbox.html"],
+# "**": ["localtoc.html", "relations.html", "searchbox.html"],
+#}
# -- For PDF output ---------------------------------------------------------
pdf_documents = [('index', u'riscv-dv', u'RISCV-DV', u'Google, Inc'),]
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 1cd3038..3c4e481 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
@@ -108,7 +108,7 @@
gen_test: riscv_instr_base_test
rtl_test: core_base_test
-.. _YAML format: https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml
+.. _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
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/customize_extend_generator.rst b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/customize_extend_generator.rst
index 7bd3a4f..59e846a 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/customize_extend_generator.rst
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/customize_extend_generator.rst
@@ -1,2 +1,29 @@
Customize and Extend Generator
==============================
+
+Add custom instructions
+-----------------------
+
+1. Add the new instruction enum to `riscv_custom_instr_enum.sv`_
+
+.. code-block:: verilog
+
+ CUSTOM_ADD,
+ CUSTOM_SUB,
+ ...
+
+2. Add custom instruction definition to `rv32x_instr.sv`_/`rv64x_instr.sv`_
+
+.. code-block:: verilog
+
+ `DEFINE_CUSTOM_INSTR(CUSTOM_ADD, R_FORMAT, ARITHMETIC, RV32X)
+ `DEFINE_CUSTOM_INSTR(CUSTOM_SUB, R_FORMAT, ARITHMETIC, RV32X)
+ ...
+
+3. Extend `riscv_custom_instr.sv`_ and implement key functions like get_instr_name, convert2asm
+4. Add RV32X/RV64X to supported_isa in riscv_core_setting.sv
+
+.. _riscv_custom_instr_enum.sv: https://github.com/google/riscv-dv/blob/master/src/isa/custom/riscv_custom_instr_enum.sv
+.. _riscv_custom_instr.sv: https://github.com/google/riscv-dv/blob/master/src/isa/custom/riscv_custom_instr.sv
+.. _rv32x_instr.sv: https://github.com/google/riscv-dv/blob/master/src/isa/custom/rv32x_instr.sv
+.. _rv64x_instr.sv: https://github.com/google/riscv-dv/blob/master/src/isa/custom/rv64x_instr.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 d2582f9..a53a183 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
@@ -179,21 +179,24 @@
run --test=riscv_rand_instr_test --iss=ovpsim,whisper
run --test=riscv_rand_instr_test --iss=spike,sail
-Run directed assembly tests
+Run directed assembly/C tests
---------------------------
-Sometimes it might be useful to run some hand-coded assembly tests to hit some
+Sometimes it might be useful to run some hand-coded assembly/C tests to hit some
corner cases::
- # Run a single/multiple assembly test
+ # Run a single/multiple assembly/C test
run --asm_tests asm_test_path1/asm_test1.S,asm_test_path2/asm_test2.S
+ run --c_tests c_test_path1/c_test1.c,c_test_path2/c_test2.c
- # Run regression with all assembly tests(*.S) under a given directory
+ # Run regression with all assembly tests(*.S)/ C tests(*.c) under a given directory
run --asm_tests asm_test_path1,asm_test_path2
+ run --c_tests c_test_path1,c_test_path2
- # Run mix between the assembly test and assembly tests under a directory
+ # Run mix between the assembly/C test and assembly/C tests under a directory
run --asm_tests asm_test_path1/asm_test1.S,asm_test_path2
+ run --c_tests c_test_path1/c_test1.c,c_test_path2
-You could also use this approach to integrate the assembly tests
+You could also use this approach to integrate the assembly/C tests
from other sources to riscv-dv flow.
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/index.rst b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/index.rst
index 332fb6c..1a9dc61 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/index.rst
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/index.rst
@@ -19,6 +19,7 @@
customize_extend_generator
class_reference
cmd_line_reference
+ appendix
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/trace_csv.png b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/trace_csv.png
new file mode 100644
index 0000000..f694a96
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/docs/source/trace_csv.png
Binary files differ
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/qrun_option.f b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/qrun_option.f
index bd1de09..0d2998d 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/qrun_option.f
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/qrun_option.f
@@ -1,6 +1,7 @@
-64
-uvmhome uvm-1.2
-sv
+-access=rwc+/.
-mfcu
-cuname design_cuname
+define+UVM_REGEX_NO_DPI
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/requirements.txt b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/requirements.txt
index 57100e4..e616e98 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/requirements.txt
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/requirements.txt
@@ -4,4 +4,5 @@
Pallets-Sphinx-Themes
sphinxcontrib-log-cabinet
sphinx-issues
+sphinx_rtd_theme
rst2pdf
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 b5c0c91..7fcdbfe 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/run.py
@@ -33,7 +33,7 @@
LOGGER = logging.getLogger()
-def get_generator_cmd(simulator, simulator_yaml, cov, exp):
+def get_generator_cmd(simulator, simulator_yaml, cov, exp, debug_cmd):
""" Setup the compile and simulation command for the generator
Args:
@@ -41,6 +41,7 @@
simulator_yaml : RTL simulator configuration file in YAML format
cov : Enable functional coverage
exp : Use experimental version
+ debug_cmd : Produce the debug cmd log without running
Returns:
compile_cmd : RTL simulator command to compile the instruction generator
@@ -69,14 +70,15 @@
if 'env_var' in entry:
for env_var in entry['env_var'].split(','):
for i in range(len(compile_cmd)):
- compile_cmd[i] = re.sub("<"+env_var+">", get_env_var(env_var), compile_cmd[i])
- sim_cmd = re.sub("<"+env_var+">", get_env_var(env_var), sim_cmd)
+ compile_cmd[i] = re.sub("<"+env_var+">", get_env_var(env_var, debug_cmd = debug_cmd),
+ compile_cmd[i])
+ sim_cmd = re.sub("<"+env_var+">", get_env_var(env_var, debug_cmd = debug_cmd), sim_cmd)
return compile_cmd, sim_cmd
logging.error("Cannot find RTL simulator %0s" % simulator)
sys.exit(RET_FAIL)
-def parse_iss_yaml(iss, iss_yaml, isa, setting_dir):
+def parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd):
"""Parse ISS YAML to get the simulation command
Args:
@@ -84,6 +86,7 @@
iss_yaml : ISS configuration file in YAML format
isa : ISA variant passed to the ISS
setting_dir : Generator setting directory
+ debug_cmd : Produce the debug cmd log without running
Returns:
cmd : ISS run command
@@ -95,7 +98,7 @@
if entry['iss'] == iss:
logging.info("Found matching ISS: %s" % entry['iss'])
cmd = entry['cmd'].rstrip()
- cmd = re.sub("\<path_var\>", get_env_var(entry['path_var']), cmd)
+ cmd = re.sub("\<path_var\>", get_env_var(entry['path_var'], debug_cmd = debug_cmd), cmd)
m = re.search(r"rv(?P<xlen>[0-9]+?)(?P<variant>[a-z]+?)$", isa)
if m:
cmd = re.sub("\<xlen\>", m.group('xlen'), cmd)
@@ -130,7 +133,9 @@
cmd += (" &> %s" % log)
return cmd
-def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir, cmp_opts, output_dir):
+
+def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir,
+ cmp_opts, output_dir, debug_cmd):
"""Compile the instruction generator
Args:
@@ -141,6 +146,7 @@
ext_dir : User extension directory
cmd_opts : Compile options for the generator
output_dir : Output directory of the ELF files
+ debug_cmd : Produce the debug cmd log without running
"""
if (not((len(test_list) == 1) and (test_list[0]['test'] == 'riscv_csr_test'))):
logging.info("Building RISC-V instruction generator")
@@ -155,10 +161,11 @@
cmd = re.sub("<cmp_opts>", cmp_opts, cmd)
logging.debug("Compile command: %s" % cmd)
- run_cmd(cmd)
+ run_cmd(cmd, debug_cmd = debug_cmd)
+
def run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
- end_signature_addr, timeout_s, output_dir):
+ end_signature_addr, timeout_s, output_dir, debug_cmd):
"""Run CSR test
It calls a separate python script to generate directed CSR test code,
located at scripts/gen_csr_test.py.
@@ -172,11 +179,12 @@
if lsf_cmd:
cmd_list.append(cmd)
else:
- run_cmd(cmd, timeout_s)
+ run_cmd(cmd, timeout_s, debug_cmd = debug_cmd)
+
def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
isa, end_signature_addr, lsf_cmd, timeout_s, log_suffix,
- batch_size, output_dir, verbose, check_return_code):
+ batch_size, output_dir, verbose, check_return_code, debug_cmd):
"""Run the instruction generator
Args:
@@ -195,6 +203,7 @@
batch_size : Number of tests to generate per run
output_dir : Output directory of the ELF files
check_return_code : Check return code of the command
+ debug_cmd : Produce the debug cmd log without running
"""
cmd_list = []
sim_cmd = re.sub("<out>", os.path.abspath(output_dir), sim_cmd)
@@ -212,7 +221,7 @@
# Running a CSR test
if test['test'] == 'riscv_csr_test':
run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
- end_signature_addr, timeout_s, output_dir)
+ end_signature_addr, timeout_s, output_dir, debug_cmd)
else:
batch_cnt = 1
if batch_size > 0:
@@ -247,12 +256,13 @@
else:
logging.info("Running %s, batch %0d/%0d, test_cnt:%0d" %
(test['test'], i+1, batch_cnt, test_cnt))
- run_cmd(cmd, timeout_s, check_return_code = check_return_code)
+ run_cmd(cmd, timeout_s, check_return_code = check_return_code, debug_cmd = debug_cmd)
if sim_seed:
with open(('%s/seed.yaml' % os.path.abspath(output_dir)) , 'w') as outfile:
yaml.dump(sim_seed, outfile, default_flow_style=False)
if lsf_cmd:
- run_parallel_cmd(cmd_list, timeout_s, check_return_code = check_return_code)
+ run_parallel_cmd(cmd_list, timeout_s, check_return_code = check_return_code,
+ debug_cmd = debug_cmd)
def gen(test_list, cfg, output_dir, cwd):
@@ -281,19 +291,20 @@
# Setup the compile and simulation command for the generator
compile_cmd = []
sim_cmd = ""
- compile_cmd, sim_cmd = get_generator_cmd(argv.simulator, argv.simulator_yaml, argv.cov, argv.exp);
+ compile_cmd, sim_cmd = get_generator_cmd(argv.simulator, argv.simulator_yaml, argv.cov,
+ argv.exp, argv.debug);
# 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.cmp_opts, output_dir, argv.debug)
# 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,
argv.isa, argv.end_signature_addr, argv.lsf_cmd, argv.gen_timeout, argv.log_suffix,
- argv.batch_size, output_dir, argv.verbose, check_return_code)
+ argv.batch_size, output_dir, argv.verbose, check_return_code, argv.debug)
-def gcc_compile(test_list, output_dir, isa, mabi, opts):
+def gcc_compile(test_list, output_dir, isa, mabi, opts, debug_cmd):
"""Use riscv gcc toolchain to compile the assembly program
Args:
@@ -301,6 +312,7 @@
output_dir : Output directory of the ELF files
isa : ISA variant passed to GCC
mabi : MABI variant passed to GCC
+ debug_cmd : Produce the debug cmd log without running
"""
cwd = os.path.dirname(os.path.realpath(__file__))
for test in test_list:
@@ -312,7 +324,7 @@
elf = prefix + ".o"
binary = prefix + ".bin"
test_isa = isa
- if not os.path.isfile(asm):
+ if not os.path.isfile(asm) and not debug_cmd:
logging.error("Cannot find assembly test: %s\n", asm)
sys.exit(RET_FAIL)
# gcc comilation
@@ -321,7 +333,7 @@
-nostartfiles %s \
-I%s/user_extension \
-T%s/scripts/link.ld %s -o %s " % \
- (get_env_var("RISCV_GCC"), asm, cwd, cwd, opts, elf))
+ (get_env_var("RISCV_GCC", debug_cmd = debug_cmd), asm, cwd, cwd, opts, elf))
if 'gcc_opts' in test:
cmd += test['gcc_opts']
if 'gen_opts' in test:
@@ -335,15 +347,16 @@
if not re.search('mabi', cmd):
cmd += (" -mabi=%s" % mabi)
logging.info("Compiling %s" % asm)
- run_cmd_output(cmd.split())
+ run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
# Convert the ELF to plain binary, used in RTL sim
logging.info("Converting to %s" % binary)
- cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY"), elf, binary))
- run_cmd_output(cmd.split())
+ cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY", debug_cmd = debug_cmd),
+ elf, binary))
+ run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
def run_assembly(asm_test, iss_yaml, isa, mabi, gcc_opts, iss_opts, output_dir,
- setting_dir):
+ setting_dir, debug_cmd):
"""Run a directed assembly test with ISS
Args:
@@ -355,6 +368,7 @@
iss_opts : Instruction set simulators
output_dir : Output directory of compiled test files
setting_dir : Generator setting directory
+ debug_cmd : Produce the debug cmd log without running
"""
if not asm_test.endswith(".S"):
logging.error("%s is not an assembly .S file" % asm_test)
@@ -377,30 +391,32 @@
-nostartfiles %s \
-I%s/user_extension \
-T%s/scripts/link.ld %s -o %s " % \
- (get_env_var("RISCV_GCC"), asm_test, cwd, cwd, gcc_opts, elf))
+ (get_env_var("RISCV_GCC", debug_cmd = debug_cmd), asm_test, cwd,
+ cwd, gcc_opts, elf))
cmd += (" -march=%s" % isa)
cmd += (" -mabi=%s" % mabi)
- run_cmd_output(cmd.split())
+ run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
# Convert the ELF to plain binary, used in RTL sim
logging.info("Converting to %s" % binary)
- cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY"), elf, binary))
- run_cmd_output(cmd.split())
+ cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY", debug_cmd = debug_cmd), elf, binary))
+ run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
log_list = []
# ISS simulation
for iss in iss_list:
run_cmd("mkdir -p %s/%s_sim" % (output_dir, iss))
log = ("%s/%s_sim/%s.log" % (output_dir, iss, asm))
log_list.append(log)
- base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir)
+ base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd)
logging.info("[%0s] Running ISS simulation: %s" % (iss, elf))
cmd = get_iss_cmd(base_cmd, elf, log)
- run_cmd(cmd, 10)
+ run_cmd(cmd, 10, debug_cmd = debug_cmd)
logging.info("[%0s] Running ISS simulation: %s ...done" % (iss, elf))
if len(iss_list) == 2:
compare_iss_log(iss_list, log_list, report)
+
def run_assembly_from_dir(asm_test_dir, iss_yaml, isa, mabi, gcc_opts, iss,
- output_dir, setting_dir):
+ output_dir, setting_dir, debug_cmd):
"""Run a directed assembly test from a directory with spike
Args:
@@ -412,6 +428,7 @@
iss : Instruction set simulators
output_dir : Output directory of compiled test files
setting_dir : Generator setting directory
+ debug_cmd : Produce the debug cmd log without running
"""
result = run_cmd("find %s -name \"*.S\"" % asm_test_dir)
if result:
@@ -420,14 +437,105 @@
(len(asm_list), asm_test_dir))
for asm_file in asm_list:
run_assembly(asm_file, iss_yaml, isa, mabi, gcc_opts, iss, output_dir,
- setting_dir)
+ setting_dir, debug_cmd)
if "," in iss:
report = ("%s/iss_regr.log" % output_dir).rstrip()
save_regr_report(report)
else:
logging.error("No assembly test(*.S) found under %s" % asm_test_dir)
-def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, setting_dir, timeout_s):
+
+def run_c(c_test, iss_yaml, isa, mabi, gcc_opts, iss_opts, output_dir,
+ setting_dir, debug_cmd):
+ """Run a directed c test with ISS
+
+ Args:
+ c_test : C test file
+ iss_yaml : ISS configuration file in YAML format
+ isa : ISA variant passed to the ISS
+ mabi : MABI variant passed to GCC
+ gcc_opts : User-defined options for GCC compilation
+ iss_opts : Instruction set simulators
+ output_dir : Output directory of compiled test files
+ setting_dir : Generator setting directory
+ debug_cmd : Produce the debug cmd log without running
+ """
+ if not c_test.endswith(".c"):
+ logging.error("%s is not a .c file" % c_test)
+ return
+ cwd = os.path.dirname(os.path.realpath(__file__))
+ c_test = os.path.expanduser(c_test)
+ report = ("%s/iss_regr.log" % output_dir).rstrip()
+ c = re.sub(r"^.*\/", "", c_test)
+ c = re.sub(r"\.c$", "", c)
+ prefix = ("%s/directed_c_tests/%s" % (output_dir, c))
+ elf = prefix + ".o"
+ binary = prefix + ".bin"
+ iss_list = iss_opts.split(",")
+ run_cmd("mkdir -p %s/directed_c_tests" % output_dir)
+ logging.info("Compiling c test : %s" % c_test)
+
+ # gcc compilation
+ cmd = ("%s -mcmodel=medany -nostdlib \
+ -nostartfiles %s \
+ -I%s/user_extension \
+ -T%s/scripts/link.ld %s -o %s " % \
+ (get_env_var("RISCV_GCC", debug_cmd = debug_cmd), c_test, cwd,
+ cwd, gcc_opts, elf))
+ cmd += (" -march=%s" % isa)
+ cmd += (" -mabi=%s" % mabi)
+ run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
+ # Convert the ELF to plain binary, used in RTL sim
+ logging.info("Converting to %s" % binary)
+ cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY", debug_cmd = debug_cmd), elf, binary))
+ run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
+ log_list = []
+ # ISS simulation
+ for iss in iss_list:
+ run_cmd("mkdir -p %s/%s_sim" % (output_dir, iss))
+ log = ("%s/%s_sim/%s.log" % (output_dir, iss, c))
+ log_list.append(log)
+ base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd)
+ logging.info("[%0s] Running ISS simulation: %s" % (iss, elf))
+ cmd = get_iss_cmd(base_cmd, elf, log)
+ run_cmd(cmd, 10, debug_cmd = debug_cmd)
+ logging.info("[%0s] Running ISS simulation: %s ...done" % (iss, elf))
+ if len(iss_list) == 2:
+ compare_iss_log(iss_list, log_list, report)
+
+
+def run_c_from_dir(c_test_dir, iss_yaml, isa, mabi, gcc_opts, iss,
+ output_dir, setting_dir, debug_cmd):
+ """Run a directed c test from a directory with spike
+
+ Args:
+ c_test_dir : C test file directory
+ iss_yaml : ISS configuration file in YAML format
+ isa : ISA variant passed to the ISS
+ mabi : MABI variant passed to GCC
+ gcc_opts : User-defined options for GCC compilation
+ iss : Instruction set simulators
+ output_dir : Output directory of compiled test files
+ setting_dir : Generator setting directory
+ debug_cmd : Produce the debug cmd log without running
+ """
+ result = run_cmd("find %s -name \"*.c\"" % c_test_dir)
+ if result:
+ c_list = result.splitlines()
+ logging.info("Found %0d c tests under %s" %
+ (len(c_list), c_test_dir))
+ for c_file in c_list:
+ run_c(c_file, iss_yaml, isa, mabi, gcc_opts, iss, output_dir,
+ setting_dir, debug_cmd)
+ if "," in iss:
+ report = ("%s/iss_regr.log" % output_dir).rstrip()
+ save_regr_report(report)
+ else:
+ 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):
"""Run ISS simulation with the generated test program
Args:
@@ -438,10 +546,11 @@
isa : ISA variant passed to the ISS
setting_dir : Generator setting directory
timeout_s : Timeout limit in seconds
+ debug_cmd : Produce the debug cmd log without running
"""
for iss in iss_list.split(","):
log_dir = ("%s/%s_sim" % (output_dir, iss))
- base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir)
+ base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd)
logging.info("%s sim log dir: %s" % (iss, log_dir))
run_cmd_output(["mkdir", "-p", log_dir])
for test in test_list:
@@ -455,13 +564,13 @@
cmd = get_iss_cmd(base_cmd, elf, log)
logging.info("Running %s sim: %s" % (iss, elf))
if iss == "ovpsim":
- run_cmd(cmd, timeout_s, check_return_code=False)
+ run_cmd(cmd, timeout_s, check_return_code=False, debug_cmd = debug_cmd)
else:
- run_cmd(cmd, timeout_s)
+ run_cmd(cmd, timeout_s, debug_cmd = debug_cmd)
logging.debug(cmd)
-def iss_cmp(test_list, iss, output_dir, stop_on_first_error, exp):
+def iss_cmp(test_list, iss, output_dir, stop_on_first_error, exp, debug_cmd):
"""Compare ISS simulation reult
Args:
@@ -470,7 +579,10 @@
output_dir : Output directory of the ELF files
stop_on_first_error : will end run on first error detected
exp : Use experimental version
+ debug_cmd : Produce the debug cmd log without running
"""
+ if debug_cmd:
+ return
iss_list = iss.split(",")
if len(iss_list) != 2:
return
@@ -488,6 +600,7 @@
compare_iss_log(iss_list, log_list, report, stop_on_first_error, exp)
save_regr_report(report)
+
def compare_iss_log(iss_list, log_list, report, stop_on_first_error=0, exp=False):
if (len(iss_list) != 2 or len(log_list) != 2) :
logging.error("Only support comparing two ISS logs")
@@ -593,6 +706,8 @@
help="Path for the user extension directory")
parser.add_argument("--asm_tests", type=str, default="",
help="Directed assembly tests")
+ parser.add_argument("--c_tests", type=str, default="",
+ help="Directed c tests")
parser.add_argument("--log_suffix", type=str, default="",
help="Simulation log name suffix")
parser.add_argument("--exp", action="store_true", default=False,
@@ -605,8 +720,11 @@
help="Stop on detecting first error")
parser.add_argument("--noclean", action="store_true", default=True,
help="Do not clean the output of the previous runs")
+ parser.add_argument("-d", "--debug", type=str, default="",
+ help="Generate debug command log file")
return parser
+
def load_config(args, cwd):
"""
Load configuration from the command line and the configuration file.
@@ -615,6 +733,8 @@
Returns:
Loaded configuration dictionary.
"""
+ if args.debug:
+ args.debug = open(args.debug, "w")
if not args.csr_yaml:
args.csr_yaml = cwd + "/yaml/csr_template.yaml"
@@ -666,6 +786,7 @@
cfg = vars(args)
return cfg
+
def main():
"""This is the main entry point."""
try:
@@ -687,11 +808,31 @@
# path_asm_test is a directory
if os.path.isdir(full_path):
run_assembly_from_dir(full_path, args.iss_yaml, args.isa, args.mabi,
- args.gcc_opts, args.iss, output_dir, args.core_setting_dir)
+ args.gcc_opts, args.iss, output_dir,
+ args.core_setting_dir, args.debug)
# path_asm_test is an assembly file
- elif os.path.isfile(full_path):
+ elif os.path.isfile(full_path) or args.debug:
run_assembly(full_path, args.iss_yaml, args.isa, args.mabi, args.gcc_opts,
- args.iss, output_dir, args.core_setting_dir)
+ args.iss, output_dir, args.core_setting_dir, args.debug)
+ else:
+ logging.error('%s does not exist' % full_path)
+ sys.exit(RET_FAIL)
+ return
+
+ # Run any handcoded/directed c tests specified by args.c_tests
+ if args.c_tests != "":
+ c_test = args.c_tests.split(',')
+ for path_c_test in c_test:
+ full_path = os.path.expanduser(path_c_test)
+ # path_c_test is a directory
+ if os.path.isdir(full_path):
+ run_c_from_dir(full_path, args.iss_yaml, args.isa, args.mabi,
+ args.gcc_opts, args.iss, output_dir,
+ args.core_setting_dir, args.debug)
+ # path_c_test is a c file
+ elif os.path.isfile(full_path) or args.debug:
+ run_c(full_path, args.iss_yaml, args.isa, args.mabi, args.gcc_opts,
+ args.iss, output_dir, args.core_setting_dir, args.debug)
else:
logging.error('%s does not exist' % full_path)
sys.exit(RET_FAIL)
@@ -701,27 +842,38 @@
# Process regression test list
matched_list = []
# Any tests in the YAML test list that specify a directed assembly test
- directed_list = []
+ asm_directed_list = []
+ # Any tests in the YAML test list that specify a directed c test
+ c_directed_list = []
if not args.co:
process_regression_list(args.testlist, args.test, args.iterations, matched_list, cwd)
for t in list(matched_list):
+ # Check mutual exclusive between gen_test, asm_tests, and c_tests
if 'asm_tests' in t:
- if 'gen_test' in t:
- logging.error('asm_test must not be defined in the testlist '
- 'together with the gen_test field')
+ if 'gen_test' in t or 'c_tests' in t:
+ logging.error('asm_tests must not be defined in the testlist '
+ 'together with the gen_test or c_tests field')
sys.exit(RET_FATAL)
- directed_list.append(t)
+ asm_directed_list.append(t)
matched_list.remove(t)
- if len(matched_list) == 0 and len(directed_list) == 0:
+ if 'c_tests' in t:
+ if 'gen_test' in t or 'asm_tests' in t:
+ logging.error('c_tests must not be defined in the testlist '
+ 'together with the gen_test or asm_tests field')
+ sys.exit(RET_FATAL)
+ c_directed_list.append(t)
+ matched_list.remove(t)
+
+ if len(matched_list) == 0 and len(asm_directed_list) == 0 and len(c_directed_list) == 0:
sys.exit("Cannot find %s in %s" % (args.test, args.testlist))
# Run instruction generator
if args.steps == "all" or re.match(".*gen.*", args.steps):
# Run any handcoded/directed assembly tests specified in YAML format
- if len(directed_list) != 0:
- for test_entry in directed_list:
+ if len(asm_directed_list) != 0:
+ for test_entry in asm_directed_list:
gcc_opts = args.gcc_opts
gcc_opts += test_entry.get('gcc_opts', '')
path_asm_test = os.path.expanduser(test_entry.get('asm_tests'))
@@ -729,30 +881,56 @@
# path_asm_test is a directory
if os.path.isdir(path_asm_test):
run_assembly_from_dir(path_asm_test, args.iss_yaml, args.isa, args.mabi,
- gcc_opts, args.iss, output_dir, args.core_setting_dir)
+ gcc_opts, args.iss, output_dir,
+ args.core_setting_dir, args.debug)
# path_asm_test is an assembly file
elif os.path.isfile(path_asm_test):
run_assembly(path_asm_test, args.iss_yaml, args.isa, args.mabi, gcc_opts,
- args.iss, output_dir, args.core_setting_dir)
+ args.iss, output_dir, args.core_setting_dir, args.debug)
else:
- logging.error('%s does not exist' % path_asm_test)
- sys.exit(RET_FAIL)
+ if not args.debug:
+ logging.error('%s does not exist' % path_asm_test)
+ sys.exit(RET_FAIL)
+
+ # Run any handcoded/directed C tests specified in YAML format
+ if len(c_directed_list) != 0:
+ for test_entry in c_directed_list:
+ gcc_opts = args.gcc_opts
+ gcc_opts += test_entry.get('gcc_opts', '')
+ path_c_test = os.path.expanduser(test_entry.get('c_tests'))
+ if path_c_test:
+ # path_c_test is a directory
+ if os.path.isdir(path_c_test):
+ run_c_from_dir(path_c_test, args.iss_yaml, args.isa, args.mabi,
+ gcc_opts, args.iss, output_dir,
+ args.core_setting_dir, args.debug)
+ # path_c_test is a C file
+ elif os.path.isfile(path_c_test):
+ run_c(path_c_test, args.iss_yaml, args.isa, args.mabi, gcc_opts,
+ args.iss, output_dir, args.core_setting_dir, args.debug)
+ else:
+ if not args.debug:
+ logging.error('%s does not exist' % path_c_test)
+ sys.exit(RET_FAIL)
+
# Run remaining tests using the instruction generator
gen(matched_list, cfg, output_dir, cwd)
if not args.co:
# Compile the assembly program to ELF, convert to plain binary
if args.steps == "all" or re.match(".*gcc_compile.*", args.steps):
- gcc_compile(matched_list, output_dir, args.isa, args.mabi, args.gcc_opts)
+ gcc_compile(matched_list, output_dir, args.isa, args.mabi,
+ args.gcc_opts, args.debug)
# Run ISS simulation
if args.steps == "all" or re.match(".*iss_sim.*", args.steps):
iss_sim(matched_list, output_dir, args.iss, args.iss_yaml,
- args.isa, args.core_setting_dir, args.iss_timeout)
+ args.isa, args.core_setting_dir, args.iss_timeout, args.debug)
# Compare ISS simulation result
if args.steps == "all" or re.match(".*iss_cmp.*", args.steps):
- iss_cmp(matched_list, args.iss, output_dir, args.stop_on_first_error, args.exp)
+ iss_cmp(matched_list, args.iss, output_dir, args.stop_on_first_error,
+ args.exp, args.debug)
sys.exit(RET_SUCCESS)
except KeyboardInterrupt:
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/lib.py b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/lib.py
index df70b52..b974637 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/lib.py
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/scripts/lib.py
@@ -65,7 +65,7 @@
return yaml_data
-def get_env_var(var):
+def get_env_var(var, debug_cmd = None):
"""Get the value of environment variable
Args:
@@ -77,8 +77,11 @@
try:
val = os.environ[var]
except KeyError:
- logging.warning("Please set the environment variable %0s" % var)
- sys.exit(RET_FAIL)
+ if debug_cmd:
+ return var
+ else:
+ logging.warning("Please set the environment variable %0s" % var)
+ sys.exit(RET_FAIL)
return val
@@ -96,7 +99,7 @@
return random.getrandbits(32)
-def run_cmd(cmd, timeout_s = 999, exit_on_error = 1, check_return_code = True):
+def run_cmd(cmd, timeout_s = 999, exit_on_error = 1, check_return_code = True, debug_cmd = None):
"""Run a command and return output
Args:
@@ -106,6 +109,10 @@
command output
"""
logging.debug(cmd)
+ if debug_cmd:
+ debug_cmd.write(cmd)
+ debug_cmd.write("\n\n")
+ return
try:
ps = subprocess.Popen("exec " + cmd,
shell=True,
@@ -135,7 +142,8 @@
return output
-def run_parallel_cmd(cmd_list, timeout_s = 999, exit_on_error = 0, check_return_code = True):
+def run_parallel_cmd(cmd_list, timeout_s = 999, exit_on_error = 0,
+ check_return_code = True, debug_cmd = None):
"""Run a list of commands in parallel
Args:
@@ -144,6 +152,11 @@
Returns:
command output
"""
+ if debug_cmd:
+ for cmd in cmd_list:
+ debug_cmd.write(cmd)
+ debug_cmd.write("\n\n")
+ return
children = []
for cmd in cmd_list:
ps = subprocess.Popen("exec " + cmd,
@@ -174,12 +187,16 @@
os.system("stty sane")
logging.debug(output)
-def run_cmd_output(cmd):
+def run_cmd_output(cmd, debug_cmd = None):
"""Run a command and return output
Args:
cmd : Command line to execute
"""
logging.debug(" ".join(cmd))
+ if debug_cmd:
+ debug_cmd.write(" ".join(cmd))
+ debug_cmd.write("\n\n")
+ return
try:
output = subprocess.check_output(cmd)
except subprocess.CalledProcessError as exc:
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_amo_instr_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_amo_instr_lib.sv
deleted file mode 100644
index ba60035..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_amo_instr_lib.sv
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2019 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Base class for AMO instruction stream
-class riscv_amo_base_instr_stream extends riscv_mem_access_stream;
-
- rand int unsigned num_amo;
- rand int unsigned num_mixed_instr;
- rand int base;
- rand riscv_reg_t rs1_reg;
- rand int unsigned data_page_id;
- rand int max_load_store_offset;
-
- // User can specify a small group of available registers to generate various hazard condition
- rand riscv_reg_t avail_regs[];
-
- `uvm_object_utils(riscv_amo_base_instr_stream)
-
- constraint rs1_c {
- !(rs1_reg inside {cfg.reserved_regs, reserved_rd, ZERO});
- }
-
- constraint addr_range_c {
- data_page_id < max_data_page_id;
- base inside {[0 : max_load_store_offset-1]};
- }
-
- constraint aligned_amo_c {
- if (XLEN == 32) {
- base % 4 == 0;
- } else {
- base % 8 == 0;
- }
- }
-
- function new(string name = "");
- super.new(name);
- endfunction
-
- function void post_randomize();
- gen_amo_instr();
- // rs1 cannot be modified by other instructions
- if(!(rs1_reg inside {reserved_rd})) begin
- reserved_rd = {reserved_rd, rs1_reg};
- end
- add_mixed_instr(num_mixed_instr);
- add_rs1_init_la_instr(rs1_reg, data_page_id);
- super.post_randomize();
- endfunction
-
- // AMO instruction generation
- virtual function void gen_amo_instr();
- endfunction
-
-endclass
-
-// A pair of LR/SC instruction
-class riscv_lr_sc_instr_stream extends riscv_amo_base_instr_stream;
-
- riscv_rand_instr lr_instr;
- riscv_rand_instr sc_instr;
-
- constraint legal_c {
- num_amo == 1;
- num_mixed_instr inside {[0:15]};
- }
-
- `uvm_object_utils(riscv_lr_sc_instr_stream)
-
- function new(string name = "");
- super.new(name);
- lr_instr = riscv_rand_instr::type_id::create("lr_instr");
- sc_instr = riscv_rand_instr::type_id::create("sc_instr");
- endfunction
-
- virtual function void gen_amo_instr();
- lr_instr.cfg = cfg;
- sc_instr.cfg = cfg;
- lr_instr.disable_a_extension_c.constraint_mode(0);
- sc_instr.disable_a_extension_c.constraint_mode(0);
- `DV_CHECK_RANDOMIZE_WITH_FATAL(lr_instr,
- rs1 == rs1_reg;
- rd != rs1_reg;
- instr_name inside {LR_W, LR_D};)
- `DV_CHECK_RANDOMIZE_WITH_FATAL(sc_instr,
- rs1 == rs1_reg;
- rd != rs1_reg;
- instr_name inside {SC_W, SC_D};)
- instr_list.push_front(lr_instr);
- instr_list.push_front(sc_instr);
- endfunction
-
-endclass
-
-class riscv_amo_instr_stream extends riscv_amo_base_instr_stream;
-
- riscv_rand_instr amo_instr[];
-
- constraint reasonable_c {
- solve num_amo before num_mixed_instr;
- num_amo inside {[1:10]};
- num_mixed_instr inside {[0:2*num_amo]};
- }
-
- `uvm_object_utils(riscv_amo_instr_stream)
- `uvm_object_new
-
- virtual function void gen_amo_instr();
- amo_instr = new[num_amo];
- foreach (amo_instr[i]) begin
- amo_instr[i] = riscv_rand_instr::type_id::create($sformatf("amo_instr_%0d", i));
- amo_instr[i].cfg = cfg;
- amo_instr[i].disable_a_extension_c.constraint_mode(0);
- `ifdef DSIM
- `DV_CHECK_RANDOMIZE_WITH_FATAL(amo_instr[i],
- rs1 == rs1_reg;
- rd != rs1_reg;
- instr_name inside {[AMOSWAP_W:AMOMAXU_D]};)
- `else
- `DV_CHECK_RANDOMIZE_WITH_FATAL(amo_instr[i],
- rs1 == rs1_reg;
- rd != rs1_reg;
- category == AMO;)
- `endif
- instr_list.push_front(amo_instr[i]);
- end
- endfunction
-
-endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_directed_instr_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_directed_instr_lib.sv
deleted file mode 100644
index 30a5343..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_directed_instr_lib.sv
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Base class for directed instruction stream
-class riscv_directed_instr_stream extends riscv_rand_instr_stream;
-
- `uvm_object_utils(riscv_directed_instr_stream)
-
- string label;
-
- function new(string name = "");
- super.new(name);
- endfunction
-
- function void post_randomize();
- foreach(instr_list[i]) begin
- instr_list[i].has_label = 1'b0;
- instr_list[i].atomic = 1'b1;
- end
- instr_list[0].comment = $sformatf("Start %0s", get_name());
- instr_list[$].comment = $sformatf("End %0s", get_name());
- if(label!= "") begin
- instr_list[0].label = label;
- instr_list[0].has_label = 1'b1;
- end
- endfunction
-
-endclass
-
-// Base class for memory access stream
-class riscv_mem_access_stream extends riscv_directed_instr_stream;
-
- int max_data_page_id;
- mem_region_t data_page[$];
-
- `uvm_object_utils(riscv_mem_access_stream)
- `uvm_object_new
-
- function void pre_randomize();
- if(kernel_mode) begin
- data_page = cfg.s_mem_region;
- end else begin
- data_page = cfg.mem_region;
- end
- 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;
- if(kernel_mode) begin
- la_instr.imm_str = $sformatf("%s+%0d", cfg.s_mem_region[id].name, base);
- end else begin
- la_instr.imm_str = $sformatf("%s+%0d", cfg.mem_region[id].name, base);
- end
- instr_list.push_front(la_instr);
- endfunction
-
- // Insert some other instructions to mix with mem_access instruction
- virtual function void add_mixed_instr(int instr_cnt);
- riscv_instr_base instr;
- setup_allowed_instr(1, 1);
- for(int i = 0; i < instr_cnt; i ++) begin
- instr = riscv_instr_base::type_id::create("instr");
- randomize_instr(instr);
- insert_instr(instr);
- end
- endfunction
-
-endclass
-
-// Jump instruction (JAL, JALR)
-// la rd0, jump_tagert_label
-// addi rd1, offset, rd0
-// jalr rd, offset, rd1
-// For JAL, restore the stack before doing the jump
-class riscv_jump_instr extends riscv_directed_instr_stream;
-
- riscv_instr_base jump;
- riscv_instr_base addi;
- riscv_pseudo_instr la;
- riscv_instr_base branch;
- rand riscv_reg_t gpr;
- rand int imm;
- rand bit enable_branch;
- rand int mixed_instr_cnt;
- riscv_instr_base stack_exit_instr[];
- string target_program_label;
- int idx;
- bit use_jalr;
-
- constraint instr_c {
- !(gpr inside {cfg.reserved_regs, ZERO});
- imm inside {[-1023:1023]};
- mixed_instr_cnt inside {[5:10]};
- }
-
- `uvm_object_utils(riscv_jump_instr)
-
- function new(string name = "");
- super.new(name);
- jump = riscv_instr_base::type_id::create("jump");
- la = riscv_pseudo_instr::type_id::create("la");
- addi = riscv_instr_base::type_id::create("addi");
- branch = riscv_instr_base::type_id::create("branch");
- endfunction
-
- function void post_randomize();
- riscv_instr_base instr[];
- `DV_CHECK_RANDOMIZE_WITH_FATAL(jump,
- (use_jalr) -> (instr_name == JALR);
- instr_name dist {JAL := 2, JALR := 6, C_JALR := 2};
- if (cfg.disable_compressed_instr || (cfg.ra != RA)) {
- instr_name != C_JALR;
- }
- rd == cfg.ra;
- rs1 == gpr;
- )
- `DV_CHECK_RANDOMIZE_WITH_FATAL(addi,
- rs1 == gpr;
- instr_name == ADDI;
- rd == gpr;
- )
- `DV_CHECK_RANDOMIZE_WITH_FATAL(branch,
- instr_name inside {BEQ, BNE, BLT, BGE, BLTU, BGEU};)
- la.pseudo_instr_name = LA;
- la.imm_str = target_program_label;
- la.rd = gpr;
- // Generate some random instructions to mix with jump instructions
- reserved_rd = {gpr};
- initialize_instr_list(mixed_instr_cnt);
- gen_instr(1'b1);
- addi.imm_str = $sformatf("%0d", imm);
- jump.imm_str = $sformatf("%0d", -imm);
- // The branch instruction is always inserted right before the jump instruction to avoid
- // skipping other required instructions like restore stack, load jump base etc.
- // The purse of adding the branch instruction here is to cover branch -> jump scenario.
- if(enable_branch) instr = {branch};
- // Restore stack before unconditional jump
- if(jump.rd == ZERO) begin
- instr= {stack_exit_instr, instr};
- end
- if(jump.instr_name == JAL) begin
- jump.imm_str = target_program_label;
- end else if (jump.instr_name == C_JALR) begin
- instr = {la, instr};
- end else begin
- instr = {la, addi, instr};
- end
- mix_instr_stream(instr);
- instr_list = {instr_list, jump};
- foreach(instr_list[i]) begin
- instr_list[i].has_label = 1'b0;
- 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;
- branch.comment = "branch to jump instr";
- branch.branch_assigned = 1'b1;
- endfunction
-endclass
-
-// Stress back to back jump instruction
-class riscv_jal_instr extends riscv_rand_instr_stream;
-
- riscv_instr_base jump[];
- riscv_instr_base jump_start;
- riscv_instr_base jump_end;
- rand int unsigned num_of_jump_instr;
- riscv_instr_name_t jal[$];
-
- constraint instr_c {
- num_of_jump_instr inside {[10:30]};
- }
-
- `uvm_object_utils(riscv_jal_instr)
-
- function new(string name = "");
- super.new(name);
- endfunction
-
- function void post_randomize();
- int order[];
- order = new[num_of_jump_instr];
- jump = new[num_of_jump_instr];
- foreach (order[i]) begin
- order[i] = i;
- end
- order.shuffle();
- setup_allowed_instr(1, 1);
- jal = {JAL};
- if (!cfg.disable_compressed_instr) begin
- jal.push_back(C_J);
- if (XLEN == 32) begin
- jal.push_back(C_JAL);
- end
- end
- // First instruction
- jump_start = riscv_instr_base::type_id::create("jump_start");
- `DV_CHECK_RANDOMIZE_WITH_FATAL(jump_start,
- instr_name == JAL;
- rd == cfg.ra;
- )
- jump_start.imm_str = $sformatf("%0df", order[0]);
- jump_start.label = label;
- // Last instruction
- jump_end = riscv_instr_base::type_id::create("jump_end");
- randomize_instr(jump_end);
- jump_end.label = $sformatf("%0d", num_of_jump_instr);
- foreach (jump[i]) begin
- jump[i] = riscv_instr_base::type_id::create($sformatf("jump_%0d", i));
- `DV_CHECK_RANDOMIZE_WITH_FATAL(jump[i],
- instr_name inside {jal};
- rd dist {RA := 5, T1 := 2, [SP:T0] :/ 1, [T2:T6] :/ 2};
- !(rd inside {cfg.reserved_regs});
- )
- jump[i].label = $sformatf("%0d", i);
- end
- foreach (order[i]) begin
- if (i == num_of_jump_instr - 1) begin
- jump[order[i]].imm_str = $sformatf("%0df", num_of_jump_instr);
- end else begin
- if (order[i+1] > order[i]) begin
- jump[order[i]].imm_str = $sformatf("%0df", order[i+1]);
- end else begin
- jump[order[i]].imm_str = $sformatf("%0db", order[i+1]);
- end
- end
- end
- instr_list = {jump_start, jump, jump_end};
- foreach (instr_list[i]) begin
- instr_list[i].has_label = 1'b1;
- instr_list[i].atomic = 1'b1;
- end
- endfunction
-endclass
-
-// Push stack instruction stream
-class riscv_push_stack_instr extends riscv_rand_instr_stream;
-
- int stack_len;
- int num_of_reg_to_save;
- int num_of_redudant_instr;
- riscv_instr_base push_stack_instr[];
- riscv_reg_t saved_regs[];
- rand riscv_rand_instr branch_instr;
- rand bit enable_branch;
- string push_start_label;
-
- `uvm_object_utils(riscv_push_stack_instr)
-
- function new(string name = "");
- super.new(name);
- endfunction
-
- function void init();
- // Save RA, T0
- reserved_rd = {cfg.ra};
- saved_regs = {cfg.ra};
- num_of_reg_to_save = saved_regs.size();
- if(num_of_reg_to_save * (XLEN/8) > stack_len) begin
- `uvm_fatal(get_full_name(), $sformatf("stack len [%0d] is not enough to store %d regs",
- stack_len, num_of_reg_to_save))
- end
- num_of_redudant_instr = $urandom_range(3,10);
- initialize_instr_list(num_of_redudant_instr);
- endfunction
-
- virtual function void gen_push_stack_instr(int stack_len, bit allow_branch = 1);
- this.stack_len = stack_len;
- init();
- gen_instr(1'b1);
- push_stack_instr = new[num_of_reg_to_save+1];
- foreach(push_stack_instr[i]) begin
- push_stack_instr[i] = riscv_instr_base::type_id::
- create($sformatf("push_stack_instr_%0d", i));
- end
- // addi sp,sp,-imm
- `DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[0],
- instr_name == ADDI; rd == cfg.sp; rs1 == cfg.sp;
- imm == (~stack_len + 1);)
- push_stack_instr[0].imm_str = $sformatf("-%0d", stack_len);
- foreach(saved_regs[i]) begin
- if(XLEN == 32) begin
- `DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[i+1],
- instr_name == SW; rs2 == saved_regs[i]; rs1 == cfg.sp; imm == 4 * (i+1);)
- end else begin
- `DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[i+1],
- instr_name == SD; rs2 == saved_regs[i]; rs1 == cfg.sp; imm == 8 * (i+1);)
- end
- push_stack_instr[i+1].process_load_store = 0;
- end
- if (allow_branch) begin
- `DV_CHECK_STD_RANDOMIZE_FATAL(enable_branch)
- end else begin
- enable_branch = 0;
- end
- if(enable_branch) begin
- // Cover jal -> branch scenario, the branch is added before push stack operation
- branch_instr = riscv_rand_instr::type_id::create("branch_instr");
- branch_instr.cfg = cfg;
- `ifdef DSIM
- `DV_CHECK_RANDOMIZE_WITH_FATAL(branch_instr,
- instr_name inside {[BEQ:BGEU], C_BEQZ, C_BNEZ};)
- `else
- `DV_CHECK_RANDOMIZE_WITH_FATAL(branch_instr, category == BRANCH;)
- `endif
- branch_instr.imm_str = push_start_label;
- branch_instr.branch_assigned = 1'b1;
- push_stack_instr[0].label = push_start_label;
- push_stack_instr[0].has_label = 1'b1;
- push_stack_instr = {branch_instr, push_stack_instr};
- end
- mix_instr_stream(push_stack_instr);
- foreach(instr_list[i]) begin
- instr_list[i].atomic = 1'b1;
- if(instr_list[i].label == "")
- instr_list[i].has_label = 1'b0;
- end
- endfunction
-
-endclass
-
-// Pop stack instruction stream
-class riscv_pop_stack_instr extends riscv_rand_instr_stream;
-
- int stack_len;
- int num_of_reg_to_save;
- int num_of_redudant_instr;
- riscv_instr_base pop_stack_instr[];
- riscv_reg_t saved_regs[];
-
- `uvm_object_utils(riscv_pop_stack_instr)
-
- function new(string name = "");
- super.new(name);
- endfunction
-
- function void init();
- reserved_rd = {cfg.ra};
- num_of_reg_to_save = saved_regs.size();
- if(num_of_reg_to_save * 4 > stack_len) begin
- `uvm_fatal(get_full_name(), $sformatf("stack len [%0d] is not enough to store %d regs",
- stack_len, num_of_reg_to_save))
- end
- num_of_redudant_instr = $urandom_range(3,10);
- initialize_instr_list(num_of_redudant_instr);
- endfunction
-
- virtual function void gen_pop_stack_instr(int stack_len, riscv_reg_t saved_regs[]);
- this.stack_len = stack_len;
- this.saved_regs = saved_regs;
- init();
- gen_instr(1'b1);
- pop_stack_instr = new[num_of_reg_to_save+1];
- foreach(pop_stack_instr[i]) begin
- pop_stack_instr[i] = riscv_instr_base::type_id::
- create($sformatf("pop_stack_instr_%0d", i));
- end
- foreach(saved_regs[i]) begin
- if(XLEN == 32) begin
- `DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[i],
- instr_name == LW; rd == saved_regs[i]; rs1 == cfg.sp; imm == 4 * (i+1);)
- end else begin
- `DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[i],
- instr_name == LD; rd == saved_regs[i]; rs1 == cfg.sp; imm == 8 * (i+1);)
- end
- pop_stack_instr[i].process_load_store = 0;
- end
- // addi sp,sp,imm
- `DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[num_of_reg_to_save],
- instr_name == ADDI; rd == cfg.sp; rs1 == cfg.sp; imm == stack_len;)
- pop_stack_instr[num_of_reg_to_save].imm_str = $sformatf("%0d", stack_len);
- mix_instr_stream(pop_stack_instr);
- foreach(instr_list[i]) begin
- instr_list[i].atomic = 1'b1;
- instr_list[i].has_label = 1'b0;
- end
- endfunction
-
-endclass
-
-// Cover the long fprward and backward jump
-class riscv_long_branch_instr extends riscv_rand_instr_stream;
-
- int branch_instr_stream_len = 100;
- int branch_instr_offset = 999;
- riscv_rand_instr_stream forward_branch_instr_stream;
- riscv_rand_instr_stream backward_branch_instr_stream;
- riscv_instr_base jump_instr;
-
- `uvm_object_utils(riscv_long_branch_instr)
-
- function new(string name = "");
- super.new(name);
- forward_branch_instr_stream = riscv_rand_instr_stream::type_id::
- create("forward_branch_instr_stream");
- backward_branch_instr_stream = riscv_rand_instr_stream::type_id::
- create("backward_branch_instr_stream");
- jump_instr = riscv_instr_base::type_id::create("jump_instr");
- endfunction
-
- function void init(int instr_len);
- branch_instr_stream_len = instr_len;
- initialize_instr_list(branch_instr_offset-branch_instr_stream_len);
- forward_branch_instr_stream.cfg = cfg;
- backward_branch_instr_stream.cfg = cfg;
- forward_branch_instr_stream.initialize_instr_list(branch_instr_stream_len);
- backward_branch_instr_stream.initialize_instr_list(branch_instr_stream_len);
- endfunction
-
- virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1,
- bit is_debug_program = 1'b0);
- int branch_offset;
- super.gen_instr(1'b1);
- forward_branch_instr_stream.gen_instr();
- backward_branch_instr_stream.gen_instr();
- `DV_CHECK_RANDOMIZE_WITH_FATAL(jump_instr, instr_name == JAL;)
- jump_instr.imm_str = "test_done";
- instr_list = {forward_branch_instr_stream.instr_list, instr_list,
- jump_instr, backward_branch_instr_stream.instr_list};
- foreach(instr_list[i]) begin
- instr_list[i].atomic = 1'b1;
- if(!instr_list[i].is_branch_target) begin
- instr_list[i].has_label = 1'b0;
- end
- if(instr_list[i].category == BRANCH) begin
- if(i < branch_instr_stream_len)
- branch_offset = branch_instr_offset;
- else
- branch_offset = -branch_instr_offset;
- instr_list[i].imm_str = $sformatf("target_%0d", i);
- instr_list[i].branch_assigned = 1'b1;
- // Avoid dead loop
- if(((instr_list[i+branch_offset].category == BRANCH) ||
- instr_list[i+branch_offset].is_branch_target) && (branch_offset < 0))
- branch_offset = branch_offset + 1;
- `uvm_info(get_full_name(), $sformatf("Branch [%0d] %0s -> [%0d] %0s", i,
- instr_list[i].convert2asm(), i+branch_offset,
- instr_list[i+branch_offset].convert2asm()), UVM_LOW)
- if(i < -branch_offset)
- `uvm_fatal(get_name(), $sformatf("Unexpected branch instr at %0d", i))
- instr_list[i+branch_offset].label = $sformatf("target_%0d", i);
- instr_list[i+branch_offset].has_label = 1'b1;
- instr_list[i+branch_offset].is_branch_target = 1;
- end
- end
- endfunction
-
-endclass
-
-class riscv_sw_interrupt_instr extends riscv_directed_instr_stream;
-
- rand bit usip;
- rand bit ssip;
- rand bit msip;
- rand privileged_reg_t ip_reg;
- rand riscv_pseudo_instr li_instr;
- rand riscv_instr_base csr_instr;
- riscv_privil_reg ip;
- rand riscv_reg_t rs1_reg;
-
- constraint ip_reg_c {
- if(cfg.init_privileged_mode == MACHINE_MODE) {
- ip_reg == MIP;
- } else {
- ip_reg == SIP;
- }
- (ip_reg == MIP) -> (usip || ssip || msip);
- (ip_reg == SIP) -> (usip || ssip);
- }
-
- constraint instr_c {
- !(rs1_reg inside {cfg.reserved_regs});
- rs1_reg != ZERO;
- li_instr.pseudo_instr_name == LI;
- li_instr.rd == rs1_reg;
- csr_instr.instr_name == CSRRW;
- csr_instr.rs1 == rs1_reg;
- // TODO: Support non-zero rd for SIP, MIP
- // csr_instr.rd inside {cfg.avail_regs};
- csr_instr.rd == ZERO;
- csr_instr.csr == ip_reg;
- }
-
- `uvm_object_utils(riscv_sw_interrupt_instr)
-
- function new(string name = "");
- super.new(name);
- li_instr = riscv_pseudo_instr::type_id::create("li_instr");
- csr_instr = riscv_instr_base::type_id::create("csr_instr");
- ip = riscv_privil_reg::type_id::create("ip");
- endfunction
-
- function void post_randomize();
- // TODO: Support UIP
- if(cfg.init_privileged_mode == USER_MODE) return;
- ip.init_reg(ip_reg);
- if(ip_reg == SIP) begin
- ip.set_field("USIP", usip);
- ip.set_field("SSIP", ssip);
- end else begin
- ip.set_field("USIP", usip);
- ip.set_field("SSIP", ssip);
- ip.set_field("MSIP", msip);
- end
- li_instr.imm_str = $sformatf("0x%0x", ip.get_val());
- csr_instr.comment = ip_reg.name();
- instr_list = {li_instr, csr_instr};
- super.post_randomize();
- endfunction
-
-endclass
-
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_base.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_base.sv
deleted file mode 100644
index 548758e..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_base.sv
+++ /dev/null
@@ -1,1215 +0,0 @@
-/*
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class riscv_instr_base extends uvm_object;
-
- rand riscv_instr_group_t group;
- rand riscv_instr_format_t format;
- rand riscv_instr_category_t category;
- rand riscv_instr_name_t instr_name;
- rand bit [11:0] csr;
-
- rand riscv_reg_t rs2;
- rand riscv_reg_t rs1;
- rand riscv_reg_t rd;
- rand riscv_fpr_t fs1;
- rand riscv_fpr_t fs2;
- rand riscv_fpr_t fs3;
- rand riscv_fpr_t fd;
- rand bit [31:0] imm;
- rand imm_t imm_type;
- rand bit [4:0] imm_len;
- rand bit aq;
- rand bit rl;
- bit is_pseudo_instr;
- bit is_branch_target;
- bit has_label = 1'b1;
- bit atomic = 0;
- bit branch_assigned;
- bit process_load_store = 1'b1;
- bit is_compressed;
- bit is_illegal_instr;
- bit is_hint_instr;
- bit has_imm;
- bit has_rs1;
- bit has_rs2;
- bit has_rd;
- bit has_fs1;
- bit has_fs2;
- bit has_fs3;
- bit has_fd;
- bit is_floating_point;
- bit [31:0] imm_mask = '1;
- string imm_str;
- string comment;
- string label;
- bit is_local_numeric_label;
- int idx = -1;
- `VECTOR_INCLUDE("riscv_instr_base_inc_riscv_instr_base_declares.sv")
-
- `uvm_object_utils(riscv_instr_base)
-
- constraint default_c {
- instr_name != INVALID_INSTR;
- }
-
- // Immediate bit length for different instruction format
- constraint imm_len_c {
- solve imm_type before imm_len;
- if(format inside {U_FORMAT, J_FORMAT}) {
- imm_len == 20;
- }
- if(format inside {I_FORMAT, S_FORMAT, B_FORMAT}) {
- if(imm_type == UIMM) {
- imm_len == 5;
- } else {
- imm_len == 11;
- }
- }
- if(format inside {CI_FORMAT, CSS_FORMAT}) {
- // TODO: gcc compiler seems to not support 6 bits unsigned imm for c.lui,
- // hardcoded to 5 bits for now
- if(instr_name == C_LUI) {
- imm_len == 5;
- } else {
- imm_len == 6;
- }
- }
- if(format inside {CL_FORMAT, CS_FORMAT}) {
- imm_len == 5;
- }
- if(format inside {CJ_FORMAT}) {
- imm_len == 11;
- }
- if(format inside {CB_FORMAT, CIW_FORMAT}) {
- if(instr_name == C_ANDI) {
- imm_len == 6;
- } else {
- imm_len == 8;
- }
- }
- imm_len <= 20;
- }
-
- constraint legal_operand_c {
- (instr_name == C_LUI) -> (rd != SP);
- }
-
- constraint imm_val_c {
- if(imm_type inside {NZIMM, NZUIMM}) {
- imm != 0;
- }
- }
-
- constraint aq_rl_c {
- aq && rl == 0;
- }
-
- // Avoid generating HINT or illegal instruction by default as it's not supported by the compiler
- constraint no_hint_illegal_instr_c {
- if (instr_name inside {C_ADDI, C_ADDIW, C_LI, C_LUI, C_SLLI, C_SLLI64,
- C_LQSP, C_LDSP, C_MV, C_ADD}) {
- rd != ZERO;
- }
- if (instr_name == C_JR) {
- rs1 != ZERO;
- }
- if (instr_name inside {C_ADD, C_MV}) {
- rs2 != ZERO;
- }
- }
-
- // Cannot shift more than the width of the bus
- constraint shift_imm_val_c {
- solve category before imm;
- if(category == SHIFT) {
- if(group == RV64I) {
- // The new instruction in RV64I only handles 32 bits value
- imm < 32;
- } else {
- imm < XLEN;
- }
- }
- }
-
- constraint load_store_c {
- if(category inside {LOAD, STORE}) {
- rs1 != ZERO; // x0 cannot be used to save the base address
- }
- }
-
- constraint nop_c {
- if(instr_name inside {NOP, C_NOP}) {
- rs1 == ZERO;
- rs2 == ZERO;
- rd == ZERO;
- }
- }
-
- constraint jal_c {
- if (XLEN != 32) {
- soft instr_name != C_JAL;
- }
- }
-
- constraint system_instr_c {
- if (category inside {SYSTEM, SYNCH}) {
- rd == ZERO;
- rs1 == ZERO;
- }
- }
-
- constraint rvc_csr_c {
- // Registers specified by the three-bit rs1’, rs2’, and rd’
- if(format inside {CIW_FORMAT, CL_FORMAT, CS_FORMAT, CB_FORMAT, CA_FORMAT}) {
- rs1 inside {[S0:A5]};
- rs2 inside {[S0:A5]};
- rd inside {[S0:A5]};
- }
- // C_ADDI16SP is only valid when rd == SP
- if(instr_name == C_ADDI16SP) {
- rd == SP;
- rs1 == SP;
- }
-
- if(instr_name inside {C_JR, C_JALR}) {
- rs2 == ZERO;
- rs1 != ZERO;
- }
- }
-
- //////////// RV32I instructions //////////////
- // LOAD instructions
- `add_instr(LB, I_FORMAT, LOAD, RV32I)
- `add_instr(LH, I_FORMAT, LOAD, RV32I)
- `add_instr(LW, I_FORMAT, LOAD, RV32I)
- `add_instr(LBU, I_FORMAT, LOAD, RV32I)
- `add_instr(LHU, I_FORMAT, LOAD, RV32I)
- // STORE instructions
- `add_instr(SB, S_FORMAT, STORE, RV32I)
- `add_instr(SH, S_FORMAT, STORE, RV32I)
- `add_instr(SW, S_FORMAT, STORE, RV32I)
- // SHIFT intructions
- `add_instr(SLL, R_FORMAT, SHIFT, RV32I)
- `add_instr(SLLI, I_FORMAT, SHIFT, RV32I)
- `add_instr(SRL, R_FORMAT, SHIFT, RV32I)
- `add_instr(SRLI, I_FORMAT, SHIFT, RV32I)
- `add_instr(SRA, R_FORMAT, SHIFT, RV32I)
- `add_instr(SRAI, I_FORMAT, SHIFT, RV32I)
- // ARITHMETIC intructions
- `add_instr(ADD, R_FORMAT, ARITHMETIC, RV32I)
- `add_instr(ADDI, I_FORMAT, ARITHMETIC, RV32I)
- `add_instr(NOP, I_FORMAT, ARITHMETIC, RV32I)
- `add_instr(SUB, R_FORMAT, ARITHMETIC, RV32I)
- `add_instr(LUI, U_FORMAT, ARITHMETIC, RV32I, UIMM)
- `add_instr(AUIPC, U_FORMAT, ARITHMETIC, RV32I, UIMM)
- // LOGICAL instructions
- `add_instr(XOR, R_FORMAT, LOGICAL, RV32I)
- `add_instr(XORI, I_FORMAT, LOGICAL, RV32I)
- `add_instr(OR, R_FORMAT, LOGICAL, RV32I)
- `add_instr(ORI, I_FORMAT, LOGICAL, RV32I)
- `add_instr(AND, R_FORMAT, LOGICAL, RV32I)
- `add_instr(ANDI, I_FORMAT, LOGICAL, RV32I)
- // COMPARE instructions
- `add_instr(SLT, R_FORMAT, COMPARE, RV32I)
- `add_instr(SLTI, I_FORMAT, COMPARE, RV32I)
- `add_instr(SLTU, R_FORMAT, COMPARE, RV32I)
- `add_instr(SLTIU, I_FORMAT, COMPARE, RV32I)
- // BRANCH instructions
- `add_instr(BEQ, B_FORMAT, BRANCH, RV32I)
- `add_instr(BNE, B_FORMAT, BRANCH, RV32I)
- `add_instr(BLT, B_FORMAT, BRANCH, RV32I)
- `add_instr(BGE, B_FORMAT, BRANCH, RV32I)
- `add_instr(BLTU, B_FORMAT, BRANCH, RV32I)
- `add_instr(BGEU, B_FORMAT, BRANCH, RV32I)
- // JUMP instructions
- `add_instr(JAL, J_FORMAT, JUMP, RV32I)
- `add_instr(JALR, I_FORMAT, JUMP, RV32I)
- // SYNCH instructions
- `add_instr(FENCE, I_FORMAT, SYNCH, RV32I)
- `add_instr(FENCE_I, I_FORMAT, SYNCH, RV32I)
- // SYSTEM instructions
- `add_instr(ECALL, I_FORMAT, SYSTEM, RV32I)
- `add_instr(EBREAK, I_FORMAT, SYSTEM, RV32I)
- `add_instr(URET, I_FORMAT, SYSTEM, RV32I)
- `add_instr(SRET, I_FORMAT, SYSTEM, RV32I)
- `add_instr(MRET, I_FORMAT, SYSTEM, RV32I)
- `add_instr(DRET, I_FORMAT, SYSTEM, RV32I)
- `add_instr(WFI, I_FORMAT, INTERRUPT, RV32I)
- // CSR instructions
- `add_instr(CSRRW, R_FORMAT, CSR, RV32I, UIMM)
- `add_instr(CSRRS, R_FORMAT, CSR, RV32I, UIMM)
- `add_instr(CSRRC, R_FORMAT, CSR, RV32I, UIMM)
- `add_instr(CSRRWI, I_FORMAT, CSR, RV32I, UIMM)
- `add_instr(CSRRSI, I_FORMAT, CSR, RV32I, UIMM)
- `add_instr(CSRRCI, I_FORMAT, CSR, RV32I, UIMM)
-
- //////////// RV32M instructions //////////////
- `add_instr(MUL, R_FORMAT, ARITHMETIC, RV32M)
- `add_instr(MULH, R_FORMAT, ARITHMETIC, RV32M)
- `add_instr(MULHSU, R_FORMAT, ARITHMETIC, RV32M)
- `add_instr(MULHU, R_FORMAT, ARITHMETIC, RV32M)
- `add_instr(DIV, R_FORMAT, ARITHMETIC, RV32M)
- `add_instr(DIVU, R_FORMAT, ARITHMETIC, RV32M)
- `add_instr(REM, R_FORMAT, ARITHMETIC, RV32M)
- `add_instr(REMU, R_FORMAT, ARITHMETIC, RV32M)
-
- //////////// RV64M instructions //////////////
- `add_instr(MULW, R_FORMAT, ARITHMETIC, RV64M)
- `add_instr(DIVW, R_FORMAT, ARITHMETIC, RV64M)
- `add_instr(DIVUW, R_FORMAT, ARITHMETIC, RV64M)
- `add_instr(REMW, R_FORMAT, ARITHMETIC, RV64M)
- `add_instr(REMUW, R_FORMAT, ARITHMETIC, RV64M)
-
- //////////// RV32F instructions //////////////
- `add_instr(FLW, I_FORMAT, LOAD, RV32F)
- `add_instr(FSW, S_FORMAT, STORE, RV32F)
- `add_instr(FMADD_S, R4_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FMSUB_S, R4_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FNMSUB_S, R4_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FNMADD_S, R4_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FADD_S, R_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FSUB_S, R_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FMUL_S, R_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FDIV_S, R_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FSQRT_S, I_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FSGNJ_S, R_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FSGNJN_S, R_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FSGNJX_S, R_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FMIN_S, R_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FMAX_S, R_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FCVT_W_S, I_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FCVT_WU_S, I_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FMV_X_W, I_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FEQ_S, R_FORMAT, COMPARE, RV32F)
- `add_instr(FLT_S, R_FORMAT, COMPARE, RV32F)
- `add_instr(FLE_S, R_FORMAT, COMPARE, RV32F)
- `add_instr(FCLASS_S, R_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FCVT_S_W, I_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FCVT_S_WU, I_FORMAT, ARITHMETIC, RV32F)
- `add_instr(FMV_W_X, I_FORMAT, ARITHMETIC, RV32F)
-
- ///////////// RV64F instruction /////////////////
- `add_instr(FCVT_L_S, I_FORMAT, ARITHMETIC, RV64F)
- `add_instr(FCVT_LU_S, I_FORMAT, ARITHMETIC, RV64F)
- `add_instr(FCVT_S_L, I_FORMAT, ARITHMETIC, RV64F)
- `add_instr(FCVT_S_LU, I_FORMAT, ARITHMETIC, RV64F)
-
- //////////// RV32D instructions ////////////////
- `add_instr(FLD, I_FORMAT, LOAD, RV32D)
- `add_instr(FSD, S_FORMAT, STORE, RV32D)
- `add_instr(FMADD_D, R4_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FMSUB_D, R4_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FNMSUB_D, R4_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FNMADD_D, R4_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FADD_D, R_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FSUB_D, R_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FMUL_D, R_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FDIV_D, R_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FSQRT_D, I_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FSGNJ_D, R_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FSGNJN_D, R_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FSGNJX_D, R_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FMIN_D, R_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FMAX_D, R_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FCVT_S_D, I_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FCVT_D_S, I_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FEQ_D, R_FORMAT, COMPARE, RV32D)
- `add_instr(FLT_D, R_FORMAT, COMPARE, RV32D)
- `add_instr(FLE_D, R_FORMAT, COMPARE, RV32D)
- `add_instr(FCLASS_D, R_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FCVT_W_D, I_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FCVT_WU_D, I_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FCVT_D_W, I_FORMAT, ARITHMETIC, RV32D)
- `add_instr(FCVT_D_WU, I_FORMAT, ARITHMETIC, RV32D)
-
- ////////////// RV64D instruction ///////////////
- `add_instr(FMV_X_D, I_FORMAT, ARITHMETIC, RV64D)
- `add_instr(FMV_D_X, I_FORMAT, ARITHMETIC, RV64D)
- `add_instr(FCVT_L_D, I_FORMAT, ARITHMETIC, RV64D)
- `add_instr(FCVT_LU_D, I_FORMAT, ARITHMETIC, RV64D)
- `add_instr(FCVT_D_L, I_FORMAT, ARITHMETIC, RV64D)
- `add_instr(FCVT_D_LU, I_FORMAT, ARITHMETIC, RV64D)
-
- // RV64I instructions
- // LOAD/STORE instructions
- `add_instr(LWU, I_FORMAT, LOAD, RV64I)
- `add_instr(LD, I_FORMAT, LOAD, RV64I)
- `add_instr(SD, S_FORMAT, STORE, RV64I)
- // SHIFT intructions
- `add_instr(SLLW, R_FORMAT, SHIFT, RV64I)
- `add_instr(SLLIW, I_FORMAT, SHIFT, RV64I)
- `add_instr(SRLW, R_FORMAT, SHIFT, RV64I)
- `add_instr(SRLIW, I_FORMAT, SHIFT, RV64I)
- `add_instr(SRAW, R_FORMAT, SHIFT, RV64I)
- `add_instr(SRAIW, I_FORMAT, SHIFT, RV64I)
- // ARITHMETIC intructions
- `add_instr(ADDW, R_FORMAT, ARITHMETIC, RV64I)
- `add_instr(ADDIW, I_FORMAT, ARITHMETIC, RV64I)
- `add_instr(SUBW, R_FORMAT, ARITHMETIC, RV64I)
-
- // RV32IC
- `add_instr(C_LW, CL_FORMAT, LOAD, RV32C, UIMM)
- `add_instr(C_SW, CS_FORMAT, STORE, RV32C, UIMM)
- `add_instr(C_LWSP, CI_FORMAT, LOAD, RV32C, UIMM)
- `add_instr(C_SWSP, CSS_FORMAT, STORE, RV32C, UIMM)
- `add_instr(C_ADDI4SPN, CIW_FORMAT, ARITHMETIC, RV32C, NZUIMM)
- `add_instr(C_ADDI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM)
- `add_instr(C_ADDI16SP, CI_FORMAT, ARITHMETIC, RV32C, NZIMM)
-
- `add_instr(C_LI, CI_FORMAT, ARITHMETIC, RV32C)
- `add_instr(C_LUI, CI_FORMAT, ARITHMETIC, RV32C, NZUIMM)
- `add_instr(C_SUB, CA_FORMAT, ARITHMETIC, RV32C)
- `add_instr(C_ADD, CR_FORMAT, ARITHMETIC, RV32C)
- `add_instr(C_NOP, CI_FORMAT, ARITHMETIC, RV32C)
- `add_instr(C_MV, CR_FORMAT, ARITHMETIC, RV32C)
- `add_instr(C_ANDI, CB_FORMAT, LOGICAL, RV32C)
- `add_instr(C_XOR, CA_FORMAT, LOGICAL, RV32C)
- `add_instr(C_OR, CA_FORMAT, LOGICAL, RV32C)
- `add_instr(C_AND, CA_FORMAT, LOGICAL, RV32C)
- `add_instr(C_BEQZ, CB_FORMAT, BRANCH, RV32C)
- `add_instr(C_BNEZ, CB_FORMAT, BRANCH, RV32C)
- `add_instr(C_SRLI, CB_FORMAT, SHIFT, RV32C, NZUIMM)
- `add_instr(C_SRAI, CB_FORMAT, SHIFT, RV32C, NZUIMM)
- `add_instr(C_SLLI, CI_FORMAT, SHIFT, RV32C, NZUIMM)
- `add_instr(C_J, CJ_FORMAT, JUMP, RV32C)
- `add_instr(C_JAL, CJ_FORMAT, JUMP, RV32C)
- `add_instr(C_JR, CR_FORMAT, JUMP, RV32C)
- `add_instr(C_JALR, CR_FORMAT, JUMP, RV32C)
- `add_instr(C_EBREAK, CI_FORMAT, SYSTEM, RV32C)
-
- // RV64C
- `add_instr(C_ADDIW, CI_FORMAT, ARITHMETIC, RV64C)
- `add_instr(C_SUBW, CA_FORMAT, ARITHMETIC, RV64C)
- `add_instr(C_ADDW, CA_FORMAT, ARITHMETIC, RV64C)
- `add_instr(C_LD, CL_FORMAT, LOAD, RV64C, UIMM)
- `add_instr(C_SD, CS_FORMAT, STORE, RV64C, UIMM)
- `add_instr(C_LDSP, CI_FORMAT, LOAD, RV64C, UIMM)
- `add_instr(C_SDSP, CSS_FORMAT, STORE, RV64C, UIMM)
-
- // RV128C
- `add_instr(C_SRLI64, CB_FORMAT, SHIFT, RV128C, NZUIMM)
- `add_instr(C_SRAI64, CB_FORMAT, SHIFT, RV128C, NZUIMM)
- `add_instr(C_SLLI64, CI_FORMAT, SHIFT, RV128C, NZUIMM)
- `add_instr(C_LQ, CL_FORMAT, LOAD, RV32DC, UIMM)
- `add_instr(C_SQ, CS_FORMAT, STORE, RV32DC, UIMM)
- `add_instr(C_LQSP, CI_FORMAT, LOAD, RV32DC, UIMM)
- `add_instr(C_SQSP, CSS_FORMAT, STORE, RV32DC, UIMM)
-
- // RV32FC
- `add_instr(C_FLW, CL_FORMAT, LOAD, RV32FC, UIMM)
- `add_instr(C_FSW, CS_FORMAT, STORE, RV32FC, UIMM)
- `add_instr(C_FLWSP, CI_FORMAT, LOAD, RV32FC, UIMM)
- `add_instr(C_FSWSP, CSS_FORMAT, STORE, RV32FC, UIMM)
-
- // RV32DC
- `add_instr(C_FLD, CL_FORMAT, LOAD, RV32DC, UIMM)
- `add_instr(C_FSD, CS_FORMAT, STORE, RV32DC, UIMM)
- `add_instr(C_FLDSP, CI_FORMAT, LOAD, RV32DC, UIMM)
- `add_instr(C_FSDSP, CSS_FORMAT, STORE, RV32DC, UIMM)
-
- // RV32A
- `add_instr(LR_W, R_FORMAT, LOAD, RV32A)
- `add_instr(SC_W, R_FORMAT, STORE, RV32A)
- `add_instr(AMOSWAP_W, R_FORMAT, AMO, RV32A)
- `add_instr(AMOADD_W, R_FORMAT, AMO, RV32A)
- `add_instr(AMOAND_W, R_FORMAT, AMO, RV32A)
- `add_instr(AMOOR_W, R_FORMAT, AMO, RV32A)
- `add_instr(AMOXOR_W, R_FORMAT, AMO, RV32A)
- `add_instr(AMOMIN_W, R_FORMAT, AMO, RV32A)
- `add_instr(AMOMAX_W, R_FORMAT, AMO, RV32A)
- `add_instr(AMOMINU_W, R_FORMAT, AMO, RV32A)
- `add_instr(AMOMAXU_W, R_FORMAT, AMO, RV32A)
-
- // RV64A
- `add_instr(LR_D, R_FORMAT, LOAD, RV64A)
- `add_instr(SC_D, R_FORMAT, STORE, RV64A)
- `add_instr(AMOSWAP_D, R_FORMAT, AMO, RV64A)
- `add_instr(AMOADD_D, R_FORMAT, AMO, RV64A)
- `add_instr(AMOAND_D, R_FORMAT, AMO, RV64A)
- `add_instr(AMOOR_D, R_FORMAT, AMO, RV64A)
- `add_instr(AMOXOR_D, R_FORMAT, AMO, RV64A)
- `add_instr(AMOMIN_D, R_FORMAT, AMO, RV64A)
- `add_instr(AMOMAX_D, R_FORMAT, AMO, RV64A)
- `add_instr(AMOMINU_D, R_FORMAT, AMO, RV64A)
- `add_instr(AMOMAXU_D, R_FORMAT, AMO, RV64A)
-
- // Supervisor Instructions
- `add_instr(SFENCE_VMA, R_FORMAT,SYNCH,RV32I)
-
- `VECTOR_INCLUDE("riscv_instr_base_inc_add_instr.sv")
-
- function void post_randomize();
- if (group inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) begin
- is_compressed = 1'b1;
- end
- if (!(format inside {R_FORMAT, CR_FORMAT})) begin
- imm_mask = '1;
- imm_mask = imm_mask << imm_len;
- has_imm = 1'b1;
- mask_imm();
- if (imm_str == "") begin
- update_imm_str();
- end
- end
- if (format inside {R_FORMAT, S_FORMAT, B_FORMAT, CSS_FORMAT,
- CS_FORMAT, CR_FORMAT, CA_FORMAT}) begin
- has_rs2 = 1'b1;
- end
- if (!(format inside {J_FORMAT, U_FORMAT, CJ_FORMAT, CSS_FORMAT,
- CA_FORMAT, CR_FORMAT, CI_FORMAT})) begin
- has_rs1 = 1'b1;
- end else if (instr_name inside {C_JR, C_JALR}) begin
- has_rs1 = 1'b1;
- has_rs2 = 1'b0;
- end
- if (!(format inside {CJ_FORMAT, CB_FORMAT, CS_FORMAT, CSS_FORMAT, B_FORMAT, S_FORMAT})) begin
- has_rd = 1'b1;
- end
- if (category == CSR) begin
- has_rs2 = 1'b0;
- if (instr_name inside {CSRRWI, CSRRSI, CSRRCI}) begin
- has_rs1 = 1'b0;
- end
- end
- // TODO(taliu) Add support for compressed floating point format
- if (group inside {RV32F, RV64F, RV32D, RV64D, RV32FC, RV32DC}) begin
- is_floating_point = 1'b1;
- has_rs1 = 1'b0;
- has_rs2 = 1'b0;
- has_rd = 1'b0;
- has_fs1 = 1'b1;
- if (format == R4_FORMAT) begin
- has_fs3 = 1'b1;
- end
- if (format != S_FORMAT) begin
- if ((category == COMPARE) || (instr_name inside {FCLASS_S, FCLASS_D})) begin
- has_rd = 1'b1;
- end else begin
- has_fd = 1'b1;
- end
- end
- if (format != I_FORMAT) begin
- has_fs2 = 1'b1;
- end
- if (instr_name inside {FMV_X_W, FMV_X_D, FCVT_W_S, FCVT_WU_S,
- FCVT_L_S, FCVT_LU_S, FCVT_L_D, FCVT_LU_D, FCVT_LU_S,
- FCVT_W_D, FCVT_WU_D}) begin
- // Floating point to integer operation
- has_rd = 1'b1;
- has_fs1 = 1'b1;
- has_fd = 1'b0;
- end else if (instr_name inside {FMV_W_X, FMV_D_X, FCVT_S_W, FCVT_S_WU,
- FCVT_S_L, FCVT_D_L, FCVT_S_LU, FCVT_D_W,
- FCVT_D_LU, FCVT_D_WU, FLW, FLD, FSW, FSD,
- C_FLW, C_FLD, C_FSW, C_FSD}) begin
- // Integer to floating point operation
- has_fd = 1'b1;
- has_fs1 = 1'b0;
- has_rs1 = 1'b1;
- end
- end
-
- `VECTOR_INCLUDE("riscv_instr_base_inc_post_randomize.sv")
-
- endfunction
-
- function void mask_imm();
- // Process the immediate value and sign extension
- if (imm_type inside {UIMM, NZUIMM}) begin
- imm = imm & ~imm_mask;
- end else begin
- if (imm[imm_len-1]) begin
- imm = imm | imm_mask;
- end else begin
- imm = imm & ~imm_mask;
- end
- end
- // Give a random value if imm is zero after masking unexpectedly
- if((imm_type inside {NZIMM, NZUIMM}) && (imm == '0)) begin
- imm = $urandom_range(2 ** (imm_len-1) - 1, 1);
- end
- endfunction
-
- function void gen_rand_imm();
- if (!randomize(imm)) begin
- `uvm_fatal(`gfn, "Cannot randomize imm")
- end
- mask_imm();
- update_imm_str();
- endfunction
-
- function void update_imm_str();
- imm_str = $sformatf("%0d", $signed(imm));
- endfunction
-
- function void set_imm(int imm);
- this.imm = imm;
- mask_imm();
- update_imm_str();
- endfunction
-
- function riscv_reg_t gen_rand_gpr(riscv_reg_t included_reg[] = {},
- riscv_reg_t excluded_reg[] = {});
- riscv_reg_t gpr;
- int unsigned i;
- riscv_reg_t legal_gpr[$];
- if (included_reg.size() > 0) begin
- legal_gpr = included_reg;
- if (is_compressed && !(format inside {CR_FORMAT, CI_FORMAT, CSS_FORMAT})) begin
- while (i < legal_gpr.size()) begin
- if (legal_gpr[i] < S0 || legal_gpr[i] > A5) begin
- legal_gpr.delete(i);
- end else begin
- i++;
- end
- end
- end
- end else if (is_compressed &&
- !(format inside {CR_FORMAT, CI_FORMAT, CSS_FORMAT})) begin
- legal_gpr = riscv_instr_pkg::compressed_gpr;
- end else begin
- legal_gpr = riscv_instr_pkg::all_gpr;
- end
- if (format inside {CR_FORMAT, CI_FORMAT}) begin
- excluded_reg = {excluded_reg, ZERO};
- end
- if (excluded_reg.size() > 0) begin
- i = 0;
- while (i < legal_gpr.size()) begin
- if (legal_gpr[i] inside {excluded_reg}) begin
- legal_gpr.delete(i);
- end else begin
- i++;
- end
- end
- end
- `DV_CHECK_FATAL(legal_gpr.size() > 0)
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(i, i < legal_gpr.size();)
- gpr = legal_gpr[i];
- return gpr;
- endfunction
-
- function riscv_fpr_t gen_rand_fpr(riscv_fpr_t excluded_reg[] = {});
- riscv_fpr_t fpr;
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(fpr,
- if (excluded_reg.size() > 0) {
- !(fpr inside {excluded_reg});
- }
- if (is_compressed) {
- fpr inside {[F8:F15]};
- });
- return fpr;
- endfunction
-
- function void gen_rand_csr(bit illegal_csr_instr = 0,
- bit legal_invalid_csr_instr = 0,
- privileged_reg_t invalid_csrs[$] = {},
- bit enable_floating_point = 0,
- privileged_mode_t privileged_mode = MACHINE_MODE);
- privileged_reg_t preg[$];
- if (illegal_csr_instr) begin
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(csr, !(csr inside {implemented_csr});)
- end else if (legal_invalid_csr_instr) begin
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(csr, csr inside {invalid_csrs};)
- end else begin
- // Use scratch register to avoid the side effect of modifying other privileged mode CSR.
- if (privileged_mode == MACHINE_MODE)
- preg = {MSCRATCH};
- else if (privileged_mode == SUPERVISOR_MODE)
- preg = {SSCRATCH};
- else
- preg = {USCRATCH};
- if (enable_floating_point) begin
- preg = {preg, FFLAGS, FRM, FCSR};
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(csr, csr inside {preg};)
- end else begin
- csr = preg[0];
- end
- end
- endfunction
-
- function new(string name = "");
- super.new(name);
- endfunction
-
- // Convert the instruction to one-liner print message
- virtual function string convert2string();
- return convert2asm();
- endfunction
-
- virtual function void do_print (uvm_printer printer);
- `uvm_info(get_type_name(), convert2string(), UVM_LOW)
- endfunction
-
- // Convert the instruction to assembly code
- virtual function string convert2asm(string prefix = "");
- string asm_str;
- asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
- if (is_floating_point) begin
- case (format)
- I_FORMAT:
- if (category == LOAD) begin
- asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fd.name(), get_imm(), rs1.name());
- end else if (instr_name inside {FMV_X_W, FMV_X_D, FCVT_W_S, FCVT_WU_S,
- FCVT_L_S, FCVT_LU_S, FCVT_L_D, FCVT_LU_D, FCVT_LU_S,
- FCVT_W_D, FCVT_WU_D}) begin
- asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), fs1.name());
- end else if (instr_name inside {FMV_W_X, FMV_D_X, FCVT_S_W, FCVT_S_WU,
- FCVT_S_L, FCVT_D_L, FCVT_S_LU, FCVT_D_W,
- FCVT_D_LU, FCVT_D_WU}) begin
- asm_str = $sformatf("%0s%0s, %0s", asm_str, fd.name(), rs1.name());
- end else begin
- asm_str = $sformatf("%0s%0s, %0s", asm_str, fd.name(), fs1.name());
- end
- S_FORMAT:
- asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fs2.name(), get_imm(), rs1.name());
- R_FORMAT:
- if (category == COMPARE) begin
- asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), fs1.name(), fs2.name());
- end else if (instr_name inside {FCLASS_S, FCLASS_D}) begin
- asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), fs1.name());
- end else begin
- asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, fd.name(), fs1.name(), fs2.name());
- end
- R4_FORMAT:
- asm_str = $sformatf("%0s%0s, %0s, %0s, %0s", asm_str, fd.name(), fs1.name(),
- fs2.name(), fs3.name());
- CL_FORMAT:
- asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fd.name(), get_imm(), rs1.name());
- CS_FORMAT:
- asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fs2.name(), get_imm(), rs1.name());
- default:
- `uvm_fatal(`gfn, $sformatf("Unsupported floating point format: %0s", format.name()))
- endcase
- end else if((category != SYSTEM) && !(group inside {RV32A, RV64A})) begin
- case(format)
- J_FORMAT, U_FORMAT : // instr rd,imm
- asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm());
- I_FORMAT: // instr rd,rs1,imm
- if(instr_name == NOP)
- asm_str = "nop";
- else if(instr_name == C_NOP)
- asm_str = "c.nop";
- else if(instr_name == WFI)
- asm_str = "wfi";
- else if(instr_name == FENCE)
- asm_str = $sformatf("fence"); // TODO: Support all fence combinations
- else if(instr_name == FENCE_I)
- asm_str = "fence.i";
- else if(category == LOAD) // Use psuedo instruction format
- asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
- else if(category == CSR)
- asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, get_imm());
- else
- asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), rs1.name(), get_imm());
- S_FORMAT, B_FORMAT: // instr rs1,rs2,imm
- if(category == STORE) // Use psuedo instruction format
- asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name());
- else
- asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rs1.name(), rs2.name(), get_imm());
- R_FORMAT: // instr rd,rs1,rs2
- if(category == CSR) begin
- asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, rs1.name());
- end else if(instr_name == SFENCE_VMA) begin
- asm_str = "sfence.vma x0, x0"; // TODO: Support all possible sfence
- end else begin
- asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
- end
- CI_FORMAT, CIW_FORMAT:
- if(instr_name == C_NOP)
- asm_str = "c.nop";
- else if(instr_name == C_ADDI16SP)
- asm_str = $sformatf("%0ssp, %0s", asm_str, get_imm());
- else
- asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm());
- CL_FORMAT:
- asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
- CS_FORMAT:
- if(category == STORE)
- asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name());
- else
- asm_str = $sformatf("%0s%0s, %0s", asm_str, rs1.name(), rs2.name());
- CA_FORMAT:
- asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name());
- CB_FORMAT:
- asm_str = $sformatf("%0s%0s, %0s", asm_str, rs1.name(), get_imm());
- CSS_FORMAT:
- asm_str = $sformatf("%0s%0s, %0s", asm_str, rs2.name(), get_imm());
- CR_FORMAT:
- if (instr_name inside {C_JR, C_JALR}) begin
- asm_str = $sformatf("%0s%0s", asm_str, rs1.name());
- end else begin
- asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name());
- end
- CJ_FORMAT:
- asm_str = $sformatf("%0s%0s", asm_str, get_imm());
- endcase
- end else if (group inside {RV32A, RV64A}) begin
- if (instr_name inside {LR_W, LR_D}) begin
- asm_str = $sformatf("%0s %0s, (%0s)", asm_str, rd.name(), rs1.name());
- end else begin
- asm_str = $sformatf("%0s %0s, %0s, (%0s)", asm_str, rd.name(), rs2.name(), rs1.name());
- end
- `VECTOR_INCLUDE("riscv_instr_base_inc_convert2asm.sv")
- end else begin
- // For EBREAK,C.EBREAK, making sure pc+4 is a valid instruction boundary
- // This is needed to resume execution from epc+4 after ebreak handling
- if(instr_name == EBREAK) begin
- asm_str = ".4byte 0x00100073 # ebreak";
- end else if(instr_name == C_EBREAK) begin
- asm_str = "c.ebreak;c.nop;";
- end
- end
- if(comment != "")
- asm_str = {asm_str, " #",comment};
- return asm_str.tolower();
- endfunction
-
- function bit [6:0] get_opcode();
- case (instr_name) inside
- LUI : get_opcode = 7'b0110111;
- AUIPC : get_opcode = 7'b0010111;
- JAL : get_opcode = 7'b1101111;
- JALR : get_opcode = 7'b1100111;
- BEQ, BNE, BLT, BGE, BLTU, BGEU : get_opcode = 7'b1100011;
- LB, LH, LW, LBU, LHU, LWU, LD : get_opcode = 7'b0000011;
- SB, SH, SW, SD : get_opcode = 7'b0100011;
- ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI, NOP : get_opcode = 7'b0010011;
- ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, MUL,
- MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU : get_opcode = 7'b0110011;
- ADDIW, SLLIW, SRLIW, SRAIW : get_opcode = 7'b0011011;
- MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU : get_opcode = 7'b0110011;
- FENCE, FENCE_I : get_opcode = 7'b0001111;
- ECALL, EBREAK, CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI : get_opcode = 7'b1110011;
- ADDW, SUBW, SLLW, SRLW, SRAW, MULW, DIVW, DIVUW, REMW, REMUW : get_opcode = 7'b0111011;
- ECALL, EBREAK, URET, SRET, MRET, DRET, WFI, SFENCE_VMA : get_opcode = 7'b1110011;
- default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
- endcase
- endfunction
-
- // Get opcode for compressed instruction
- function bit [1:0] get_c_opcode();
- case (instr_name) inside
- C_ADDI4SPN, C_FLD, C_FLD, C_LQ, C_LW, C_FLW,
- C_LD, C_FSD, C_SQ, C_SW, C_FSW, C_SD : get_c_opcode = 2'b00;
- C_NOP, C_ADDI, C_JAL, C_ADDIW, C_LI, C_ADDI16SP,
- C_LUI, C_SRLI, C_SRLI64, C_SRAI, C_SRAI64,
- C_ANDI, C_SUB, C_XOR, C_OR, C_AND, C_SUBW,
- C_ADDW, C_J, C_BEQZ, C_BNEZ : get_c_opcode = 2'b01;
- C_SLLI, C_SLLI64, C_FLDSP, C_LQSP, C_LWSP,
- C_FLWSP, C_LDSP, C_JR, C_MV, C_EBREAK, C_JALR,
- C_ADD, C_FSDSP, C_SQSP, C_SWSP, C_FSWSP, C_SDSP : get_c_opcode = 2'b10;
- default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
- endcase
- endfunction
-
- function bit [2:0] get_func3();
- case (instr_name) inside
- JALR : get_func3 = 3'b000;
- BEQ : get_func3 = 3'b000;
- BNE : get_func3 = 3'b001;
- BLT : get_func3 = 3'b100;
- BGE : get_func3 = 3'b101;
- BLTU : get_func3 = 3'b110;
- BGEU : get_func3 = 3'b111;
- LB : get_func3 = 3'b000;
- LH : get_func3 = 3'b001;
- LW : get_func3 = 3'b010;
- LBU : get_func3 = 3'b100;
- LHU : get_func3 = 3'b101;
- SB : get_func3 = 3'b000;
- SH : get_func3 = 3'b001;
- SW : get_func3 = 3'b010;
- ADDI : get_func3 = 3'b000;
- NOP : get_func3 = 3'b000;
- SLTI : get_func3 = 3'b010;
- SLTIU : get_func3 = 3'b011;
- XORI : get_func3 = 3'b100;
- ORI : get_func3 = 3'b110;
- ANDI : get_func3 = 3'b111;
- SLLI : get_func3 = 3'b001;
- SRLI : get_func3 = 3'b101;
- SRAI : get_func3 = 3'b101;
- ADD : get_func3 = 3'b000;
- SUB : get_func3 = 3'b000;
- SLL : get_func3 = 3'b001;
- SLT : get_func3 = 3'b010;
- SLTU : get_func3 = 3'b011;
- XOR : get_func3 = 3'b100;
- SRL : get_func3 = 3'b101;
- SRA : get_func3 = 3'b101;
- OR : get_func3 = 3'b110;
- AND : get_func3 = 3'b111;
- FENCE : get_func3 = 3'b000;
- FENCE_I : get_func3 = 3'b001;
- ECALL : get_func3 = 3'b000;
- EBREAK : get_func3 = 3'b000;
- CSRRW : get_func3 = 3'b001;
- CSRRS : get_func3 = 3'b010;
- CSRRC : get_func3 = 3'b011;
- CSRRWI : get_func3 = 3'b101;
- CSRRSI : get_func3 = 3'b110;
- CSRRCI : get_func3 = 3'b111;
- LWU : get_func3 = 3'b110;
- LD : get_func3 = 3'b011;
- SD : get_func3 = 3'b011;
- ADDIW : get_func3 = 3'b000;
- SLLIW : get_func3 = 3'b001;
- SRLIW : get_func3 = 3'b101;
- SRAIW : get_func3 = 3'b101;
- ADDW : get_func3 = 3'b000;
- SUBW : get_func3 = 3'b000;
- SLLW : get_func3 = 3'b001;
- SRLW : get_func3 = 3'b101;
- SRAW : get_func3 = 3'b101;
- MUL : get_func3 = 3'b000;
- MULH : get_func3 = 3'b001;
- MULHSU : get_func3 = 3'b010;
- MULHU : get_func3 = 3'b011;
- DIV : get_func3 = 3'b100;
- DIVU : get_func3 = 3'b101;
- REM : get_func3 = 3'b110;
- REMU : get_func3 = 3'b111;
- MULW : get_func3 = 3'b000;
- DIVW : get_func3 = 3'b100;
- DIVUW : get_func3 = 3'b101;
- REMW : get_func3 = 3'b110;
- REMUW : get_func3 = 3'b111;
- C_ADDI4SPN : get_func3 = 3'b000;
- C_FLD : get_func3 = 3'b001;
- C_LQ : get_func3 = 3'b001;
- C_LW : get_func3 = 3'b010;
- C_FLW : get_func3 = 3'b011;
- C_LD : get_func3 = 3'b011;
- C_FSD : get_func3 = 3'b101;
- C_SQ : get_func3 = 3'b101;
- C_SW : get_func3 = 3'b110;
- C_FSW : get_func3 = 3'b111;
- C_SD : get_func3 = 3'b111;
- C_NOP : get_func3 = 3'b000;
- C_ADDI : get_func3 = 3'b000;
- C_JAL : get_func3 = 3'b001;
- C_ADDIW : get_func3 = 3'b001;
- C_LI : get_func3 = 3'b010;
- C_ADDI16SP : get_func3 = 3'b011;
- C_LUI : get_func3 = 3'b011;
- C_SRLI : get_func3 = 3'b100;
- C_SRLI64 : get_func3 = 3'b100;
- C_SRAI : get_func3 = 3'b100;
- C_SRAI64 : get_func3 = 3'b100;
- C_ANDI : get_func3 = 3'b100;
- C_SUB : get_func3 = 3'b100;
- C_XOR : get_func3 = 3'b100;
- C_OR : get_func3 = 3'b100;
- C_AND : get_func3 = 3'b100;
- C_SUBW : get_func3 = 3'b100;
- C_ADDW : get_func3 = 3'b100;
- C_J : get_func3 = 3'b101;
- C_BEQZ : get_func3 = 3'b110;
- C_BNEZ : get_func3 = 3'b111;
- C_SLLI : get_func3 = 3'b000;
- C_SLLI64 : get_func3 = 3'b000;
- C_FLDSP : get_func3 = 3'b001;
- C_LQSP : get_func3 = 3'b001;
- C_LWSP : get_func3 = 3'b010;
- C_FLWSP : get_func3 = 3'b011;
- C_LDSP : get_func3 = 3'b011;
- C_JR : get_func3 = 3'b100;
- C_MV : get_func3 = 3'b100;
- C_EBREAK : get_func3 = 3'b100;
- C_JALR : get_func3 = 3'b100;
- C_ADD : get_func3 = 3'b100;
- C_FSDSP : get_func3 = 3'b101;
- C_SQSP : get_func3 = 3'b101;
- C_SWSP : get_func3 = 3'b110;
- C_FSWSP : get_func3 = 3'b111;
- C_SDSP : get_func3 = 3'b111;
- ECALL, EBREAK, URET, SRET, MRET, DRET, WFI, SFENCE_VMA : get_func3 = 3'b000;
- default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
- endcase
- endfunction
-
- function bit [6:0] get_func7();
- case (instr_name)
- SLLI : get_func7 = 7'b0000000;
- SRLI : get_func7 = 7'b0000000;
- SRAI : get_func7 = 7'b0100000;
- ADD : get_func7 = 7'b0000000;
- SUB : get_func7 = 7'b0100000;
- SLL : get_func7 = 7'b0000000;
- SLT : get_func7 = 7'b0000000;
- SLTU : get_func7 = 7'b0000000;
- XOR : get_func7 = 7'b0000000;
- SRL : get_func7 = 7'b0000000;
- SRA : get_func7 = 7'b0100000;
- OR : get_func7 = 7'b0000000;
- AND : get_func7 = 7'b0000000;
- FENCE : get_func7 = 7'b0000000;
- FENCE_I : get_func7 = 7'b0000000;
- SLLIW : get_func7 = 7'b0000000;
- SRLIW : get_func7 = 7'b0000000;
- SRAIW : get_func7 = 7'b0100000;
- ADDW : get_func7 = 7'b0000000;
- SUBW : get_func7 = 7'b0100000;
- SLLW : get_func7 = 7'b0000000;
- SRLW : get_func7 = 7'b0000000;
- SRAW : get_func7 = 7'b0100000;
- MUL : get_func7 = 7'b0000001;
- MULH : get_func7 = 7'b0000001;
- MULHSU : get_func7 = 7'b0000001;
- MULHU : get_func7 = 7'b0000001;
- DIV : get_func7 = 7'b0000001;
- DIVU : get_func7 = 7'b0000001;
- REM : get_func7 = 7'b0000001;
- REMU : get_func7 = 7'b0000001;
- MULW : get_func7 = 7'b0000001;
- DIVW : get_func7 = 7'b0000001;
- DIVUW : get_func7 = 7'b0000001;
- REMW : get_func7 = 7'b0000001;
- REMUW : get_func7 = 7'b0000001;
- ECALL : get_func7 = 7'b0000000;
- EBREAK : get_func7 = 7'b0000000;
- URET : get_func7 = 7'b0000000;
- SRET : get_func7 = 7'b0001000;
- MRET : get_func7 = 7'b0011000;
- DRET : get_func7 = 7'b0111101;
- WFI : get_func7 = 7'b0001000;
- SFENCE_VMA: get_func7 = 7'b0001001;
- default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
- endcase
- endfunction
-
- // Convert the instruction to assembly code
- virtual function string convert2bin(string prefix = "");
- string binary;
- if (!is_compressed) begin
- case(format)
- J_FORMAT: begin
- binary = $sformatf("%8h", {imm[20], imm[10:1], imm[11], imm[19:12], rd, get_opcode()});
- end
- U_FORMAT: begin
- binary = $sformatf("%8h", {imm[31:12], rd, get_opcode()});
- end
- I_FORMAT: begin
- if(instr_name inside {FENCE, FENCE_I})
- binary = $sformatf("%8h", {17'b0, get_func3(), 5'b0, get_opcode()});
- else if(category == CSR)
- binary = $sformatf("%8h", {csr[10:0], imm[4:0], get_func3(), rd, get_opcode()});
- 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()});
- 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()});
- else if(instr_name == WFI)
- binary = $sformatf("%8h", {get_func7(), 5'b101, 13'b0, get_opcode()});
- else
- binary = $sformatf("%8h", {imm[11:0], rs1, get_func3(), rd, get_opcode()});
- end
- S_FORMAT: begin
- binary = $sformatf("%8h", {imm[11:5], rs2, rs1, get_func3(), imm[4:0], get_opcode()});
- end
- B_FORMAT: begin
- binary = $sformatf("%8h",
- {imm[12], imm[10:5], rs2, rs1, get_func3(),
- imm[4:1], imm[11], get_opcode()});
- end
- R_FORMAT: begin
- if(category == CSR)
- binary = $sformatf("%8h", {csr[10:0], rs1, get_func3(), rd, get_opcode()});
- else if(instr_name == SFENCE_VMA)
- binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()});
- else
- binary = $sformatf("%8h", {get_func7(), rs2, rs1, get_func3(), rd, get_opcode()});
- end
- endcase
- end else begin
- case (instr_name) inside
- C_ADDI4SPN:
- binary = $sformatf("%4h", {get_func3(), imm[5:4], imm[9:6],
- imm[2], imm[3], get_c_gpr(rd), get_c_opcode()});
- C_LQ:
- binary = $sformatf("%4h", {get_func3(), imm[5:4], imm[8],
- get_c_gpr(rs1), imm[7:6], get_c_gpr(rd), get_c_opcode()});
- C_FLD, C_LD:
- binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1),
- imm[7:6], get_c_gpr(rd), get_c_opcode()});
- C_LW, C_FLW:
- binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1),
- imm[2], imm[6], get_c_gpr(rd), get_c_opcode()});
- C_SQ:
- binary = $sformatf("%4h", {get_func3(), imm[5:4], imm[8],
- get_c_gpr(rs1), imm[7:6], get_c_gpr(rs2), get_c_opcode()});
- C_FSD, C_SD:
- binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1),
- imm[7:6], get_c_gpr(rs2), get_c_opcode()});
- C_SW, C_FSW:
- binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1),
- imm[2], imm[6], get_c_gpr(rs2), get_c_opcode()});
- C_NOP, C_ADDI, C_LI, C_ADDIW:
- binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:0], get_c_opcode()});
- C_JAL, C_J:
- 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,
- 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()});
- C_SRLI:
- binary = $sformatf("%4h", {get_func3(), imm[5],
- 2'b0, get_c_gpr(rd), imm[4:0], get_c_opcode()});
- C_SRLI64:
- binary = $sformatf("%4h", {get_func3(), 3'b0, get_c_gpr(rd), 5'b0, get_c_opcode()});
- C_SRAI:
- binary = $sformatf("%4h", {get_func3(), imm[5],
- 2'b01, get_c_gpr(rd), imm[4:0], get_c_opcode()});
- C_SRAI64:
- binary = $sformatf("%4h", {get_func3(), 3'b001,
- get_c_gpr(rd), 5'b0, get_c_opcode()});
- C_ANDI:
- binary = $sformatf("%4h", {get_func3(), imm[5],
- 2'b10, get_c_gpr(rd), imm[4:0], get_c_opcode()});
- C_SUB:
- binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd),
- 2'b00, get_c_gpr(rs2), get_c_opcode()});
- C_XOR:
- binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd),
- 2'b01, get_c_gpr(rs2), get_c_opcode()});
- C_OR:
- binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd),
- 2'b10, get_c_gpr(rs2), get_c_opcode()});
- C_AND:
- binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd),
- 2'b11, get_c_gpr(rs2), get_c_opcode()});
- C_SUBW:
- binary = $sformatf("%4h", {get_func3(), 3'b111, get_c_gpr(rd),
- 2'b00, get_c_gpr(rs2), get_c_opcode()});
- C_ADDW:
- binary = $sformatf("%4h", {get_func3(), 3'b111, get_c_gpr(rd),
- 2'b01, get_c_gpr(rs2), get_c_opcode()});
- C_BEQZ, C_BNEZ:
- binary = $sformatf("%4h", {get_func3(), imm[8], imm[4:3],
- get_c_gpr(rs1), imm[7:6], imm[2:1], imm[5], get_c_opcode()});
- C_SLLI:
- binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:0], get_c_opcode()});
- C_SLLI64:
- binary = $sformatf("%4h", {get_func3(), 1'b0, rd, 5'b0, get_c_opcode()});
- C_FLDSP, C_LDSP:
- binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:3], imm[8:6], get_c_opcode()});
- C_LQSP:
- binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4], imm[9:6], get_c_opcode()});
- C_LWSP, C_FLWSP:
- binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:2], imm[7:6], get_c_opcode()});
- C_JR:
- binary = $sformatf("%4h", {get_func3(), 1'b0, rs1, 5'b0, get_c_opcode()});
- C_MV:
- binary = $sformatf("%4h", {get_func3(), 1'b0, rd, rs2, get_c_opcode()});
- C_EBREAK:
- binary = $sformatf("%4h", {get_func3(), 1'b1, 10'b0, get_c_opcode()});
- C_JALR:
- binary = $sformatf("%4h", {get_func3(), 1'b1, 10'b0, get_c_opcode()});
- C_ADD:
- binary = $sformatf("%4h", {get_func3(), 1'b1, rd, rs2, get_c_opcode()});
- C_FSDSP, C_SDSP:
- binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:3], imm[8:6], rs2, get_c_opcode()});
- C_SQSP:
- binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:4], imm[9:6], rs2, get_c_opcode()});
- C_SWSP, C_FSWSP:
- binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:2], imm[7:6], rs2, get_c_opcode()});
- default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
- endcase
- end
- return {prefix, binary};
- endfunction
-
- virtual function string get_instr_name();
- get_instr_name = instr_name.name();
- if(get_instr_name.substr(0, 1) == "C_") begin
- get_instr_name = {"c.", get_instr_name.substr(2, get_instr_name.len() - 1)};
- end else if (group == RV32A) begin
- get_instr_name = {get_instr_name.substr(0, get_instr_name.len() - 3), ".w"};
- get_instr_name = aq ? {get_instr_name, ".aq"} :
- rl ? {get_instr_name, ".rl"} : get_instr_name;
- end else if (group == RV64A) begin
- get_instr_name = {get_instr_name.substr(0, get_instr_name.len() - 3), ".d"};
- get_instr_name = aq ? {get_instr_name, ".aq"} :
- rl ? {get_instr_name, ".rl"} : get_instr_name;
- end else if (group inside {RV32F, RV64F, RV32D, RV64D}) begin
- foreach(get_instr_name[i]) begin
- if (get_instr_name[i] == "_") begin
- get_instr_name[i] = ".";
- end
- end
- end
- return get_instr_name;
- endfunction
-
- // Get RVC register name for CIW, CL, CS, CB format
- function bit [2:0] get_c_gpr(riscv_reg_t gpr);
- return gpr[2:0];
- endfunction
-
- // Default return imm value directly, can be overriden to use labels and symbols
- // Example: %hi(symbol), %pc_rel(label) ...
- virtual function string get_imm();
- return imm_str;
- endfunction
-
- virtual function void clear_unused_label();
- if(has_label && !is_branch_target && is_local_numeric_label) begin
- has_label = 1'b0;
- end
- endfunction
-
- // Copy the rand fields of the base instruction
- virtual function void copy_base_instr(riscv_instr_base obj);
- this.group = obj.group;
- this.format = obj.format;
- this.category = obj.category;
- this.instr_name = obj.instr_name;
- this.rs2 = obj.rs2;
- this.rs1 = obj.rs1;
- this.rd = obj.rd;
- this.imm = obj.imm;
- this.imm_type = obj.imm_type;
- this.imm_len = obj.imm_len;
- this.imm_mask = obj.imm_mask;
- this.imm_str = obj.imm_str;
- this.is_pseudo_instr = obj.is_pseudo_instr;
- this.aq = obj.aq;
- this.rl = obj.rl;
- this.is_compressed = obj.is_compressed;
- this.has_imm = obj.has_imm;
- this.has_rs1 = obj.has_rs1;
- this.has_rs2 = obj.has_rs2;
- this.has_rd = obj.has_rd;
- this.fs3 = obj.fs3;
- this.fs2 = obj.fs2;
- this.fs1 = obj.fs1;
- this.fd = obj.fd;
- this.has_fs1 = obj.has_fs1;
- this.has_fs2 = obj.has_fs2;
- this.has_fs3 = obj.has_fs3;
- this.has_fd = obj.has_fd;
- this.is_floating_point = obj.is_floating_point;
- `VECTOR_INCLUDE("riscv_instr_base_inc_copy_base_instr.sv")
- endfunction
-
-endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_cov_test.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_cov_test.sv
deleted file mode 100644
index 10175fe..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_cov_test.sv
+++ /dev/null
@@ -1,295 +0,0 @@
-// This test read all trace CSV, and collect functional coverage from the instruction trace
-class riscv_instr_cov_test extends uvm_test;
-
- typedef uvm_enum_wrapper#(riscv_instr_name_t) instr_enum;
- typedef uvm_enum_wrapper#(riscv_reg_t) gpr_enum;
- typedef uvm_enum_wrapper#(privileged_reg_t) preg_enum;
- `VECTOR_INCLUDE("riscv_instr_cov_test_inc_typedef.sv")
-
- riscv_instr_gen_config cfg;
- riscv_instr_cover_group instr_cg;
- riscv_instr_cov_item instr;
- string trace_csv[$];
- string trace[string];
- int unsigned entry_cnt;
- int unsigned total_entry_cnt;
- int unsigned skipped_cnt;
- int unsigned unexpected_illegal_instr_cnt;
-
- `uvm_component_utils(riscv_instr_cov_test)
- `uvm_component_new
-
- task run_phase(uvm_phase phase);
- int i;
- string args;
- string csv;
- string line;
- string header[$];
- string entry[$];
- int fd;
- while(1) begin
- args = {$sformatf("trace_csv_%0d", i), "=%s"};
- if ($value$plusargs(args, csv)) begin
- trace_csv.push_back(csv);
- end else begin
- break;
- end
- i++;
- end
- cfg = riscv_instr_gen_config::type_id::create("cfg");
- // disable_compressed_instr is not relevant to coverage test
- cfg.disable_compressed_instr = 0;
- `ifdef DEPRECATED
- cfg.build_instruction_template(.skip_instr_exclusion(1));
- `else
- riscv_instr::create_instr_list(cfg);
- `endif
- instr = riscv_instr_cov_item::type_id::create("instr");
- instr.rand_mode(0);
- `ifdef DEPRECATED
- instr.no_hint_illegal_instr_c.constraint_mode(0);
- instr.imm_val_c.constraint_mode(0);
- `endif
- instr_cg = new(cfg);
- `uvm_info(`gfn, $sformatf("%0d CSV trace files to be processed", trace_csv.size()), UVM_LOW)
- foreach (trace_csv[i]) begin
- bit expect_illegal_instr;
- entry_cnt = 0;
- instr_cg.reset();
- if (uvm_is_match("*illegal*", trace_csv[i])) begin
- expect_illegal_instr = 1;
- end
- `uvm_info(`gfn, $sformatf("Processing CSV trace[%0d]: %s", i, trace_csv[i]), UVM_LOW)
- fd = $fopen(trace_csv[i], "r");
- if (fd) begin
- // Get the header line
- if ($fgets(line, fd)) begin
- split_string(line, ",", header);
- `uvm_info(`gfn, $sformatf("Header: %0s", line), UVM_HIGH);
- end else begin
- `uvm_info(`gfn, $sformatf("Skipping empty trace file: %0s", trace_csv[i]), UVM_LOW)
- continue;
- end
- while ($fgets(line, fd)) begin
- split_string(line, ",", entry);
- if (entry.size() != header.size()) begin
- `uvm_info(`gfn, $sformatf("Skipping malformed entry[%0d] : %0s", entry_cnt, line), UVM_LOW)
- skipped_cnt += 1;
- end else begin
- trace["csv_entry"] = line;
- foreach (header[j]) begin
- trace[header[j]] = entry[j];
- end
- post_process_trace();
- if (trace["instr"] inside {"li", "ret", "la"}) continue;
- if (uvm_is_match("amo*",trace["instr"]) ||
- uvm_is_match("lr*" ,trace["instr"]) ||
- uvm_is_match("sc*" ,trace["instr"])) begin
- // TODO: Enable functional coverage for AMO test
- continue;
- end
- if (!sample()) begin
- `uvm_info(`gfn, $sformatf("Found illegal instr: %0s [%0s]",
- trace["instr"], line), UVM_HIGH)
- if (!expect_illegal_instr) begin
- unexpected_illegal_instr_cnt++;
- end
- end
- end
- entry_cnt += 1;
- end
- end else begin
- `uvm_error(`gfn, $sformatf("%0s cannot be openned", trace_csv[i]))
- end
- `uvm_info(`gfn, $sformatf("[%s] : %0d instructions processed",
- trace_csv[i], entry_cnt), UVM_LOW)
- total_entry_cnt += entry_cnt;
- end
- `uvm_info(`gfn, $sformatf("Finished processing %0d trace CSV, %0d instructions",
- trace_csv.size(), total_entry_cnt), UVM_LOW)
- if ((skipped_cnt > 0) || (unexpected_illegal_instr_cnt > 0)) begin
- `uvm_error(`gfn, $sformatf("%0d instructions skipped, %0d illegal instruction",
- skipped_cnt, unexpected_illegal_instr_cnt))
-
- end else begin
- `uvm_info(`gfn, "TEST PASSED", UVM_NONE);
- end
- endtask
-
- virtual function void post_process_trace();
- endfunction
-
- function void fatal (string str);
- `uvm_info(`gfn, str, UVM_NONE);
- if ($test$plusargs("stop_on_first_error")) begin
- `uvm_fatal(`gfn, "Errors: *. Warnings: * (written by riscv_instr_cov.sv)")
- end
- endfunction
-
- function bit sample();
- riscv_instr_name_t instr_name;
- bit [XLEN-1:0] val;
- if (instr_enum::from_name(process_instr_name(trace["instr"]), instr_name)) begin
- `ifdef DEPRECATED
- if (cfg.instr_template.exists(instr_name)) begin
- instr.copy_base_instr(cfg.instr_template[instr_name]);
- `else
- if (riscv_instr::instr_template.exists(instr_name)) begin
- instr.copy(riscv_instr::instr_template[instr_name]);
- `endif
- assign_trace_info_to_instr(instr);
- instr.pre_sample();
- instr_cg.sample(instr);
- return 1'b1;
- end
- end
- `uvm_info(`gfn, $sformatf("Cannot find opcode: %0s",
- process_instr_name(trace["instr"])), UVM_LOW)
- get_val(trace["binary"], val);
- if ((val[1:0] != 2'b11) && (RV32C inside {supported_isa})) begin
- `SAMPLE(instr_cg.compressed_opcode_cg, val[15:0])
- `SAMPLE(instr_cg.illegal_compressed_instr_cg, val)
- end
- if (val[1:0] == 2'b11) begin
- `uvm_info("DBG", $sformatf("Sample opcode: %0x [%0s]", val[6:2], trace["instr"]), UVM_LOW)
- `SAMPLE(instr_cg.opcode_cg, val[6:2])
- end
- endfunction
-
- virtual function void assign_trace_info_to_instr(riscv_instr_cov_item instr);
- riscv_reg_t gpr;
- `VECTOR_INCLUDE("riscv_instr_cov_test_inc_assign_trace_info_to_instr_declares.sv")
- privileged_reg_t preg;
- get_val(trace["addr"], instr.pc);
- get_val(trace["binary"], instr.binary);
- instr.trace = trace["str"];
- if (instr.instr_name inside {ECALL, EBREAK, FENCE, FENCE_I, NOP,
- C_NOP, WFI, MRET, C_EBREAK}) begin
- return;
- end
- if (instr.has_rs2) begin
- if (get_gpr(trace["rs2"], gpr)) begin
- instr.rs2 = gpr;
- get_val(trace["rs2_val"], instr.rs2_value);
- end else begin
- `uvm_error(`gfn, $sformatf("Unrecognized rs2: [%0s] (%0s)",
- trace["rs2"], trace["csv_entry"]))
- end
- end
- if (instr.has_rd) begin
- if (get_gpr(trace["rd"], gpr)) begin
- instr.rd = gpr;
- get_val(trace["rd_val"], instr.rd_value);
- end else begin
- `uvm_error(`gfn, $sformatf("Unrecognized rd: [%0s] (%0s)",
- trace["rd"], trace["csv_entry"]))
- end
- end
- if (instr.has_rs1) begin
- if (instr.format inside {CI_FORMAT, CR_FORMAT} &&
- !(instr.instr_name inside {C_JR, C_JALR})) begin
- instr.rs1 = instr.rd;
- end else begin
- if (get_gpr(trace["rs1"], gpr)) begin
- instr.rs1 = gpr;
- get_val(trace["rs1_val"], instr.rs1_value);
- end else begin
- `uvm_error(`gfn, $sformatf("Unrecognized rs1: [%0s] (%0s)",
- trace["rs1"], trace["csv_entry"]))
- end
- end
- end
- if (instr.has_imm) begin
- get_val(trace["imm"], instr.imm);
- end
- if (instr.category == CSR) begin
- if (preg_enum::from_name(trace["csr"].toupper(), preg)) begin
- instr.csr = preg;
- end else begin
- get_val(trace["csr"], instr.csr);
- end
- end
- if (instr.category inside {LOAD, STORE}) begin
- if (XLEN == 32) begin
- instr.mem_addr = instr.rs1_value + instr.imm;
- end else begin
- bit [XLEN-32-1:0] padding;
- if (instr.imm[31]) begin
- padding = '1;
- end else begin
- padding = '0;
- end
- instr.mem_addr = instr.rs1_value + {padding, instr.imm};
- end
- end
-
- `VECTOR_INCLUDE("riscv_instr_cov_test_inc_assign_trace_info_to_instr.sv")
-
- endfunction
-
- function bit get_gpr(input string str, output riscv_reg_t gpr);
- str = str.toupper();
- if (gpr_enum::from_name(str, gpr)) begin
- return 1'b1;
- end else begin
- return 1'b0;
- end
- endfunction
-
- `VECTOR_INCLUDE("riscv_instr_cov_test_inc_assign_trace_info_to_instr_functions.sv")
-
- function void get_val(input string str, output bit [XLEN-1:0] val);
- val = str.atohex();
- endfunction
-
- function string process_instr_name(string instr_name);
- instr_name = instr_name.toupper();
- foreach (instr_name[i]) begin
- if (instr_name[i] == ".") begin
- instr_name[i] = "_";
- end
- end
- return instr_name;
- endfunction
-
- function void split_string(string str, byte step, ref string result[$]);
- string tmp_str;
- int i;
- bit in_quote;
- result = {};
- while (i < str.len()) begin
- if (str[i] == "\"") begin
- in_quote = ~in_quote;
- end else if ((str[i] == step) && !in_quote) begin
- result.push_back(tmp_str);
- tmp_str = "";
- end else begin
- tmp_str = {tmp_str, str[i]};
- end
- if (i == str.len()-1) begin
- result.push_back(tmp_str);
- end
- i++;
- end
- endfunction
-
- function void report_phase(uvm_phase phase);
- uvm_report_server rs;
- int error_count;
-
- rs = uvm_report_server::get_server();
-
- error_count = rs.get_severity_count(UVM_WARNING) +
- rs.get_severity_count(UVM_ERROR) +
- rs.get_severity_count(UVM_FATAL);
-
- if (error_count == 0) begin
- `uvm_info("", "TEST PASSED", UVM_NONE);
- end else begin
- `uvm_info("", "TEST FAILED", UVM_NONE);
- end
- `uvm_info("", "TEST GENERATION DONE", UVM_NONE);
- super.report_phase(phase);
- endfunction
-
-endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_gen_config.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_gen_config.sv
deleted file mode 100644
index d6ccb46..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_gen_config.sv
+++ /dev/null
@@ -1,700 +0,0 @@
-/*
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//-----------------------------------------------------------------------------
-// RISC-V assembly program generator configuration class
-//-----------------------------------------------------------------------------
-
-class riscv_instr_gen_config extends uvm_object;
-
- //-----------------------------------------------------------------------------
- // Random instruction generation settings
- //-----------------------------------------------------------------------------
-
- // Instruction count of the main program
- rand int main_program_instr_cnt;
-
- // Instruction count of each sub-program
- rand int sub_program_instr_cnt[];
-
- // Instruction count of the debug rom
- rand int debug_program_instr_cnt;
-
- // Instruction count of debug sub-programs
- rand int debug_sub_program_instr_cnt[];
-
- // Pattern of data section: RAND_DATA, ALL_ZERO, INCR_VAL
- rand data_pattern_t data_page_pattern;
-
- // Associate array for delegation configuration for each exception and interrupt
- // When the bit is 1, the corresponding delegation is enabled.
- rand bit m_mode_exception_delegation[exception_cause_t];
- rand bit s_mode_exception_delegation[exception_cause_t];
- rand bit m_mode_interrupt_delegation[interrupt_cause_t];
- rand bit s_mode_interrupt_delegation[interrupt_cause_t];
-
- // Priviledged mode after boot
- rand privileged_mode_t init_privileged_mode;
-
- rand bit[XLEN-1:0] mstatus, mie,
- sstatus, sie,
- ustatus, uie;
-
- // Key fields in xSTATUS
- // Memory protection bits
- rand bit mstatus_mprv;
- rand bit mstatus_mxr;
- rand bit mstatus_sum;
- rand bit mstatus_tvm;
- rand bit [1:0] mstatus_fs;
- rand mtvec_mode_t mtvec_mode;
-
- // Floating point rounding mode
- rand f_rounding_mode_t fcsr_rm;
-
- // Enable sfence.vma instruction
- rand bit enable_sfence;
-
- // Reserved register
- // Reserved for various hardcoded routines
- rand riscv_reg_t gpr[4];
- // Used by any DCSR operations inside of the debug rom
- rand riscv_reg_t scratch_reg;
- // Use a random register for stack pointer/thread pointer
- rand riscv_reg_t sp;
- rand riscv_reg_t tp;
- rand riscv_reg_t ra;
-
- // Options for privileged mode CSR checking
- // Below checking can be made optional as the ISS implementation could be different with the
- // processor.
- bit check_misa_init_val = 1'b0;
- bit check_xstatus = 1'b1;
-
- // Virtual address translation is on for this test
- rand bit virtual_addr_translation_on;
-
- //-----------------------------------------------------------------------------
- // User space memory region and stack setting
- //-----------------------------------------------------------------------------
-
- mem_region_t mem_region[$] = '{
- '{name:"region_0", size_in_bytes: 4096, xwr: 3'b111},
- '{name:"region_1", size_in_bytes: 4096 * 4, xwr: 3'b111},
- '{name:"region_2", size_in_bytes: 4096 * 2, xwr: 3'b111},
- '{name:"region_3", size_in_bytes: 512, xwr: 3'b111},
- '{name:"region_4", size_in_bytes: 4096, xwr: 3'b111}
- };
-
- // Stack section word length
- int stack_len = 5000;
-
- //-----------------------------------------------------------------------------
- // Kernel section setting, used by supervisor mode programs
- //-----------------------------------------------------------------------------
-
- mem_region_t s_mem_region[$] = '{
- '{name:"s_region_0", size_in_bytes: 4096, xwr: 3'b111},
- '{name:"s_region_1", size_in_bytes: 4096, xwr: 3'b111}};
-
- // Kernel Stack section word length
- int kernel_stack_len = 4000;
-
- // Number of instructions for each kernel program
- int kernel_program_instr_cnt = 400;
-
- //-----------------------------------------------------------------------------
- // Instruction list based on the config, generate by build_instruction_template
- //-----------------------------------------------------------------------------
- riscv_instr_base instr_template[riscv_instr_name_t];
- riscv_instr_name_t basic_instr[$];
- riscv_instr_name_t instr_group[riscv_instr_group_t][$];
- riscv_instr_name_t instr_category[riscv_instr_category_t][$];
-
- // Queue of all the main implemented CSRs that the boot privilege mode cannot access
- // e.g. these CSRs are in higher privilege modes - access should raise an exception
- privileged_reg_t invalid_priv_mode_csrs[$];
-
- //-----------------------------------------------------------------------------
- // Command line options or control knobs
- //-----------------------------------------------------------------------------
- // Main options for RISC-V assembly program generation
- // Number of sub-programs per test
- int num_of_sub_program = 5;
- int instr_cnt = 200;
- int num_of_tests = 1;
- // For tests doesn't involve load/store, the data section generation could be skipped
- bit no_data_page;
- // Options to turn off some specific types of instructions
- bit no_branch_jump; // No branch/jump instruction
- bit no_load_store; // No load/store instruction
- bit no_csr_instr; // No csr instruction
- bit no_ebreak = 1; // No ebreak instruction
- bit no_dret = 1; // No dret instruction
- bit no_fence; // No fence instruction
- bit no_wfi = 1; // No WFI instruction
- bit enable_unaligned_load_store;
- int illegal_instr_ratio;
- int hint_instr_ratio;
- // Directed boot privileged mode, u, m, s
- string boot_mode_opts;
- int enable_page_table_exception;
- bit no_directed_instr;
- // A name suffix for the generated assembly program
- string asm_test_suffix;
- // Enable interrupt bit in MSTATUS (MIE, SIE, UIE)
- bit enable_interrupt;
- // We need a separate control knob for enabling timer interrupts, as Spike
- // throws an exception if xIE.xTIE is enabled
- bit enable_timer_irq;
- // Generate a bare program without any init/exit/error handling/page table routines
- // The generated program can be integrated with a larger program.
- // Note that the bare mode program is not expected to run in standalone mode
- bit bare_program_mode;
- // Enable accessing illegal CSR instruction
- // - Accessing non-existence CSR
- // - Accessing CSR with wrong privileged mode
- bit enable_illegal_csr_instruction;
- // Enable accessing CSRs at an invalid privilege level
- bit enable_access_invalid_csr_level;
- // Enable some dummy writes to main system CSRs (xSTATUS/xIE) at beginning of test
- // to check repeated writes
- bit enable_dummy_csr_write;
- bit randomize_csr = 0;
- // sfence support
- bit allow_sfence_exception = 0;
- // Interrupt/Exception Delegation
- bit no_delegation = 1;
- bit force_m_delegation = 0;
- bit force_s_delegation = 0;
- bit support_supervisor_mode;
- bit disable_compressed_instr;
- // "Memory mapped" address that when written to will indicate some event to
- // the testbench - testbench will take action based on the value written
- int signature_addr = 32'hdead_beef;
- bit require_signature_addr = 1'b0;
- // Enable a full or empty debug_rom section.
- // Full debug_rom will contain random instruction streams.
- // Empty debug_rom will contain just dret instruction and will return immediately.
- // Will be empty by default.
- bit gen_debug_section = 1'b0;
- // Enable generation of a directed sequence of instructions containing
- // ebreak inside the debug_rom.
- // Disabled by default.
- bit enable_ebreak_in_debug_rom = 1'b0;
- // Enable setting dcsr.ebreak(m/s/u)
- bit set_dcsr_ebreak = 1'b0;
- // Number of sub programs in the debug rom
- int num_debug_sub_program = 0;
- // Enable debug single stepping
- bit enable_debug_single_step = 0;
- // Number of single stepping iterations
- rand int single_step_iterations;
- // Enable mstatus.tw bit - causes u-mode WFI to raise illegal instruction exceptions
- bit set_mstatus_tw;
- // Stack space allocated to each program, need to be enough to store necessary context
- // Example: RA, SP, T0
- int min_stack_len_per_program = 10 * (XLEN/8);
- int max_stack_len_per_program = 16 * (XLEN/8);
- // Maximum branch distance, avoid skipping large portion of the code
- int max_branch_step = 20;
- // Maximum directed instruction stream sequence count
- int max_directed_instr_stream_seq = 20;
- // Reserved registers
- riscv_reg_t reserved_regs[];
- // Floating point support
- bit enable_floating_point;
-
- //-----------------------------------------------------------------------------
- // Command line options for instruction distribution control
- //-----------------------------------------------------------------------------
- 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;
- debug_sub_program_instr_cnt.size() == num_debug_sub_program;
- main_program_instr_cnt inside {[10 : instr_cnt]};
- foreach(sub_program_instr_cnt[i]) {
- sub_program_instr_cnt[i] inside {[10 : instr_cnt]};
- }
- // Disable sfence if the program is not boot to supervisor mode
- // If sfence exception is allowed, we can enable sfence instruction in any priviledged mode.
- // When MSTATUS.TVM is set, executing sfence.vma will be treate as illegal instruction
- if(allow_sfence_exception) {
- 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);
- }
- }
-
- constraint debug_mode_c {
- if (riscv_instr_pkg::support_debug_mode) {
- debug_program_instr_cnt inside {[100 : 300]};
- foreach(debug_sub_program_instr_cnt[i]) {
- debug_sub_program_instr_cnt[i] inside {[100 : 300]};
- }
- }
- `ifndef DSIM
- main_program_instr_cnt + sub_program_instr_cnt.sum() == instr_cnt;
- `else
- // dsim has some issue supporting sum(), use some approximate constraint to generate
- // instruction cnt
- if (num_of_sub_program > 0) {
- main_program_instr_cnt inside {[10:instr_cnt/2]};
- foreach (sub_program_instr_cnt[i]) {
- sub_program_instr_cnt[i] inside {[10:instr_cnt/num_of_sub_program]};
- }
- } else {
- main_program_instr_cnt == instr_cnt;
- }
- `endif
- }
-
- // Keep the number of single step iterations relatively small
- constraint debug_single_step_c {
- if (enable_debug_single_step) {
- single_step_iterations inside {[10 : 50]};
- }
- }
-
- // Boot privileged mode distribution
- constraint boot_privileged_mode_dist_c {
- // Boot to higher privileged mode more often
- if(riscv_instr_pkg::supported_privileged_mode.size() == 2) {
- init_privileged_mode dist {riscv_instr_pkg::supported_privileged_mode[0] := 6,
- riscv_instr_pkg::supported_privileged_mode[1] := 4};
- } else if (riscv_instr_pkg::supported_privileged_mode.size() == 3) {
- init_privileged_mode dist {riscv_instr_pkg::supported_privileged_mode[0] := 4,
- riscv_instr_pkg::supported_privileged_mode[1] := 3,
- riscv_instr_pkg::supported_privileged_mode[2] := 3};
- } else {
- init_privileged_mode == riscv_instr_pkg::supported_privileged_mode[0];
- }
- }
-
- constraint mtvec_c {
- mtvec_mode inside {supported_interrupt_mode};
- }
-
- constraint mstatus_c {
- // This is default disabled at setup phase. It can be enabled in the exception and interrupt
- // handling routine
- mstatus_mprv == 1'b0;
- }
-
- // Exception delegation setting
- constraint exception_delegation_c {
- // Do not delegate instructino page fault to supervisor/user mode because this may introduce
- // dead loop. All the subsequent instruction fetches may fail and program cannot recover.
- m_mode_exception_delegation[INSTRUCTION_PAGE_FAULT] == 1'b0;
- if(force_m_delegation) {
- foreach(m_mode_exception_delegation[i]) {
- soft m_mode_exception_delegation[i] == 1'b1;
- }
- foreach(m_mode_interrupt_delegation[i]) {
- soft m_mode_interrupt_delegation[i] == 1'b1;
- }
- }
- if(force_s_delegation) {
- foreach(s_mode_exception_delegation[i]) {
- soft s_mode_exception_delegation[i] == 1'b1;
- }
- foreach(s_mode_interrupt_delegation[i]) {
- soft s_mode_interrupt_delegation[i] == 1'b1;
- }
- }
- }
-
- // Spike only supports a subset of exception and interrupt delegation
- // You can modify this constraint if your ISS support different set of delegations
- constraint delegation_c {
- foreach(m_mode_exception_delegation[i]) {
- if(!support_supervisor_mode || no_delegation) {
- m_mode_exception_delegation[i] == 0;
- }
- if(!(i inside {INSTRUCTION_ADDRESS_MISALIGNED, BREAKPOINT, ECALL_UMODE,
- INSTRUCTION_PAGE_FAULT, LOAD_PAGE_FAULT, STORE_AMO_PAGE_FAULT})) {
- m_mode_exception_delegation[i] == 0;
- }
- }
- foreach(m_mode_interrupt_delegation[i]) {
- if(!support_supervisor_mode || no_delegation) {
- m_mode_interrupt_delegation[i] == 0;
- }
- if(!(i inside {S_SOFTWARE_INTR, S_TIMER_INTR, S_EXTERNAL_INTR})) {
- m_mode_interrupt_delegation[i] == 0;
- }
- }
- }
-
- constraint ra_c {
- ra dist {RA := 5, T1 := 2, [SP:T0] :/ 1, [T2:T6] :/ 2};
- ra != sp;
- ra != tp;
- ra != ZERO;
- }
-
- constraint sp_tp_c {
- sp != tp;
- sp dist {SP := 6, RA := 1, [GP:T6] :/ 3};
- !(sp inside {GP, RA, ZERO});
- !(tp inside {GP, RA, ZERO});
- }
-
- constraint reserve_scratch_reg_c {
- scratch_reg != ZERO;
- scratch_reg != sp;
- scratch_reg != tp;
- }
-
- constraint gpr_c {
- foreach (gpr[i]) {
- !(gpr[i] inside {sp, tp, scratch_reg, ZERO, RA, GP});
- }
- unique {gpr};
- }
-
- constraint addr_translaction_c {
- solve init_privileged_mode before virtual_addr_translation_on;
- if ((init_privileged_mode != MACHINE_MODE) && (SATP_MODE != BARE)) {
- virtual_addr_translation_on == 1'b1;
- } else {
- virtual_addr_translation_on == 1'b0;
- }
- }
-
- constraint floating_point_c {
- if (enable_floating_point) {
- mstatus_fs == 2'b01;
- } else {
- mstatus_fs == 2'b00;
- }
- }
-
- `uvm_object_utils_begin(riscv_instr_gen_config)
- `uvm_field_int(main_program_instr_cnt, UVM_DEFAULT)
- `uvm_field_sarray_int(sub_program_instr_cnt, UVM_DEFAULT)
- `uvm_field_int(debug_program_instr_cnt, UVM_DEFAULT)
- `uvm_field_enum(data_pattern_t, data_page_pattern, UVM_DEFAULT)
- `uvm_field_enum(privileged_mode_t, init_privileged_mode, UVM_DEFAULT)
- `uvm_field_array_enum(riscv_reg_t, reserved_regs, UVM_DEFAULT)
- `uvm_object_utils_end
-
- function new (string name = "");
- string s;
- super.new(name);
- init_delegation();
- inst = uvm_cmdline_processor::get_inst();
- get_int_arg_value("+num_of_tests=", num_of_tests);
- get_int_arg_value("+enable_page_table_exception=", enable_page_table_exception);
- get_bool_arg_value("+enable_interrupt=", enable_interrupt);
- get_bool_arg_value("+enable_timer_irq=", enable_timer_irq);
- get_int_arg_value("+num_of_sub_program=", num_of_sub_program);
- get_int_arg_value("+instr_cnt=", instr_cnt);
- get_bool_arg_value("+no_ebreak=", no_ebreak);
- get_bool_arg_value("+no_dret=", no_dret);
- get_bool_arg_value("+no_wfi=", no_wfi);
- 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("+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_dummy_csr_write=", enable_dummy_csr_write);
- get_bool_arg_value("+allow_sfence_exception=", allow_sfence_exception);
- get_bool_arg_value("+no_data_page=", no_data_page);
- get_bool_arg_value("+no_directed_instr=", no_directed_instr);
- get_bool_arg_value("+no_fence=", no_fence);
- get_bool_arg_value("+no_delegation=", no_delegation);
- get_int_arg_value("+illegal_instr_ratio=", illegal_instr_ratio);
- get_int_arg_value("+hint_instr_ratio=", hint_instr_ratio);
- 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);
- get_bool_arg_value("+require_signature_addr=", require_signature_addr);
- get_bool_arg_value("+disable_compressed_instr=", disable_compressed_instr);
- get_bool_arg_value("+randomize_csr=", randomize_csr);
- if (this.require_signature_addr) begin
- get_hex_arg_value("+signature_addr=", signature_addr);
- end
- get_bool_arg_value("+gen_debug_section=", gen_debug_section);
- get_bool_arg_value("+bare_program_mode=", bare_program_mode);
- get_int_arg_value("+num_debug_sub_program=", num_debug_sub_program);
- get_bool_arg_value("+enable_ebreak_in_debug_rom=", enable_ebreak_in_debug_rom);
- get_bool_arg_value("+set_dcsr_ebreak=", set_dcsr_ebreak);
- get_bool_arg_value("+enable_debug_single_step=", enable_debug_single_step);
- get_bool_arg_value("+set_mstatus_tw=", set_mstatus_tw);
- get_bool_arg_value("+enable_floating_point=", enable_floating_point);
- if(inst.get_arg_value("+boot_mode=", boot_mode_opts)) begin
- `uvm_info(get_full_name(), $sformatf(
- "Got boot mode option - %0s", boot_mode_opts), UVM_LOW)
- case(boot_mode_opts)
- "m" : init_privileged_mode = MACHINE_MODE;
- "s" : init_privileged_mode = SUPERVISOR_MODE;
- "u" : init_privileged_mode = USER_MODE;
- default: `uvm_fatal(get_full_name(),
- $sformatf("Illegal boot mode option - %0s", boot_mode_opts))
- endcase
- init_privileged_mode.rand_mode(0);
- end
- `uvm_info(`gfn, $sformatf("riscv_instr_pkg::supported_privileged_mode = %0d",
- riscv_instr_pkg::supported_privileged_mode.size()), UVM_LOW)
- void'(inst.get_arg_value("+asm_test_suffix=", asm_test_suffix));
- // Directed march list from the runtime options, ex. RV32I, RV32M etc.
- void'(inst.get_arg_value("+march=", s));
- if(s != "") begin
- string cmdline_march_list[$];
- riscv_instr_group_t march;
- uvm_split_string(s, ",", cmdline_march_list);
- riscv_instr_pkg::supported_isa.delete();
- foreach(cmdline_march_list[i]) begin
- if(uvm_enum_wrapper#(riscv_instr_group_t)::from_name(
- cmdline_march_list[i].toupper(), march)) begin
- riscv_instr_pkg::supported_isa.push_back(march);
- end else begin
- `uvm_fatal(get_full_name(), $sformatf(
- "Invalid march %0s specified in command line", cmdline_march_list[i]))
- end
- end
- end
- if (!(RV32C inside {supported_isa})) begin
- disable_compressed_instr = 1;
- end
- setup_instr_distribution();
- get_invalid_priv_lvl_csr();
- endfunction
-
- function void setup_instr_distribution();
- string opts;
- int val;
- get_int_arg_value("+dist_control_mode=", dist_control_mode);
- if (dist_control_mode == 1) begin
- riscv_instr_category_t category;
- category = category.first;
- do begin
- opts = {$sformatf("dist_%0s=", category.name()), "%d"};
- opts = opts.tolower();
- if ($value$plusargs(opts, val)) begin
- category_dist[category] = val;
- end else begin
- category_dist[category] = 10; // Default ratio
- end
- `uvm_info(`gfn, $sformatf("Set dist[%0s] = %0d",
- category.name(), category_dist[category]), UVM_LOW)
- category = category.next;
- end
- while(category != category.first);
- end
- endfunction
-
- // Initialize the exception/interrupt delegation associate array, set all delegation default to 0
- virtual function void init_delegation();
- exception_cause_t cause;
- interrupt_cause_t intr_cause;
- cause = cause.first;
- // Init exception delegation array
- do begin
- m_mode_exception_delegation[cause] = 1'b0;
- s_mode_exception_delegation[cause] = 1'b0;
- cause = cause.next;
- end
- while(cause != cause.first);
- // Init interrupt delegation array
- intr_cause = intr_cause.first;
- do begin
- m_mode_interrupt_delegation[intr_cause] = 1'b0;
- s_mode_interrupt_delegation[intr_cause] = 1'b0;
- intr_cause = intr_cause.next;
- end
- while(intr_cause != intr_cause.first);
- endfunction
-
- function void pre_randomize();
- foreach (riscv_instr_pkg::supported_privileged_mode[i]) begin
- if(riscv_instr_pkg::supported_privileged_mode[i] == SUPERVISOR_MODE)
- support_supervisor_mode = 1;
- end
- endfunction
-
- function void get_non_reserved_gpr();
- endfunction
-
- function void post_randomize();
- // Setup the list all reserved registers
- reserved_regs = {tp, sp, scratch_reg};
- // Need to save all loop registers, and RA/T0
- min_stack_len_per_program = 2 * (XLEN/8);
- // Check if the setting is legal
- check_setting();
- // WFI is not supported in umode
- if (init_privileged_mode == USER_MODE) begin
- no_wfi = 1'b1;
- end
- endfunction
-
- function void check_setting();
- bit support_64b;
- bit support_128b;
- foreach (riscv_instr_pkg::supported_isa[i]) begin
- if (riscv_instr_pkg::supported_isa[i] inside {RV64I, RV64M, RV64A, RV64F, RV64D, RV64C}) begin
- support_64b = 1'b1;
- end else if (riscv_instr_pkg::supported_isa[i] inside {RV128I, RV128C}) begin
- support_128b = 1'b1;
- end
- end
- if (support_128b && XLEN != 128) begin
- `uvm_fatal(`gfn, "XLEN should be set to 128 based on riscv_instr_pkg::supported_isa setting")
- end
- if (!support_128b && support_64b && XLEN != 64) begin
- `uvm_fatal(`gfn, "XLEN should be set to 64 based on riscv_instr_pkg::supported_isa setting")
- end
- if (!(support_128b || support_64b) && XLEN != 32) begin
- `uvm_fatal(`gfn, "XLEN should be set to 32 based on riscv_instr_pkg::supported_isa setting")
- end
- if (!(support_128b || support_64b) && !(SATP_MODE inside {SV32, BARE})) begin
- `uvm_fatal(`gfn, $sformatf("SATP mode %0s is not supported for RV32G ISA", SATP_MODE.name()))
- end
- endfunction
-
- // 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[$];
- string csr_name;
- privileged_reg_t csr;
- // Debug CSRs are inaccessible from all but Debug Mode, and we cannot boot into Debug Mode
- invalid_lvl.push_back("D");
- case (init_privileged_mode)
- MACHINE_MODE: begin
- end
- SUPERVISOR_MODE: begin
- invalid_lvl.push_back("M");
- end
- USER_MODE: begin
- invalid_lvl.push_back("S");
- invalid_lvl.push_back("M");
- end
- default: begin
- `uvm_fatal(`gfn, "Unsupported initialization privilege mode")
- end
- endcase
- foreach (implemented_csr[i]) begin
- privileged_reg_t csr = implemented_csr[i];
- csr_name = csr.name();
- if (csr_name[0] inside {invalid_lvl}) begin
- invalid_priv_mode_csrs.push_back(implemented_csr[i]);
- end
- 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
-
- // Build instruction template
- virtual function void build_instruction_template(bit skip_instr_exclusion = 0);
- riscv_instr_name_t instr_name;
- riscv_instr_name_t excluded_instr[$];
- excluded_instr = {INVALID_INSTR};
- if (!skip_instr_exclusion) begin
- get_excluded_instr(excluded_instr);
- end
- instr_name = instr_name.first;
- do begin
- riscv_instr_base instr;
- if (!(instr_name inside {unsupported_instr, excluded_instr})) begin
- instr = riscv_instr_base::type_id::create("instr");
- `DV_CHECK_RANDOMIZE_WITH_FATAL(instr, instr_name == local::instr_name;)
- if ((instr.group inside {supported_isa}) &&
- !(disable_compressed_instr && instr.is_compressed) &&
- !(!enable_floating_point && (instr.group inside {RV32F, RV64F, RV32D, RV64D}))) begin
- `uvm_info(`gfn, $sformatf("Adding [%s] %s to the list",
- instr.group.name(), instr.instr_name.name()), UVM_HIGH)
- instr_group[instr.group].push_back(instr_name);
- instr_category[instr.category].push_back(instr_name);
- instr_template[instr_name] = instr;
- end
- end
- instr_name = instr_name.next;
- end
- while (instr_name != instr_name.first);
- endfunction
-
- virtual function void build_instruction_list();
- basic_instr = {instr_category[SHIFT], instr_category[ARITHMETIC],
- instr_category[LOGICAL], instr_category[COMPARE]};
- basic_instr = {basic_instr, EBREAK};
- foreach(riscv_instr_pkg::supported_isa[i]) begin
- if (riscv_instr_pkg::supported_isa[i] inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) begin
- basic_instr = {basic_instr, C_EBREAK};
- break;
- end
- end
- if (no_dret == 0) begin
- basic_instr = {basic_instr, DRET};
- end
- if (no_fence == 0) begin
- basic_instr = {basic_instr, instr_category[SYNCH]};
- end
- // TODO: Support CSR instruction in other mode
- if ((no_csr_instr == 0) && (init_privileged_mode == MACHINE_MODE)) begin
- `uvm_info(`gfn, $sformatf("Adding CSR instr, mode: %0s", init_privileged_mode.name()), UVM_LOW)
- basic_instr = {basic_instr, instr_category[CSR]};
- end
- if (no_wfi == 0) begin
- basic_instr = {basic_instr, WFI};
- end
- endfunction
-
- virtual function void get_excluded_instr(ref riscv_instr_name_t excluded[$]);
- // Below instrutions will modify stack pointer, not allowed in normal instruction stream.
- // It can be used in stack operation instruction stream.
- excluded = {excluded, C_SWSP, C_SDSP, C_ADDI16SP};
- if (!enable_sfence) begin
- excluded = {excluded, SFENCE_VMA};
- end
- if (no_fence) begin
- excluded = {excluded, FENCE, FENCE_I, SFENCE_VMA};
- end
- // TODO: Support C_ADDI4SPN
- excluded = {excluded, C_ADDI4SPN};
- endfunction
-
-endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_stream.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_stream.sv
deleted file mode 100644
index b4defc8..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_instr_stream.sv
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Base class for RISC-V instruction stream
-// A instruction stream here is a queue of RISC-V basic instructions.
-// This class also provides some functions to manipulate the instruction stream, like insert a new
-// instruction, mix two instruction streams etc.
-class riscv_instr_stream extends uvm_object;
-
- `INSTR instr_list[$];
- int unsigned instr_cnt;
- string label = "";
- // User can specify a small group of available registers to generate various hazard condition
- rand riscv_reg_t avail_regs[];
- // Some additional reserved registers that should not be used as rd register
- // by this instruction stream
- riscv_reg_t reserved_rd[];
-
- `uvm_object_utils(riscv_instr_stream)
- `uvm_object_new
-
- // Initialize the instruction stream, create each instruction instance
- function void initialize_instr_list(int unsigned instr_cnt);
- instr_list = {};
- this.instr_cnt = instr_cnt;
- create_instr_instance();
- endfunction
-
- virtual function void create_instr_instance();
- `INSTR instr;
- for(int i = 0; i < instr_cnt; i++) begin
- instr = `INSTR::type_id::create($sformatf("instr_%0d", i));
- instr_list.push_back(instr);
- end
- endfunction
-
- // Insert an instruction to the existing instruction stream at the given index
- // When index is -1, the instruction is injected at a random location
- function void insert_instr(`INSTR instr, int idx = -1);
- int current_instr_cnt = instr_list.size();
- if(idx == -1) begin
- idx = $urandom_range(0, current_instr_cnt-1);
- while(instr_list[idx].atomic) begin
- idx += 1;
- if (idx == current_instr_cnt - 1) begin
- instr_list = {instr_list, instr};
- return;
- end
- end
- end else if((idx > current_instr_cnt) || (idx < 0)) begin
- `uvm_error(`gfn, $sformatf("Cannot insert instr:%0s at idx %0d",
- instr.convert2asm(), idx))
- end
- instr_list.insert(idx, instr);
- endfunction
-
- // Insert an instruction to the existing instruction stream at the given index
- // When index is -1, the instruction is injected at a random location
- // When replace is 1, the original instruction at the inserted position will be replaced
- function void insert_instr_stream(`INSTR new_instr[], int idx = -1, bit replace = 1'b0);
- int current_instr_cnt = instr_list.size();
- int new_instr_cnt = new_instr.size();
- if(current_instr_cnt == 0) begin
- instr_list = new_instr;
- return;
- end
- if(idx == -1) begin
- idx = $urandom_range(0, current_instr_cnt-1);
- repeat(10) begin
- if (instr_list[idx].atomic) break;
- idx = $urandom_range(0, current_instr_cnt-1);
- end
- if (instr_list[idx].atomic) begin
- foreach (instr_list[i]) begin
- if (!instr_list[i].atomic) begin
- idx = i;
- break;
- end
- end
- if (instr_list[idx].atomic) begin
- `uvm_fatal(`gfn, $sformatf("Cannot inject the instruction"))
- end
- end
- end else if((idx > current_instr_cnt) || (idx < 0)) begin
- `uvm_error(`gfn, $sformatf("Cannot insert instr stream at idx %0d", idx))
- end
- // When replace is 1, the original instruction at this index will be removed. The label of the
- // original instruction will be copied to the head of inserted instruction stream.
- if(replace) begin
- new_instr[0].label = instr_list[idx].label;
- new_instr[0].has_label = instr_list[idx].has_label;
- if (idx == 0) begin
- instr_list = {new_instr, instr_list[idx+1:current_instr_cnt-1]};
- end else begin
- instr_list = {instr_list[0:idx-1], new_instr, instr_list[idx+1:current_instr_cnt-1]};
- end
- end else begin
- if (idx == 0) begin
- instr_list = {new_instr, instr_list[idx:current_instr_cnt-1]};
- end else begin
- instr_list = {instr_list[0:idx-1], new_instr, instr_list[idx:current_instr_cnt-1]};
- end
- end
- endfunction
-
- // Mix the input instruction stream with the original instruction, the instruction order is
- // preserved. When 'contained' is set, the original instruction stream will be inside the
- // new instruction stream with the first and last instruction from the input instruction stream.
- function void mix_instr_stream(`INSTR new_instr[], bit contained = 1'b0);
- int current_instr_cnt = instr_list.size();
- int insert_instr_position[];
- int new_instr_cnt = new_instr.size();
- insert_instr_position = new[new_instr_cnt];
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(insert_instr_position,
- foreach(insert_instr_position[i]) {
- insert_instr_position[i] inside {[0:current_instr_cnt-1]};
- })
- if (insert_instr_position.size() > 0) begin
- insert_instr_position.sort();
- end
- if(contained) begin
- insert_instr_position[0] = 0;
- if(new_instr_cnt > 1)
- insert_instr_position[new_instr_cnt-1] = current_instr_cnt-1;
- end
- foreach(new_instr[i]) begin
- insert_instr(new_instr[i], insert_instr_position[i] + i);
- end
- endfunction
-
- function string convert2string();
- string str;
- foreach(instr_list[i])
- str = {str, instr_list[i].convert2asm(), "\n"};
- return str;
- endfunction
-
-endclass
-
-// Generate a random instruction stream based on the configuration
-// There are two ways to use this class to generate instruction stream
-// 1. For short instruction stream, you can call randomize() directly.
-// 2. For long instruction stream (>1K), randomize() all instructions together might take a long
-// time for the constraint solver. In this case, you can call gen_instr to generate instructions
-// one by one. The time only grows linearly with the instruction count
-class riscv_rand_instr_stream extends riscv_instr_stream;
-
- riscv_instr_gen_config cfg;
- bit kernel_mode;
- riscv_instr_name_t allowed_instr[$];
- int unsigned category_dist[riscv_instr_category_t];
-
- `uvm_object_utils(riscv_rand_instr_stream)
- `uvm_object_new
-
- virtual function void create_instr_instance();
- `INSTR instr;
- for (int i = 0; i < instr_cnt; i++) begin
- instr = `INSTR::type_id::create($sformatf("instr_%0d", i));
- instr_list.push_back(instr);
- end
- endfunction
-
- virtual function void setup_allowed_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1);
- allowed_instr = cfg.basic_instr;
- if (no_branch == 0) begin
- allowed_instr = {allowed_instr, cfg.instr_category[BRANCH]};
- end
- if (no_load_store == 0) begin
- allowed_instr = {allowed_instr, cfg.instr_category[LOAD], cfg.instr_category[STORE]};
- end
- setup_instruction_dist(no_branch, no_load_store);
- endfunction
-
- function void setup_instruction_dist(bit no_branch = 1'b0, bit no_load_store = 1'b1);
- if (cfg.dist_control_mode) begin
- category_dist = cfg.category_dist;
- if (no_branch) begin
- category_dist[BRANCH] = 0;
- end
- if (no_load_store) begin
- category_dist[LOAD] = 0;
- category_dist[STORE] = 0;
- end
- `uvm_info(`gfn, $sformatf("setup_instruction_dist: %0d", category_dist.size()), UVM_LOW)
- end
- endfunction
-
- virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1,
- bit is_debug_program = 1'b0);
- setup_allowed_instr(no_branch, no_load_store);
- foreach(instr_list[i]) begin
- randomize_instr(instr_list[i], is_debug_program);
- end
- // Do not allow branch instruction as the last instruction because there's no
- // forward branch target
- while (instr_list[$].category == BRANCH) begin
- void'(instr_list.pop_back());
- if (instr_list.size() == 0) break;
- end
- endfunction
-
- function void randomize_instr(riscv_instr_base instr,
- bit is_in_debug = 1'b0,
- bit skip_rs1 = 1'b0,
- bit skip_rs2 = 1'b0,
- bit skip_rd = 1'b0,
- bit skip_imm = 1'b0,
- bit skip_csr = 1'b0,
- bit disable_dist = 1'b0);
- riscv_instr_name_t instr_name;
- if ((cfg.dist_control_mode == 1) && !disable_dist) begin
- riscv_instr_category_t category;
- int unsigned idx;
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(category,
- category dist {LOAD := category_dist[LOAD],
- STORE := category_dist[STORE],
- SHIFT := category_dist[SHIFT],
- ARITHMETIC := category_dist[ARITHMETIC],
- LOGICAL := category_dist[LOGICAL],
- COMPARE := category_dist[COMPARE],
- BRANCH := category_dist[BRANCH],
- SYNCH := category_dist[SYNCH],
- CSR := category_dist[CSR]};)
- idx = $urandom_range(0, cfg.instr_category[category].size() - 1);
- instr_name = cfg.instr_category[category][idx];
- // if set_dcsr_ebreak is set, we do not want to generate any ebreak
- // instructions inside the debug_rom
- end else if ((cfg.no_ebreak && !is_in_debug) ||
- (!cfg.enable_ebreak_in_debug_rom && is_in_debug)) begin
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name,
- instr_name inside {allowed_instr};
- !(instr_name inside {EBREAK, C_EBREAK});)
- end else begin
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name,
- instr_name inside {allowed_instr};)
- end
- instr.copy_base_instr(cfg.instr_template[instr_name]);
- `uvm_info(`gfn, $sformatf("%s: rs1:%0d, rs2:%0d, rd:%0d, imm:%0d",
- instr.instr_name.name(),
- instr.has_rs1,
- instr.has_rs2,
- instr.has_rd,
- instr.has_imm), UVM_FULL)
- if (instr.has_imm && !skip_imm) begin
- instr.gen_rand_imm();
- end
- if (instr.has_rs1 && !skip_rs1) begin
- if (instr.is_compressed) begin
- // Compressed instruction could use the same register for rs1 and rd
- instr.rs1 = instr.gen_rand_gpr(
- .included_reg(avail_regs),
- .excluded_reg({reserved_rd, cfg.reserved_regs}));
- end else begin
- instr.rs1 = instr.gen_rand_gpr(.included_reg(avail_regs));
- end
- end
- if (instr.has_rs2 && !skip_rs2) begin
- instr.rs2 = instr.gen_rand_gpr(.included_reg(avail_regs));
- end
- if (instr.has_rd && !skip_rd) begin
- if (instr_name == C_LUI) begin
- instr.rd = instr.gen_rand_gpr(
- .included_reg(avail_regs),
- .excluded_reg({reserved_rd, cfg.reserved_regs, SP}));
- end else begin
- instr.rd = instr.gen_rand_gpr(
- .included_reg(avail_regs),
- .excluded_reg({reserved_rd, cfg.reserved_regs}));
- end
- end
- if ((instr.category == CSR) && !skip_csr) begin
- instr.gen_rand_csr(.privileged_mode(cfg.init_privileged_mode),
- .enable_floating_point(cfg.enable_floating_point),
- .illegal_csr_instr(cfg.enable_illegal_csr_instruction),
- .legal_invalid_csr_instr(cfg.enable_access_invalid_csr_level),
- .invalid_csrs(cfg.invalid_priv_mode_csrs));
- end
- if (instr.has_fs1) begin
- instr.fs1 = instr.gen_rand_fpr();
- end
- if (instr.has_fs2) begin
- instr.fs2 = instr.gen_rand_fpr();
- end
- if (instr.has_fs3) begin
- instr.fs3 = instr.gen_rand_fpr();
- end
- if (instr.has_fd) begin
- instr.fd = instr.gen_rand_fpr();
- end
- endfunction
-
-endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_load_store_instr_lib.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_load_store_instr_lib.sv
deleted file mode 100644
index 92b0570..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_load_store_instr_lib.sv
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Base class for all load/store instruction stream
-
-class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
-
- typedef enum bit [1:0] {
- NARROW,
- HIGH,
- MEDIUM,
- SPARSE
- } locality_e;
-
- rand int unsigned num_load_store;
- rand int unsigned num_mixed_instr;
- rand int base;
- int offset[];
- int addr[];
- riscv_instr_base load_store_instr[$];
- rand int unsigned data_page_id;
- rand riscv_reg_t rs1_reg;
- rand locality_e locality;
- rand int max_load_store_offset;
-
- `uvm_object_utils(riscv_load_store_base_instr_stream)
-
- constraint rs1_c {
- !(rs1_reg inside {cfg.reserved_regs, reserved_rd, ZERO});
- }
-
- constraint addr_c {
- solve data_page_id before max_load_store_offset;
- solve max_load_store_offset before base;
- data_page_id < max_data_page_id;
- foreach (data_page[i]) {
- if (i == data_page_id) {
- max_load_store_offset == data_page[i].size_in_bytes;
- }
- }
- base inside {[0 : max_load_store_offset-1]};
- }
-
- function new(string name = "");
- super.new(name);
- endfunction
-
- virtual function void randomize_offset();
- int offset_, addr_;
- offset = new[num_load_store];
- addr = new[num_load_store];
- for (int i=0; i<num_load_store; i++) begin
- if (!std::randomize(offset_, addr_) with {
- // Locality
- if (locality == NARROW) {
- soft offset_ inside {[-16:16]};
- } else if (locality == HIGH) {
- soft offset_ inside {[-64:64]};
- } else if (locality == MEDIUM) {
- soft offset_ inside {[-256:256]};
- } else if (locality == SPARSE) {
- soft offset_ inside {[-2048:2047]};
- }
- addr_ == base + offset_;
- addr_ inside {[0 : max_load_store_offset - 1]};
- }) begin
- `uvm_fatal(`gfn, "Cannot randomize load/store offset")
- end
- offset[i] = offset_;
- addr[i] = addr_;
- end
- endfunction
-
- function void post_randomize();
- randomize_offset();
- // rs1 cannot be modified by other instructions
- if(!(rs1_reg inside {reserved_rd})) begin
- reserved_rd = {reserved_rd, rs1_reg};
- end
- gen_load_store_instr();
- add_mixed_instr(num_mixed_instr);
- add_rs1_init_la_instr(rs1_reg, data_page_id, base);
- super.post_randomize();
- endfunction
-
- // Generate each load/store instruction
- virtual function void gen_load_store_instr();
- bit enable_compressed_load_store;
- riscv_instr_base instr;
- if(avail_regs.size() > 0) begin
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(avail_regs,
- unique{avail_regs};
- avail_regs[0] inside {[S0 : A5]};
- foreach(avail_regs[i]) {
- !(avail_regs[i] inside {cfg.reserved_regs, reserved_rd});
- },
- "Cannot randomize avail_regs")
- end
- if ((rs1_reg inside {[S0 : A5]}) && !cfg.disable_compressed_instr) begin
- enable_compressed_load_store = 1;
- end
- foreach(addr[i]) begin
- instr = riscv_instr_base::type_id::create("instr");
- // Assign the allowed load/store instructions based on address alignment
- // This is done separately rather than a constraint to improve the randomization performance
- allowed_instr = {LB, LBU, SB};
- if (!cfg.enable_unaligned_load_store) begin
- if (addr[i][0] == 1'b0) begin
- allowed_instr = {LH, LHU, SH, allowed_instr};
- end
- if (addr[i] % 4 == 0) begin
- allowed_instr = {LW, SW, allowed_instr};
- if (cfg.enable_floating_point) begin
- allowed_instr = {FLW, FSW, allowed_instr};
- end
- if((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0) &&
- (RV32C inside {riscv_instr_pkg::supported_isa}) &&
- enable_compressed_load_store) begin
- allowed_instr = {C_LW, C_SW, allowed_instr};
- if (cfg.enable_floating_point && (RV32FC inside {supported_isa})) begin
- allowed_instr = {C_FLW, C_FSW, allowed_instr};
- end
- end
- end
- if ((XLEN >= 64) && (addr[i] % 8 == 0)) begin
- allowed_instr = {LWU, LD, SD, allowed_instr};
- if (cfg.enable_floating_point && (RV32D inside {supported_isa})) begin
- allowed_instr = {FLD, FSD, allowed_instr};
- end
- if((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0) &&
- (RV64C inside {riscv_instr_pkg::supported_isa} &&
- enable_compressed_load_store)) begin
- allowed_instr = {C_LD, C_SD, allowed_instr};
- if (cfg.enable_floating_point && (RV32DC inside {supported_isa})) begin
- allowed_instr = {C_FLD, C_FSD, allowed_instr};
- end
- end
- end
- end else begin
- allowed_instr = {LW, SW, LH, LHU, SH, allowed_instr};
- if ((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0) &&
- (RV32C inside {riscv_instr_pkg::supported_isa}) &&
- enable_compressed_load_store) begin
- allowed_instr = {C_LW, C_SW, allowed_instr};
- end
- if (XLEN >= 64) begin
- allowed_instr = {LWU, LD, SD, allowed_instr};
- if ((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0) &&
- (RV64C inside {riscv_instr_pkg::supported_isa}) &&
- enable_compressed_load_store) begin
- allowed_instr = {C_LD, C_SD, allowed_instr};
- end
- end
- end
- randomize_instr(instr, .skip_rs1(1'b1), .skip_imm(1'b1), .disable_dist(1'b1));
- instr.rs1 = rs1_reg;
- instr.set_imm(offset[i]);
- instr.process_load_store = 0;
- instr_list.push_back(instr);
- load_store_instr.push_back(instr);
- end
- endfunction
-
-endclass
-
-// A single load/store instruction
-class riscv_single_load_store_instr_stream extends riscv_load_store_base_instr_stream;
-
- constraint legal_c {
- num_load_store == 1;
- num_mixed_instr < 5;
- }
-
- `uvm_object_utils(riscv_single_load_store_instr_stream)
- `uvm_object_new
-
-endclass
-
-// Back to back load/store instructions
-class riscv_load_store_stress_instr_stream extends riscv_load_store_base_instr_stream;
-
- int unsigned max_instr_cnt = 30;
- int unsigned min_instr_cnt = 10;
-
- constraint legal_c {
- num_load_store inside {[min_instr_cnt:max_instr_cnt]};
- num_mixed_instr == 0;
- }
-
- `uvm_object_utils(riscv_load_store_stress_instr_stream)
- `uvm_object_new
-
-endclass
-
-// Random load/store sequence
-// A random mix of load/store instructions and other instructions
-class riscv_load_store_rand_instr_stream extends riscv_load_store_base_instr_stream;
-
- constraint legal_c {
- num_load_store inside {[10:30]};
- num_mixed_instr inside {[10:30]};
- }
-
- `uvm_object_utils(riscv_load_store_rand_instr_stream)
- `uvm_object_new
-
-endclass
-
-// Use a small set of GPR to create various WAW, RAW, WAR hazard scenario
-class riscv_hazard_instr_stream extends riscv_load_store_base_instr_stream;
-
- int unsigned num_of_avail_regs = 6;
-
- constraint legal_c {
- num_load_store inside {[10:30]};
- num_mixed_instr inside {[10:30]};
- }
-
- `uvm_object_utils(riscv_hazard_instr_stream)
- `uvm_object_new
-
- function void pre_randomize();
- avail_regs = new[num_of_avail_regs];
- super.pre_randomize();
- endfunction
-
-endclass
-
-// Use a small set of address to create various load/store hazard sequence
-// This instruction stream focus more on hazard handling of load store unit.
-class riscv_load_store_hazard_instr_stream extends riscv_load_store_base_instr_stream;
-
- rand int avail_addr[];
-
- constraint legal_c {
- num_load_store inside {[10:30]};
- num_mixed_instr inside {[10:30]};
- }
-
- constraint avail_addr_c {
- avail_addr.size() inside {[1:3]};
- foreach(avail_addr[i]) {
- avail_addr[i] inside {[0 : max_load_store_offset - 1]};
- }
- }
-
- `uvm_object_utils(riscv_load_store_hazard_instr_stream)
- `uvm_object_new
-
- // Randomize each address in the post_randomize to reduce the complexity of solving everything
- // in one shot.
- function void post_randomize();
- int temp_addr;
- foreach(addr[i]) begin
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(temp_addr,
- temp_addr inside {avail_addr};,
- "Cannot randomize address")
- addr[i] = temp_addr;
- end
- endfunction
-endclass
-
-// Back to back access to multiple data pages
-// This is useful to test data TLB switch and replacement
-class riscv_multi_page_load_store_instr_stream extends riscv_mem_access_stream;
-
- riscv_load_store_stress_instr_stream load_store_instr_stream[];
- rand int unsigned num_of_instr_stream;
- rand int unsigned data_page_id[];
- rand riscv_reg_t rs1_reg[];
-
- constraint default_c {
- foreach(data_page_id[i]) {
- data_page_id[i] < max_data_page_id;
- }
- data_page_id.size() == num_of_instr_stream;
- rs1_reg.size() == num_of_instr_stream;
- unique {rs1_reg};
- foreach(rs1_reg[i]) {
- !(rs1_reg[i] inside {cfg.reserved_regs, ZERO});
- }
- }
-
- constraint page_c {
- solve num_of_instr_stream before data_page_id;
- num_of_instr_stream inside {[1 : max_data_page_id]};
- unique {data_page_id};
- }
-
- // Avoid accessing a large number of pages because we may run out of registers for rs1
- // Each page access needs a reserved register as the base address of load/store instruction
- constraint reasonable_c {
- num_of_instr_stream inside {[2:8]};
- }
-
- `uvm_object_utils(riscv_multi_page_load_store_instr_stream)
- `uvm_object_new
-
- // Generate each load/store seq, and mix them together
- function void post_randomize();
- load_store_instr_stream = new[num_of_instr_stream];
- foreach(load_store_instr_stream[i]) begin
- load_store_instr_stream[i] = riscv_load_store_stress_instr_stream::type_id::
- create($sformatf("load_store_instr_stream_%0d", i));
- load_store_instr_stream[i].min_instr_cnt = 5;
- load_store_instr_stream[i].max_instr_cnt = 10;
- load_store_instr_stream[i].cfg = cfg;
- // Make sure each load/store sequence doesn't override the rs1 of other sequences.
- foreach(rs1_reg[j]) begin
- if(i != j) begin
- load_store_instr_stream[i].reserved_rd =
- {load_store_instr_stream[i].reserved_rd, rs1_reg[j]};
- end
- end
- `DV_CHECK_RANDOMIZE_WITH_FATAL(load_store_instr_stream[i],
- rs1_reg == local::rs1_reg[i];
- data_page_id == local::data_page_id[i];,
- "Cannot randomize load/store instruction")
- // Mix the instruction stream of different page access, this could trigger the scenario of
- // frequent data TLB switch
- if(i == 0) begin
- instr_list = load_store_instr_stream[i].instr_list;
- end else begin
- mix_instr_stream(load_store_instr_stream[i].instr_list);
- end
- end
- endfunction
-
-endclass
-
-// Access the different locations of the same memory regions
-class riscv_mem_region_stress_test extends riscv_multi_page_load_store_instr_stream;
-
- `uvm_object_utils(riscv_mem_region_stress_test)
- `uvm_object_new
-
- constraint page_c {
- num_of_instr_stream inside {[2:5]};
- foreach (data_page_id[i]) {
- if (i > 0) {
- data_page_id[i] == data_page_id[i-1];
- }
- }
- }
-
-endclass
-
-// Random load/store sequence to full address range
-// The address range is not preloaded with data pages, use store instruction to initialize first
-class riscv_load_store_rand_addr_instr_stream extends riscv_load_store_base_instr_stream;
-
- rand bit [XLEN-1:0] addr_offset;
-
- // Find an unused 4K page from address 1M onward
- constraint addr_offset_c {
- |addr_offset[XLEN-1:20] == 1'b1;
- // TODO(taliu) Support larger address range
- addr_offset[XLEN-1:31] == 0;
- addr_offset[11:0] == 0;
- }
-
- constraint legal_c {
- num_load_store inside {[5:10]};
- num_mixed_instr inside {[5:10]};
- }
-
- `uvm_object_utils(riscv_load_store_rand_addr_instr_stream)
-
- virtual function void randomize_offset();
- int offset_, addr_;
- offset = new[num_load_store];
- addr = new[num_load_store];
- for (int i=0; i<num_load_store; i++) begin
- if (!std::randomize(offset_) with {
- offset_ inside {[-2048:2047]};
- }
- ) begin
- `uvm_fatal(`gfn, "Cannot randomize load/store offset")
- end
- offset[i] = offset_;
- addr[i] = addr_offset + offset_;
- end
- endfunction `uvm_object_new
-
- virtual function void add_rs1_init_la_instr(riscv_reg_t gpr, int id, int base = 0);
- riscv_instr_base instr[$];
- riscv_pseudo_instr li_instr;
- riscv_instr_base store_instr;
- riscv_instr_base add_instr;
- int min_offset[$];
- int max_offset[$];
- min_offset = offset.min();
- max_offset = offset.max();
- // Use LI to initialize the address offset
- li_instr = riscv_pseudo_instr::type_id::create("li_instr");
- `DV_CHECK_RANDOMIZE_WITH_FATAL(li_instr,
- pseudo_instr_name == LI;
- rd inside {cfg.gpr};
- rd != gpr;
- )
- li_instr.imm_str = $sformatf("0x%0x", addr_offset);
- // Add offset to the base address
- add_instr = riscv_instr_base::type_id::create("add_instr");
- `DV_CHECK_RANDOMIZE_WITH_FATAL(add_instr,
- instr_name == ADD;
- rs1 == gpr;
- rs2 == li_instr.rd;
- rd == gpr;
- )
- instr.push_back(li_instr);
- instr.push_back(add_instr);
- // Create SW instruction template
- store_instr = riscv_instr_base::type_id::create("store_instr");
- `DV_CHECK_RANDOMIZE_WITH_FATAL(store_instr,
- instr_name == SB;
- rs1 == gpr;
- )
- // Initialize the location which used by load instruction later
- foreach (load_store_instr[i]) begin
- if (load_store_instr[i].category == LOAD) begin
- riscv_instr_base store;
- store = riscv_instr_base::type_id::create("store");
- store.copy_base_instr(store_instr);
- store.rs2 = riscv_reg_t'(i % 32);
- store.imm_str = load_store_instr[i].imm_str;
- case (load_store_instr[i].instr_name) inside
- LB, LBU : store.instr_name = SB;
- LH, LHU : store.instr_name = SH;
- LW, C_LW, FLW, C_FLW : store.instr_name = SW;
- LD, C_LD, FLD, C_FLD, LWU : store.instr_name = SD;
- default : `uvm_fatal(`gfn, $sformatf("Unexpected op: %0s",
- load_store_instr[i].convert2asm()))
- endcase
- instr.push_back(store);
- end
- end
- instr_list = {instr, instr_list};
- super.add_rs1_init_la_instr(gpr, id, 0);
- endfunction
-
-endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_loop_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_loop_instr.sv
deleted file mode 100644
index 4503263..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_loop_instr.sv
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO: Support other loop counter update instruction other than ADDI
-// TODO: Support forward branch inside the loop
-
-class riscv_loop_instr extends riscv_rand_instr_stream;
-
- rand riscv_reg_t loop_cnt_reg[];
- rand riscv_reg_t loop_limit_reg[];
- rand int loop_init_val[];
- rand int loop_step_val[];
- rand int loop_limit_val[];
- rand bit [2:0] num_of_nested_loop;
- rand int num_of_instr_in_loop;
- rand riscv_instr_name_t branch_type[];
- riscv_instr_base loop_init_instr[];
- riscv_instr_base loop_update_instr[];
- riscv_instr_base loop_branch_instr[];
- riscv_rand_instr loop_branch_target_instr[];
- // Aggregated loop instruction stream
- riscv_instr_base loop_instr[];
-
- constraint legal_loop_regs_c {
- solve num_of_nested_loop before loop_cnt_reg;
- solve num_of_nested_loop before loop_limit_reg;
- foreach (loop_cnt_reg[i]) {
- loop_cnt_reg[i] != ZERO;
- foreach (cfg.reserved_regs[j]) {
- loop_cnt_reg[i] != cfg.reserved_regs[j];
- }
- }
- foreach (loop_limit_reg[i]) {
- foreach (cfg.reserved_regs[j]) {
- loop_limit_reg[i] != cfg.reserved_regs[j];
- }
- }
- unique {loop_cnt_reg, loop_limit_reg};
- loop_cnt_reg.size() == num_of_nested_loop;
- loop_limit_reg.size() == num_of_nested_loop;
- }
-
- constraint loop_c {
- solve num_of_nested_loop before loop_init_val;
- solve num_of_nested_loop before loop_step_val;
- solve num_of_nested_loop before loop_limit_val;
- solve loop_limit_val before loop_limit_reg;
- solve branch_type before loop_init_val;
- solve branch_type before loop_step_val;
- solve branch_type before loop_limit_val;
- num_of_instr_in_loop inside {[1:25]};
- num_of_nested_loop inside {[1:2]};
- loop_init_val.size() == num_of_nested_loop;
- loop_step_val.size() == num_of_nested_loop;
- loop_limit_val.size() == num_of_nested_loop;
- branch_type.size() == num_of_nested_loop;
- foreach (branch_type[i]) {
- if (!cfg.disable_compressed_instr) {
- branch_type[i] inside {C_BNEZ, C_BEQZ, BEQ, BNE, BLTU, BLT, BGEU, BGE};
- } else {
- branch_type[i] inside {BEQ, BNE, BLTU, BLT, BGEU, BGE};
- }
- }
- foreach(loop_init_val[i]) {
- if (branch_type[i] inside {C_BNEZ, C_BEQZ}) {
- loop_limit_val[i] == 0;
- loop_limit_reg[i] == ZERO;
- loop_cnt_reg[i] inside {riscv_instr_pkg::compressed_gpr};
- } else {
- loop_limit_val[i] inside {[-20:20]};
- loop_limit_reg[i] != ZERO;
- }
- if (branch_type[i] inside {C_BNEZ, C_BEQZ, BEQ, BNE}) {
- ((loop_limit_val[i] - loop_init_val[i]) % loop_step_val[i] == 0) &&
- (loop_limit_val[i] != loop_init_val[i]);
- } else if (branch_type[i] == BGE) {
- loop_step_val[i] < 0;
- } else if (branch_type[i] == BGEU) {
- loop_step_val[i] < 0;
- loop_init_val[i] > 0;
- // Avoid count to negative
- loop_step_val[i] + loop_limit_val[i] > 0;
- } else if (branch_type[i] == BLT) {
- loop_step_val[i] > 0;
- } else if (branch_type[i] == BLTU) {
- loop_step_val[i] > 0;
- loop_limit_val[i] > 0;
- }
- loop_init_val[i] inside {[-10:10]};
- loop_step_val[i] inside {[-10:10]};
- if(loop_init_val[i] < loop_limit_val[i]) {
- loop_step_val[i] > 0;
- } else {
- loop_step_val[i] < 0;
- }
- }
- }
-
- `uvm_object_utils(riscv_loop_instr)
- `uvm_object_new
-
- function void post_randomize();
- reserved_rd = {loop_cnt_reg, loop_limit_reg};
- // Generate instructions that mixed with the loop instructions
- initialize_instr_list(num_of_instr_in_loop);
- gen_instr(1'b1);
- // Randomize the key loop instructions
- loop_init_instr = new[num_of_nested_loop*2];
- loop_update_instr = new[num_of_nested_loop];
- loop_branch_instr = new[num_of_nested_loop];
- loop_branch_target_instr = new[num_of_nested_loop];
- for(int i = 0; i < num_of_nested_loop; i++) begin
- // Instruction to init the loop counter
- loop_init_instr[2*i] = riscv_instr_base::type_id::create("loop_init_instr");
- `DV_CHECK_RANDOMIZE_WITH_FATAL(loop_init_instr[2*i],
- instr_name == ADDI;
- rd == loop_cnt_reg[i];
- rs1 == ZERO;
- imm == loop_init_val[i];,
- "Cannot randomize loop init insturction")
- loop_init_instr[2*i].comment = $sformatf("init loop %0d counter", i);
-
- // Instruction to init loop limit
- loop_init_instr[2*i+1] = riscv_instr_base::type_id::create("loop_init_instr");
- `DV_CHECK_RANDOMIZE_WITH_FATAL(loop_init_instr[2*i+1],
- instr_name == ADDI;
- rd == loop_limit_reg[i];
- rs1 == ZERO;
- imm == loop_limit_val[i];,
- "Cannot randomize init loop instruction")
- loop_init_instr[2*i+1].comment = $sformatf("init loop %0d limit", i);
-
- // Branch target instruction, can be anything
- loop_branch_target_instr[i] = riscv_rand_instr::type_id::create("loop_branch_target_instr");
- loop_branch_target_instr[i].cfg = cfg;
- loop_branch_target_instr[i].reserved_rd = reserved_rd;
- `DV_CHECK_RANDOMIZE_WITH_FATAL(loop_branch_target_instr[i],
- !(category inside {LOAD, STORE, BRANCH, JUMP});
- // TODO: allow CSR instructions in all modes
- if (cfg.init_privileged_mode == MACHINE_MODE) {
- if (category == CSR) {
- csr == MSCRATCH;
- }
- } else {
- !(category == CSR);
- },
- "Cannot randomize branch target instruction")
- loop_branch_target_instr[i].label = $sformatf("%0s_%0d_t", label, i);
-
- // Instruction to update loop counter
- loop_update_instr[i] = riscv_instr_base::type_id::create("loop_update_instr");
- `DV_CHECK_RANDOMIZE_WITH_FATAL(loop_update_instr[i],
- instr_name == ADDI;
- rd == loop_cnt_reg[i];
- rs1== loop_cnt_reg[i];
- imm == loop_step_val[i];,
- "Cannot randomize loop update instruction")
- loop_update_instr[i].comment = $sformatf("update loop %0d counter", i);
-
- // Backward branch instruction
- loop_branch_instr[i] = riscv_instr_base::type_id::create("loop_branch_instr");
- `DV_CHECK_RANDOMIZE_WITH_FATAL(loop_branch_instr[i],
- instr_name == branch_type[i];
- rs1 == loop_cnt_reg[i];
- if (!(branch_type[i] inside {C_BEQZ, C_BNEZ})) {
- rs2 == loop_limit_reg[i];
- },
- "Cannot randomize backward branch instruction")
- loop_branch_instr[i].comment = $sformatf("branch for loop %0d", i);
- loop_branch_instr[i].imm_str = loop_branch_target_instr[i].label;
- loop_branch_instr[i].branch_assigned = 1'b1;
- end
- // Randomly distribute the loop instruction in the existing instruction stream
- build_loop_instr_stream();
- mix_instr_stream(loop_instr, 1'b1);
- foreach(instr_list[i]) begin
- if(instr_list[i].label != "")
- instr_list[i].has_label = 1'b1;
- else
- instr_list[i].has_label = 1'b0;
- instr_list[i].atomic = 1'b1;
- end
- endfunction
-
- // Build the whole loop structure from innermost loop to the outermost loop
- function void build_loop_instr_stream();
- loop_instr.delete;
- for(int i = 0; i < num_of_nested_loop; i++) begin
- loop_instr = {loop_init_instr[2*i],
- loop_init_instr[2*i+1],
- loop_branch_target_instr[i],
- loop_update_instr[i],
- loop_instr,
- loop_branch_instr[i]};
- end
- `uvm_info(get_full_name(), $sformatf("Totally %0d instructions have been added",
- loop_instr.size()), UVM_HIGH)
- endfunction
-endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_rand_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_rand_instr.sv
deleted file mode 100644
index e31e946..0000000
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/deprecated/riscv_rand_instr.sv
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class riscv_rand_instr extends riscv_instr_base;
-
- riscv_instr_gen_config cfg;
-
- // Some additional reserved registers
- riscv_reg_t reserved_rd[];
-
- `uvm_object_utils(riscv_rand_instr)
-
- constraint category_c {
- soft category inside {LOAD, STORE, SHIFT, ARITHMETIC, LOGICAL,
- BRANCH, COMPARE, CSR, SYSTEM, SYNCH};
- }
-
- // Atomic extension instructions are default disabled
- // AMO instruction generation is handled by riscv_amo_instr_lib.sv
- constraint disable_a_extension_c {
- group != RV32A;
- group != RV64A;
- }
-
- constraint instr_c {
- solve instr_name before imm;
- solve instr_name before rs1;
- solve instr_name before rs2;
- !(instr_name inside {riscv_instr_pkg::unsupported_instr});
- group inside {riscv_instr_pkg::supported_isa};
- // Avoid using any special purpose register as rd, those registers are reserved for
- // special instructions
- !(rd inside {cfg.reserved_regs});
- if(reserved_rd.size() > 0) {
- !(rd inside {reserved_rd});
- }
- // Compressed instruction may use the same CSR for both rs1 and rd
- if(group inside {RV32C, RV64C, RV128C, RV32FC, RV32DC}) {
- !(rs1 inside {cfg.reserved_regs, reserved_rd});
- }
- // Below instrutions will modify stack pointer, not allowed in normal instruction stream.
- // It can be used in stack operation instruction stream.
- !(instr_name inside {C_SWSP, C_SDSP, C_ADDI16SP});
- // Avoid using reserved registers as rs1 (base address)
- if(category inside {LOAD, STORE}) {
- !(rs1 inside {reserved_rd, cfg.reserved_regs, ZERO});
- }
- if(!cfg.enable_sfence) {
- instr_name != SFENCE_VMA;
- }
- if(cfg.no_fence) {
- !(instr_name inside {FENCE, FENCE_I, SFENCE_VMA});
- }
- // TODO: Support C_ADDI4SPN
- instr_name != C_ADDI4SPN;
- }
-
- constraint constraint_cfg_knob_c {
- if(cfg.no_ebreak) {
- instr_name != EBREAK;
- instr_name != C_EBREAK;
- }
- if(cfg.no_wfi) {
- instr_name != WFI;
- }
- if(cfg.no_dret) {
- instr_name != DRET;
- }
- // Below previleged instruction is not generated by default
- !(instr_name inside {ECALL, URET, SRET, MRET});
- if(cfg.no_load_store) {
- category != LOAD;
- category != STORE;
- }
- if(cfg.no_branch_jump) {
- category != BRANCH;
- }
- if (cfg.disable_compressed_instr) {
- !(group inside {RV32C, RV64C, RV128C, RV32FC, RV32DC});
- }
- }
-
- constraint csr_instr_c {
- // TODO: support CSR instruction in other modes
- if(cfg.no_csr_instr) {
- category != CSR;
- } else {
- if (category == CSR) {
- if (cfg.enable_illegal_csr_instruction) {
- !(csr inside {implemented_csr});
- } else if (cfg.enable_access_invalid_csr_level) {
- csr inside {cfg.invalid_priv_mode_csrs};
- } else {
- // Use scratch register to avoid the side effect of modifying other privileged mode CSR.
- if (cfg.init_privileged_mode == MACHINE_MODE) {
- if (MSCRATCH inside {implemented_csr}) {
- csr == MSCRATCH;
- }
- } else if (cfg.init_privileged_mode == SUPERVISOR_MODE) {
- if (SSCRATCH inside {implemented_csr}) {
- csr == SSCRATCH;
- }
- } else {
- if (USCRATCH inside {implemented_csr}) {
- csr == USCRATCH;
- }
- }
- }
- }
- }
- }
-
- constraint floating_point_c {
- if (!cfg.enable_floating_point) {
- !(group inside {RV32F, RV64F, RV32D, RV64D});
- }
- }
-
- function void pre_randomize();
- if (!cfg.enable_floating_point) begin
- fs1.rand_mode(0);
- fs2.rand_mode(0);
- fs3.rand_mode(0);
- fd.rand_mode(0);
- end
- endfunction
-
- // No label is needed if there's no branch/jump instruction
- function void post_randomize();
- super.post_randomize();
- if (cfg.no_branch_jump) begin
- has_label = 1'b0;
- end
- endfunction
-
- `uvm_object_new
-
-endclass
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/riscv_custom_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/riscv_custom_instr.sv
new file mode 100644
index 0000000..5669005
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/riscv_custom_instr.sv
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+// Custom instruction class
+
+class riscv_custom_instr extends riscv_instr;
+
+ // TODO: Add custom operands here, example:
+ // rand riscv_reg_t rs3;
+
+ `uvm_object_utils(riscv_custom_instr)
+ `uvm_object_new
+
+ virtual function string get_instr_name();
+ get_instr_name = instr_name.name();
+ // TODO: Add custom instruction name encoding here
+ return get_instr_name;
+ endfunction : get_instr_name
+
+ // Convert the instruction to assembly code
+ virtual function string convert2asm(string prefix = "");
+ string asm_str;
+ asm_str = format_string("nop", MAX_INSTR_STR_LEN);
+ /* TODO: Convert custom instruction to assembly format. Example:
+ asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
+ case (instr_name)
+ CUSTOM_1: asm_str = $sformatf("%0s %0s, (%0s)", asm_str, rd.name(), rs1.name());
+ CUSTOM_2: asm_str = $sformatf("%0s %0s", asm_str, r3.name());
+ endcase
+ */
+ comment = {get_instr_name(), " ", comment};
+ if (comment != "") begin
+ asm_str = {asm_str, " #",comment};
+ end
+ return asm_str.tolower();
+ endfunction : convert2asm
+
+endclass : riscv_custom_instr
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/riscv_custom_instr_enum.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/riscv_custom_instr_enum.sv
new file mode 100644
index 0000000..5341091
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/riscv_custom_instr_enum.sv
@@ -0,0 +1,2 @@
+// TODO: Add custom instruction name enum
+CUSTOM_1,
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/rv32x_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/rv32x_instr.sv
new file mode 100644
index 0000000..8757236
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/rv32x_instr.sv
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+// TODO: Add custom RV32X instruction. Example:
+`DEFINE_CUSTOM_INSTR(CUSTOM_1, R_FORMAT, ARITHMETIC, RV32X)
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/rv64x_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/rv64x_instr.sv
new file mode 100644
index 0000000..4ff4ffc
--- /dev/null
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/isa/custom/rv64x_instr.sv
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+// TODO: Add custom RV32X instruction. Example:
+// `DEFINE_CUSTOM_INSTR(CUSTOM1, R_FORMAT, LOAD, RV64X)
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 6a84cbe..821ae8d 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
@@ -362,6 +362,7 @@
RV32F, RV64F, RV32FC : misa[MISA_EXT_F] = 1'b1;
RV32D, RV64D, RV32DC : misa[MISA_EXT_D] = 1'b1;
RV32V, RV64V : misa[MISA_EXT_V] = 1'b1;
+ RV32X, RV64X : misa[MISA_EXT_X] = 1'b1;
default : `uvm_fatal(`gfn, $sformatf("%0s is not yet supported",
supported_isa[i].name()))
endcase
@@ -820,21 +821,6 @@
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);
- // If nested interrupts are enabled, set xSTATUS.xIE in the interrupt handler
- // to re-enable interrupt handling capabilities
- if (cfg.enable_nested_interrupt) begin
- case (status)
- MSTATUS: begin
- intr_handler.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 8));
- end
- SSTATUS: begin
- intr_handler.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 2));
- end
- USTATUS: begin
- intr_handler.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 1));
- end
- endcase
- end
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()),
@@ -845,7 +831,7 @@
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(cause));
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(ie));
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(ip));
- // Jump to commmon interrupt handling routine
+ // Jump to commmon interrupt handling routine
intr_handler = {intr_handler,
$sformatf("j %0smode_intr_handler", mode),
"1: j test_done"};
@@ -1022,6 +1008,25 @@
end
default: `uvm_fatal(get_full_name(), $sformatf("Unsupported mode: %0s", mode.name()))
endcase
+ // If nested interrupts are enabled, set xSTATUS.xIE in the interrupt handler
+ // to re-enable interrupt handling capabilities
+ if (cfg.enable_nested_interrupt) begin
+ interrupt_handler_instr.push_back($sformatf("csrr x%0d, 0x%0x", cfg.gpr[0], scratch));
+ interrupt_handler_instr.push_back($sformatf("bgtz x%0d, 1f", cfg.gpr[0]));
+ interrupt_handler_instr.push_back($sformatf("csrwi 0x%0x, 0x1", scratch));
+ case (status)
+ MSTATUS: begin
+ interrupt_handler_instr.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 8));
+ end
+ SSTATUS: begin
+ interrupt_handler_instr.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 2));
+ end
+ USTATUS: begin
+ interrupt_handler_instr.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 1));
+ end
+ endcase
+ interrupt_handler_instr.push_back($sformatf("1: csrwi 0x%0x,0", scratch));
+ end
// Read back interrupt related privileged CSR
// The value of these CSR are checked by comparing with spike simulation result.
interrupt_handler_instr = {
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_defines.svh b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_defines.svh
index f46f2e6..e423f76 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_defines.svh
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_defines.svh
@@ -93,3 +93,8 @@
`define DEFINE_VA_INSTR(instr_n, instr_format, instr_category, instr_group, vav = {}, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_vector_instr; \
`VA_INSTR_BODY(instr_n, instr_format, instr_category, instr_group, vav, imm_tp)
+
+// Custom extension instruction
+`define DEFINE_CUSTOM_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
+ class riscv_``instr_n``_instr extends riscv_custom_instr; \
+ `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
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 5b8dcdc..2777337 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
@@ -1,4 +1,4 @@
-class riscv_instr_cov_item extends `INSTR;
+class riscv_instr_cov_item extends riscv_instr;
typedef enum bit[1:0] {
POSITIVE, NEGATIVE
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv
index 13a6b87..72fef81 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv
@@ -1315,17 +1315,9 @@
riscv_instr_name_t instr_name;
instr_name = instr_name.first;
do begin
- `INSTR instr;
+ riscv_instr instr;
if (!(instr_name inside {unsupported_instr}) && (instr_name != INVALID_INSTR)) begin
- `ifdef DEPRECATED
- instr = riscv_instr_base::type_id::create("instr");
- if (!instr.randomize() with {instr_name == local::instr_name;}) begin
- `uvm_fatal("riscv_instr_cover_group",
- $sformatf("Instruction %0s randomization failure", instr_name.name()))
- end
- `else
- instr = riscv_instr::create_instr(instr_name);
- `endif
+ instr = riscv_instr::create_instr(instr_name);
if ((instr.group inside {supported_isa}) &&
(instr.group inside {RV32I, RV32M, RV64M, RV64I, RV32C, RV64C,
RV32V, RV64V, RV64B, RV32B})) begin
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 ca1cccd..9b06e94 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
@@ -90,7 +90,9 @@
RV32V,
RV32B,
RV64V,
- RV64B
+ RV64B,
+ RV32X,
+ RV64X
} riscv_instr_group_t;
typedef enum {
@@ -491,6 +493,8 @@
SRET,
WFI,
SFENCE_VMA,
+ // Custom instructions
+ `include "isa/custom/riscv_custom_instr_enum.sv"
// You can add other instructions here
INVALID_INSTR
} riscv_instr_name_t;
@@ -1076,37 +1080,33 @@
SYNCH, SYSTEM, COUNTER, CSR, CHANGELEVEL, TRAP, INTERRUPT, AMO
};
- `include "riscv_vector_cfg.sv"
- `ifdef DEPRECATED
- `define INSTR riscv_instr_base
- `include "deprecated/riscv_instr_base.sv"
- `include "deprecated/riscv_instr_gen_config.sv"
- `else
- `define INSTR riscv_instr
- typedef class riscv_instr;
- `include "riscv_instr_gen_config.sv"
- `include "isa/riscv_instr.sv"
- `include "isa/riscv_amo_instr.sv"
- `include "isa/riscv_floating_point_instr.sv"
- `include "isa/riscv_vector_instr.sv"
- `include "isa/riscv_compressed_instr.sv"
- `include "isa/rv32a_instr.sv"
- `include "isa/rv32c_instr.sv"
- `include "isa/rv32dc_instr.sv"
- `include "isa/rv32d_instr.sv"
- `include "isa/rv32fc_instr.sv"
- `include "isa/rv32f_instr.sv"
- `include "isa/rv32i_instr.sv"
- `include "isa/rv32m_instr.sv"
- `include "isa/rv64a_instr.sv"
- `include "isa/rv64c_instr.sv"
- `include "isa/rv64d_instr.sv"
- `include "isa/rv64f_instr.sv"
- `include "isa/rv64i_instr.sv"
- `include "isa/rv64m_instr.sv"
- `include "isa/rv128c_instr.sv"
- `include "isa/rv32v_instr.sv"
- `endif
+ `include "riscv_vector_cfg.sv"
+ typedef class riscv_instr;
+ `include "riscv_instr_gen_config.sv"
+ `include "isa/riscv_instr.sv"
+ `include "isa/riscv_amo_instr.sv"
+ `include "isa/riscv_floating_point_instr.sv"
+ `include "isa/riscv_vector_instr.sv"
+ `include "isa/riscv_compressed_instr.sv"
+ `include "isa/rv32a_instr.sv"
+ `include "isa/rv32c_instr.sv"
+ `include "isa/rv32dc_instr.sv"
+ `include "isa/rv32d_instr.sv"
+ `include "isa/rv32fc_instr.sv"
+ `include "isa/rv32f_instr.sv"
+ `include "isa/rv32i_instr.sv"
+ `include "isa/rv32m_instr.sv"
+ `include "isa/rv64a_instr.sv"
+ `include "isa/rv64c_instr.sv"
+ `include "isa/rv64d_instr.sv"
+ `include "isa/rv64f_instr.sv"
+ `include "isa/rv64i_instr.sv"
+ `include "isa/rv64m_instr.sv"
+ `include "isa/rv128c_instr.sv"
+ `include "isa/rv32v_instr.sv"
+ `include "isa/custom/riscv_custom_instr.sv"
+ `include "isa/custom/rv32x_instr.sv"
+ `include "isa/custom/rv64x_instr.sv"
`include "riscv_pseudo_instr.sv"
`include "riscv_illegal_instr.sv"
@@ -1120,20 +1120,11 @@
`include "riscv_callstack_gen.sv"
`include "riscv_data_page_gen.sv"
-`ifdef DEPRECATED
- `include "deprecated/riscv_rand_instr.sv"
- `include "deprecated/riscv_instr_stream.sv"
- `include "deprecated/riscv_loop_instr.sv"
- `include "deprecated/riscv_directed_instr_lib.sv"
- `include "deprecated/riscv_load_store_instr_lib.sv"
- `include "deprecated/riscv_amo_instr_lib.sv"
-`else
`include "riscv_instr_stream.sv"
`include "riscv_loop_instr.sv"
`include "riscv_directed_instr_lib.sv"
`include "riscv_load_store_instr_lib.sv"
`include "riscv_amo_instr_lib.sv"
-`endif
`include "riscv_instr_sequence.sv"
`include "riscv_asm_program_gen.sv"
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_stream.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_instr_stream.sv
index cea93dc..473e8d8 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
@@ -20,7 +20,7 @@
// instruction, mix two instruction streams etc.
class riscv_instr_stream extends uvm_object;
- `INSTR instr_list[$];
+ riscv_instr instr_list[$];
int unsigned instr_cnt;
string label = "";
// User can specify a small group of available registers to generate various hazard condition
@@ -40,16 +40,16 @@
endfunction
virtual function void create_instr_instance();
- `INSTR instr;
+ riscv_instr instr;
for(int i = 0; i < instr_cnt; i++) begin
- instr = `INSTR::type_id::create($sformatf("instr_%0d", i));
+ instr = riscv_instr::type_id::create($sformatf("instr_%0d", i));
instr_list.push_back(instr);
end
endfunction
// Insert an instruction to the existing instruction stream at the given index
// When index is -1, the instruction is injected at a random location
- function void insert_instr(`INSTR instr, int idx = -1);
+ function void insert_instr(riscv_instr instr, int idx = -1);
int current_instr_cnt = instr_list.size();
if(idx == -1) begin
idx = $urandom_range(0, current_instr_cnt-1);
@@ -70,7 +70,7 @@
// Insert an instruction to the existing instruction stream at the given index
// When index is -1, the instruction is injected at a random location
// When replace is 1, the original instruction at the inserted position will be replaced
- function void insert_instr_stream(`INSTR new_instr[], int idx = -1, bit replace = 1'b0);
+ function void insert_instr_stream(riscv_instr new_instr[], int idx = -1, bit replace = 1'b0);
int current_instr_cnt = instr_list.size();
int new_instr_cnt = new_instr.size();
if(current_instr_cnt == 0) begin
@@ -119,7 +119,7 @@
// Mix the input instruction stream with the original instruction, the instruction order is
// preserved. When 'contained' is set, the original instruction stream will be inside the
// new instruction stream with the first and last instruction from the input instruction stream.
- function void mix_instr_stream(`INSTR new_instr[], bit contained = 1'b0);
+ function void mix_instr_stream(riscv_instr new_instr[], bit contained = 1'b0);
int current_instr_cnt = instr_list.size();
int insert_instr_position[];
int new_instr_cnt = new_instr.size();
@@ -167,7 +167,7 @@
`uvm_object_new
virtual function void create_instr_instance();
- `INSTR instr;
+ riscv_instr instr;
for (int i = 0; i < instr_cnt; i++) begin
instr_list.push_back(null);
end
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_pseudo_instr.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_pseudo_instr.sv
index 6423be4..181b2fd 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_pseudo_instr.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/src/riscv_pseudo_instr.sv
@@ -1,5 +1,5 @@
// Psuedo instructions are used to simplify assembly program writing
-class riscv_pseudo_instr extends `INSTR;
+class riscv_pseudo_instr extends riscv_instr;
rand riscv_pseudo_instr_name_t pseudo_instr_name;
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 2321908..15ea4c6 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
@@ -31,7 +31,7 @@
// ISA supported by the processor
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C, RV32A, RV64A,
- RV32F, RV64F, RV32D, RV64D};
+ RV32F, RV64F, RV32D, RV64D, RV32X};
// Interrupt mode support
mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_base_test.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_base_test.sv
index 1de3d87..5063d46 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_base_test.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_base_test.sv
@@ -80,17 +80,10 @@
task run_phase(uvm_phase phase);
int fd;
- `ifdef DEPRECATED
- cfg.build_instruction_template();
- `endif
for(int i = 0; i < cfg.num_of_tests; i++) begin
string test_name;
randomize_cfg();
- `ifdef DEPRECATED
- cfg.build_instruction_list();
- `else
- riscv_instr::create_instr_list(cfg);
- `endif
+ riscv_instr::create_instr_list(cfg);
asm_gen = riscv_asm_program_gen::type_id::create("asm_gen", , `gfn);
asm_gen.cfg = cfg;
asm_gen.get_directed_instr_stream();
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv
index f13d282..cfbb318 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv
@@ -39,17 +39,9 @@
cfg = riscv_instr_gen_config::type_id::create("cfg");
// disable_compressed_instr is not relevant to coverage test
cfg.disable_compressed_instr = 0;
- `ifdef DEPRECATED
- cfg.build_instruction_template(.skip_instr_exclusion(1));
- `else
- riscv_instr::create_instr_list(cfg);
- `endif
+ riscv_instr::create_instr_list(cfg);
instr = riscv_instr_cov_item::type_id::create("instr");
instr.rand_mode(0);
- `ifdef DEPRECATED
- instr.no_hint_illegal_instr_c.constraint_mode(0);
- instr.imm_val_c.constraint_mode(0);
- `endif
instr_cg = new(cfg);
`uvm_info(`gfn, $sformatf("%0d CSV trace files to be processed", trace_csv.size()), UVM_LOW)
foreach (trace_csv[i]) begin
@@ -142,13 +134,8 @@
`SAMPLE(instr_cg.opcode_cg, binary[6:2])
end
if (instr_enum::from_name(process_instr_name(trace["instr"]), instr_name)) begin
- `ifdef DEPRECATED
- if (cfg.instr_template.exists(instr_name)) begin
- instr.copy_base_instr(cfg.instr_template[instr_name]);
- `else
if (riscv_instr::instr_template.exists(instr_name)) begin
instr.copy(riscv_instr::instr_template[instr_name]);
- `endif
if (instr.group inside {RV32I, RV32M, RV32C, RV64I, RV64M, RV64C}) begin
assign_trace_info_to_instr(instr);
end
diff --git a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/base_testlist.yaml b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/base_testlist.yaml
index 094a9f9..1ef0d20 100644
--- a/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/base_testlist.yaml
+++ b/hw/vendor/lowrisc_ibex/vendor/google_riscv-dv/yaml/base_testlist.yaml
@@ -22,6 +22,7 @@
# 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
+# c_tests : Path to directed, hand-coded C 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
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 09313c3..d0a214b 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
@@ -68,7 +68,6 @@
cov_opts: >
-do "coverage save -onexit <out>/cov.ucdb;"
-# TODO: Remove +DEPRECATED for dsim
- tool: dsim
env_var: DSIM,DSIM_LIB_PATH
compile:
@@ -77,7 +76,6 @@
- "<DSIM> -sv -work <out>/dsim
-genimage image
+incdir+$UVM_HOME/src
- +define+DEPRECATED
$UVM_HOME/src/uvm_pkg.sv
+define+DSIM
+incdir+<setting>