Update google_riscv-dv to a07e0a7 (#203)

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

* Merge pull request #53 from google/flow (taoliug)
* Update README file for the new flow (Tao Liu)
* Merge pull request #52 from google/flow (taoliug)
* Add timeout mechanism to the flow (Tao Liu)
* Merge pull request #51 from google/flow (taoliug)
* Simulation flow update (Tao Liu)
* Merge pull request #50 from udinator/master (taoliug)
* added license for csr_template.yaml (Udi)
* Merge pull request #49 from google/dev (taoliug)
* Update log process script (Tao Liu)
* Merge pull request #48 from google/dev (taoliug)
* Fix illegal instruction issue (Tao Liu)
* Merge pull request #47 from google/dev (taoliug)
* Refactor the simulation flow (Tao Liu)
* Merge pull request #45 from danghai/master (taoliug)
* Add .gitignore to remove untracked files (danghai)
* Fix warning from Questa optmize (danghai)
* Add optimize log file for Questa simulator (danghai)
* New YAML based simulation flow (Tao Liu)
* Merge pull request #40 from scottj97/typos-redone (taoliug)
* Fix typos in comments (Scott Johnson)
* Fix typos/grammar in README (Scott Johnson)
* Merge pull request #43 from udinator/master (taoliug)
* use hex format in YAML description (Udi)
* CSR test description (Udi)
* removed run script (Udi)
* Modified CSR test generation code to adhere to style guidelines.
  (Udi)
* Merge pull request #41 from vandanaprabhu/questa (taoliug)
* CSR Generation Script and YAML template (Udi)
* Prevent Xcelium from attempting to run a simulation during the
  compile step (Scott Johnson)
* Document support for Questa (Scott Johnson)
* Fix simulation-time warnings from Mentor Questa (Scott Johnson)
* Fix compile warnings from Mentor Questa (Scott Johnson)
* Fix warning from Questa compiler (Scott Johnson)
* Fix warning from Questa compiler (Scott Johnson)
* Adding support for using the Questa simulator (Vandana Prabhu)
* Pass proper seed to Cadence Xcelium simulator (Scott Johnson)
* Convert compile commands to functions instead of variables (Scott
  Johnson)
This commit is contained in:
taoliug 2019-08-01 09:53:26 -07:00 committed by udinator
parent 76ac3ef658
commit ba5c63b8d1
25 changed files with 1629 additions and 238 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 112dcc2e669f124dfe48c35a09477603c3ccb180
rev: a07e0a726edf0230314c08d31546eecbed23054b
}
}

4
vendor/google_riscv-dv/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
*.ini
*.bin
out_*/
work/

View file

@ -12,23 +12,254 @@ processor verification. It currently supports the following features:
- Support sub-programs and random program calls
- Support illegal instruction and HINT instruction
- Random forward/backward branch instructions
- Support mix directed instruciton with random instruction stream
- Support co-simulation with multiple ISS : spike, riscv-ovpsim
- Supports mixing directed instructions with random instruction stream
- Supports co-simulation with multiple ISS : spike, riscv-ovpsim
## Getting Started
### Prerequisites
To be able to run the instruction generator, you need to have an RTL simulator
which supports Systemverilog and UVM 1.2. This generator has been verified with
Synopsys VCS and Cadence Incisive/Xcelium simulator. Please make sure the EDA
tool environment is properly setup before running the generator.
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.
### Running the generator
A simple script "run" is provided for you to run a single test or a regression.
Here is the command to run a single test:
```
python3 run.py --test=riscv_arithmetic_basic_test
```
You can specify the simulator by "-simulator" option
```
python3 run.py --test=riscv_arithmetic_basic_test --simulator=irun
python3 run.py --test=riscv_arithmetic_basic_test --simulator=vcs
python3 run.py --test=riscv_arithmetic_basic_test --simulator=questa
```
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
```
python3 run.py
```
You can also run multiple generator jobs in parallel through LSF
```
python3 run.py --lsf_cmd="bsub -Is"
```
Here's a few more examples of the run command:
```
// Get the complete command reference info
python3 run.py --help
// Run a single test 10 times
python3 run.py --test=riscv_page_table_exception_test --iterations=10
// Run a test with a specified seed
python3 run.py --test=riscv_page_table_exception_test --seed=123
// Skip the generation, run ISS simulation with previously generated program
python3 run.py --test=riscv_page_table_exception_test --steps=iss_sim
....
```
## Configuration
### Setup regression test list
[Test list in YAML format](https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml)
```
# test : Assembly test name
# description : Description of this test
# gen_opts : Instruction generator options
# iterations : Number of iterations of this test
# gen_test : Test name used by the instruction generator
# rtl_test : RTL simulation test name
# cmp_opts : Compile options passed to the instruction generator
# sim_opts : Simulation options passed to the instruction generator
# compare_opts : Options for the RTL & ISS trace comparison
- test: 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
```
### Configure the generator to match your processor features
The default configuration of the instruction generator is for RV64IMC 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
```
// 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};
...
```
### Runtime options of the generator
| Option | Description | default |
|----------|:-------------:|:------:|
| num_of_tests | Number of assembly tests to be generated | 1 |
| num_of_sub_program | Number of sub-program in one test | 5 |
| instr_cnt | Instruction count per test | 200 |
| enable_page_table_exception | Enable page table exception | 0 |
| no_ebreak | Disable ebreak instruction | 1 |
| no_wfi | Disable WFI instruction | 1 |
| no_branch_jump | Disable branch/jump instruction | 0 |
| no_load_store | Disable load/store instruction | 0 |
| no_csr_instr | Disable CSR instruction | 0 |
| no_fence | Disable fence instruction | 0 |
| enable_illegal_instruction | Enable illegal instructions | 0 |
| enable_hint_instruction | Enable HINT instruction | 0 |
| boot_mode | m:Machine mode, s:Supervisor mode, u:User mode | m |
| no_directed_instr | Disable directed instruction stream | 0 |
| enable_interrupt | Enable MStatus.MIE, used in interrupt test | 0 |
### 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
```
//+directed_instr_n=instr_sequence_name,frequency(number of insertions per 1000 instructions)
+directed_instr_5=riscv_multi_page_load_store_instr_stream,4
```
## Run ISS(Instruction Set Simulator) simulation
The default ISS is spike. Thanks for the great support from Imperas Software Ltd.,
we have added the support for [riscv-ovpsim](https://github.com/riscv/riscv-ovpsim).
- spike setup
- Follow the [steps](https://github.com/riscv/riscv-isa-sim#build-steps) to build spike
- Make sure RISCV_ENABLE_COMMITLOG is defined in [config.h.in](https://github.com/riscv/riscv-isa-sim/blob/master/config.h.in)
- Set environment variable SPIKE_PATH to the directory of the spike binary
- [riscv-ovpsim](https://github.com/riscv/riscv-ovpsim) setup
- Download the riscv-ovpsim binary
- Set environment variable OVPSIM_PATH to the directory of the ovpsim binary
You can use -iss to run with different ISS.
```
// Run ISS with spike
python3 run.py --test=riscv_page_table_exception_test --iss=spike
// Run ISS with riscv-ovpsim
python3 run.py --test=riscv_rand_instr_test --iss=ovpsim
```
To run with ISS simulation for RV32IMC, you can specify ISA and ABI from command
line like this:
```
// Run a full regression with RV32IMC
python3 run.py --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.
```
python3 run.py --test=riscv_rand_instr_test --iss=spike,ovpsim
```
### Integrate a new ISS
You can add a new entry in [iss.yaml](https://github.com/google/riscv-dv/blob/master/yaml/iss.yaml)
```
- iss: new_iss_name
path_var: ISS_PATH
cmd: >
<path_var>/iss_executable --isa=<variant> -l <elf>
```
Simulate with the new ISS
```
python3 run.py --test=riscv_page_table_exception_test --iss=new_iss_name
```
## End-to-end RTL and ISS co-simulation flow
We have collaborated with LowRISC to apply this flow for [IBEX RISC-V core
verification](https://github.com/lowRISC/ibex/tree/master/dv/uvm). You can use
it as a reference to setup end-to-end co-simulation flow. It's also a good
reference for [customizing the generator](https://github.com/lowRISC/ibex/tree/master/dv/uvm/riscv_dv_extension) without getting impacted by upstream
changes.
We have plan to open-source the end-to-end environment of other advanced RISC-V
processors. Stay tuned!
## Supporting model
Please file an issue under this repository for any bug report / integration
issue / feature request. We are looking forward to knowing your experience of
using this flow and how we can make it better together.
## External contributions
We definitely welcome external contributions. We hope it could be a
collaborative effort to build a strong open source RISC-V processor
verification platform. Free feel to submit your pull request for review.
Please refer to CONTRIBUTING.md for license related questions.
## Future release plan
We have some work in progress which will be part of future releases:
- Privileged CSR test suite.
- Coverage model.
- Debug mode support
### DEPRECATED simulation flow
Note: The flow mentioned below will soon be deprecated. Please switch to new
flow.
A simple script "run" is provided for you to run a single test or a regression.
Here is the command to run a single test:
```
./run -test riscv_instr_base_test
```
@ -37,6 +268,7 @@ You can specify the simulator by "-tool" option
```
./run -test riscv_instr_base_test -tool irun
./run -test riscv_instr_base_test -tool vcs
./run -test riscv_instr_base_test -tool questa
```
The complete test list can be found in testlist. To run a full regression, you
can just specify the test name to "all".
@ -67,7 +299,9 @@ following output:
./out_2018-11-20/asm_tests/riscv_rand_jump_test.0.S
./out_2018-11-20/asm_tests/riscv_sfence_exception_test.0.S
```
Here's a few more examples of the run command:
```
// Run a single test 10 times
./run -test riscv_page_table_exception_test -n 10
@ -85,106 +319,6 @@ Here's a few more examples of the run command:
./run -so -test riscv_mmu_stress_test -n 20
....
```
### Use the generated test in your RTL and ISS simulation
You need to use the RISC-V gcc/llvm compiler to compile the assembly tests to an ELF
file and feed into your TB. We currently don't provide a reference TB for the
co-simulation as it could be quite different based on the processor and ISS
implementation. A reference script "iss_sim" is provided to compile the program
with the RISC-V gcc compiler and simulate with spike.
```
./run -test all; ./iss_sim
```
To run with ISS simulation for RV32IMC, you can specify ISA and ABI from command
line like this:
```
./iss_sim -isa rv32imc -abi ilp32
```
The default ISS is spike. Thanks for the great support from Imperas Software Ltd.,
we have added the support for [riscv-ovpsim](https://github.com/riscv/riscv-ovpsim).
You can use -iss to run with different ISS.
```
./iss_sim -iss spike # Use spike as ISS
./iss_sim -iss ovpsim # Use riscv-ovpsim as ISS
```
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.
```
./iss_sim -iss all # Run ISS simulation with spike + riscv-ovpsim
```
## Configure the generator to match your processor features
The default configuration of the instruction generator is for RV64IMC 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
```
// 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};
...
```
## Runtime options of the generator
## 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.
```
virtual function void apply_directed_instr();
asm_gen.add_directed_instr_stream("my_new_instr_stream_class_name", 10);
endfunction
```
After the new instruction stream is created, you
can refer to test/riscv_instr_test_lib.sv to see how an instruction stream can
be mixed with existing random instruction stream.
## Supporting model
Please file an issue under this repository for any bug report / integration
issue / feature request. We are looking forward to knowing your experience of
using this flow and how we can make it better together.
## External contributions
We definitely welcome external contributions. We hope it could be a
collaborative effort to build a strong open source RISC-V processor
verification platform. Free feel to submit your pull request for review.
Please refer to CONTRIBUTING.md for license related questions.
## Future release plan
We have some work in progress which will be part of future releases:
- Privileged CSR test suite.
- Coverage model.
## Disclaimer
This is not an officially supported Google product.

View file

@ -20,26 +20,14 @@ report_file="$3"
# -----------------------------------------------------------------------------
# Convert spike log to standard instruction trace csv
# -----------------------------------------------------------------------------
# Remove all the init spike boot instructions
# 0xffffffff80000000 is the first user instruction
if [[ "$XLEN" == "32" ]]; then
sed -i '/0xffffffff80000000/,$!d' "$spike_log"
else
sed -i '/core.*0x0000000080000000/,$!d' "$spike_log"
fi
# Remove all instructions after ecall (end of program excecution)
sed -i '/ecall/q' "$spike_log"
# Convert the spike log to riscv_instr_trace.proto format
spike_csv=$(echo "$spike_log" | sed 's/\.log/.csv/g')
python scripts/spike_log_to_trace_csv.py --log $spike_log --csv $spike_csv
python scripts/spike_log_to_trace_csv.py --log $spike_log \
--csv $spike_csv --xlen 64
# -----------------------------------------------------------------------------
# Convert ovpsim log to standard instruction trace csv
# -----------------------------------------------------------------------------
# Remove the header part of ovpsim log
sed -i '/Info 1:/,$!d' "$ovpsim_log"
# Remove all instructions after ecall (end of program excecution)
sed -i '/ecall/q' "$ovpsim_log"
# Convert the spike log to riscv_instr_trace.proto format
ovpsim_csv=$(echo "$ovpsim_log" | sed 's/\.log/.csv/g')
python scripts/ovpsim_log_to_trace_csv.py --log $ovpsim_log --csv $ovpsim_csv
@ -47,4 +35,6 @@ python scripts/ovpsim_log_to_trace_csv.py --log $ovpsim_log --csv $ovpsim_csv
# -----------------------------------------------------------------------------
# Compare the trace log
# -----------------------------------------------------------------------------
python scripts/instr_trace_compare.py $spike_csv $ovpsim_csv "spike" "ovpsim" >> $report_file
python scripts/instr_trace_compare.py $spike_csv $ovpsim_csv \
spike ovpsim >> $report_file
echo >> $report_file

View file

@ -31,7 +31,7 @@ OVPSIM_VARIANT="RV64GC"
# Binary of RISC-V ovpsim ISS
# https://github.com/riscv/riscv-ovpsim
RISCV_OVPSIM="${OVPSIM_PATH}/riscv-ovpsim/bin/Linux64/riscvOVPsim.exe"
RISCV_OVPSIM="${OVPSIM_PATH}/riscvOVPsim.exe"
# Directory of assemble tests
SRC_DIR="./out_${DATE}/asm_tests"

1
vendor/google_riscv-dv/questa_sim.tcl vendored Normal file
View file

@ -0,0 +1 @@
run -all ; quit

View file

@ -28,7 +28,7 @@
DATE=`date +%Y-%m-%d`
# RTL simulator, support vcs and irun
# RTL simulator, supports vcs, irun, and questa
SIMULATOR="vcs"
# random seed
@ -141,25 +141,53 @@ OUT=`realpath ${OUT}`
# Generate compile and simulation commands
if [[ "$SIMULATOR" == "vcs" ]]; then
COMPILE_CMD="vcs -file ./vcs.compile.option.f \
-f ./files.f -full64 \
-l $OUT/compile.log \
-Mdir=$OUT/vcs_simv.csrc \
-o $OUT/vcs_simv ${CMP_OPTS}"
function run_compile {
vcs -file ./vcs.compile.option.f \
-f ./files.f -full64 \
-l $OUT/compile.log \
-Mdir=$OUT/vcs_simv.csrc \
-o $OUT/vcs_simv ${CMP_OPTS}
}
SIM_CMD="$OUT/vcs_simv +vcs+lic+wait +UVM_TESTNAME="
SIM_SEED="+ntb_random_seed="
elif [[ "$SIMULATOR" == "irun" ]]; then
COMPILE_CMD="irun -64bit \
-access +rwc \
-f ./files.f \
-q -sv -uvm \
-vlog_ext +.vh -I. \
-uvmhome CDNS-1.2 \
-l ${OUT}/compile.log ${CMP_OPTS}"
function run_compile {
irun -64bit \
-access +rwc \
-f ./files.f \
-q -sv -uvm \
-vlog_ext +.vh -I. \
-uvmhome CDNS-1.2 \
-elaborate \
-l ${OUT}/compile.log ${CMP_OPTS}
}
SIM_CMD="irun -R +UVM_TESTNAME="
SIM_SEED="-svseed "
elif [[ "$SIMULATOR" == "questa" ]]; then
#Questa requires mapping libraries to compile correctly
function run_compile {
vmap mtiUvm $QUESTA_HOME/questasim/uvm-1.2
vlog -64 \
-access=rwc \
-f ./files.f \
-sv \
-mfcu -cuname design_cuname \
+define+UVM_REGEX_NO_DPI \
-writetoplevels ${OUT}/top.list \
-l ${OUT}/compile.log ${CMP_OPTS}
vopt -64 -debug \
+designfile -f ${OUT}/top.list \
-l ${OUT}/optimize.log ${CMP_OPTS} \
-o design_opt
}
SIM_CMD="vsim -64 -c -do questa_sim.tcl design_opt +UVM_TESTNAME="
SIM_SEED="-sv_seed "
else
echo "unsupported simulator $SIMULATOR"
@ -180,9 +208,9 @@ mkdir -p ${OUT}/asm_tests
if [[ $SIM_ONLY == 0 ]]; then
echo "Building RISC-V instruction generator..."
if [[ $VERBOSE == 1 ]]; then
${COMPILE_CMD}
run_compile
else
${COMPILE_CMD} > /dev/null
run_compile > /dev/null
fi
echo "Building RISC-V instruction generator...done"
fi
@ -209,7 +237,7 @@ if [[ ${TEST} == "all" ]]; then
if [[ ${ITERATION} != "0" ]]; then
echo "Running ${TEST} to generate ${ITERATION} tests"
CMD="${SIM_CMD}${TEST} +asm_file_name=${OUT}/asm_tests/${TEST} \
+ntb_random_seed=${SEED} ${TEST_OPTS} ${SIM_OPTS} \
${SIM_SEED}${SEED} ${TEST_OPTS} ${SIM_OPTS} \
-l ${OUT}/sim_${TEST}.log +num_of_tests=${ITERATION}"
((PROGRAM_CNT+=$ITERATION))
echo "${OUT}/sim_${TEST}.log" >> ${LOG_LIST}
@ -262,7 +290,7 @@ if [[ ${TEST} == "all" ]]; then
else
echo "Running test ${TEST} to generate ${NUM_TESTS} tests"
CMD="${SIM_CMD}${TEST} +asm_file_name=${OUT}/asm_tests/${TEST} \
+ntb_random_seed=${SEED} \
${SIM_SEED}${SEED} \
-l ${OUT}/sim_${TEST}.log \
+num_of_tests=${NUM_TESTS} ${SIM_OPTS}"
if [[ $VERBOSE == 1 ]]; then

350
vendor/google_riscv-dv/run.py vendored Normal file
View file

@ -0,0 +1,350 @@
"""
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.
Regression script for RISC-V random instruction generator
"""
import argparse
import os
import subprocess
import re
import sys
from scripts.lib import *
from scripts.spike_log_to_trace_csv import *
from scripts.ovpsim_log_to_trace_csv import *
from scripts.instr_trace_compare import *
def get_generator_cmd(simulator, simulator_yaml):
""" Setup the compile and simulation command for the generator
Args:
simulator : RTL simulator used to run instruction generator
simulator_yaml : RTL simulator configuration file in YAML format
Returns:
compile_cmd : RTL simulator command to compile the instruction generator
sim_cmd : RTL simulator command to run the instruction generator
"""
print("Processing simulator setup file : %s" % simulator_yaml)
yaml_data = read_yaml(simulator_yaml)
# Search for matched simulator
for entry in yaml_data:
if entry['tool'] == simulator:
print ("Found matching simulator: %s" % entry['tool'])
compile_cmd = entry['compile_cmd']
sim_cmd = entry['sim_cmd']
return compile_cmd, sim_cmd
print ("Cannot find RTL simulator %0s" % simulator)
sys.exit(1)
def parse_iss_yaml(iss, iss_yaml, isa):
"""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
Returns:
cmd : ISS run command
"""
print("Processing ISS setup file : %s" % iss_yaml)
yaml_data = read_yaml(iss_yaml)
# Search for matched ISS
for entry in yaml_data:
if entry['iss'] == iss:
print ("Found matching ISS: %s" % entry['iss'])
cmd = entry['cmd'].rstrip()
cmd = re.sub("\<path_var\>", get_env_var(entry['path_var']), cmd)
if iss == "ovpsim":
cmd = re.sub("\<variant\>", isa.upper(), cmd)
else:
cmd = re.sub("\<variant\>", isa, cmd)
return cmd
print ("Cannot find ISS %0s" % iss)
sys.exit(1)
def get_iss_cmd(base_cmd, elf, log):
"""Get the ISS simulation command
Args:
base_cmd : Original command template
elf : ELF file to run ISS simualtion
log : ISS simulation log name
Returns:
cmd : Command for ISS simulation
"""
cmd = re.sub("\<elf\>", elf, base_cmd)
cmd += (" &> %s" % log)
return cmd
def gen(test_list, simulator, simulator_yaml, output_dir, sim_only,
compile_only, lsf_cmd, seed, cwd, cmp_opts, sim_opts, timeout_s, verbose):
"""Run the instruction generator
Args:
test_list : List of assembly programs to be compiled
simulator : RTL simulator used to run instruction generator
simulator_yaml : RTL simulator configuration file in YAML format
output_dir : Output directory of the ELF files
sim_only : Simulation only
compile_only : Compile the generator only
lsf_cmd : LSF command used to run the instruction generator
seed : Seed to the instruction generator
cmp_opts : Compile options for the generator
sim_opts : Simulation options for the generator
timeout_s : Timeout limit in seconds
verbose : Verbose logging
"""
# Setup the compile and simulation command for the generator
compile_cmd = []
sim_cmd = ""
compile_cmd, sim_cmd = get_generator_cmd(simulator, simulator_yaml);
# Compile the instruction generator
if not sim_only:
print ("Building RISC-V instruction generator")
for cmd in compile_cmd:
cmd = re.sub("<out>", os.path.abspath(output_dir), cmd)
cmd = re.sub("<cwd>", cwd, cmd)
cmd = re.sub("<cmp_opts>", cmp_opts, cmd)
if verbose:
print("Compile command: %s" % cmd)
output = run_cmd(cmd)
if verbose:
print(output)
# Run the instruction generator
if not compile_only:
cmd_list = []
sim_cmd = re.sub("<out>", os.path.abspath(output_dir), sim_cmd)
sim_cmd = re.sub("<cwd>", cwd, sim_cmd)
sim_cmd = re.sub("<sim_opts>", sim_opts, sim_cmd)
print ("Running RISC-V instruction generator")
for test in test_list:
if test['iterations'] > 0:
rand_seed = get_seed(seed)
cmd = lsf_cmd + " " + sim_cmd.rstrip() + \
(" +UVM_TESTNAME=%s " % test['gen_test']) + \
(" +num_of_tests=%d " % test['iterations']) + \
(" +asm_file_name=%s/asm_tests/%s " % (output_dir, test['test'])) + \
(" -l %s/sim_%s.log " % (output_dir, test['test']))
cmd = re.sub("<seed>", str(rand_seed), cmd)
if "gen_opts" in test:
cmd += test['gen_opts']
print("Generating %d %s" % (test['iterations'], test['test']))
if lsf_cmd:
cmd_list.append(cmd)
else:
run_cmd(cmd, verbose, timeout_s)
if lsf_cmd:
run_parallel_cmd(cmd_list, verbose, timeout_s)
def gcc_compile(test_list, output_dir, isa, mabi, verbose):
"""Use riscv gcc toolchain to compile the assembly program
Args:
test_list : List of assembly programs to be compiled
output_dir : Output directory of the ELF files
isa : ISA variant passed to GCC
mabi : MABI variant passed to GCC
verbose : Verbose logging
"""
for test in test_list:
for i in range(0, test['iterations']):
prefix = ("%s/asm_tests/%s.%d" % (output_dir, test['test'], i))
asm = prefix + ".S"
elf = prefix + ".o"
binary = prefix + ".bin"
# gcc comilation
cmd = ("%s -march=%s -mabi=%s -static -mcmodel=medany \
-fvisibility=hidden -nostdlib \
-nostartfiles \
-Tscripts/link.ld %s -o %s" % \
(get_env_var("RISCV_GCC") ,isa, mabi, asm, elf))
print("Compiling %s" % asm)
if verbose:
print(cmd)
output = subprocess.check_output(cmd.split())
if verbose:
print(output)
# Convert the ELF to plain binary, used in RTL sim
print ("Converting to %s" % binary)
cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY"), elf, binary))
output = subprocess.check_output(cmd.split())
if verbose:
print(output)
def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s, verbose):
"""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
verbose : Verbose logging
"""
for iss in iss_list.split(","):
log_dir = ("%s/%s_sim" % (output_dir, iss))
base_cmd = parse_iss_yaml(iss, iss_yaml, isa)
print ("%s sim log dir: %s" % (iss, log_dir))
subprocess.run(["mkdir", "-p", log_dir])
for test in test_list:
for i in range(0, test['iterations']):
prefix = ("%s/asm_tests/%s.%d" % (output_dir, test['test'], i))
elf = prefix + ".o"
log = ("%s/%s.%d.log" % (log_dir, test['test'], i))
cmd = get_iss_cmd(base_cmd, elf, log)
print ("Running ISS simulation: %s" % elf)
run_cmd(cmd, 0, timeout_s)
if verbose:
print (cmd)
def iss_cmp(test_list, iss, output_dir, isa, verbose):
"""Compare ISS simulation reult
Args:
test_list : List of assembly programs to be compiled
iss : List of instruction set simulators
output_dir : Output directory of the ELF files
isa : ISA
verbose : Verbose logging
"""
iss_list = iss.split(",")
if len(iss_list) != 2:
return
report = ("%s/iss_regr.log" % output_dir).rstrip()
run_cmd("rm -rf %s" % report)
for test in test_list:
for i in range(0, test['iterations']):
elf = ("%s/asm_tests/%s.%d.o" % (output_dir, test['test'], i))
print("Comparing ISS sim result %s/%s : %s" %
(iss_list[0], iss_list[1], elf))
csv_list = []
run_cmd(("echo 'Test binary: %s' >> %s" % (elf, report)))
for iss in iss_list:
log = ("%s/%s_sim/%s.%d.log" % (output_dir, iss, test['test'], i))
csv = ("%s/%s_sim/%s.%d.csv" % (output_dir, iss, test['test'], i))
csv_list.append(csv)
if iss == "spike":
process_spike_sim_log(log, csv)
elif iss == "ovpsim":
process_ovpsim_sim_log(log, csv)
else:
print("Unsupported ISS" % iss)
sys.exit(1)
compare_trace_csv(csv_list[0], csv_list[1], iss_list[0], iss_list[1], report)
passed_cnt = run_cmd("grep PASSED %s | wc -l" % report).strip()
failed_cnt = run_cmd("grep FAILED %s | wc -l" % report).strip()
summary = ("%s PASSED, %s FAILED" % (passed_cnt, failed_cnt))
print(summary)
run_cmd(("echo %s >> %s" % (summary, report)))
print("ISS regression report is saved to %s" % report)
# Parse input arguments
parser = argparse.ArgumentParser()
parser.add_argument("--o", type=str, default="./out",
help="Output directory name")
parser.add_argument("--testlist", type=str, default="",
help="Regression testlist")
parser.add_argument("--isa", type=str, default="rv64imc",
help="RISC-V ISA subset")
parser.add_argument("--mabi", type=str, default="lp64",
help="mabi used for compilation, lp32 or lp64")
parser.add_argument("--test", type=str, default="all",
help="Test name, 'all' means all tests in the list")
parser.add_argument("--seed", type=int, default=-1,
help="Randomization seed, default -1 means random seed")
parser.add_argument("--iterations", type=int, default=0,
help="Override the iteration count in the test list")
parser.add_argument("--simulator", type=str, default="vcs",
help="Simulator used to run the generator, default VCS")
parser.add_argument("--simulator_yaml", type=str, default="",
help="RTL simulator setting YAML")
parser.add_argument("--iss", type=str, default="spike",
help="RISC-V instruction set simulator: spike, ovpsim")
parser.add_argument("--iss_yaml", type=str, default="",
help="ISS setting YAML")
parser.add_argument("--verbose", type=int, default=0,
help="Verbose logging")
parser.add_argument("--co", type=int, default=0,
help="Compile the generator only")
parser.add_argument("--so", type=int, default=0,
help="Simulate the generator only")
parser.add_argument("--cmp_opts", type=str, default="",
help="Compile options for the generator")
parser.add_argument("--sim_opts", type=str, default="",
help="Simulation options for the generator")
parser.add_argument("--steps", type=str, default="all",
help="Run steps: gen,gcc_compile,iss_sim,iss_cmp")
parser.add_argument("--lsf_cmd", type=str, default="",
help="LSF command. Run in local sequentially if lsf \
command is not specified")
parser.add_argument("--gen_timeout", type=int, default=360,
help="Generator timeout limit in seconds")
parser.add_argument("--iss_timeout", type=int, default=50,
help="ISS sim timeout limit in seconds")
args = parser.parse_args()
cwd = os.path.dirname(os.path.realpath(__file__))
if not args.iss_yaml:
args.iss_yaml = cwd + "/yaml/iss.yaml"
if not args.simulator_yaml:
args.simulator_yaml = cwd + "/yaml/simulator.yaml"
if not args.testlist:
args.testlist = cwd + "/yaml/testlist.yaml"
# Create output directory
subprocess.run(["mkdir", "-p", args.o])
subprocess.run(["mkdir", "-p", ("%s/asm_tests" % args.o)])
# Process regression test list
matched_list = []
process_regression_list(args.testlist, args.test, args.iterations, matched_list)
if len(matched_list) == 0:
sys.exit("Cannot find %s in %s" % (args.test, args.testlist))
# Run instruction generator
if args.steps == "all" or re.match("gen", args.steps):
gen(matched_list, args.simulator, args.simulator_yaml, args.o,
args.so, args.co, args.lsf_cmd, args.seed, cwd,
args.cmp_opts, args.sim_opts, args.gen_timeout, args.verbose)
# Compile the assembly program to ELF, convert to plain binary
if args.steps == "all" or re.match("gcc_compile", args.steps):
gcc_compile(matched_list, args.o, args.isa, args.mabi, args.verbose)
# Run ISS simulation
if args.steps == "all" or re.match("iss_sim", args.steps):
iss_sim(matched_list, args.o, args.iss, args.iss_yaml,
args.isa, args.iss_timeout, args.verbose)
# Compare ISS simulation result
if args.steps == "all" or re.match("iss_cmp", args.steps):
iss_cmp(matched_list, args.iss, args.o, args.isa, args.verbose)

View file

@ -0,0 +1,280 @@
"""
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.
Parse processor-specific CSR description YAML file and generate a CSR test file.
This test code will utilize every CSR instruction, writing values to the CSR
and then using a prediction function to calculate a reference value that will
be written into another register and compared against the value actually stored
in the CSR at this point, allowing for the test to self-check in order to
determine success or failure.
"""
"""
To install the bitstring library:
1) sudo apt-get install python3-bitstring OR
2) pip install bitstring
"""
import sys
import yaml
import argparse
import random
from bitstring import BitArray as bitarray
def get_csr_map(csr_file, xlen):
"""
Parses the YAML file containing CSR descriptions.
Args:
csr_file: The CSR YAML file.
xlen: The current RISC-V ISA bit length.
Returns:
A dictionary contining mappings for each CSR, of the form:
{ csr_name : [csr_val_bitarray, csr_mask_bitarray] }
"""
rv_string = "rv{}".format(str(xlen))
csrs = {}
with open(csr_file, "r") as c:
csr_description = yaml.safe_load(c)
for csr_dict in csr_description:
csr_name = csr_dict.get("csr")
assert(rv_string in csr_dict), "The {} CSR must be configured for rv{}".format(csr_name, str(rv))
csr_value = bitarray(uintbe=0, length=xlen)
csr_mask = bitarray(uintbe=0, length=xlen)
csr_field_list = csr_dict.get(rv_string)
for csr_field_detail_dict in csr_field_list:
field_type = csr_field_detail_dict.get("type")
field_val = csr_field_detail_dict.get("reset_val")
field_msb = csr_field_detail_dict.get("msb")
field_lsb = csr_field_detail_dict.get("lsb")
field_size = field_msb - field_lsb
if field_type != "WPRI":
val_size = field_msb - field_lsb + 1
val_bitarray = bitarray(uint=field_val, length=val_size)
mask_bitarray = bitarray(uint=1, length=1) * val_size
csr_value.overwrite(val_bitarray, xlen - 1 - field_msb)
csr_mask.overwrite(mask_bitarray, xlen - 1 - field_msb)
csrs.update({csr_name : [csr_value, csr_mask]})
return csrs
def get_rs1_val(iteration, xlen):
"""
Calculates and returns the 3 test RS1 values that will be used
to exercise the CSR.
Args:
iteration: Integer between 0 and 2 inclusive, indicates which
test value to return.
xlen: The currnet RISC-V ISA bit length.
Returns:
A bitarray encoding the value that will be written to the CSR to test it.
Will be one of 3 values:
1) 0xa5a5...
2) 0x5a5a...
3) A randomly generated number
"""
if iteration == 0:
return bitarray(hex=f"0x{'a5'*int(xlen/8)}")
elif iteration == 1:
return bitarray(hex=f"0x{'5a'*int(xlen/8)}")
elif iteration == 2:
val = bitarray(uint=0, length=xlen)
# Must randomize all 32 bits, due to randomization library limitations
for i in range(32):
bit = random.randint(0, 1)
val.set(bit, i)
return val
def csr_write(val, csr_val, csr_mask):
"""
Performs a CSR write.
Args:
val: A bitarray containing the value to be written.
csr_val: A bitarray containing the current CSR value.
csr_mask: A bitarray containing the CSR's mask.
"""
if val.len != csr_mask.len:
csr_val.overwrite(val & csr_mask, 0)
"""
CSR Read:
Reads the given CSR, after applying the bitmask
"""
def csr_read(csr_val, csr_mask):
"""
Performs a CSR read.
Args:
csr_val: A bitarray containing the current CSR value.
csr_mask: A bitarray containing the CSR's mask.
Returns:
A bitarray of the logical AND of csr_val and csr_mask.
"""
return csr_val & csr_mask
def predict_csr_val(csr_op, rs1_val, csr_val, csr_mask):
"""
Predicts the CSR reference value, based on the current CSR operation.
Args:
csr_op: A string of the CSR operation being performed.
rs1_val: A bitarray containing the value to be written to the CSR.
csr_val: A bitarray containing the current value of the CSR.
csr_mask: A bitarray containing the CSR's mask.
Returns:
A hexadecimal string of the predicted CSR value.
"""
prediction = None
# create a zero bitarray to zero extend immediates
zero = bitarray(uint=0, length=csr_val.len - 5)
if csr_op == 'csrrw':
prediction = csr_read(csr_val, csr_mask)
csr_write(rs1_val, csr_val, csr_mask)
elif csr_op == 'csrrs':
prediction = csr_read(csr_val, csr_mask)
csr_write(rs1_val | prediction, csr_val, csr_mask)
elif csr_op == 'csrrc':
prediction = csr_read(csr_val, csr_mask)
csr_write((~rs1_val) & prediction, csr_val, csr_mask)
elif csr_op == 'csrrwi':
prediction = csr_read(csr_val, csr_mask)
zero.append(rs1_val[-5:])
csr_write(zero, csr_val, csr_mask)
elif csr_op == 'csrrsi':
prediction = csr_read(csr_val, csr_mask)
zero.append(rs1_val[-5:])
csr_write(zero | prediction, csr_val, csr_mask)
elif csr_op == 'csrrci':
prediction = csr_read(csr_val, csr_mask)
zero.append(rs1_val[-5:])
csr_write((~zero) & prediction, csr_val, csr_mask)
return f"0x{prediction.hex}"
def gen_csr_test_fail(test_file):
"""
Generates code to handle a test failure.
This code consists of writing 1 to the GP register in an infinite loop.
The testbench will poll this register at the end of the test to detect failure.
Args:
The file containing the generated assembly test code.
"""
test_file.write(f"csr_fail:\n")
test_file.write(f"\tli gp, 1\n")
test_file.write(f"\tj csr_fail\n")
def gen_csr_test_pass(test_file):
"""
Generates code to handle test success.
This code consists of writing 2 to the GP register in an infinite loop.
The testbench will poll this register at the end of the test to detect success.
Args:
The file containing the generated assembly test code.
"""
test_file.write(f"csr_pass:\n")
test_file.write(f"\tli gp, 1\n")
test_file.write(f"\tj csr_pass\n")
def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out):
"""
Uses the information in the map produced by get_csr_map() to generate
test CSR instructions operating on the generated random values.
Args:
csr_map: The dictionary containing CSR mappings generated by get_csr_map()
csr_instructions: A list of all supported CSR instructions in string form.
xlen: The RISC-V ISA bit length.
iterations: Indicates how many randomized test files will be generated.
out: A string containing the directory path that the tests will be generated in.
Returns:
No explicit return value, but will write the randomized assembly test code
to the specified number of files.
"""
for i in range(iterations):
# pick two GPRs at random to act as source and destination registers
# for CSR operations
source_reg, dest_reg = [f"x{i}" for i in random.sample(range(5, 15), 2)]
csr_list = list(csr_map.keys())
with open(f"{out}/riscv_csr_test.{i}.S", "w") as csr_test_file:
csr_test_file.write(f"csr_test:\n")
for csr in csr_list:
last_csr = csr
csr_val, csr_mask = csr_map.get(csr)
for op in csr_instructions:
for i in range(3):
# hex string
rand_rs1_val = get_rs1_val(i, xlen)
# I type CSR instruction
first_li = ""
if op[-1] == "i":
imm = rand_rs1_val[-5:]
csr_inst = f"\t{op} {dest_reg}, {csr}, 0b{imm.bin}\n"
else:
first_li = f"\tli {source_reg}, 0x{rand_rs1_val.hex}\n"
csr_inst = f"\t{op} {dest_reg}, {csr}, {source_reg}\n"
predict_li = f"\tli {source_reg}, {predict_csr_val(op, rand_rs1_val, csr_val, csr_mask)}\n"
branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n"
csr_test_file.write(first_li)
csr_test_file.write(csr_inst)
csr_test_file.write(predict_li)
csr_test_file.write(branch_check)
"""
We must hardcode in one final CSR check, as the value that has last
been written to the CSR has not been tested.
"""
if csr == csr_list[-1] and op == csr_instructions[-1] and i == 2:
final_csr_read = f"\tcsrr {dest_reg}, {csr_list[-1]}\n"
csrrs_read_mask = bitarray(uint=0, length=xlen)
final_li = f"\tli {source_reg}, {predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_mask)}\n"
final_branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n"
csr_test_file.write(final_csr_read)
csr_test_file.write(final_li)
csr_test_file.write(final_branch_check)
gen_csr_test_pass(csr_test_file)
gen_csr_test_fail(csr_test_file)
"""
Define command line arguments.
"""
parser = argparse.ArgumentParser()
parser.add_argument("--csr_file", type=str, help="The YAML file contating descriptions of all processor supported CSRs")
parser.add_argument("--xlen", type=int, default=32, help="Specify the ISA width, e.g. 32 or 64 or 128")
parser.add_argument("--num_test", type=int, default=1, help="Specify how many tests to be generated")
parser.add_argument("--out", type=str, default="./", help="Specify output directory")
args = parser.parse_args()
"""
A list containing all supported CSR instructions.
"""
csr_ops = ['csrrw', 'csrrs', 'csrrc', 'csrrwi', 'csrrsi', 'csrrci']
gen_csr_instr(get_csr_map(args.csr_file, args.xlen), csr_ops, args.xlen, args.num_test, args.out)

View file

@ -15,18 +15,31 @@ limitations under the License.
Compare the instruction trace CSV
"""
import re
import argparse
import re
import sys
from riscv_trace_csv import *
def compare_trace_csv(csv1, csv2, name1, name2,
in_order_mode, coalescing_limit, verbose,
mismatch_print_limit, compare_final_value_only):
def compare_trace_csv(csv1, csv2, name1, name2, log,
in_order_mode = 1,
coalescing_limit = 0,
verbose = 0,
mismatch_print_limit = 5,
compare_final_value_only = 0):
"""Compare two trace CSV file"""
matched_cnt = 0
mismatch_cnt = 0
if log:
fd = open(log, 'a+')
else:
fd = sys.stdout
fd.write("%s : %s\n" % (name1, csv1))
fd.write("%s : %s\n" % (name2, csv2))
with open(csv1, "r") as fd1, open(csv2, "r") as fd2:
instr_trace_1 = []
instr_trace_2 = []
@ -58,21 +71,21 @@ def compare_trace_csv(csv1, csv2, name1, name2,
# Check if the GPR update is the same between trace 1 and 2
if gpr_state_change_2 == 0:
mismatch_cnt += 1
print("Mismatch[%d]:\n[%d] %s : %s" %
(mismatch_cnt, trace_1_index, name1, trace.get_trace_string()))
print ("%0d instructions left in trace %0s" %
(len(instr_trace_1) - trace_1_index + 1, name1))
fd.write("Mismatch[%d]:\n[%d] %s : %s\n" %
(mismatch_cnt, trace_1_index, name1, trace.get_trace_string()))
fd.write("%0d instructions left in trace %0s\n" %
(len(instr_trace_1) - trace_1_index + 1, name1))
elif (trace.rd != instr_trace_2[trace_2_index-1].rd or
trace.rd_val != instr_trace_2[trace_2_index-1].rd_val):
mismatch_cnt += 1
# print first few mismatches
if mismatch_cnt <= mismatch_print_limit:
print("Mismatch[%d]:\n%s[%d] : %s" %
(mismatch_cnt, name1, trace_2_index - 1,
trace.get_trace_string()))
print("%s[%d] : %s" %
(name2, trace_2_index - 1,
instr_trace_2[trace_2_index-1].get_trace_string()))
fd.write("Mismatch[%d]:\n%s[%d] : %s\n" %
(mismatch_cnt, name1, trace_2_index - 1,
trace.get_trace_string()))
fd.write("%s[%d] : %s\n" %
(name2, trace_2_index - 1,
instr_trace_2[trace_2_index-1].get_trace_string()))
else:
matched_cnt += 1
# Break the loop if it reaches the end of trace 2
@ -86,8 +99,8 @@ def compare_trace_csv(csv1, csv2, name1, name2,
instr_trace_2[trace_2_index].rd_val,
gpr_val_2)
if gpr_state_change_2 == 1:
print ("%0d instructions left in trace %0s" %
(len(instr_trace_2) - trace_2_index, name2))
fd.write("%0d instructions left in trace %0s\n" %
(len(instr_trace_2) - trace_2_index, name2))
mismatch_cnt += len(instr_trace_2) - trace_2_index
break
trace_2_index += 1
@ -101,17 +114,17 @@ def compare_trace_csv(csv1, csv2, name1, name2,
parse_gpr_update_from_trace(instr_trace_1, gpr_trace_1)
parse_gpr_update_from_trace(instr_trace_2, gpr_trace_2)
if len(gpr_trace_1) != len(gpr_trace_2):
print("Mismatch: affected GPR count mismtach %s:%d VS %s:%d" %
(name1, len(gpr_trace_1), name2, len(gpr_trace_2)))
fd.write("Mismatch: affected GPR count mismtach %s:%d VS %s:%d\n" %
(name1, len(gpr_trace_1), name2, len(gpr_trace_2)))
mismatch_cnt += 1
if not compare_final_value_only:
for gpr in gpr_trace_1:
coalesced_updates = 0
if (len(gpr_trace_1[gpr]) != len(gpr_trace_2[gpr]) and
coalescing_limit == 0):
print("Mismatch: GPR[%s] trace count mismtach %s:%d VS %s:%d" %
(gpr, name1, len(gpr_trace_1[gpr]),
name2, len(gpr_trace_2[gpr])))
fd.write("Mismatch: GPR[%s] trace count mismtach %s:%d VS %s:%d\n" %
(gpr, name1, len(gpr_trace_1[gpr]),
name2, len(gpr_trace_2[gpr])))
mismatch_cnt += 1
trace_2_index = 0
coalesced_updates = 0
@ -124,45 +137,47 @@ def compare_trace_csv(csv1, csv2, name1, name2,
coalesced_updates = 0
mismatch_cnt += 1
if mismatch_cnt <= mismatch_print_limit:
print("Mismatch:")
print("%s[%d] : %s" % (name1, trace_1_index,
gpr_trace_1[gpr][trace_1_index].get_trace_string()))
print("%s[%d] : %s" % (name2, trace_2_index,
gpr_trace_2[gpr][trace_2_index].get_trace_string()))
fd.write("Mismatch:\n")
fd.write("%s[%d] : %s\n" % (name1, trace_1_index,
gpr_trace_1[gpr][trace_1_index].get_trace_string()))
fd.write("%s[%d] : %s\n" % (name2, trace_2_index,
gpr_trace_2[gpr][trace_2_index].get_trace_string()))
trace_2_index += 1
else:
if verbose:
print("Skipping %s[%d] : %s" %
(name1, trace_1_index,
gpr_trace_1[gpr][trace_1_index].get_trace_string()))
fd.write("Skipping %s[%d] : %s\n" %
(name1, trace_1_index,
gpr_trace_1[gpr][trace_1_index].get_trace_string()))
coalesced_updates += 1
else:
coalesced_updates = 0
matched_cnt += 1
if verbose:
print("Matched [%0d]: %s : %s" %
(trace_1_index, name1,
gpr_trace_1[gpr][trace_1_index].get_trace_string()))
fd.write("Matched [%0d]: %s : %s\n" %
(trace_1_index, name1,
gpr_trace_1[gpr][trace_1_index].get_trace_string()))
trace_2_index += 1
# Check the final value match between the two traces
for gpr in gpr_trace_1:
if (len(gpr_trace_1[gpr]) == 0 or len(gpr_trace_2[gpr]) == 0):
mismatch_cnt += 1
print("Zero GPR[%s] updates observed: %s:%d, %s:%d" % (gpr,
name1, len(gpr_trace_1[gpr]), name2, len(gpr_trace_2[gpr])))
fd.write("Zero GPR[%s] updates observed: %s:%d, %s:%d\n" % (gpr,
name1, len(gpr_trace_1[gpr]), name2, len(gpr_trace_2[gpr])))
elif long(gpr_trace_1[gpr][-1].rd_val, 16) != \
long(gpr_trace_2[gpr][-1].rd_val, 16):
mismatch_cnt += 1
if mismatch_cnt <= mismatch_print_limit:
print("Mismatch final value:")
print("%s : %s" % (name1, gpr_trace_1[gpr][-1].get_trace_string()))
print("%s : %s" % (name2, gpr_trace_2[gpr][-1].get_trace_string()))
fd.write("Mismatch final value:\n")
fd.write("%s : %s\n" % (name1, gpr_trace_1[gpr][-1].get_trace_string()))
fd.write("%s : %s\n" % (name2, gpr_trace_2[gpr][-1].get_trace_string()))
if mismatch_cnt == 0:
compare_result = "PASSED"
else:
compare_result = "FAILED"
print("Compare result[%s]: %d matched, %d mismatch" %
(compare_result, matched_cnt, mismatch_cnt))
fd.write("Compare result[%s]: %d matched, %d mismatch\n\n" %
(compare_result, matched_cnt, mismatch_cnt))
if log:
fd.close()
def parse_gpr_update_from_trace(trace_csv, gpr_trace):
@ -188,34 +203,41 @@ def check_update_gpr(rd, rd_val, gpr):
return gpr_state_change
# Parse input arguments
parser = argparse.ArgumentParser()
parser.add_argument("csv_file_1", type=str, help="Instruction trace 1 CSV")
parser.add_argument("csv_file_2", type=str, help="Instruction trace 2 CSV")
parser.add_argument("csv_name_1", type=str, help="Instruction trace 1 name")
parser.add_argument("csv_name_2", type=str, help="Instruction trace 2 name")
# optional arguments
parser.add_argument("--in_order_mode", type=int, default=1,
help="In order comparison mode")
parser.add_argument("--gpr_update_coalescing_limit", type=int, default=1,
help="Allow the core to merge multiple updates to the \
same GPR into one. This option only applies to \
trace 2")
parser.add_argument("--mismatch_print_limit", type=int, default=5,
help="Max number of mismatches printed")
parser.add_argument("--verbose", type=int, default=0,
help="Verbose logging")
parser.add_argument("--compare_final_value_only", type=int, default=0,
help="Only compare the final value of the GPR")
def main():
# Parse input arguments
parser = argparse.ArgumentParser()
parser.add_argument("csv_file_1", type=str, help="Instruction trace 1 CSV")
parser.add_argument("csv_file_2", type=str, help="Instruction trace 2 CSV")
parser.add_argument("csv_name_1", type=str, help="Instruction trace 1 name")
parser.add_argument("csv_name_2", type=str, help="Instruction trace 2 name")
# optional arguments
parser.add_argument("--log", type=str, default="",
help="Log file")
parser.add_argument("--in_order_mode", type=int, default=1,
help="In order comparison mode")
parser.add_argument("--gpr_update_coalescing_limit", type=int, default=1,
help="Allow the core to merge multiple updates to the \
same GPR into one. This option only applies to \
trace 2")
parser.add_argument("--mismatch_print_limit", type=int, default=5,
help="Max number of mismatches printed")
parser.add_argument("--verbose", type=int, default=0,
help="Verbose logging")
parser.add_argument("--compare_final_value_only", type=int, default=0,
help="Only compare the final value of the GPR")
args = parser.parse_args()
args = parser.parse_args()
if args.compare_final_value_only:
args.in_order_mode = 0
if args.compare_final_value_only:
args.in_order_mode = 0
# Compare trace CSV
compare_trace_csv(args.csv_file_1, args.csv_file_2,
args.csv_name_1, args.csv_name_2,
args.in_order_mode, args.gpr_update_coalescing_limit,
args.verbose, args.mismatch_print_limit,
args.compare_final_value_only)
# Compare trace CSV
compare_trace_csv(args.csv_file_1, args.csv_file_2,
args.csv_name_1, args.csv_name_2, args.log,
args.in_order_mode, args.gpr_update_coalescing_limit,
args.verbose, args.mismatch_print_limit,
args.compare_final_value_only)
if __name__ == "__main__":
main()

157
vendor/google_riscv-dv/scripts/lib.py vendored Normal file
View file

@ -0,0 +1,157 @@
"""
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.
Parse the regression testlist in YAML format
"""
import os
import random
import sys
import subprocess
import time
import yaml
def read_yaml(yaml_file):
""" Read YAML file to a dictionary
Args:
yaml_file : YAML file
Returns:
yaml_data : data read from YAML in dictionary format
"""
with open(yaml_file, "r") as f:
try:
yaml_data = yaml.safe_load(f)
except yaml.YAMLError as exc:
print(exc)
sys.exit(1)
return yaml_data
def get_env_var(var):
"""Get the value of environment variable
Args:
var : Name of the environment variable
Returns:
val : Value of the environment variable
"""
try:
val = os.environ[var]
except KeyError:
print ("Please set the environment variable %0s" % var)
sys.exit(1)
return val
def get_seed(seed):
"""Get the seed to run the generator
Args:
seed : input seed
Returns:
seed to run instruction generator
"""
if seed >= 0:
return seed
else:
return random.getrandbits(32)
def run_cmd(cmd, verbose = 0, timeout_s = 999):
"""Run a command and return output
Args:
cmd : shell command to run
Returns:
command output
"""
try:
ps = subprocess.Popen(cmd,
shell=True,
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as exc:
print(ps.communicate()[0])
sys.exit(1)
try:
output = ps.communicate(timeout = timeout_s)[0]
except subprocess.TimeoutExpired:
print("Timeout[%ds]: %s" % (timeout_s, cmd))
output = ""
ps.kill()
if verbose:
print(output)
return output
def run_parallel_cmd(cmd_list, verbose = 0, timeout_s = 999):
"""Run a list of commands in parallel
Args:
cmd_list: command list
Returns:
command output
"""
children = []
for cmd in cmd_list:
ps = subprocess.Popen(cmd,
shell=True,
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
children.append(ps)
for i in range(len(children)):
print("Command progress: %d/%d" % (i, len(children)))
if verbose:
print("Waiting for command: %s" % cmd_list[i])
try:
output = children[i].communicate(timeout = timeout_s)[0]
except subprocess.TimeoutExpired:
print("Timeout[%ds]: %s" % (timeout_s, cmd))
children[i].kill()
# Restore stty setting otherwise the terminal may go crazy
os.system("stty sane")
if verbose:
print(output)
def process_regression_list(testlist, test, iterations, matched_list):
""" Get the matched tests from the regression test list
Args:
testlist : Regression test list
test : Test to run, "all" means all tests in the list
iterations : Number of iterations for each test
Returns:
matched_list : A list of matched tests
"""
print("Processing regression test list : %s, test: %s" % (testlist, test))
yaml_data = read_yaml(testlist)
for entry in yaml_data:
if (entry['test'] == test) or (test == "all"):
if iterations > 0:
entry['iterations'] = iterations
if entry['iterations'] > 0:
print ("Found matched tests: %s, iterations:%0d" %
(entry['test'], entry['iterations']))
matched_list.append(entry)

View file

@ -16,6 +16,7 @@ limitations under the License.
Convert ovpsim sim log to standard riscv instruction trace format
"""
import re
import os
import argparse
from riscv_trace_csv import *
@ -32,6 +33,13 @@ def process_ovpsim_sim_log(ovpsim_log, csv):
trace_bin = ""
trace_addr = ""
# Remove the header part of ovpsim log
cmd = ("sed -i '/Info 1:/,$!d' %s" % ovpsim_log)
os.system(cmd)
# Remove all instructions after ecall (end of program excecution)
cmd = ("sed -i '/ecall/q' %s" % ovpsim_log)
os.system(cmd)
with open(ovpsim_log, "r") as f, open(csv, "w") as csv_fd:
trace_csv = RiscvInstructiontTraceCsv(csv_fd)
trace_csv.start_new_trace()
@ -60,11 +68,18 @@ def process_ovpsim_sim_log(ovpsim_log, csv):
trace_csv.write_trace_entry(rv_instr_trace)
print("Processed instruction count : %d" % instr_cnt)
instr_trace = []
# Parse input arguments
parser = argparse.ArgumentParser()
parser.add_argument("--log", type=str, help="Input ovpsim simulation log")
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
args = parser.parse_args()
# Process ovpsim log
process_ovpsim_sim_log(args.log, args.csv)
def main():
instr_trace = []
# Parse input arguments
parser = argparse.ArgumentParser()
parser.add_argument("--log", type=str, help="Input ovpsim simulation log")
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
args = parser.parse_args()
# Process ovpsim log
process_ovpsim_sim_log(args.log, args.csv)
if __name__ == "__main__":
main()

View file

@ -15,8 +15,13 @@ limitations under the License.
Convert spike sim log to standard riscv instruction trace format
"""
import re
import argparse
import os
import re
import sys
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
from riscv_trace_csv import *
@ -30,6 +35,13 @@ def process_spike_sim_log(spike_log, csv):
instr_cnt = 0
spike_instr = ""
# Remove all the init spike boot instructions
cmd = ("sed -i '/core.*0x0000000000001010/,$!d' %s" % spike_log)
os.system(cmd)
# Remove all instructions after ecall (end of program excecution)
cmd = ("sed -i '/ecall/q' %s" % spike_log)
os.system(cmd)
with open(spike_log, "r") as f, open(csv, "w") as csv_fd:
trace_csv = RiscvInstructiontTraceCsv(csv_fd)
trace_csv.start_new_trace()
@ -55,11 +67,16 @@ def process_spike_sim_log(spike_log, csv):
trace_csv.write_trace_entry(rv_instr_trace)
print("Processed instruction count : %d" % instr_cnt)
instr_trace = []
# Parse input arguments
parser = argparse.ArgumentParser()
parser.add_argument("--log", type=str, help="Input spike simulation log")
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
args = parser.parse_args()
# Process spike log
process_spike_sim_log(args.log, args.csv)
def main():
instr_trace = []
# Parse input arguments
parser = argparse.ArgumentParser()
parser.add_argument("--log", type=str, help="Input spike simulation log")
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
args = parser.parse_args()
# Process spike log
process_spike_sim_log(args.log, args.csv)
if __name__ == "__main__":
main()

View file

@ -33,15 +33,15 @@
`endif
`ifndef DV_CHECK
`define DV_CHECK(T_, MSG_="", SEV_=error, ID_=`gfn) \
if (!(T_)) begin \
`define DV_CHECK(T_, MSG_="", SEV_=error, ID_=`gfn, WITH_C_=) \
if (!(T_ WITH_C_)) begin \
`uvm_``SEV_(ID_, $sformatf("Check failed (%s) %s ", `"T_`", MSG_)); \
end
`endif
`ifndef DV_CHECK_FATAL
`define DV_CHECK_FATAL(T_, MSG_="", ID_=`gfn) \
`DV_CHECK(T_, MSG_, fatal, ID_)
`define DV_CHECK_FATAL(T_, MSG_="", ID_=`gfn, WITH_C_=) \
`DV_CHECK(T_, MSG_, fatal, ID_, WITH_C_)
`endif
// Shorthand for common foo.randomize() + fatal check
@ -59,11 +59,11 @@
// Shorthand for common foo.randomize() with { } + fatal check
`ifndef DV_CHECK_RANDOMIZE_WITH_FATAL
`define DV_CHECK_RANDOMIZE_WITH_FATAL(VAR_, WITH_C_, MSG_="Randomization failed!", ID_=`gfn) \
`DV_CHECK_FATAL(VAR_.randomize() with {WITH_C_}, MSG_, ID_)
`DV_CHECK_FATAL(VAR_.randomize(), MSG_, ID_, with { WITH_C_ })
`endif
// Shorthand for common std::randomize(foo) with { } + fatal check
`ifndef DV_CHECK_STD_RANDOMIZE_WITH_FATAL
`define DV_CHECK_STD_RANDOMIZE_WITH_FATAL(VAR_, WITH_C_,MSG_="Randomization failed!",ID_=`gfn) \
`DV_CHECK_FATAL(std::randomize(VAR_) with {WITH_C_}, MSG_, ID_)
`DV_CHECK_FATAL(std::randomize(VAR_), MSG_, ID_, with { WITH_C_ })
`endif

View file

@ -330,7 +330,7 @@ class riscv_asm_program_gen extends uvm_object;
endfunction
// Setup MISA based on supported extensions
virtual function setup_misa();
virtual function void setup_misa();
bit [XLEN-1:0] misa;
misa[XLEN-1:XLEN-3] = (XLEN == 32) ? 1 :
(XLEN == 64) ? 2 : 3;
@ -829,6 +829,23 @@ class riscv_asm_program_gen extends uvm_object;
directed_instr_stream_ratio[name] = ratio;
endfunction
virtual function void get_directed_instr_stream();
string args, val;
string opts[$];
for (int i=0; i<cfg.max_directed_instr_stream_seq; i++) begin
args = $sformatf("directed_instr_%0d=", i);
if ($value$plusargs({args,"%0s"}, val)) begin
uvm_split_string(val, ",", opts);
if (opts.size() != 2) begin
`uvm_fatal(`gfn, $sformatf(
"Incorrect directed instruction format : %0s, expect: name,ratio", val))
end else begin
add_directed_instr_stream(opts[0], opts[1].atoi());
end
end
end
endfunction
// Generate directed instruction stream based on the ratio setting
virtual function void generate_directed_instr_stream(input string label,
input int unsigned original_instr_cnt,
@ -896,7 +913,7 @@ class riscv_asm_program_gen extends uvm_object;
// Generate the program in the debug ROM
// Processor will fetch instruction from here upon receiving debug request from debug module
virtual function gen_debug_mode_section();
virtual function void gen_debug_mode_section();
string instr[];
if (riscv_instr_pkg::support_debug_mode) begin
instr = {"dret"};

View file

@ -137,6 +137,8 @@ class riscv_illegal_instr extends uvm_object;
(opcode == 7'b1110011) -> (func3 == 3'b100);
(opcode == 7'b0011011) -> (!(func3 inside {3'b000, 3'b001, 3'b101}));
(opcode == 7'b0111011) -> (func3 inside {3'b010, 3'b011});
opcode inside {7'b1100111, 7'b1100011, 7'b0000011, 7'b0100011,
7'b0001111, 7'b1110011, 7'b0011011, 7'b0111011};
} else {
(opcode == 7'b1100111) -> (func3 == 3'b000);
(opcode == 7'b1100011) -> (!(func3 inside {3'b010, 3'b011}));
@ -182,7 +184,7 @@ class riscv_illegal_instr extends uvm_object;
`uvm_object_utils(riscv_illegal_instr)
`uvm_object_new
function init(riscv_instr_gen_config cfg);
function void init(riscv_instr_gen_config cfg);
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

View file

@ -395,7 +395,7 @@ class riscv_instr_base extends uvm_object;
super.new(name);
endfunction
// Convert the instrunction to one-liner print message
// Convert the instruction to one-liner print message
virtual function string convert2string();
return convert2asm();
endfunction

View file

@ -107,6 +107,8 @@ class riscv_instr_gen_config extends uvm_object;
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
// Default reserved registers, only used by special instructions
riscv_reg_t default_reserved_regs[];

View file

@ -131,7 +131,7 @@ class riscv_instr_sequence extends uvm_sequence;
virtual function void post_process_instr();
int i;
int label_idx;
int branch_target[string];
int branch_target[string] = '{default: 0};
// Insert directed instructions, it's randomly mixed with the random instruction stream.
foreach (directed_instr[i]) begin
instr_stream.insert_instr_stream(directed_instr[i].instr_list);

View file

@ -104,7 +104,7 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
// Take SV39 for example: (PTE_SIZE = 8B)
// Table size is 4KB, PTE_SIZE=8B, entry count = 4K/8 = 512
// Level 2: Root table, 2 entries, PTE[0] and PTE[1] is non-leaf PTE, PTE[2] is leaf PTE, all
// other PTEs are invalid, totally 1 page table with 3 PTEs at this level.
// other PTEs are invalid, totalling 1 page table with 3 PTEs at this level.
// Level 1: Two page tables, map to PTE[0] and PTE[1] of the root table.
// Each table has 512 entries, PTE[0], PTE[1] are non-leaf PTE, cover 4MB memory
// space. PTE[2:511] are leaf PTE, cover 510 * 2MB memory space.
@ -113,7 +113,7 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
// In summary, 7(1+2+4) tables are needed for SV39.
// Similarly, 3 (1+2) page tables for SV32, 15 (1 + 2 + 4 + 8) page tables for SV48.
// Note:
// - The number of randomization call is optmized to improve performance
// - The number of randomization call is optimized to improve performance
// - PPN assignment is done at program run time
virtual function void randomize_page_table();
int pte_index;
@ -196,7 +196,7 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
`DV_CHECK_RANDOMIZE_FATAL(exception_cfg)
`DV_CHECK_RANDOMIZE_WITH_FATAL(illegal_pte,
!(xwr inside {NEXT_LEVEL_PAGE, R_W_EXECUTE_PAGE});)
// Wrong privielge mode setting
// Wrong privilege mode setting
if(exception_cfg.allow_privileged_mode_exception) begin
pte.u = ~pte.u;
end

View file

@ -91,7 +91,8 @@ class riscv_rand_instr extends riscv_instr_base;
}
constraint csr_instr_c {
if(cfg.no_csr_instr == 1) {
// TODO: support CSR instruction in other modes
if(cfg.no_csr_instr || (cfg.init_privileged_mode != MACHINE_MODE)) {
category != CSR;
} else {
if (cfg.enable_illegal_csr_instruction) {

View file

@ -0,0 +1,86 @@
# 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 CSR template that should be followed when describing all processor supported CSRs to enable correct generation of directed test sequences
#- csr: CSR_NAME
# description: >
# BRIEF_DESCRIPTION
# privilege_mode: MODE (D/M/S/H/U)
# rv32:
# - MSB_FIELD_NAME:
# - description: >
# BRIEF_DESCRIPTION
# - type: TYPE (WPRI/WLRL/WARL)
# - reset_val: RESET_VAL
# - msb: MSB_POS
# - lsb: LSB_POS
# - ...
# - ...
# - LSB_FIELD_NAME:
# - description: ...
# - type: ...
# - ...
# rv64:
# - MSB_FIELD_NAME:
# - description: >
# BRIEF_DESCRIPTION
# - type: TYPE (WPRI/WLRL/WARL)
# - reset_val: RESET_VAL
# - msb: MSB_POS
# - lsb: LSB_POS
# - ...
# - ...
# - LSB_FIELD_NAME:
# - description: ...
# - type: ...
# - ...
# Example template, using the CSR misa
# Note: assume the processor supports only the RISC-V I/C extensions
- csr: misa
description: >
Machine ISA Register
privilege_mode: M
rv32:
- field_name: MXL
description: >
Encodes native base ISA width
type: WARL
reset_val: 1
msb: 31
lsb: 30
- field_name: Extensions
description: >
Encodes all supported ISA extensions
type: WARL
reset_val: 0x104
msb: 25
lsb: 0
rv64:
- field_name: MXL
description: >
Encodes native base ISA width
type: WARL
reset_val: 2
msb: 63
lsb: 62
- field_name: Extensions
description: >
Encodes all supported ISA extensions
type: WARL
reset_val: 0x104
msb: 25
lsb: 0

28
vendor/google_riscv-dv/yaml/iss.yaml vendored Normal file
View file

@ -0,0 +1,28 @@
# 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.
- iss: spike
path_var: SPIKE_PATH
cmd: >
<path_var>/spike --isa=<variant> -l <elf>
- iss: ovpsim
path_var: OVPSIM_PATH
cmd: >
<path_var>/riscvOVPsim.exe
--variant <variant>
--override riscvOVPsim/cpu/PMP_registers=0
--override riscvOVPsim/cpu/simulateexceptions=T
--trace --tracechange --traceshowicount --program <elf>
--finishafter 500000

View file

@ -0,0 +1,50 @@
# 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.
- tool: vcs
compile_cmd:
- "vcs -file <cwd>/vcs.compile.option.f
-f <cwd>/files.f -full64
-l <out>/compile.log
-Mdir=<out>/vcs_simv.csrc
-o <out>/vcs_simv <cmp_opts>"
sim_cmd: >
<out>/vcs_simv +vcs+lic+wait <sim_opts> +ntb_random_seed=<seed>
- tool: ius
compile_cmd:
- "irun -64bit -access +rwc -f <cwd>/files.f
-q -sv -uvm -vlog_ext +.vh -I.
-uvmhome CDNS-1.2
-elaborate
-l <out>/compile.log <cmp_opts>"
sim_cmd: >
irun -R <sim_opts> -svseed <seed>
- tool: questa
compile_cmd:
- "vmap mtiUvm $QUESTA_HOME/questasim/uvm-1.2"
- "vlog -64
-access=rwc
-f <cwd>/files.f
-sv
-mfcu -cuname design_cuname
+define+UVM_REGEX_NO_DPI
-writetoplevels <out>/top.list
-l <out>/compile.log <cmp_opts>"
- "vopt -64 -debug
+designfile -f <out>/top.list
-o design_opt"
sim_cmd: >
vsim -64 -c -do <cwd>/questa_sim.tcl design_opt <sim_opts> -svseed <seed>

View file

@ -0,0 +1,207 @@
# 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
# gen_test : Test name used by the instruction generator
# rtl_test : RTL simulation test name
# cmp_opts : Compile options passed to the instruction generator
# sim_opts : Simulation options passed to the instruction generator
# compare_opts : Options for the RTL & ISS trace comparison
# ----------------------------------------------------------------------
- test: 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_machine_mode_rand_test
description: >
Machine mode random instruction test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+boot_mode=m
rtl_test: core_base_test
- test: riscv_privileged_mode_rand_test
description: >
Random previliged mode test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
rtl_test: core_base_test
- test: riscv_rand_instr_test
description: >
Random instruction stress test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,4
+directed_instr_1=riscv_loop_instr,4
+directed_instr_2=riscv_hazard_instr_stream,4
+directed_instr_3=riscv_load_store_hazard_instr_stream,4
+directed_instr_4=riscv_cache_line_stress_instr_stream,4
+directed_instr_5=riscv_multi_page_load_store_instr_stream,4
rtl_test: core_base_test
- test: riscv_rand_jump_test
description: >
Jump among large number of sub-programs, stress testing iTLB operations.
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=15000
+num_of_sub_program=20
+directed_instr_0=riscv_load_store_rand_instr_stream,8
rtl_test: core_base_test
- test: riscv_mmu_stress_test
description: >
Test with different patterns of load/store instructions, stress test MMU
operations.
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,40
+directed_instr_1=riscv_load_store_hazard_instr_stream,40
+directed_instr_2=riscv_cache_line_stress_instr_stream,40
+directed_instr_3=riscv_multi_page_load_store_instr_stream,40
rtl_test: core_base_test
- test: riscv_page_table_exception_test
description: >
Test random page table exception handling. An exception handling routine is
designed to fix the page table error and resume execution.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+enable_page_table_exception=1
rtl_test: core_base_test
- test: riscv_no_fence_test
description: >
Random instruction with FENCE disabled, used to test processor pipeline with
less stall/flush operations caused by FENCE instruction.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+no_fence=1
rtl_test: core_base_test
- test: riscv_sfence_exception_test
description: >
Random instruction test with S.FENCE exceptions
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+allow_sfence_exception=1
rtl_test: core_base_test
- test: riscv_illegal_instr_test
description: >
Illegal instruction test, verify the processor can detect illegal
instruction and handle corresponding exception properly. An exception
handling routine is designed to resume execution after illegal
instruction exception.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+enable_illegal_instruction=1
rtl_test: core_base_test
- test: riscv_hint_instr_test
description: >
HINT instruction test, verify the processor can detect HINT instruction
treat it as NOP. No illegal instruction exception is expected
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+enable_hint_instruction=1
rtl_test: core_base_test
- test: riscv_ebreak_test
description: >
Random instruction test with ebreak instruction enabled. Debug mode is not
enabled for this test, processor should raise ebreak exception.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=6000
+no_ebreak=0
rtl_test: core_base_test
- test: riscv_ebreak_debug_mode_test
description: >
Ebreak instruction test with debug mode enabled.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=6000
+no_ebreak=0
rtl_test: core_base_test
sim_opts: >
+enable_debug_seq=1
compare_opts: >
+compare_final_value_only=1
- test: riscv_fast_interrupt_test
description: >
WFI(wait for interrupt) instruction test. If WFI is supported, processor
should halt execution upon decoding WFI instruction and resume execution
by interrupt. Otherwise WFI should be executed as NOP instruction.
Interrupt handling routine is skipped to allow instruction strace comparison
with ISS which is not interrupted during execution.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+skip_trap_handling=1
+no_wfi=0
rtl_test: core_base_test
sim_opts: >
+enable_irq_seq=1
- test: riscv_full_interrupt_test
description: >
Random instruction test with complete interrupt handling
iterations: 2
gen_test: riscv_rand_instr_test
rtl_test: core_base_test
sim_opts: >
+enable_irq_seq=1
compare_opts: >
+compare_final_value_only=1