Update google_riscv-dv to google/riscv-dv@e905e9f (#234)

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

* add pass_val and fail_val into csr test flow for EOT correctness
  checking (Udi)
* Support unaligned load/store (Tao Liu)
* refactored test generation logic (Udi)
* refactored test generation logic (Udi)
* Give error when mutually exclusive between -co, and -so argument
  (dang hai)
* documentation, and small fixes (Udi)
* no_iss bug (Udi)
* no_iss/no_post_compare optional, CSR read_only is now only specified
  at field level granularity (Udi)
* made no_iss optional (Udi)
* rm print (Udi)
* setup_logging call (Udi)
* undo overriding --verbose in run.py, comment cleanup in csr gen
  script (Udi)
* missed verbose arguments (Udi)
* verbose arg (Udi)
* updated csr description, integrated csr test into flow (Udi)
* updated csr description, integrated csr test into flow (Udi)
* Enhance verbose information by logging instead of using print (dang
  hai)
* Report date time for output directory (dang hai)
* Add main entry point for run.py (dang hai)
* Separate command line parser by function (dang hai)
* Skip generating S/U mode program for machine mode test (Tao Liu)
* minor update to README.md (Tao Liu)
* Update the README.md to match command reference from --help (Tao
  Liu)
* Ignore untrack file from python script (dang hai)
* Make questa work for new YAML based regression flow (dang hai)
* Fix typo in README (Tao Liu)
* Fix README google/riscv-dv#54 (Tao Liu)
* changed formatting of generator option table (Udi)
This commit is contained in:
udinator 2019-08-12 16:22:07 -07:00 committed by taoliug
parent 9a231c9ba6
commit 97105f42b1
16 changed files with 569 additions and 297 deletions

View file

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

View file

@ -2,3 +2,4 @@
*.bin
out_*/
work/
*.pyc

View file

@ -15,6 +15,10 @@ processor verification. It currently supports the following features:
- Supports mixing directed instructions with random instruction stream
- Supports co-simulation with multiple ISS : spike, riscv-ovpsim
A CSR test generation script written in Python is also provided, to generate a
directed test suite that stresses all CSR instructions on all of the CSRs that
the core implements.
## Getting Started
### Prerequisites
@ -24,9 +28,26 @@ 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
```
### Running the generator
A simple script "run" is provided for you to run a single test or a regression.
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:
```
python3 run.py --help
```
Here is the command to run a single test:
```
@ -35,9 +56,9 @@ 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
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
```
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
@ -55,36 +76,129 @@ 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
python3 run.py --test riscv_page_table_exception_test --iterations 10
// Run a test with verbose logging
python3 run.py --test riscv_page_table_exception_test --verbose
// Run a test with a specified seed
python3 run.py --test=riscv_page_table_exception_test --seed=123
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
python3 run.py --test riscv_page_table_exception_test --steps iss_sim
// Run the generator only, do not compile and simluation with ISS
python3 run.py --test riscv_page_table_exception_test --steps gen
// Compile the generator only, do not simulate
python3 run.py --test riscv_page_table_exception_test --co
....
```
### Privileged CSR Test Generation
The CSR generation script is located at [scripts/gen_csr_test.py](https://github.com/google/riscv-dv/blob/master/scripts/gen_csr_test.py). The CSR test code that this script generates will execute every CSR instruction on every processor implemented CSR, writing values to the CSR and then using a prediction function to calculate a reference value that will be written into another GPR. The reference value will then be compared to the value actually stored in the CSR to determine whether to jump to the failure condition or continue executing, allowing it to be completely self checking.
To quickly generate a basic CSR test, run the below command:
```
python3 scripts/gen_csr_test.py
```
To create a new processor-specific CSR description YAML file, format it as
detailed below, and then run:
```
python3 scripts/gen_csr_test.py --csr_file PATH_TO_NEW_CSR_DESCRIPTION_FILE
```
If the CSRs are a different XLEN, such as 64-bit or 128-bit, use the `--xlen`
option to change the ISA length used to generate the test.
```
python3 scripts/gen_csr_test.py --xlen 64
```
To input the number of CSR test files that should be generated, use the
`--iterations` option. Say 10 tests should be generated:
```
python3 scripts/gen_csr_test.py --iterations 10
```
To change the output directory that the tests are generated into, use the
`--out` option. Say the tests should be generated into the home directory:
```
python3 scripts/gen_csr_test.py --out ~
```
Any number of the above options can be combined together, and all of them have
default values should they not be specified at runtime.
## Configuration
### Setup CSR description list
This YAML description file of all CSRs is only required for the privileged CSR
test. All other standard tests do not use this description.
[CSR descriptions in YAML
format](https://github.com/google/riscv-dv/blob/master/yaml/csr_template.yaml)
```
- csr: CSR_NAME
description: >
BRIEF_DESCRIPTION
address: 0x###
privilege_mode: MODE (D/M/S/H/U)
rv32:
- MSB_FIELD_NAME:
- description: >
BRIEF_DESCRIPTION
- type: TYPE (WPRI/WLRL/WARL/R)
- reset_val: RESET_VAL
- msb: MSB_POS
- lsb: LSB_POS
- ...
- ...
- LSB_FIELD_NAME:
- description: ...
- type: ...
- ...
rv64:
- MSB_FIELD_NAME:
- description: >
BRIEF_DESCRIPTION
- type: TYPE (WPRI/WLRL/WARL/R)
- reset_val: RESET_VAL
- msb: MSB_POS
- lsb: LSB_POS
- ...
- ...
- LSB_FIELD_NAME:
- description: ...
- type: ...
- ...
```
To specify what ISA width should be generated in the test, simply include the
matching rv32/rv64/rv128 entry and fill in the appropriate CSR field entries.
### 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 : Assembly test name
# description : Description of this test
# gen_opts : Instruction generator options
# iterations : Number of iterations of this test
# no_iss : Enable/disable ISS simulation (Optional)
# gen_test : Test name used by the instruction generator
# rtl_test : RTL simulation test name
# cmp_opts : Compile options passed to the instruction generator
# sim_opts : Simulation options passed to the instruction generator
# no_post_compare : Enable/disable log comparison (Optional)
# compare_opts : Options for the RTL & ISS trace comparison
- test: riscv_arithmetic_basic_test
description: >
@ -102,6 +216,11 @@ python3 run.py --test=riscv_page_table_exception_test --steps=iss_sim
```
Note: To automatically generate CSR tests without having to explicitly run the
script, include `riscv_csr_test` in the testlist as shown in the example YAML
file above.
### Configure the generator to match your processor features
The default configuration of the instruction generator is for RV64IMC RISC-V
@ -133,23 +252,23 @@ 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 |
| 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
@ -163,7 +282,13 @@ it with random instructions
+directed_instr_5=riscv_multi_page_load_store_instr_stream,4
```
## Run ISS(Instruction Set Simulator) simulation
## Compile generated programs with GCC
- Install [riscv-gcc](https://github.com/riscv/riscv-gcc) toolchain
- Set environment variable RISCV_GCC to the directory of the RISC-V gcc
executable. (example: <install_dir>/bin/riscv32-unknown-elf-gcc)
## 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).
@ -181,10 +306,10 @@ You can use -iss to run with different ISS.
```
// Run ISS with spike
python3 run.py --test=riscv_page_table_exception_test --iss=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
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
@ -192,7 +317,7 @@ line like this:
```
// Run a full regression with RV32IMC
python3 run.py --isa=rv32imc --mabi=ilp32
python3 run.py --isa rv32imc --mabi ilp32
```
We have added a flow to run ISS simulation with both spike and riscv-ovpsim,
@ -218,13 +343,13 @@ You can add a new entry in [iss.yaml](https://github.com/google/riscv-dv/blob/ma
Simulate with the new ISS
```
python3 run.py --test=riscv_page_table_exception_test --iss=new_iss_name
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
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. 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.

View file

@ -21,12 +21,16 @@ import os
import subprocess
import re
import sys
import logging
from datetime import date
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 *
LOGGER = logging.getLogger()
def get_generator_cmd(simulator, simulator_yaml):
""" Setup the compile and simulation command for the generator
@ -38,16 +42,16 @@ def get_generator_cmd(simulator, simulator_yaml):
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)
logging.info("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'])
logging.info("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)
logging.error("Cannot find RTL simulator %0s" % simulator)
sys.exit(1)
@ -62,12 +66,12 @@ def parse_iss_yaml(iss, iss_yaml, isa):
Returns:
cmd : ISS run command
"""
print("Processing ISS setup file : %s" % iss_yaml)
logging.info("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'])
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":
@ -75,7 +79,7 @@ def parse_iss_yaml(iss, iss_yaml, isa):
else:
cmd = re.sub("\<variant\>", isa, cmd)
return cmd
print ("Cannot find ISS %0s" % iss)
logging.error("Cannot find ISS %0s" % iss)
sys.exit(1)
@ -95,68 +99,84 @@ def get_iss_cmd(base_cmd, elf, 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):
def gen(test_list, csr_file, end_signature_addr, isa, simulator,
simulator_yaml, output_dir, sim_only, compile_only, lsf_cmd, seed,
cwd, cmp_opts, sim_opts, timeout_s):
"""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
test_list : List of assembly programs to be compiled
csr_file : YAML file containing description of all CSRs
end_signature_addr : Address that tests will write pass/fail signature to at end of test
isa : Processor supported ISA subset
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
"""
# Mutually exclusive options between compile_only and sim_only
if compile_only and sim_only:
logging.error("argument -co is not allowed with argument -so")
# 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")
logging.info("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)
logging.debug("Compile command: %s" % cmd)
logging.debug(run_cmd(cmd))
# 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")
logging.info("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']))
iterations = test['iterations']
if iterations > 0:
"""
If we are running a CSR test, need to call a separate python script
to generate directed CSR test code, located at scripts/gen_csr_test.py.
"""
if test['test'] == 'riscv_csr_test':
cmd = "python3 scripts/gen_csr_test.py" + \
(" --csr_file %s" % csr_file) + \
(" --xlen %s" % re.search(r"(?P<xlen>[0-9]+)", isa).group("xlen")) + \
(" --iterations %i" % iterations) + \
(" --out %s/asm_tests" % output_dir) + \
(" --end_signature_addr %s" % end_signature_addr)
else:
rand_seed = get_seed(seed)
cmd = lsf_cmd + " " + sim_cmd.rstrip() + \
(" +UVM_TESTNAME=%s " % test['gen_test']) + \
(" +num_of_tests=%d " % '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']
logging.info("Generating %d %s" % (iterations, test['test']))
if lsf_cmd:
cmd_list.append(cmd)
else:
run_cmd(cmd, verbose, timeout_s)
run_cmd(cmd, timeout_s)
if lsf_cmd:
run_parallel_cmd(cmd_list, verbose, timeout_s)
run_parallel_cmd(cmd_list, timeout_s)
def gcc_compile(test_list, output_dir, isa, mabi, verbose):
def gcc_compile(test_list, output_dir, isa, mabi):
"""Use riscv gcc toolchain to compile the assembly program
Args:
@ -164,7 +184,6 @@ def gcc_compile(test_list, output_dir, isa, mabi, verbose):
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']):
@ -178,21 +197,18 @@ def gcc_compile(test_list, output_dir, isa, mabi, verbose):
-nostartfiles \
-Tscripts/link.ld %s -o %s" % \
(get_env_var("RISCV_GCC") ,isa, mabi, asm, elf))
print("Compiling %s" % asm)
if verbose:
print(cmd)
logging.info("Compiling %s" % asm)
logging.debug(cmd)
output = subprocess.check_output(cmd.split())
if verbose:
print(output)
logging.debug(output)
# Convert the ELF to plain binary, used in RTL sim
print ("Converting to %s" % binary)
logging.info("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)
logging.debug(output)
def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s, verbose):
def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s):
"""Run ISS simulation with the generated test program
Args:
@ -202,26 +218,27 @@ def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s, verbose):
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))
logging.info("%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)
if 'no_iss' in test and test['no_iss'] == 1:
continue
else:
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)
logging.info("Running ISS simulation: %s" % elf)
run_cmd(cmd, timeout_s)
logging.debug(cmd)
def iss_cmp(test_list, iss, output_dir, isa, verbose):
def iss_cmp(test_list, iss, output_dir, isa):
"""Compare ISS simulation reult
Args:
@ -229,7 +246,6 @@ def iss_cmp(test_list, iss, output_dir, isa, verbose):
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:
@ -239,8 +255,8 @@ def iss_cmp(test_list, iss, output_dir, isa, verbose):
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))
logging.info("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:
@ -252,99 +268,145 @@ def iss_cmp(test_list, iss, output_dir, isa, verbose):
elif iss == "ovpsim":
process_ovpsim_sim_log(log, csv)
else:
print("Unsupported ISS" % iss)
logging.error("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)
logging.info(summary)
run_cmd(("echo %s >> %s" % (summary, report)))
print("ISS regression report is saved to %s" % report)
logging.info("ISS regression report is saved to %s" % report)
# Parse input arguments
parser = argparse.ArgumentParser()
def setup_parser():
"""Create a command line parser.
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")
Returns: The created parser.
"""
# Parse input arguments
parser = argparse.ArgumentParser()
args = parser.parse_args()
cwd = os.path.dirname(os.path.realpath(__file__))
parser.add_argument("--o", type=str,
help="Output directory name")
parser.add_argument("--testlist", type=str, default="",
help="Regression testlist")
parser.add_argument("--csr_yaml", type=str, default="",
help="CSR description file")
parser.add_argument("--end_signature_addr", type=str, default="0",
help="Address that privileged CSR test writes to at EOT")
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("-v", "--verbose", dest="verbose", action="store_true",
help="Verbose logging")
parser.add_argument("--co", dest="co", action="store_true",
help="Compile the generator only")
parser.add_argument("--so", dest="so", action="store_true",
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")
if not args.iss_yaml:
args.iss_yaml = cwd + "/yaml/iss.yaml"
parser.set_defaults(co=False)
parser.set_defaults(so=False)
parser.set_defaults(verbose=False)
if not args.simulator_yaml:
args.simulator_yaml = cwd + "/yaml/simulator.yaml"
return parser
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)])
def setup_logging(verbose):
"""Setup the root logger.
# 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))
Args:
verbose: Verbose logging
"""
if verbose:
logging.basicConfig(format="%(asctime)s %(filename)s:%(lineno)-5s %(levelname)-8s %(message)s",
datefmt='%a, %d %b %Y %H:%M:%S',
level=logging.DEBUG)
else:
logging.basicConfig(format="%(asctime)s %(levelname)-8s %(message)s",
datefmt='%a, %d %b %Y %H:%M:%S',
level=logging.INFO)
# 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)
def main():
"""This is the main entry point."""
# 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)
parser = setup_parser()
args = parser.parse_args()
cwd = os.path.dirname(os.path.realpath(__file__))
setup_logging(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)
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
if args.o is None:
output_dir = "out_" + str(date.today())
else:
output_dir = args.o
subprocess.run(["mkdir", "-p", output_dir])
subprocess.run(["mkdir", "-p", ("%s/asm_tests" % output_dir)])
# 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.csr_yaml, args.end_signature_addr, args.isa,
args.simulator, args.simulator_yaml, output_dir, args.so,
args.co, args.lsf_cmd, args.seed, cwd, args.cmp_opts,
args.sim_opts, args.gen_timeout)
if not args.co:
# Compile the assembly program to ELF, convert to plain binary
if args.steps == "all" or re.match("gcc_compile", args.steps):
gcc_compile(matched_list, output_dir, args.isa, args.mabi)
# 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)
# Compare ISS simulation result
if args.steps == "all" or re.match("iss_cmp", args.steps):
iss_cmp(matched_list, args.iss, output_dir, args.isa)
if __name__ == "__main__":
main()

View file

View file

@ -33,6 +33,12 @@ import argparse
import random
from bitstring import BitArray as bitarray
"""
Defines the test's success/failure values, one of which will be written to
the chosen signature address to indicate the test's result.
"""
PASS_VAL = 1
FAIL_VAL = 0
def get_csr_map(csr_file, xlen):
"""
@ -44,7 +50,7 @@ def get_csr_map(csr_file, xlen):
Returns:
A dictionary contining mappings for each CSR, of the form:
{ csr_name : [csr_val_bitarray, csr_mask_bitarray] }
{ csr_name : [csr_address, csr_val_bitarray, csr_write_mask_bitarray, csr_read_mask_bitarray] }
"""
rv_string = "rv{}".format(str(xlen))
csrs = {}
@ -52,23 +58,28 @@ def get_csr_map(csr_file, xlen):
csr_description = yaml.safe_load(c)
for csr_dict in csr_description:
csr_name = csr_dict.get("csr")
csr_address = csr_dict.get("address")
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_write_mask = []
csr_read_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
field_size = field_msb - field_lsb + 1
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
val_bitarray = bitarray(uint=field_val, length=field_size)
mask_bitarray = bitarray(uint=1, length=1) * field_size
start_pos = xlen - 1 - field_msb
end_pos = xlen - 1 - field_lsb
csr_read_mask.overwrite(mask_bitarray, xlen - 1 - field_msb)
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]})
access = True if field_type == "R" else False
csr_write_mask.append([mask_bitarray, (start_pos, end_pos), access])
csrs.update({csr_name : [csr_address, csr_value, csr_write_mask, csr_read_mask]})
return csrs
@ -102,38 +113,46 @@ def get_rs1_val(iteration, xlen):
return val
def csr_write(val, csr_val, csr_mask):
def csr_write(val, csr_val, csr_write_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.
csr_write_mask: A bitarray containing the CSR's mask.
"""
if val.len != csr_mask.len:
csr_val.overwrite(val & csr_mask, 0)
for bitslice in csr_write_mask:
read_only = bitslice[2]
start_index = bitslice[1][0]
end_index = bitslice[1][1]
length = end_index - start_index + 1
mask_val = bitslice[0]
# only write if not read only
if not read_only:
val_slice = val[start_index:end_index+1]
csr_val.overwrite(mask_val & val_slice, start_index)
"""
CSR Read:
Reads the given CSR, after applying the bitmask
"""
def csr_read(csr_val, csr_mask):
def csr_read(csr_val, csr_read_mask):
"""
Performs a CSR read.
Args:
csr_val: A bitarray containing the current CSR value.
csr_mask: A bitarray containing the CSR's mask.
csr_read_mask: A bitarray containing the CSR's read mask.
Returns:
A bitarray of the logical AND of csr_val and csr_mask.
A bitarray of the logical AND of csr_val and csr_read_mask.
"""
return csr_val & csr_mask
return csr_val & csr_read_mask
def predict_csr_val(csr_op, rs1_val, csr_val, csr_mask):
def predict_csr_val(csr_op, rs1_val, csr_val, csr_write_mask, csr_read_mask):
"""
Predicts the CSR reference value, based on the current CSR operation.
@ -141,7 +160,8 @@ def predict_csr_val(csr_op, rs1_val, csr_val, csr_mask):
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.
csr_write_mask: A bitarray containing the CSR's write mask.
csr_read_mask: A bitarray containing the CSR's read mask
Returns:
A hexadecimal string of the predicted CSR value.
@ -150,58 +170,82 @@ def predict_csr_val(csr_op, rs1_val, csr_val, csr_mask):
# 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)
prediction = csr_read(csr_val, csr_read_mask)
csr_write(rs1_val, csr_val, csr_write_mask)
elif csr_op == 'csrrs':
prediction = csr_read(csr_val, csr_mask)
csr_write(rs1_val | prediction, csr_val, csr_mask)
prediction = csr_read(csr_val, csr_read_mask)
csr_write(rs1_val | prediction, csr_val, csr_write_mask)
elif csr_op == 'csrrc':
prediction = csr_read(csr_val, csr_mask)
csr_write((~rs1_val) & prediction, csr_val, csr_mask)
prediction = csr_read(csr_val, csr_read_mask)
csr_write((~rs1_val) & prediction, csr_val, csr_write_mask)
elif csr_op == 'csrrwi':
prediction = csr_read(csr_val, csr_mask)
prediction = csr_read(csr_val, csr_read_mask)
zero.append(rs1_val[-5:])
csr_write(zero, csr_val, csr_mask)
csr_write(zero, csr_val, csr_write_mask)
elif csr_op == 'csrrsi':
prediction = csr_read(csr_val, csr_mask)
prediction = csr_read(csr_val, csr_read_mask)
zero.append(rs1_val[-5:])
csr_write(zero | prediction, csr_val, csr_mask)
csr_write(zero | prediction, csr_val, csr_write_mask)
elif csr_op == 'csrrci':
prediction = csr_read(csr_val, csr_mask)
prediction = csr_read(csr_val, csr_read_mask)
zero.append(rs1_val[-5:])
csr_write((~zero) & prediction, csr_val, csr_mask)
csr_write((~zero) & prediction, csr_val, csr_write_mask)
return f"0x{prediction.hex}"
def gen_csr_test_fail(test_file):
def gen_setup(test_file):
"""
Generates the setup code for the CSR test.
Args:
test_file: the file containing the generated assembly code.
"""
test_file.write(f".macro init\n")
test_file.write(f".endm\n")
test_file.write(f".section .text.init\n")
test_file.write(f".globl _start\n")
test_file.write(f".option norvc\n")
for i in range(32):
test_file.write(f"j csr_fail\n")
test_file.write(f"_start:\n")
def gen_csr_test_fail(test_file, end_addr):
"""
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: the file containing the generated assembly test code.
end_addr: address that should be written to at end of test
"""
test_file.write(f"csr_fail:\n")
test_file.write(f"\tli gp, 1\n")
test_file.write(f"\tli x1, {FAIL_VAL}\n")
test_file.write(f"\tli x2, {end_addr}\n")
test_file.write(f"\tsw x1, 0(x2)\n")
test_file.write(f"\tj csr_fail\n")
def gen_csr_test_pass(test_file):
def gen_csr_test_pass(test_file, end_addr):
"""
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: the file containing the generated assembly test code.
end_addr: address that should be written to at end of test
"""
test_file.write(f"csr_pass:\n")
test_file.write(f"\tli gp, 1\n")
test_file.write(f"\tli x1, {PASS_VAL}\n")
test_file.write(f"\tli x2, {end_addr}\n")
test_file.write(f"\tsw x1, 0(x2)\n")
test_file.write(f"\tj csr_pass\n")
def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out):
def gen_csr_instr(csr_map, csr_instructions, xlen,
iterations, out, end_signature_addr):
"""
Uses the information in the map produced by get_csr_map() to generate
test CSR instructions operating on the generated random values.
@ -212,6 +256,7 @@ def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out):
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.
end_signature_addr: The address the test should write to upon terminating
Returns:
No explicit return value, but will write the randomized assembly test code
@ -220,13 +265,13 @@ def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out):
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)]
source_reg, dest_reg = [f"x{i}" for i in random.sample(range(1, 16), 2)]
csr_list = list(csr_map.keys())
with open(f"{out}/riscv_csr_test.{i}.S", "w") as csr_test_file:
csr_test_file.write(f"csr_test:\n")
gen_setup(csr_test_file)
for csr in csr_list:
last_csr = csr
csr_val, csr_mask = csr_map.get(csr)
csr_address, csr_val, csr_write_mask, csr_read_mask = csr_map.get(csr)
csr_test_file.write(f"\t# {csr}\n")
for op in csr_instructions:
for i in range(3):
# hex string
@ -235,11 +280,16 @@ def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out):
first_li = ""
if op[-1] == "i":
imm = rand_rs1_val[-5:]
csr_inst = f"\t{op} {dest_reg}, {csr}, 0b{imm.bin}\n"
csr_inst = f"\t{op} {dest_reg}, {csr_address}, 0b{imm.bin}\n"
imm_val = bitarray(uint=0, length=xlen-5)
imm_val.append(imm)
predict_li = (f"\tli {source_reg}, "
f"{predict_csr_val(op, imm_val, csr_val, csr_write_mask, csr_read_mask)}\n")
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"
csr_inst = f"\t{op} {dest_reg}, {csr_address}, {source_reg}\n"
predict_li = (f"\tli {source_reg}, "
f"{predict_csr_val(op, rand_rs1_val, csr_val, csr_write_mask, csr_read_mask)}\n")
branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n"
csr_test_file.write(first_li)
csr_test_file.write(csr_inst)
@ -250,25 +300,32 @@ def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out):
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"
final_csr_read = f"\tcsrr {dest_reg}, {csr_address}\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_li = (f"\tli {source_reg}, "
f"{predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_write_mask, csr_read_mask)}\n")
final_branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n"
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)
gen_csr_test_pass(csr_test_file, end_signature_addr)
gen_csr_test_fail(csr_test_file, end_signature_addr)
"""
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")
parser.add_argument("--csr_file", type=str, default="yaml/csr_template.yaml",
help="The YAML file contating descriptions of all processor supported CSRs")
parser.add_argument("--xlen", type=int, default=32,
help="Specify the ISA width, e.g. 32 or 64 or 128")
parser.add_argument("--iterations", type=int, default=1,
help="Specify how many tests to be generated")
parser.add_argument("--out", type=str, default="./",
help="Specify output directory")
parser.add_argument("--end_signature_addr", type=str, default="0",
help="Address that should be written to at end of this test")
args = parser.parse_args()
@ -277,4 +334,6 @@ 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)
gen_csr_instr(get_csr_map(args.csr_file, args.xlen),
csr_ops, args.xlen, args.iterations, args.out,
args.end_signature_addr)

View file

@ -22,6 +22,7 @@ import sys
import subprocess
import time
import yaml
import logging
def read_yaml(yaml_file):
""" Read YAML file to a dictionary
@ -36,7 +37,7 @@ def read_yaml(yaml_file):
try:
yaml_data = yaml.safe_load(f)
except yaml.YAMLError as exc:
print(exc)
logging.error(exc)
sys.exit(1)
return yaml_data
@ -53,7 +54,7 @@ def get_env_var(var):
try:
val = os.environ[var]
except KeyError:
print ("Please set the environment variable %0s" % var)
logging.warning("Please set the environment variable %0s" % var)
sys.exit(1)
return val
@ -73,7 +74,7 @@ def get_seed(seed):
return random.getrandbits(32)
def run_cmd(cmd, verbose = 0, timeout_s = 999):
def run_cmd(cmd, timeout_s = 999):
"""Run a command and return output
Args:
@ -89,20 +90,19 @@ def run_cmd(cmd, verbose = 0, timeout_s = 999):
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as exc:
print(ps.communicate()[0])
logging.error(ps.communicate()[0])
sys.exit(1)
try:
output = ps.communicate(timeout = timeout_s)[0]
except subprocess.TimeoutExpired:
print("Timeout[%ds]: %s" % (timeout_s, cmd))
logging.error("Timeout[%ds]: %s" % (timeout_s, cmd))
output = ""
ps.kill()
if verbose:
print(output)
logging.debug(output)
return output
def run_parallel_cmd(cmd_list, verbose = 0, timeout_s = 999):
def run_parallel_cmd(cmd_list, timeout_s = 999):
"""Run a list of commands in parallel
Args:
@ -120,18 +120,16 @@ def run_parallel_cmd(cmd_list, verbose = 0, timeout_s = 999):
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])
logging.info("Command progress: %d/%d" % (i, len(children)))
logging.debug("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))
logging.error("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)
logging.debug(output)
def process_regression_list(testlist, test, iterations, matched_list):
@ -145,13 +143,13 @@ def process_regression_list(testlist, test, iterations, matched_list):
Returns:
matched_list : A list of matched tests
"""
print("Processing regression test list : %s, test: %s" % (testlist, test))
logging.info("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']))
logging.info("Found matched tests: %s, iterations:%0d" %
(entry['test'], entry['iterations']))
matched_list.append(entry)

View file

@ -18,6 +18,7 @@ Convert ovpsim sim log to standard riscv instruction trace format
import re
import os
import argparse
import logging
from riscv_trace_csv import *
@ -27,7 +28,7 @@ def process_ovpsim_sim_log(ovpsim_log, csv):
Extract instruction and affected register information from ovpsim simulation
log and save to a list.
"""
print("Processing ovpsim log : %s" % ovpsim_log)
logging.info("Processing ovpsim log : %s" % ovpsim_log)
instr_cnt = 0
trace_instr = ""
trace_bin = ""
@ -66,7 +67,7 @@ def process_ovpsim_sim_log(ovpsim_log, csv):
rv_instr_trace.binary = trace_bin
rv_instr_trace.addr = trace_addr
trace_csv.write_trace_entry(rv_instr_trace)
print("Processed instruction count : %d" % instr_cnt)
logging.info("Processed instruction count : %d" % instr_cnt)
def main():

View file

@ -20,6 +20,7 @@ import argparse
import os
import re
import sys
import logging
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
@ -31,7 +32,7 @@ def process_spike_sim_log(spike_log, csv):
Extract instruction and affected register information from spike simulation
log and save to a list.
"""
print("Processing spike log : %s" % spike_log)
logging.info("Processing spike log : %s" % spike_log)
instr_cnt = 0
spike_instr = ""
@ -65,7 +66,7 @@ def process_spike_sim_log(spike_log, csv):
rv_instr_trace.binary = m.group("bin")
rv_instr_trace.instr_str = spike_instr
trace_csv.write_trace_entry(rv_instr_trace)
print("Processed instruction count : %d" % instr_cnt)
logging.info("Processed instruction count : %d" % instr_cnt)
def main():

View file

@ -199,13 +199,17 @@ class riscv_asm_program_gen extends uvm_object;
virtual function void gen_kernel_sections();
instr_stream.push_back("_kernel_start: .align 12");
// Kernel programs
smode_accessible_umode_program = riscv_instr_sequence::type_id::
create("smode_accessible_umode_program");
if (cfg.init_privileged_mode != MACHINE_MODE) begin
smode_accessible_umode_program = riscv_instr_sequence::type_id::
create("smode_accessible_umode_program");
gen_kernel_program(smode_accessible_umode_program);
end
smode_program = riscv_instr_sequence::type_id::create("smode_program");
gen_kernel_program(smode_accessible_umode_program);
gen_kernel_program(smode_program);
smode_ls_umem_program = riscv_instr_sequence::type_id::create("smode_ls_umem_program");
gen_kernel_program(smode_ls_umem_program);
if (cfg.init_privileged_mode != MACHINE_MODE) begin
smode_ls_umem_program = riscv_instr_sequence::type_id::create("smode_ls_umem_program");
gen_kernel_program(smode_ls_umem_program);
end
// All trap/interrupt handling is in the kernel region
// Trap/interrupt delegation to user mode is not supported now
// Trap handler

View file

@ -79,6 +79,7 @@ class riscv_instr_gen_config extends uvm_object;
bit no_ebreak = 1; // No ebreak instruction
bit no_fence; // No fence instruction
bit no_wfi = 1; // No WFI instruction
bit enable_unaligned_load_store;
bit enable_illegal_instruction;
bit enable_hint_instruction;
int bin_program_instr_cnt = 200;
@ -249,6 +250,7 @@ class riscv_instr_gen_config extends uvm_object;
get_bool_arg_value("+no_directed_instr=", no_directed_instr);
get_bool_arg_value("+no_fence=", no_fence);
get_bool_arg_value("+no_delegation=", no_delegation);
get_bool_arg_value("+enable_unaligned_load_store=", enable_unaligned_load_store);
get_bool_arg_value("+enable_illegal_instruction=", enable_illegal_instruction);
get_bool_arg_value("+enable_hint_instruction=", enable_hint_instruction);
get_bool_arg_value("+force_m_delegation=", force_m_delegation);

View file

@ -121,7 +121,11 @@ class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream;
`DV_CHECK_RANDOMIZE_WITH_FATAL(rand_instr,
solve rs1 before rd;
rs1 == rs1_reg;
instr_name inside {allowed_instr};
if (!cfg.enable_unaligned_load_store) {
instr_name inside {allowed_instr};
} else {
category inside {LOAD, STORE};
}
if(avail_regs.size() > 0) {
rd inside {avail_regs};
}

View file

@ -64,26 +64,28 @@ class riscv_instr_base_test extends uvm_test;
endfunction
function void get_directed_instr_stream_opts();
string instr_name;
int ratio;
string cmd_opts_prefix;
string opts;
string opt[$];
int i = 0;
while(1) begin
cmd_opts_prefix = $sformatf("directed_instr_%0d", i);
if($value$plusargs({cmd_opts_prefix, "=%0s"}, instr_name) &&
$value$plusargs({cmd_opts_prefix, "_ratio=%0d"}, ratio)) begin
asm_gen.add_directed_instr_stream(instr_name, ratio);
if($value$plusargs({cmd_opts_prefix, "=%0s"}, opts)) begin
uvm_split_string(opts, ",", opt);
`DV_CHECK_FATAL(opt.size() == 2)
asm_gen.add_directed_instr_stream(opt[0], opt[1].atoi());
end else begin
break;
end
`uvm_info(`gfn, $sformatf("Got directed instr[%0d] %0s, ratio = %0d/1000",
i, instr_name, ratio), UVM_LOW)
`uvm_info(`gfn, $sformatf("Got directed instr[%0d] %0s, ratio = %0s/1000",
i, opt[0], opt[1]), UVM_LOW)
i++;
end
endfunction
virtual function void apply_directed_instr();
endfunction
task run_phase(uvm_phase phase);

View file

@ -17,12 +17,13 @@
#- csr: CSR_NAME
# description: >
# BRIEF_DESCRIPTION
# address: 0x###
# privilege_mode: MODE (D/M/S/H/U)
# rv32:
# - MSB_FIELD_NAME:
# - description: >
# BRIEF_DESCRIPTION
# - type: TYPE (WPRI/WLRL/WARL)
# - type: TYPE (WPRI/WLRL/WARL/R)
# - reset_val: RESET_VAL
# - msb: MSB_POS
# - lsb: LSB_POS
@ -36,7 +37,7 @@
# - MSB_FIELD_NAME:
# - description: >
# BRIEF_DESCRIPTION
# - type: TYPE (WPRI/WLRL/WARL)
# - type: TYPE (WPRI/WLRL/WARL/R)
# - reset_val: RESET_VAL
# - msb: MSB_POS
# - lsb: LSB_POS
@ -53,6 +54,7 @@
- csr: misa
description: >
Machine ISA Register
address: 0x301
privilege_mode: M
rv32:
- field_name: MXL

View file

@ -36,15 +36,16 @@
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>"
-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"
+designfile -f <out>/top.list
-l <out>/optimize.log <cmp_opts>
-o design_opt"
sim_cmd: >
vsim -64 -c -do <cwd>/questa_sim.tcl design_opt <sim_opts> -svseed <seed>
vsim -64 -c -do <cwd>/questa_sim.tcl design_opt <sim_opts> -sv_seed <seed>

View file

@ -12,19 +12,21 @@
# 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 : 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
# --------------------------------------------------------------------------------
- test: riscv_arithmetic_basic_test
description: >
@ -205,3 +207,11 @@
+enable_irq_seq=1
compare_opts: >
+compare_final_value_only=1
- test: riscv_csr_test
description: >
Test all CSR instructions on all implemented CSR registers
iterations: 1
no_iss: 1
rtl_test: core_ibex_csr_test
no_post_compare: 1