Update google_riscv-dv to google/riscv-dv@cce71d2 (#445)

Update code from upstream repository https://github.com/google/riscv-
dv to revision cce71d24b56f641d994fbf69b8b50aa3756b9322

* Add handshake documentation (Udi)
* Fix coverage debug mode (google/riscv-dv#281) (taoliug)
* Fix coverage script issue (google/riscv-dv#280) (taoliug)
* code block highlight (google/riscv-dv#279) (taoliug)
* Replace setting directory with a default target (google/riscv-
  dv#278) (taoliug)
* fixed trace handling issues (google/riscv-dv#274) (eroom)
* Allow running the script from other directory (google/riscv-dv#277)
  (taoliug)
* Add dummy writes to status and ie CSRs (Udi)
* Script typo fix (google/riscv-dv#272) (Dan Petrisko)
* Fix misa setup issue (google/riscv-dv#271) (taoliug)
* Enable mie.mtie for timer interrupts (Udi)
* Update illegal system instr generation (Udi)
* Fix duplicate (google/riscv-dv#268) (taoliug)
* Add experimental instruction distribution control (google/riscv-
  dv#267) (taoliug)
* Update README to clarify the flow setup instructions (google/riscv-
  dv#265) (taoliug)
* Remove debug logging (google/riscv-dv#264) (taoliug)
* Fix compressed instruction test setup (google/riscv-dv#263)
  (taoliug)
* adding __init__ in the scripts dir since python3.7 requires that for
  directories to be recognized as modules (google/riscv-dv#252)
  (Jielun Tan)
* Fix riscvOVPsim.ic (google/riscv-dv#261) (taoliug)
* Fix ovpsim sim problem (google/riscv-dv#260) (taoliug)
* Add alternative command options for directed instruction stream
  (google/riscv-dv#254) (taoliug)
* Fix dsim compilation issue (google/riscv-dv#253) (taoliug)
This commit is contained in:
udinator 2019-11-04 10:48:02 -08:00 committed by GitHub
parent 48adda0b47
commit f3f3f3de09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 960 additions and 239 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 46ec4bc48bc1eebc5a2bcd48fe4ce4c77105fead
rev: cce71d24b56f641d994fbf69b8b50aa3756b9322
}
}

250
vendor/google_riscv-dv/HANDSHAKE.md vendored Normal file
View file

@ -0,0 +1,250 @@
## Overview
While the `RISCV-DV` Instruction Generator provides a `debug_rom` section as
well as various interrupt and exception handlers, from a verification
standpoint this is not enough to help ensure that a core's internal state is being
updated correctly upon receiving external stimulus such as interrupts or debug
requests, such as the values of any relevant CSRs.
To help with this issue, the instruction generator also provides a mechanism by
which to communicate information to a RTL simulation environment by means of a
handshaking protocol.
## Usage
Every handshake produced by the instruction generator is just a small segment of
RISC-V assembly code, that end in one or more `sw` instructions to a specified memory
address `signature_addr`.
This `signature_addr` is completely customizable, and
can be specified through a `plusarg` runtime option to the generator.
There is also an enable bit `require_signature_addr` that must be set through
another `plusarg` argument to enable these handshake code segments to be
generated in the main random assembly program.
An RTL simulation environment that utilizes
this handshaking mechanism should provide a basic set of tasks to monitor this
`signature_addr` for any writes, as this will indicate that the core under test is
executing a particular handshake assembly sequence and is transmitting some
information to the testbench for analysis.
As a result, this `signature_addr`
acts as sort of memory-mapped address that the testbench will monitor, and as
such, case should be taken when setting this address to ensure that the generator's
program randomization will not somehow create a sequence of random load/store
instructions that access the same `signature_addr`.
A suggested value for this `signature_addr` is the value `0x8ffffffc`.
More details, and an example, as to how to interface the testbench with this
handshake mechanism will be provided below.
## Handshake Sequence Architecture
The function `gen_signature_handshake(...)` contained in
[src/riscv_asm_program_gen.sv](https://github.com/google/riscv-dv/blob/master/src/riscv_asm_program_gen.sv)
is used to actually generate the handshaking code and push it into the specified
instruction queue. Its usage can be seen repeatedly throughout the program
generation in various places, such as trap handlers and the debug ROM, where it
is important to send information to a testbench for further verification.
The `signature_type_t`, `core_status_t`, and `test_result_t` enums specified as
input values to this function are defined in
[src/riscv_signature_pkg.sv](https://github.com/google/riscv-dv/blob/master/src/riscv_signature_pkg.sv).
Note that all of these definitions are within a standalone package, this is so
that an RTL simulation environment can also import this package to gain access
to these enums.
The `signature_type_t` enum is by far the most important enum value, as
this specifies what kind of handshake will be generated.
There are currently 4 defined values of `signature_type`, each corresponding
to a different handshake type that will be generated; each will be explained below.
Note that two GPRs must be used to temporarily hold the store address and the
actual data to store to this address; the generator randomizes these two GPRs
for every generated program, but for the purposes of this document, `x1` and
`x2` will be used, and `0x8ffffffc` will be used as the example `signature_addr`.
#### CORE_STATUS
When the `signature_type` argument is specified as `CORE_STATUS`, a single word
of data will be written to the `signature_addr`. As the actual `signature_type`
value is 8 bits wide, as specified in the `riscv_signature_pkg`, this generated
data word will contain the `CORE_STATUS` value in its bottom 8 bits, and will
contain the specified value of `core_status_t` in the upper 24 bits. This
signature handshake is intended to convey basic information about the core's
execution state to an RTL simulation environment; a handshake containing a
`core_status` of `IN_DEBUG_MODE` is added to the debug ROM to indicate to a
testbench that the core has jumped into Debug Mode and is executing the debug
ROM, a handshake containing a `core_status` of `ILLEGAL_INSTR_EXCEPTION` is
added to the illegal instruction exception handler code created by the generator
to indicate to a testbench that the core has trapped to and is executing the
proper handler after encountering an illegal instruction, and so on for the rest
of the defined `core_status_t` enum values.
Note that when generating these specific handshakes, it is only necessary to
specify the parameters `instr`, `signature_type`, and `core_status`. For
example, to generate this handshake to signal status `IN_MACHINE_MODE` to the
testbench, the call to the function looks like this:
```
gen_signature_handshake(.instr(instr_string_queue),
.signature_type(CORE_STATUS),
.core_status(IN_MACHINE_MODE));
```
The sequence of assembly code generated by this call looks like the following:
```
# First, load the signature address into a GPR
li x2, 0x8ffffffc
# Load the intended core_status_t enum value into
# a second GPR
li x1, 0x2
# Left-shift the core_status value by 8 bits
# to make room for the signature_type
slli x1, x1, 8
# Load the intended signature_type_t enum value into
# the bottom 8 bits of the data word
addi x1, x1, 0x0
# Store the data word to memory at the location of the signature_addr
sw x1, 0(x2)
```
#### TEST_RESULT
As before, when `signature_type` is set to `TEST_RESULT` a single word of data
will be written to the signature address, and the value `TEST_RESULT` will be
placed in the bottom 8 bits. The upper 24 bits will then contain a value of type
`test_result_t`, either `TEST_PASS` or `TEST_FAIL`, to indicate to the testbench
the exit status of the test. As the ISS co-simulation flow provides a robust
end-of-test correctness check, the only time that this signature handshake is
used is in the `riscv_csr_test`. Since this test is generated with a Python
script and is entirely self-checking, we must send an exit status of `TEST_PASS`
or `TEST_FAIL` to the testbench to indicate to either throw an error or end the
test correctly.
Note that when generating these handshakes, the only arguments that need to be
specified are `instr`, `signature_type`, and `test_result`. For example, to
generate a handshake to communicate `TEST_PASS` to a testbench, the function
call would look like this:
```
gen_signature_handshake(.instr(instr_string_queue),
.signature_type(TEST_RESULT),
.test_result(TEST_PASS));
```
The sequence of generated assembly code with this function call would look like
the following:
```
# Load the signature address into a GPR
li x2 0x8ffffffc
# Load the intended test_result_t enum value
li x1, 0x0
# Left-shift the test_result value by 8 bits
slli x1, x1, 8
# Load the intended signature_type_t enum value into
# the bottom 8 bits of the data word
addi x1, x1, 0x1
# Store this formatted word to memory at the signature address
sw x1, 0(x2)
```
#### WRITE_GPR
When a `signature_type` of `WRITE_GPR` is passed to the
`gen_signature_handshake(...)` function, one data word will initially be written
to the signature address, containing the `signature_type` of `WRITE_GPR` in the
lower 8 bits. After this, the value held by each of the 32 RISC-V general
purpose registers from `x0` to `x31` will be written to the signature address
with `sw` instructions.
For this particular handshake, the only function arguments that need to be
specified are `instr` and `signature_type`. A function call to generate this
particular handshake would look like the following:
```
gen_signature_handshake(.instr(instr_string_queue),
.signature_type(WRITE_GPR));
```
The generated assembly sequence would look like this:
```
# Load the signature address into a GPR
li x2, 0x8ffffffc
# Load the value of WRITE_GPR into a second GPR
li x1, 0x2
# Store this word to memory at the signature address
sw x1, 0(x2)
# Iterate through all 32 GPRs and write each one to
# memory at the signature address
sw x0, 0(x2)
sw x1, 0(x2)
sw x2, 0(x2)
sw x3, 0(x2)
...
sw x30, 0(x2)
sw x31, 0(x2)
```
#### WRITE_CSR
When `gen_signature_handshake(...)` is called with `WRITE_CSR` as the
`signature_type` argument, we will generate a first `sw` instruction that writes a
data word to the `signature_addr` that contains the value `WRITE_CSR` in the
bottom 8 bits, and the address of the desired CSR in the upper 24 bits, to
indicate to the testbench which CSR will be written.
This first generated `sw` instruction is then followed by a second one, which
writes the actual data contained in the specified CSR to the signature address.
Note the only function arguments that have to be specified to generate this
handshake are `instr`, `signature_type`, and `csr`. As an example, to generate a
handshake that writes the value of the `mie` CSR to the RTL simulation
environment, the function call would look like this:
```
gen_signature_handshake(.instr(instr_string_queue),
.signature_type(WRITE_CSR),
.csr(MIE));
```
The sequence of assembly generated by this call would look like the following:
```
# Load the signature address into a GPR
li x2, 0x8ffffffc
# Load the address of MIE into the second GPR
li x1, 0x304
# Left-shift the CSR address by 8 bits
slli x1, x1, 8
# Load the WRITE_CSR signature_type value into
# the bottom 8 bits of the data word.
# At this point, the data word is 0x00030403
addi x1, x1, 0x3
# Store this formatted word to memory at the signature address
sw x1, 0(x2)
# Read the actual CSR value into the second GPR
csrr x1, 0x304
# Write the value held by the CSR into memory at the signature address
sw x1, 0(x2)
```
## Sample Testbench Integration
Everything previously outlined has been relating to how this handshake
generation is implemented from the perspective of the `RISCV-DV` instruction
generator, but some work must be done in the RTL simulation environment to
actually interface with and use these handshakes to improve verification with
this mechanism.
This handshaking mechanism has been put to use for verification of the [Ibex
RISC-V core](https://github.com/lowRISC/ibex), in collaboration with LowRISC. To
interface with the handshaking code produced in the generator, this testbench
makes heavy use of the task `wait_for_mem_txn(...)` found in
[core_ibex_base_test.sv](https://github.com/lowRISC/ibex/blob/master/dv/uvm/tests/core_ibex_base_test.sv).
This task polls the Ibex core's data memory interface for any writes to the
chosen signature address (`0x8ffffffc`), and then based on the value of
`signature_type` encoded by the generated handshake code, this task takes
appropriate action and stores the relevant data into a queue instantiated in the
base test class.
For example upon detecting a transaction written to the
signature address that has a `signature_type` of `WRITE_CSR`, it right-shifts
the collected data word by 8 to obtain the CSR address, which is then stored to
the local queue. However, since for `WRITE_CSR` signatures there is a second
data word that gets written to memory at the signature address, the task waits
for the second write containing the CSR data to arrive, and then stores that
into the queue as well. After this task completes, it is now possible to pop
the stored data off of the queue for analysis anywhere else in the test class,
in this case examining the values of various CSR fields.
Additionally, the Ibex testbench provides a fairly basic API of some tasks
wrapping `wait_for_mem_txn(...)` for frequently used functionalities in various
test classes. This API is also found in
[core_ibex_base_test.sv](https://github.com/lowRISC/ibex/blob/master/dv/uvm/tests/core_ibex_base_test.sv).
Examples of use-cases for these API functions can be found throughout the
library of tests written for the Ibex core, found at
[core_ibex_test_lib.sv](https://github.com/lowRISC/ibex/blob/master/dv/uvm/tests/core_ibex_test_lib.sv), as these are heavily used to verify the core's response to external debug and interrupt stimulus.

View file

@ -10,14 +10,14 @@ processor verification. It currently supports the following features:
- Privileged CSR test suite
- Trap/interrupt handling
- Test suite to stress test MMU
- Support sub-programs and random program calls
- Support illegal instruction and HINT instruction
- Sub-program generation and random program calls
- Illegal instruction and HINT instruction generation
- Random forward/backward branch instructions
- 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
- Supports co-simulation with multiple ISS : spike, riscv-ovpsim
- 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
@ -32,15 +32,11 @@ which supports SystemVerilog and UVM 1.2. This generator has been verified with
Synopsys VCS, Cadence Incisive/Xcelium, and Mentor Questa simulators. Please
make sure the EDA tool environment is properly setup before running the generator.
To be able to run the CSR generation script, the open-source `bitstring`
Python library is required ([bitstring](https://github.com/scott-griffiths/bitstring)).
To install this library, either clone the repository and run the `setup.py`
setup script, or run only one of the below commands:
```
1) sudo apt-get install python3-bitstring (or your OS-specific package manager)
2) pip install bitstring
```
Install YAML python package:
```bash
pip3 install PyYAML
```
### Setup RISCV-GCC compiler toolchain
@ -50,12 +46,11 @@ setup script, or run only one of the below commands:
- Set environment variable RISCV_OBJCOPY to RISC-v objcopy executable
executable. (example: <install_dir>/bin/riscv32-unknown-elf-objcopy)
```
// Sample .bashrc setup
```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"
export SPIKE_PATH=$RISCV_TOOLCHAIN/bin
```
### Setup ISS (instruction set simulator)
@ -65,7 +60,7 @@ 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
- Install spike with "--enable-commitlog"
- 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
@ -74,24 +69,28 @@ one of below to run ISS simulation.
- Follow the [steps](https://github.com/rems-project/sail-riscv/blob/master/README.md) to install sail-riscv
- Set environment variable SAIL_RISCV to the sail-riscv binary
```bash
export SPIKE_PATH=$RISCV_TOOLCHAIN/bin
```
## 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
python3 run.py --help
```
Here is the command to run a single test:
```
```bash
python3 run.py --test=riscv_arithmetic_basic_test
```
You can specify the simulator by "-simulator" option
```
```bash
python3 run.py --test riscv_arithmetic_basic_test --simulator ius
python3 run.py --test riscv_arithmetic_basic_test --simulator vcs
python3 run.py --test riscv_arithmetic_basic_test --simulator questa
@ -100,35 +99,35 @@ python3 run.py --test riscv_arithmetic_basic_test --simulator dsim
The complete test list can be found in [yaml/testlist.yaml](https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml). To run a full
regression, simply use below command
```
```bash
python3 run.py
```
You can also run multiple generator jobs in parallel through LSF
```
```bash
python3 run.py --lsf_cmd="bsub -Is"
```
Here's a few more examples of the run command:
```
// Run a single test 10 times
```bash
# Run a single test 10 times
python3 run.py --test riscv_arithmetic_basic_test --iterations 10
// Run a test with verbose logging
# Run a test with verbose logging
python3 run.py --test riscv_arithmetic_basic_test --verbose
// Run a test with a specified seed
# Run a test with a specified seed
python3 run.py --test riscv_arithmetic_basic_test --seed 123
// Skip the generation, run ISS simulation with previously generated program
# Skip the generation, run ISS simulation with previously generated program
python3 run.py --test riscv_arithmetic_basic_test --steps iss_sim
// Run the generator only, do not compile and simluation with ISS
# Run the generator only, do not compile and simluation with ISS
python3 run.py --test riscv_arithmetic_basic_test --steps gen
// Compile the generator only, do not simulate
# Compile the generator only, do not simulate
python3 run.py --test riscv_arithmetic_basic_test --co
....
@ -138,22 +137,22 @@ python3 run.py --test riscv_arithmetic_basic_test --co
You can use -iss to run with different ISS.
```
// Run ISS with spike
```bash
# Run ISS with spike
python3 run.py --test riscv_arithmetic_basic_test --iss spike
// Run ISS with riscv-ovpsim
# Run ISS with riscv-ovpsim
python3 run.py --test riscv_rand_instr_test --iss ovpsim
// Run ISS with sail-riscv
# Run ISS with sail-riscv
python3 run.py --test riscv_rand_instr_test --iss sail
```
To run with ISS simulation for RV32IMC, you can specify ISA and ABI from command
line like this:
```
// Run a full regression with RV32IMC
```bash
# Run a full regression with RV32IMC
python3 run.py --isa rv32imc --mabi ilp32
```
@ -162,7 +161,7 @@ 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
python3 run.py --test=riscv_rand_instr_test --iss=spike,ovpsim
python3 run.py --test=riscv_rand_instr_test --iss=spike,sail
```
@ -171,13 +170,23 @@ python3 run.py --test=riscv_rand_instr_test --iss=spike,sail
### Configure the generator to match your processor features
The default configuration of the instruction generator is for **RV64GC** RISC-V
processors with address translation capability. You might want to configure the
generator according the feature of your processor.
The static setting of the processor src/riscv_core_setting.sv
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
python3 run.py # Default target rv32imc
python3 run.py --target rv32i # rv32i, machine mode only
python3 run.py --target rv32imc # rv32imc, machine mode only
python3 run.py --target rv64imc # rv64imc, machine mode only
python3 run.py --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;
@ -198,14 +207,13 @@ riscv_instr_group_t supported_isa[] = {RV32I, RV32M, RV64I, RV64M};
...
```
A few pre-defined configurations can be found under "target" directory, you can
run with these targets if it matches your processor specification.
You can then run the generator with "--custom_target <target_dir>"
```bash
# You need to manually specify isa and mabi for your custom target
python3 run.py --custom_target <target_dir> --isa <isa> --mabi <mabi>
...
```
// Run regression with RV32IMC configuration
python3 run.py --target rv32imc
```
### Setup the memory map
@ -220,7 +228,7 @@ sections to match the actual memory map
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},
@ -241,7 +249,7 @@ conditions for the load/store testing.
[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
@ -306,7 +314,7 @@ file above.
| randomize_csr | Fully randomize main CSRs (xSTATUS, xIE) | 0 |
### Setup Privileged CSR description
### 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.
@ -314,7 +322,7 @@ 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
@ -353,7 +361,17 @@ format](https://github.com/google/riscv-dv/blob/master/yaml/csr_template.yaml)
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
### Privileged CSR Test Generation (optional)
To be able to run the CSR generation script, the open-source `bitstring`
Python library is required ([bitstring](https://github.com/scott-griffiths/bitstring)).
To install this library, either clone the repository and run the `setup.py`
setup script, or run only one of the below commands:
```bash
sudo apt-get install python3-bitstring (or your OS-specific package manager)
pip install bitstring
```
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).
@ -366,7 +384,7 @@ 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
```
@ -377,16 +395,20 @@ 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: >
@ -395,7 +417,7 @@ You can add a new entry in [iss.yaml](https://github.com/google/riscv-dv/blob/ma
Simulate with the new ISS
```
```bash
python3 run.py --test riscv_arithmetic_basic_test --iss new_iss_name
```
@ -404,30 +426,41 @@ python3 run.py --test riscv_arithmetic_basic_test --iss new_iss_name
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, here's recommended approach to
customize the instruction generator while keeping the minimum effort of merging
upstream changes.
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 file for riscv_core_setting.sv, add the path with below option:
"-cs <new_core_setting_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>"
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 environment of other advanced RISC-V
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 funcitonal coverage information from the
This flow extracts functional coverage information from the
instruction trace generated by ISS. It's indepdent of the instruction generation
flow and does not require a tracer implmentation in the RTL. You can use this
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 the 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 will be run to process the CSV trace files and sample functional
@ -447,17 +480,20 @@ The functional covergroup is defined in [riscv_instr_cover_group.sv](https://git
- 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.
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 coverpoint later. You also need to get spike ISS setup before running this flow.
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 setup before running this flow.
```
// Process spike simulation log and collect functional coverage
```bash
# Process spike simulation log and collect functional coverage
python3 cov.py --dir out/spike_sim
// Get the command reference
# Get the command reference
python3 cov.py --help
# Run the coverage flow with predefined targets
python3 cov.py --dir out/spike_sim --target rv32imc
```
The coverage sampling from the CSV could be time consuming if you have a large
@ -465,7 +501,7 @@ number of log to process. You can split them to small batches and run with LSF
in parallel.
```
// Split the run to process 5 CSV at a time, and run with LSF
# Split the run to process 5 CSV at a time, and run with LSF
python3 cov.py --dir out/spike_sim --lsf_cmd "bsub ....." -bz 5
```
@ -473,8 +509,8 @@ There is also a debug mode which allow you randomize the instruction and sample
coverage directly. This is only used to test the new functional coverage
implmentation.
```
// Randomly generate 100000 instructions, split to 20000 instructions per batch
```bash
# Randomly generate 100000 instructions, split to 20000 instructions per batch
python3 cov.py -d -i 100000 -bz 20000
```

View file

@ -32,7 +32,7 @@ from scripts.sail_log_to_trace_csv import *
LOGGER = logging.getLogger()
def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, \
opts, timeout, simulator, simulator_yaml, core_setting_dir):
opts, timeout, simulator, simulator_yaml, custom_target, target):
"""Collect functional coverage from the instruction trace
Args:
@ -47,8 +47,10 @@ def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, \
timeout : Timeout limit in seconds
simulator : RTL simulator used to run
simulator_yaml : RTL simulator configuration file in YAML format
core_setting_dir : Path for riscv_core_setting.sv
custom_target : Path for the custom target dir
target : Predefined target
"""
cwd = os.path.dirname(os.path.realpath(__file__))
log_list = []
csv_list = []
trace_log = ("%s/%s_trace_log" % (out, iss))
@ -73,13 +75,21 @@ def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, \
logging.error("Full trace for %s is not supported yet" % iss)
sys.exit(1)
if steps == "all" or re.match("cov", steps):
build_cmd = ("python3 run.py --simulator %s --simulator_yaml %s "
"--core_setting_dir %s --co -o %s --cov -tl %s %s " %
(simulator, simulator_yaml, core_setting_dir, out, testlist, opts))
base_sim_cmd = ("python3 run.py --simulator %s --simulator_yaml %s "
"--core_setting_dir %s --so -o %s --cov -tl %s %s "
build_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s "
" --co -o %s --cov -tl %s %s " %
(cwd, simulator, simulator_yaml, out, testlist, opts))
base_sim_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s "
"--so -o %s --cov -tl %s %s "
"-tn riscv_instr_cov_test --steps gen --sim_opts \"<trace_csv_opts>\"" %
(simulator, simulator_yaml, core_setting_dir, out, testlist, opts))
(cwd, simulator, simulator_yaml, out, testlist, opts))
if target:
build_cmd += (" --target %s" % target)
if custom_target:
build_cmd += (" --custom_target %s" % custom_target)
if target:
base_sim_cmd += (" --target %s" % target)
if custom_target:
base_sim_cmd += (" --custom_target %s" % custom_target)
logging.info("Building the coverage collection framework")
run_cmd(build_cmd)
file_idx = 0
@ -115,7 +125,7 @@ def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, \
def run_cov_debug_test(out, instr_cnt, testlist, batch_size, opts, lsf_cmd,\
timeout, simulator, simulator_yaml, core_setting_dir):
timeout, simulator, simulator_yaml, custom_target, target):
"""Collect functional coverage from the instruction trace
Args:
@ -128,19 +138,29 @@ def run_cov_debug_test(out, instr_cnt, testlist, batch_size, opts, lsf_cmd,\
timeout : Timeout limit in seconds
simulator : RTL simulator used to run
simulator_yaml : RTL simulator configuration file in YAML format
core_setting_dir : Path for riscv_core_setting.sv
custom_target : Path for the custom target dir
target : Predefined target
"""
cwd = os.path.dirname(os.path.realpath(__file__))
sim_cmd_list = []
logging.info("Building the coverage collection framework")
build_cmd = ("python3 run.py --simulator %s --simulator_yaml %s "
"--core_setting_dir %s --co -o %s --cov -tl %s %s" %
(simulator, simulator_yaml, core_setting_dir, out, testlist, opts))
build_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s "
"--co -o %s --cov -tl %s %s" %
(cwd, simulator, simulator_yaml, out, testlist, opts))
if target:
build_cmd += (" --target %s" % target)
if custom_target:
build_cmd += (" --custom_target %s" % custom_target)
run_cmd(build_cmd)
base_sim_cmd = ("python3 run.py --simulator %s --simulator_yaml %s "
"--core_setting_dir %s --so -o %s --cov -tl %s %s "
base_sim_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s "
"--so -o %s --cov -tl %s %s "
"-tn riscv_instr_cov_debug_test --steps gen "
"--sim_opts \"+num_of_iterations=<instr_cnt>\"" %
(simulator, simulator_yaml, core_setting_dir, out, testlist, opts))
(cwd, simulator, simulator_yaml, out, testlist, opts))
if target:
base_sim_cmd += (" --target %s" % target)
if custom_target:
base_sim_cmd += (" --custom_target %s" % custom_target)
if batch_size > 0:
batch_cnt = int((instr_cnt+batch_size-1)/batch_size)
logging.info("Batch size: %0d, Batch cnt:%0d" % (batch_size, batch_cnt))
@ -200,13 +220,15 @@ def setup_parser():
parser.add_argument("--lsf_cmd", type=str, default="",
help="LSF command. Run in local sequentially if lsf \
command is not specified")
parser.add_argument("--target", type=str, default="",
parser.add_argument("--target", type=str, default="rv32imc",
help="Run the generator with pre-defined targets: \
rv32imc, rv32i, rv64imc")
rv32imc, rv32i, rv64imc, rv64gc")
parser.add_argument("-si", "--simulator", type=str, default="vcs",
help="Simulator used to run the generator, default VCS", dest="simulator")
parser.add_argument("--simulator_yaml", type=str, default="",
help="RTL simulator setting YAML")
parser.add_argument("-ct", "--custom_target", type=str, default="",
help="Directory name of the custom target")
parser.add_argument("-cs", "--core_setting_dir", type=str, default="",
help="Path for the riscv_core_setting.sv")
parser.set_defaults(verbose=False)
@ -229,10 +251,22 @@ def main():
if not args.simulator_yaml:
args.simulator_yaml = cwd + "/yaml/simulator.yaml"
if args.target:
# Debug mode only works for RV64GC target
if args.debug_mode:
args.target = "rv64gc"
# Keep the core_setting_dir option to be backward compatible, suggest to use
# --custom_target
if args.core_setting_dir:
if not args.custom_target:
args.custom_target = args.core_setting_dir
else:
args.core_setting_dir = args.custom_target
if not args.custom_target:
args.core_setting_dir = cwd + "/target/"+ args.target
elif not args.core_setting_dir:
args.core_setting_dir = cwd + "/setting/"
else:
args.testlist = args.custom_target + "/testlist.yaml"
# Create output directory
if args.o is None:
@ -245,11 +279,11 @@ def main():
if args.debug_mode:
run_cov_debug_test(output_dir, args.instr_cnt, args.testlist,
args.batch_size, args.opts, args.lsf_cmd, args.timeout,
args.simulator, args.simulator_yaml, args.core_setting_dir)
args.simulator, args.simulator_yaml, args.custom_target, args.target)
else:
collect_cov(args.dir, output_dir, args.iss, args.testlist, args.batch_size,
args.lsf_cmd, args.steps, args.opts, args.timeout,
args.simulator, args.simulator_yaml, args.core_setting_dir)
args.simulator, args.simulator_yaml, args.custom_target, args.target)
if __name__ == "__main__":
main()

View file

@ -72,29 +72,28 @@ def get_generator_cmd(simulator, simulator_yaml, cov):
sys.exit(1)
def parse_iss_yaml(iss, iss_yaml, isa):
def parse_iss_yaml(iss, iss_yaml, isa, setting_dir):
"""Parse ISS YAML to get the simulation command
Args:
iss : target ISS used to look up in ISS YAML
iss_yaml : ISS configuration file in YAML format
isa : ISA variant passed to the ISS
iss : target ISS used to look up in ISS YAML
iss_yaml : ISS configuration file in YAML format
isa : ISA variant passed to the ISS
setting_dir : Generator setting directory
Returns:
cmd : ISS run command
cmd : ISS run command
"""
logging.info("Processing ISS setup file : %s" % iss_yaml)
yaml_data = read_yaml(iss_yaml)
cwd = os.path.dirname(os.path.realpath(__file__))
# Search for matched ISS
for entry in yaml_data:
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)
if iss == "ovpsim":
cmd = re.sub("\<variant\>", isa, cmd)
else:
cmd = re.sub("\<variant\>", isa, cmd)
cmd = re.sub("\<variant\>", isa, cmd)
return cmd
logging.error("Cannot find ISS %0s" % iss)
sys.exit(1)
@ -159,10 +158,7 @@ def gen(test_list, csr_file, end_signature_addr, isa, simulator,
logging.info("Building RISC-V instruction generator")
for cmd in compile_cmd:
cmd = re.sub("<out>", os.path.abspath(output_dir), cmd)
if core_setting_dir == "":
cmd = re.sub("<setting>", "<cwd>/setting", cmd)
else:
cmd = re.sub("<setting>", core_setting_dir, cmd)
cmd = re.sub("<setting>", core_setting_dir, cmd)
if ext_dir == "":
cmd = re.sub("<user_extension>", "<cwd>/user_extension", cmd)
else:
@ -253,6 +249,7 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts):
isa : ISA variant passed to GCC
mabi : MABI variant passed to GCC
"""
cwd = os.path.dirname(os.path.realpath(__file__))
for test in test_list:
for i in range(0, test['iterations']):
if 'no_gcc' in test and test['no_gcc'] == 1:
@ -261,20 +258,24 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts):
asm = prefix + ".S"
elf = prefix + ".o"
binary = prefix + ".bin"
test_isa = isa
# gcc comilation
cmd = ("%s -static -mcmodel=medany \
-fvisibility=hidden -nostdlib \
-nostartfiles %s \
-I%s/user_extension \
-T%s/scripts/link.ld %s -o %s " % \
(get_env_var("RISCV_GCC"), asm, get_env_var("RISCV_DV_ROOT"),
get_env_var("RISCV_DV_ROOT"), opts, elf))
(get_env_var("RISCV_GCC"), asm, cwd, cwd, opts, elf))
if 'gcc_opts' in test:
cmd += test['gcc_opts']
if 'gen_opts' in test:
# Disable compressed instruction
if re.search('disable_compressed_instr', test['gen_opts']):
test_isa = re.sub("c", "", test_isa)
# If march/mabi is not defined in the test gcc_opts, use the default
# setting from the command line.
if not re.search('march', cmd):
cmd += (" -march=%s" % isa)
cmd += (" -march=%s" % test_isa)
if not re.search('mabi', cmd):
cmd += (" -mabi=%s" % mabi)
logging.info("Compiling %s" % asm)
@ -298,6 +299,7 @@ def run_assembly(asm_test, iss_yaml, isa, mabi, iss):
mabi : MABI variant passed to GCC
iss : Instruction set simulators
"""
cwd = os.path.dirname(os.path.realpath(__file__))
asm = asm_test
elf = asm_test + ".o"
binary = asm_test + ".bin"
@ -309,8 +311,7 @@ def run_assembly(asm_test, iss_yaml, isa, mabi, iss):
-nostartfiles %s \
-I%s/user_extension \
-T%s/scripts/link.ld -o %s " % \
(get_env_var("RISCV_GCC"), asm, get_env_var("RISCV_DV_ROOT"),
get_env_var("RISCV_DV_ROOT"), elf))
(get_env_var("RISCV_GCC"), asm, cwd, cwd, elf))
cmd += (" -march=%s" % isa)
cmd += (" -mabi=%s" % mabi)
logging.info("Compiling %s" % asm)
@ -327,20 +328,21 @@ def run_assembly(asm_test, iss_yaml, isa, mabi, iss):
logging.info("[%0s] Running ISS simulation: %s ...done" % (iss, elf))
def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s):
def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, setting_dir, timeout_s):
"""Run ISS simulation with the generated test program
Args:
test_list : List of assembly programs to be compiled
output_dir : Output directory of the ELF files
iss_list : List of instruction set simulators
iss_yaml : ISS configuration file in YAML format
isa : ISA variant passed to the ISS
timeout_s : Timeout limit in seconds
test_list : List of assembly programs to be compiled
output_dir : Output directory of the ELF files
iss_list : List of instruction set simulators
iss_yaml : ISS configuration file in YAML format
isa : ISA variant passed to the ISS
setting_dir : Generator setting directory
timeout_s : Timeout limit in seconds
"""
for iss in iss_list.split(","):
log_dir = ("%s/%s_sim" % (output_dir, iss))
base_cmd = parse_iss_yaml(iss, iss_yaml, isa)
base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir)
logging.info("%s sim log dir: %s" % (iss, log_dir))
subprocess.run(["mkdir", "-p", log_dir])
for test in test_list:
@ -408,6 +410,9 @@ def setup_parser():
# Parse input arguments
parser = argparse.ArgumentParser()
parser.add_argument("--target", type=str, default="rv64imc",
help="Run the generator with pre-defined targets: \
rv32imc, rv32i, rv64imc, rv64gc")
parser.add_argument("-o", "--output", type=str,
help="Output directory name", dest="o")
parser.add_argument("-tl", "--testlist", type=str, default="",
@ -441,15 +446,15 @@ def setup_parser():
parser.add_argument("--lsf_cmd", type=str, default="",
help="LSF command. Run in local sequentially if lsf \
command is not specified")
parser.add_argument("--isa", type=str, default="rv64gc",
parser.add_argument("--isa", type=str, default="",
help="RISC-V ISA subset")
parser.add_argument("-m", "--mabi", type=str, default="lp64",
help="mabi used for compilation, lp32 or lp64", dest="mabi")
parser.add_argument("-m", "--mabi", type=str, default="",
help="mabi used for compilation", dest="mabi")
parser.add_argument("--gen_timeout", type=int, default=360,
help="Generator timeout limit in seconds")
parser.add_argument("--end_signature_addr", type=str, default="0",
help="Address that privileged CSR test writes to at EOT")
parser.add_argument("--iss_timeout", type=int, default=25,
parser.add_argument("--iss_timeout", type=int, default=10,
help="ISS sim timeout limit in seconds")
parser.add_argument("--iss_yaml", type=str, default="",
help="ISS setting YAML")
@ -460,15 +465,14 @@ def setup_parser():
parser.add_argument("--seed_yaml", type=str, default="",
help="Rerun the generator with the seed specification \
from a prior regression")
parser.add_argument("-ct", "--custom_target", type=str, default="",
help="Directory name of the custom target")
parser.add_argument("-cs", "--core_setting_dir", type=str, default="",
help="Path for the riscv_core_setting.sv")
parser.add_argument("-ext", "--user_extension_dir", type=str, default="",
help="Path for the user extension directory")
parser.add_argument("--asm_test", type=str, default="",
help="Directed assembly test")
parser.add_argument("--target", type=str, default="",
help="Run the generator with pre-defined targets: \
rv32imc, rv32i, rv64imc")
parser.add_argument("--log_suffix", type=str, default="",
help="Simulation log name suffix")
parser.add_argument("-bz", "--batch_size", type=int, default=0,
@ -483,10 +487,10 @@ def setup_parser():
def main():
"""This is the main entry point."""
check_riscv_dv_setting()
parser = setup_parser()
args = parser.parse_args()
cwd = os.path.dirname(os.path.realpath(__file__))
os.environ["RISCV_DV_ROOT"] = cwd
setup_logging(args.verbose)
if not args.csr_yaml:
@ -498,8 +502,17 @@ def main():
if not args.simulator_yaml:
args.simulator_yaml = cwd + "/yaml/simulator.yaml"
if args.target:
args.testlist = cwd + "/target/"+ args.target +"/testlist.yaml"
# Keep the core_setting_dir option to be backward compatible, suggest to use
# --custom_target
if args.core_setting_dir:
if not args.custom_target:
args.custom_target = args.core_setting_dir
else:
args.core_setting_dir = args.custom_target
if not args.custom_target:
if not args.testlist:
args.testlist = cwd + "/target/"+ args.target +"/testlist.yaml"
args.core_setting_dir = cwd + "/target/"+ args.target
if args.target == "rv32imc":
args.mabi = "ilp32"
@ -510,10 +523,16 @@ def main():
elif args.target == "rv64imc":
args.mabi = "lp64"
args.isa = "rv64imc"
elif args.target == "ml":
args.mabi = "lp64"
args.isa = "rv64imc"
else:
print ("Unsupported target: %0s" % args.target)
elif not args.testlist:
args.testlist = cwd + "/yaml/testlist.yaml"
print ("Unsupported pre-defined target: %0s" % args.target)
else:
if (not args.mabi) or (not args.isa):
sys.exit("mabi and isa must be specified for custom target %0s" % args.custom_target)
if not args.testlist:
args.testlist = args.custom_target + "/testlist.yaml"
if args.asm_test != "":
run_assembly(args.asm_test, args.iss_yaml, args.isa, args.mabi, args.iss)
@ -553,7 +572,7 @@ def main():
# Run ISS simulation
if args.steps == "all" or re.match(".*iss_sim.*", args.steps):
iss_sim(matched_list, output_dir, args.iss, args.iss_yaml,
args.isa, args.iss_timeout)
args.isa, args.core_setting_dir, args.iss_timeout)
# Compare ISS simulation result
if args.steps == "all" or re.match(".*iss_cmp.*", args.steps):

View file

View file

@ -47,8 +47,8 @@ def compare_trace_csv(csv1, csv2, name1, name2, log,
with open(csv1, "r") as fd1, open(csv2, "r") as fd2:
instr_trace_1 = []
instr_trace_2 = []
trace_csv_1 = RiscvInstructiontTraceCsv(fd1)
trace_csv_2 = RiscvInstructiontTraceCsv(fd2)
trace_csv_1 = RiscvInstructionTraceCsv(fd1)
trace_csv_2 = RiscvInstructionTraceCsv(fd2)
trace_csv_1.read_trace(instr_trace_1)
trace_csv_2.read_trace(instr_trace_2)
trace_1_index = 0
@ -173,7 +173,7 @@ def compare_trace_csv(csv1, csv2, name1, name2, log,
name1, len(gpr_trace_1[gpr]), name2, len(gpr_trace_2[gpr])))
else:
if not gpr_trace_2.get(gpr):
trace = RiscvInstructiontTraceEntry()
trace = RiscvInstructionTraceEntry()
trace.rd_val = "0"
trace.rd = gpr
trace.instr_str = ""

View file

@ -75,15 +75,6 @@ def get_env_var(var):
return val
def check_riscv_dv_setting():
"""Check the RISCV-DV directory setting, default "."
"""
try:
val = os.environ["RISCV_DV_ROOT"]
except KeyError:
os.environ["RISCV_DV_ROOT"] = "."
def get_seed(seed):
"""Get the seed to run the generator
@ -112,6 +103,7 @@ def run_cmd(cmd, timeout_s = 999):
try:
ps = subprocess.Popen("exec " + cmd,
shell=True,
executable='/bin/bash',
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
@ -141,6 +133,7 @@ def run_parallel_cmd(cmd_list, timeout_s = 999):
for cmd in cmd_list:
ps = subprocess.Popen("exec " + cmd,
shell=True,
executable='/bin/bash',
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)

View file

@ -70,7 +70,52 @@ def process_if_compressed(prev_trace):
prev_trace.instr = "c."+prev_trace.instr
# logging.debug("process_if_compressed(%s, %s)" % (prev_trace.instr, prev_trace.binary))
def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 0):
pseudos={
'mv' :'addi',
'not' :'xori',
'neg' :'sub',
'negw' :'subw',
'sext.w' :'addiw',
'seqz' :'sltiu',
'snez' :'sltu',
'sltz' :'slt',
'sgtz' :'slt',
'beqz' :'beg',
'bnez' :'bnez',
'bgez' :'bgez',
'bltz' :'blt',
'blez' :'bge',
'bgtz' :'blt',
'csrr' :'csrrw',
'csrw' :'csrrw',
'csrs' :'csrrs',
'csrc' :'csrrc',
'csrwi' :'csrrwi',
'csrsi' :'csrrsi',
'csrci' :'csrrci',
'j' :'jal',
'jr' :'jal',
}
def check_conversion(entry, stop_on_first_error):
instr_str_0 =entry.instr_str.split(" ")[0]
instr =entry.instr.split(" ")[0]
if "c." in instr[0:2]:
instr = instr[2:]
if instr in instr_str_0:
return # same
#logging.debug("converted pseudo %10s -> %s" % (instr_str_0, instr))
if instr_str_0 in pseudos:
p_instr = pseudos[instr_str_0]
if p_instr in instr:
return # is pseudo, converted ok
logging.error("converted %10s -> %s <<-- not correct pseudo (%s)" % (instr_str_0, instr, p_instr))
if stop_on_first_error:
sys.exit(-1)
logging.error("converted %10s -> %s <<-- not correct at all" % (instr_str_0, instr))
if stop_on_first_error:
sys.exit(-1)
def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 0, stop_on_first_error = 1):
"""Process OVPsim simulation log.
Extract instruction and affected register information from ovpsim simulation
@ -95,7 +140,7 @@ def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 0):
gpr[g] = 0
with open(ovpsim_log, "r") as f, open(csv, "w") as csv_fd:
trace_csv = RiscvInstructiontTraceCsv(csv_fd)
trace_csv = RiscvInstructionTraceCsv(csv_fd)
trace_csv.start_new_trace()
prev_trace = 0
for line in f:
@ -104,20 +149,22 @@ def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 0):
"(?P<mode>[A-Za-z]*?)\s+(?P<bin>[a-f0-9]*?)\s+(?P<instr>.*?)$", line)
if m:
if prev_trace: # if not yet written as it had no data following it
check_conversion(prev_trace, stop_on_first_error)
trace_csv.write_trace_entry(prev_trace)
prev_trace = 0
trace_bin = m.group("bin")
trace_instr_str = m.group("instr")
trace_addr = m.group("addr")
trace_section = m.group("section") # not yet used
#trace_mode = convert_mode(m.group("mode"), line)
trace_section = m.group("section")
trace_mode = convert_mode(m.group("mode"), line)
trace_instr = trace_instr_str.split(" ")[0]
instr_cnt += 1
prev_trace = RiscvInstructiontTraceEntry()
prev_trace = RiscvInstructionTraceEntry()
prev_trace.instr_str = trace_instr_str
prev_trace.binary = trace_bin
prev_trace.addr = trace_addr
#prev_trace.privileged_mode = trace_mode
prev_trace.instr = trace_instr # wrong
prev_trace.privileged_mode = trace_mode
prev_trace.instr = trace_instr
if 0:
print ("line ::"+line)
@ -126,18 +173,13 @@ def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 0):
print ("ins ::"+trace_instr)
print ("addr ::"+trace_addr)
print ("sect ::"+trace_section)
#print ("mode ::"+prev_trace.privileged_mode)
print ("mode ::"+trace_mode)
sys.exit(-1)
if full_trace:
i = re.search (r"(?P<instr>[a-z]*?)\s", trace_instr_str)
if i:
trace_instr = i.group("instr")
if trace_instr_str == "nop" or \
trace_instr_str == "mret" or \
trace_instr_str == "ecall" :
# this will probably need also doing for things like wfi too
trace_instr = trace_instr_str
prev_trace.instr = trace_instr
process_if_compressed(prev_trace)
o = re.search (r"(?P<instr>[a-z]*?)\s(?P<operand>.*)", trace_instr_str)
@ -148,7 +190,6 @@ def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 0):
process_jalr(prev_trace, operands, gpr)
else:
assign_operand(prev_trace, operands, gpr)
# sys.exit(-1)
else:
# print("no operand for [%s] in [%s]" % (trace_instr, trace_instr_str))
pass
@ -164,29 +205,28 @@ def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 0):
# Write the extracted instruction to a csvcol buffer file
# print("%0s %0s = %0s" % (trace_instr_str, m.group("rd"), m.group("val")))
if n.group("rd") != "frm":
rv_instr_trace = RiscvInstructiontTraceEntry()
rv_instr_trace.rd = n.group("rd")
rv_instr_trace.rd_val = n.group("val")
rv_instr_trace.rs1 = prev_trace.rs1
rv_instr_trace.rs1_val = prev_trace.rs1_val
rv_instr_trace.rs2 = prev_trace.rs2
rv_instr_trace.rs2_val = prev_trace.rs2_val
rv_instr_trace.instr_str = trace_instr_str
rv_instr_trace.instr = prev_trace.instr
rv_instr_trace.binary = trace_bin
rv_instr_trace.addr = trace_addr
#rv_instr_trace.privileged_mode = trace_mode
gpr[rv_instr_trace.rd] = rv_instr_trace.rd_val
if full_trace:
rv_instr_trace.instr = prev_trace.instr
rv_instr_trace = RiscvInstructionTraceEntry()
rv_instr_trace.rd = n.group("rd")
rv_instr_trace.rd_val = n.group("val")
rv_instr_trace.rs1 = prev_trace.rs1
rv_instr_trace.rs1_val = prev_trace.rs1_val
rv_instr_trace.rs2 = prev_trace.rs2
rv_instr_trace.rs2_val = prev_trace.rs2_val
rv_instr_trace.instr_str = trace_instr_str
rv_instr_trace.instr = prev_trace.instr
rv_instr_trace.binary = trace_bin
rv_instr_trace.addr = trace_addr
rv_instr_trace.privileged_mode = trace_mode
gpr[rv_instr_trace.rd] = rv_instr_trace.rd_val
check_conversion(rv_instr_trace, stop_on_first_error)
trace_csv.write_trace_entry(rv_instr_trace)
prev_trace = 0 # we wrote out as it had data, so no need to write it next time round
if 0:
print ("write entry [[%d]]: rd[%s] val[%s] instr(%s) bin(%s) addr(%s)"
% (instr_cnt, rv_instr_trace.rd, rv_instr_trace.rd_val,
trace_instr_str, trace_bin, trace_addr))
print (rv_instr_trace.__dict__)
sys.exit(-1)
print ("write entry [[%d]]: rd[%s] val[%s] instr(%s) bin(%s) addr(%s)"
% (instr_cnt, rv_instr_trace.rd, rv_instr_trace.rd_val,
trace_instr_str, trace_bin, trace_addr))
print (rv_instr_trace.__dict__)
sys.exit(-1)
else:
if 0:
print ("write previous entry: [%s] %s " % (str(instr_cnt), line))

View file

@ -20,7 +20,7 @@ import csv
import re
import logging
class RiscvInstructiontTraceEntry(object):
class RiscvInstructionTraceEntry(object):
"""RISC-V instruction trace entry"""
def __init__(self):
self.rd = ""
@ -43,7 +43,7 @@ class RiscvInstructiontTraceEntry(object):
return ("%s -> %s(0x%s) addr:0x%s" %
(self.instr_str, self.rd, self.rd_val, self.addr))
class RiscvInstructiontTraceCsv(object):
class RiscvInstructionTraceCsv(object):
"""RISC-V instruction trace CSV class
This class provides functions to read/write trace CSV
@ -66,7 +66,7 @@ class RiscvInstructiontTraceCsv(object):
"""Read instruction trace from CSV file"""
csv_reader = csv.DictReader(self.csv_fd)
for row in csv_reader:
new_trace = RiscvInstructiontTraceEntry()
new_trace = RiscvInstructionTraceEntry()
new_trace.rd = row['rd']
new_trace.rd_val = row['rd_val']
new_trace.addr = row['addr']

View file

@ -45,7 +45,7 @@ def process_sail_sim_log(sail_log, csv):
with open(sail_log, "r") as f, open(csv, "w") as csv_fd:
search_start = 0
instr_start = 0
trace_csv = RiscvInstructiontTraceCsv(csv_fd)
trace_csv = RiscvInstructionTraceCsv(csv_fd)
trace_csv.start_new_trace()
instr = None
for line in f:
@ -71,7 +71,7 @@ def process_sail_sim_log(sail_log, csv):
if m:
# Write the extracted instruction to a csvcol buffer file
instr_cnt += 1
rv_instr_trace = RiscvInstructiontTraceEntry()
rv_instr_trace = RiscvInstructionTraceEntry()
rv_instr_trace.rd = gpr_to_abi("x%0s" % m.group("reg"))
rv_instr_trace.rd_val = m.group("val").lower()
rv_instr_trace.privileged_mode = pri

View file

@ -59,7 +59,7 @@ def process_spike_sim_log(spike_log, csv, full_trace = 0):
gpr["zero"] = 0
with open(spike_log, "r") as f, open(csv, "w") as csv_fd:
trace_csv = RiscvInstructiontTraceCsv(csv_fd)
trace_csv = RiscvInstructionTraceCsv(csv_fd)
trace_csv.start_new_trace()
for line in f:
# Extract instruction infromation
@ -67,7 +67,7 @@ def process_spike_sim_log(spike_log, csv, full_trace = 0):
if m:
spike_instr = m.group("instr").replace("pc + ", "")
spike_instr = spike_instr.replace("pc - ", "-")
rv_instr_trace = RiscvInstructiontTraceEntry()
rv_instr_trace = RiscvInstructionTraceEntry()
rv_instr_trace.instr_str = spike_instr
rv_instr_trace.addr = m.group("addr")
rv_instr_trace.binary = m.group("bin")

View file

@ -340,13 +340,14 @@ class riscv_asm_program_gen extends uvm_object;
init_floating_point_gpr();
end
core_is_initialized();
gen_dummy_csr_write();
endfunction
// Setup MISA based on supported extensions
virtual function void setup_misa();
bit [XLEN-1:0] misa;
misa[XLEN-1:XLEN-3] = (XLEN == 32) ? 1 :
(XLEN == 64) ? 2 : 3;
misa[XLEN-1:XLEN-2] = (XLEN == 32) ? 2'b01 :
(XLEN == 64) ? 2'b10 : 2'b11;
if (cfg.check_misa_init_val) begin
instr_stream.push_back({indent, "csrr x15, misa"});
end
@ -384,6 +385,37 @@ class riscv_asm_program_gen extends uvm_object;
end
endfunction
// Generate some dummy writes to xSTATUS/xIE at the beginning of the test to check
// repeated writes to these CSRs.
virtual function void gen_dummy_csr_write();
string instr[$];
case (cfg.init_privileged_mode)
MACHINE_MODE: begin
instr.push_back($sformatf("csrr x%0d, 0x%0x", cfg.gpr[0], MSTATUS));
instr.push_back($sformatf("csrr x%0d, 0x%0x", cfg.gpr[1], MIE));
instr.push_back($sformatf("csrw 0x%0x, x%0d", MSTATUS, cfg.gpr[0]));
instr.push_back($sformatf("csrw 0x%0x, x%0d", MIE, cfg.gpr[1]));
end
SUPERVISOR_MODE: begin
instr.push_back($sformatf("csrr x%0d, 0x%0x", cfg.gpr[0], SSTATUS));
instr.push_back($sformatf("csrr x%0d, 0x%0x", cfg.gpr[1], SIE));
instr.push_back($sformatf("csrw 0x%0x, x%0d", SSTATUS, cfg.gpr[0]));
instr.push_back($sformatf("csrw 0x%0x, x%0d", SIE, cfg.gpr[1]));
end
USER_MODE: begin
instr.push_back($sformatf("csrr x%0d, 0x%0x", cfg.gpr[0], USTATUS));
instr.push_back($sformatf("csrr x%0d, 0x%0x", cfg.gpr[1], UIE));
instr.push_back($sformatf("csrw 0x%0x, x%0d", USTATUS, cfg.gpr[0]));
instr.push_back($sformatf("csrw 0x%0x, x%0d", UIE, cfg.gpr[1]));
end
default: begin
`uvm_fatal(`gfn, "Unsupported boot mode")
end
endcase
format_section(instr);
instr_stream = {instr_stream, instr};
endfunction
// Initialize general purpose registers with random value
virtual function void init_gpr();
string str;
@ -1103,9 +1135,14 @@ class riscv_asm_program_gen extends uvm_object;
virtual function void get_directed_instr_stream();
string args, val;
string stream_name_opts, stream_freq_opts;
string stream_name;
int stream_freq;
string opts[$];
for (int i=0; i<cfg.max_directed_instr_stream_seq; i++) begin
args = $sformatf("directed_instr_%0d=", i);
stream_name_opts = $sformatf("stream_name_%0d=", i);
stream_freq_opts = $sformatf("stream_freq_%0d=", i);
if ($value$plusargs({args,"%0s"}, val)) begin
uvm_split_string(val, ",", opts);
if (opts.size() != 2) begin
@ -1114,6 +1151,9 @@ class riscv_asm_program_gen extends uvm_object;
end else begin
add_directed_instr_stream(opts[0], opts[1].atoi());
end
end else if ($value$plusargs({stream_name_opts,"%0s"}, stream_name) &&
$value$plusargs({stream_freq_opts,"%0d"}, stream_freq)) begin
add_directed_instr_stream(stream_name, stream_freq);
end
end
endfunction

View file

@ -184,7 +184,7 @@ class riscv_jal_instr extends riscv_rand_instr_stream;
riscv_instr_base jump_start;
riscv_instr_base jump_end;
rand int unsigned num_of_jump_instr;
riscv_instr_name_t jal[];
riscv_instr_name_t jal[$];
constraint instr_c {
num_of_jump_instr inside {[10:30]};
@ -207,7 +207,10 @@ class riscv_jal_instr extends riscv_rand_instr_stream;
setup_allowed_instr(1, 1);
jal = {JAL};
if (!cfg.disable_compressed_instr) begin
jal = (XLEN == 32) ? {jal, C_J, C_JAL} : {jal, C_J};
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");

View file

@ -29,7 +29,8 @@ class riscv_illegal_instr extends uvm_object;
kIllegalFunc3,
kIllegalFunc7,
kReservedCompressedInstr,
kHintInstr
kHintInstr,
kIllegalSystemInstr
} illegal_instr_type_e;
// Default legal opcode for RV32I instructions
@ -65,15 +66,17 @@ class riscv_illegal_instr extends uvm_object;
rand bit [1:0] c_op;
rand bit [2:0] c_msb;
riscv_instr_gen_config cfg;
privileged_reg_t csrs[$];
constraint exception_dist_c {
exception dist {
kIllegalOpcode := 4,
kIllegalOpcode := 3,
kIllegalCompressedOpcode := 1,
kIllegalFunc3 := 1,
kIllegalFunc7 := 1,
kReservedCompressedInstr := 1,
kHintInstr := 3
kHintInstr := 3,
kIllegalSystemInstr := 3
};
}
@ -97,6 +100,25 @@ class riscv_illegal_instr extends uvm_object;
}
}
// Invalid SYSTEM instructions
constraint system_instr_c {
if (exception == kIllegalSystemInstr) {
opcode == 7'b1110011;
// ECALL/EBREAK/xRET/WFI
if (func3 == 3'b000) {
// Constrain RS1 and RD to be non-zero
instr_bin[19:15] != 0;
instr_bin[11:7] != 0;
// Valid SYSTEM instructions considered by this
// Constrain the upper 12 bits to be invalid
!(instr_bin[31:20] inside {12'h0, 12'h1, 12'h2, 12'h102, 12'h302, 12'h7b2, 12'h105});
} else {
// Invalid CSR instructions
!(instr_bin[31:20] inside {csrs});
}
}
}
constraint legal_rv32_c_slli {
if ((c_msb == 3'b000) && (c_op == 2'b10) && (XLEN == 32)) {
if (exception == kReservedCompressedInstr) {
@ -111,7 +133,7 @@ class riscv_illegal_instr extends uvm_object;
if (compressed) {
exception inside {kReservedCompressedInstr, kIllegalCompressedOpcode, kHintInstr};
} else {
exception inside {kIllegalOpcode, kIllegalFunc3, kIllegalFunc7};
exception inside {kIllegalOpcode, kIllegalFunc3, kIllegalFunc7, kIllegalSystemInstr};
}
if (!has_func7) {
exception != kIllegalFunc7;
@ -269,6 +291,7 @@ class riscv_illegal_instr extends uvm_object;
`uvm_object_new
function void init(riscv_instr_gen_config cfg);
privileged_reg_t csr;
this.cfg = cfg;
if ((riscv_instr_pkg::RV32F inside {riscv_instr_pkg::supported_isa}) ||
riscv_instr_pkg::RV32D inside {riscv_instr_pkg::supported_isa}) begin
@ -289,6 +312,11 @@ class riscv_illegal_instr extends uvm_object;
legal_c00_opcode = {legal_c00_opcode, 3'b011, 3'b111};
legal_c10_opcode = {legal_c10_opcode, 3'b011, 3'b111};
end
csr = csr.first();
for (int i = 0; i < csr.num(); i = i + 1) begin
csrs.push_back(csr);
csr = csr.next();
end
endfunction
function string get_bin_str();
@ -297,6 +325,8 @@ class riscv_illegal_instr extends uvm_object;
end else begin
get_bin_str = $sformatf("%8h", instr_bin[31:0]);
end
`uvm_info(`gfn, $sformatf("Illegal instruction type: %0s, illegal instruction: 0x%0x",
exception.name(), instr_bin), UVM_HIGH)
endfunction
endclass

View file

@ -18,7 +18,7 @@ class riscv_instr_base extends uvm_object;
rand riscv_instr_group_t group;
rand riscv_instr_format_t format;
rand riscv_instr_cateogry_t category;
rand riscv_instr_category_t category;
rand riscv_instr_name_t instr_name;
rand bit [11:0] csr;
@ -159,6 +159,12 @@ class riscv_instr_base extends uvm_object;
}
}
constraint jal_c {
if (XLEN != 32) {
soft instr_name != C_JAL;
}
}
constraint system_instr_c {
if (category inside {SYSTEM, SYNCH}) {
rd == ZERO;
@ -942,8 +948,6 @@ class riscv_instr_base extends uvm_object;
AND : get_func7 = 7'b0000000;
FENCE : get_func7 = 7'b0000000;
FENCE_I : get_func7 = 7'b0000000;
ECALL : get_func7 = 7'b0000000;
EBREAK : get_func7 = 7'b0000000;
SLLIW : get_func7 = 7'b0000000;
SRLIW : get_func7 = 7'b0000000;
SRAIW : get_func7 = 7'b0100000;

View file

@ -181,7 +181,6 @@ class riscv_instr_cov_item extends riscv_instr_base;
BGE : is_branch_hit = ($signed(rs1_value) > $signed(rs2_value));
BLTU : is_branch_hit = (rs1_value < rs2_value);
BGEU : is_branch_hit = (rs1_value > rs2_value);
BGEU : is_branch_hit = (rs1_value > rs2_value);
default: `uvm_error(get_name(), $sformatf("Unexpected instr %0s", instr_name.name()))
endcase
return is_branch_hit;

View file

@ -122,7 +122,7 @@ class riscv_instr_gen_config extends uvm_object;
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_cateogry_t][$];
riscv_instr_name_t instr_category[riscv_instr_category_t][$];
//-----------------------------------------------------------------------------
// Command line options or control knobs
@ -152,7 +152,10 @@ class riscv_instr_gen_config extends uvm_object;
// A name suffix for the generated assembly program
string asm_test_suffix;
// Enable interrupt bit in MSTATUS (MIE, SIE, UIE)
int enable_interrupt;
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
@ -204,6 +207,12 @@ class riscv_instr_gen_config extends uvm_object;
// 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 {
@ -381,7 +390,8 @@ class riscv_instr_gen_config extends uvm_object;
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_int_arg_value("+enable_interrupt=", enable_interrupt);
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);
@ -449,6 +459,30 @@ class riscv_instr_gen_config extends uvm_object;
if (!(RV32C inside {supported_isa})) begin
disable_compressed_instr = 1;
end
setup_instr_distribution();
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

View file

@ -372,7 +372,7 @@ package riscv_instr_pkg;
TRAP,
INTERRUPT,
AMO
} riscv_instr_cateogry_t;
} riscv_instr_category_t;
typedef bit [11:0] riscv_csr_t;

View file

@ -157,6 +157,7 @@ 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
@ -177,6 +178,21 @@ class riscv_rand_instr_stream extends riscv_instr_stream;
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 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,
@ -199,11 +215,28 @@ class riscv_rand_instr_stream extends riscv_instr_stream;
bit skip_rs2 = 1'b0,
bit skip_rd = 1'b0,
bit skip_imm = 1'b0,
bit skip_csr = 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
if ((cfg.no_ebreak && !is_in_debug) || (!cfg.enable_ebreak_in_debug_rom && is_in_debug)) begin
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});)

View file

@ -164,7 +164,7 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
end
end
end
randomize_instr(instr, .skip_rs1(1'b1), .skip_imm(1'b1));
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;
@ -182,7 +182,7 @@ class riscv_single_load_store_instr_stream extends riscv_load_store_base_instr_s
num_mixed_instr < 5;
}
`uvm_object_utils(riscv_load_store_base_instr_stream)
`uvm_object_utils(riscv_single_load_store_instr_stream)
`uvm_object_new
endclass

View file

@ -95,12 +95,9 @@ class riscv_privileged_common_seq extends uvm_sequence;
mie.set_field("USIE", cfg.enable_interrupt);
mie.set_field("SSIE", cfg.enable_interrupt);
mie.set_field("MSIE", cfg.enable_interrupt);
// TODO(udinator) - since full CSRs are being randomized, it's necessary to hardwire the xTIE
// fields to 1'b0, as it causes some timer interrupts to be triggered in Spike after a certain
// amount of simulation time.
mie.set_field("MTIE", 1'b0);
mie.set_field("STIE", 1'b0);
mie.set_field("UTIE", 1'b0);
mie.set_field("MTIE", cfg.enable_interrupt & cfg.enable_timer_irq);
mie.set_field("STIE", cfg.enable_interrupt & cfg.enable_timer_irq);
mie.set_field("UTIE", cfg.enable_interrupt & cfg.enable_timer_irq);
regs.push_back(mie);
end
endfunction
@ -136,8 +133,8 @@ class riscv_privileged_common_seq extends uvm_sequence;
sie.set_field("SEIE", cfg.enable_interrupt);
sie.set_field("USIE", cfg.enable_interrupt);
sie.set_field("SSIE", cfg.enable_interrupt);
sie.set_field("STIE", 1'b0);
sie.set_field("UTIE", 1'b0);
sie.set_field("STIE", cfg.enable_interrupt & cfg.enable_timer_irq);
sie.set_field("UTIE", cfg.enable_interrupt & cfg.enable_timer_irq);
regs.push_back(sie);
end
endfunction
@ -160,7 +157,7 @@ class riscv_privileged_common_seq extends uvm_sequence;
end
uie.set_field("UEIE", cfg.enable_interrupt);
uie.set_field("USIE", cfg.enable_interrupt);
uie.set_field("UTIE", 1'b0);
uie.set_field("UTIE", cfg.enable_interrupt & cfg.enable_timer_irq);
regs.push_back(uie);
end
endfunction

View file

@ -0,0 +1,19 @@
# riscOVPsim configuration file converted from YAML
--variant RV64I
--override riscvOVPsim/cpu/add_Extensions=MC
--override riscvOVPsim/cpu/misa_MXL=2
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
--override riscvOVPsim/cpu/unaligned=T
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
--override riscvOVPsim/cpu/user_version=2.3
--override riscvOVPsim/cpu/priv_version=1.11
--override riscvOVPsim/cpu/mvendorid=0
--override riscvOVPsim/cpu/marchid=0
--override riscvOVPsim/cpu/mimpid=0
--override riscvOVPsim/cpu/mhartid=0
--override riscvOVPsim/cpu/cycle_undefined=F
--override riscvOVPsim/cpu/instret_undefined=F
--override riscvOVPsim/cpu/time_undefined=T
--override riscvOVPsim/cpu/reset_address=0x80000000
--override riscvOVPsim/cpu/simulateexceptions=T

View file

@ -0,0 +1,104 @@
/*
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
parameter int XLEN = 64;
// Parameter for SATP mode, set to BARE if address translation is not supported
parameter satp_mode_t SATP_MODE = BARE;
// Supported Privileged mode
privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE};
// Unsupported instructions
riscv_instr_name_t unsupported_instr[];
// ISA supported by the processor
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C};
// Interrupt mode support
mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
int max_interrupt_vector_num = 16;
// Debug mode support
bit support_debug_mode = 0;
// Support delegate trap to user mode
bit support_umode_trap = 0;
// Support sfence.vma instruction
bit support_sfence = 0;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
`ifdef DSIM
privileged_reg_t implemented_csr[] = {
`else
parameter privileged_reg_t implemented_csr[] = {
`endif
// Machine mode mode CSR
MVENDORID, // Vendor ID
MARCHID, // Architecture ID
MIMPID, // Implementation ID
MHARTID, // Hardware thread ID
MSTATUS, // Machine status
MISA, // ISA and extensions
MIE, // Machine interrupt-enable register
MTVEC, // Machine trap-handler base address
MCOUNTEREN, // Machine counter enable
MSCRATCH, // Scratch register for machine trap handlers
MEPC, // Machine exception program counter
MCAUSE, // Machine trap cause
MTVAL, // Machine bad address or instruction
MIP // Machine interrupt pending
};
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
`ifdef DSIM
interrupt_cause_t implemented_interrupt[] = {
`else
parameter interrupt_cause_t implemented_interrupt[] = {
`endif
M_SOFTWARE_INTR,
M_TIMER_INTR,
M_EXTERNAL_INTR
};
`ifdef DSIM
exception_cause_t implemented_exception[] = {
`else
parameter exception_cause_t implemented_exception[] = {
`endif
INSTRUCTION_ADDRESS_MISALIGNED,
INSTRUCTION_ACCESS_FAULT,
ILLEGAL_INSTRUCTION,
BREAKPOINT,
LOAD_ADDRESS_MISALIGNED,
LOAD_ACCESS_FAULT,
ECALL_MMODE
};

View file

@ -0,0 +1,64 @@
# Copyright Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ================================================================================
# Regression test list format
# --------------------------------------------------------------------------------
# test : Assembly test name
# description : Description of this test
# gen_opts : Instruction generator options
# iterations : Number of iterations of this test
# no_iss : Enable/disable ISS simulator (Optional)
# gen_test : Test name used by the instruction generator
# rtl_test : RTL simulation test name
# cmp_opts : Compile options passed to the instruction generator
# sim_opts : Simulation options passed to the instruction generator
# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional)
# compare_opts : Options for the RTL & ISS trace comparison
# gcc_opts : gcc compile options
# --------------------------------------------------------------------------------
- test: riscv_rand_test
description: >
Random test with all useful knobs
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+illegal_instr_ratio=5
+hint_instr_ratio=5
+stream_name_0=riscv_load_store_rand_instr_stream
+stream_freq_0=4
+stream_name_1=riscv_loop_instr
+stream_freq_1=4
+stream_name_2=riscv_hazard_instr_stream
+stream_freq_2=4
+stream_name_3=riscv_load_store_hazard_instr_stream
+stream_freq_3=4
+stream_name_4=riscv_mem_region_stress_test
+stream_freq_4=4
+stream_name_5=riscv_jal_instr
+stream_freq_5=4
+dist_control_mode=1
+dist_shift=10
+dist_arithmetic=10
+dist_logical=10
+dist_compare=10
+dist_branch=10
+dist_synch=10
+dist_csr=10
iterations: 1
gcc_opts: >
-mno-strict-align
gen_test: riscv_ml_test
rtl_test: core_base_test

View file

@ -1,12 +1,10 @@
# riscOVPsim configuration file converted from YAML
--variant RVB32I
--variant RV32I
--override riscvOVPsim/cpu/misa_MXL=1
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
--override riscvOVPsim/cpu/unaligned=T
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
--override riscvOVPsim/cpu/mtvec_is_ro=T
--override riscvOVPsim/cpu/mtvec=0x80000081 # 2147483777
--override riscvOVPsim/cpu/user_version=2.3
--override riscvOVPsim/cpu/priv_version=1.11
--override riscvOVPsim/cpu/mvendorid=0
@ -16,6 +14,5 @@
--override riscvOVPsim/cpu/cycle_undefined=F
--override riscvOVPsim/cpu/instret_undefined=F
--override riscvOVPsim/cpu/time_undefined=T
--override riscvOVPsim/cpu/nmi_address=0x800000fc # 2147483900
--override riscvOVPsim/cpu/reset_address=0x80000000
--override riscvOVPsim/cpu/reset_address=0x80000000
--override riscvOVPsim/cpu/simulateexceptions=T

View file

@ -1,13 +1,11 @@
# riscOVPsim configuration file converted from YAML
--variant RVB32I
--variant RV32I
--override riscvOVPsim/cpu/add_Extensions=MC
--override riscvOVPsim/cpu/misa_MXL=1
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
--override riscvOVPsim/cpu/unaligned=T
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
--override riscvOVPsim/cpu/mtvec_is_ro=T
--override riscvOVPsim/cpu/mtvec=0x80000081 # 2147483777
--override riscvOVPsim/cpu/user_version=2.3
--override riscvOVPsim/cpu/priv_version=1.11
--override riscvOVPsim/cpu/mvendorid=0
@ -17,6 +15,5 @@
--override riscvOVPsim/cpu/cycle_undefined=F
--override riscvOVPsim/cpu/instret_undefined=F
--override riscvOVPsim/cpu/time_undefined=T
--override riscvOVPsim/cpu/nmi_address=0x800000fc # 2147483900
--override riscvOVPsim/cpu/reset_address=0x80000000
--override riscvOVPsim/cpu/reset_address=0x80000000
--override riscvOVPsim/cpu/simulateexceptions=T

View file

@ -90,8 +90,6 @@
gen_test: riscv_rand_instr_test
gen_opts: >
+disable_compressed_instr=1
gcc_opts: >
-march=rv32im
rtl_test: core_base_test
- test: riscv_rand_jump_test

View file

@ -0,0 +1,18 @@
# riscOVPsim configuration file converted from YAML
--variant RV64GC
--override riscvOVPsim/cpu/misa_MXL=2
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
--override riscvOVPsim/cpu/unaligned=T
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
--override riscvOVPsim/cpu/user_version=2.3
--override riscvOVPsim/cpu/priv_version=1.11
--override riscvOVPsim/cpu/mvendorid=0
--override riscvOVPsim/cpu/marchid=0
--override riscvOVPsim/cpu/mimpid=0
--override riscvOVPsim/cpu/mhartid=0
--override riscvOVPsim/cpu/cycle_undefined=F
--override riscvOVPsim/cpu/instret_undefined=F
--override riscvOVPsim/cpu/time_undefined=T
--override riscvOVPsim/cpu/reset_address=0x80000000
--override riscvOVPsim/cpu/simulateexceptions=T

View file

@ -90,7 +90,8 @@
gen_opts: >
+instr_cnt=5000
+num_of_sub_program=5
+directed_instr_1=riscv_jal_instr,20
+stream_name_0=riscv_jal_instr
+stream_freq_0=10
rtl_test: core_base_test
- test: riscv_loop_test
@ -111,8 +112,6 @@
gen_test: riscv_rand_instr_test
gen_opts: >
+disable_compressed_instr=1
gcc_opts: >
-march=rv64im
rtl_test: core_base_test
- test: riscv_rand_jump_test

View file

@ -1,13 +1,11 @@
# riscOVPsim configuration file converted from YAML
--variant RVB64I
--variant RV64I
--override riscvOVPsim/cpu/add_Extensions=MC
--override riscvOVPsim/cpu/misa_MXL=2
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
--override riscvOVPsim/cpu/unaligned=T
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
--override riscvOVPsim/cpu/mtvec_is_ro=T
--override riscvOVPsim/cpu/mtvec=0x80000081 # 2147483777
--override riscvOVPsim/cpu/user_version=2.3
--override riscvOVPsim/cpu/priv_version=1.11
--override riscvOVPsim/cpu/mvendorid=0
@ -17,6 +15,5 @@
--override riscvOVPsim/cpu/cycle_undefined=F
--override riscvOVPsim/cpu/instret_undefined=F
--override riscvOVPsim/cpu/time_undefined=T
--override riscvOVPsim/cpu/nmi_address=0x800000fc # 2147483900
--override riscvOVPsim/cpu/reset_address=0x80000000
--override riscvOVPsim/cpu/reset_address=0x80000000
--override riscvOVPsim/cpu/simulateexceptions=T

View file

@ -91,8 +91,6 @@
gen_test: riscv_rand_instr_test
gen_opts: >
+disable_compressed_instr=1
gcc_opts: >
-march=rv64im
rtl_test: core_base_test
- test: riscv_rand_jump_test

View file

@ -40,3 +40,21 @@ class riscv_rand_instr_test extends riscv_instr_base_test;
endfunction
endclass
class riscv_ml_test extends riscv_instr_base_test;
`uvm_component_utils(riscv_ml_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.no_fence = 0;
cfg.no_ebreak = 0;
cfg.init_privileged_mode = MACHINE_MODE;
cfg.init_privileged_mode.rand_mode(0);
cfg.enable_unaligned_load_store = 1'b1;
`DV_CHECK_RANDOMIZE_FATAL(cfg)
`uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
cfg.sprint()), UVM_LOW)
endfunction
endclass

View file

@ -21,7 +21,7 @@
path_var: OVPSIM_PATH
cmd: >
<path_var>/riscvOVPsim.exe
--controlfile ../riscv-dv/target/<variant>/riscvOVPsim.ic
--controlfile target/<variant>/riscvOVPsim.ic
--objfilenoentry <elf>
--override riscvOVPsim/cpu/PMP_registers=0
--override riscvOVPsim/cpu/simulateexceptions=T