Update google_riscv-dv to google/riscv-dv@a655f34 (#564)

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

* Support running C test (google/riscv-dv#453) (Hai Hoang Dang)
* run.py: Do not compare csv file when specified -debug switch
  (google/riscv-dv#451) (Hai Hoang Dang)
* adjust location of nested interrupt mstatus.mie enable
  (google/riscv-dv#444) (udinator)
* Implement storing the commands that would be executed as a script
  (google/riscv-dv#450) (Hai Hoang Dang)
* Move document from README to docs, add HTML preview for the new doc
  (google/riscv-dv#448) (taoliug)
* Use single HTML format (google/riscv-dv#447) (taoliug)
* Update HTML document (google/riscv-dv#446) (taoliug)
* Add framework for custom extensions (google/riscv-dv#442) (taoliug)

Signed-off-by: Udi <udij@google.com>
This commit is contained in:
udinator 2020-01-23 15:10:14 -08:00 committed by GitHub
parent f95518a46e
commit 3d8089c235
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 445 additions and 627 deletions

View file

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

View file

@ -16,20 +16,9 @@ processor verification. It currently supports the following features:
- Supports mixing directed instructions with random instruction stream
- Debug mode support, with fully randomized debug ROM
- Instruction generation coverage model
- Communication of information to any integrated SV testbench
- Co-simulation with multiple ISS : spike, riscv-ovpsim
A CSR test generation script written in Python is also provided, to generate a
directed test suite that stresses all CSR instructions on all of the CSRs that
the core implements.
## External contributions and collaborations
This repository is still under active development. We hope the RISC-V processor
verification platform development to be a collaborative effort of the RISC-V
community. Free feel to submit issues, feature requests, pull requests through
Github. You can also send your private collaboration request to [riscv_dv_dev@google.com](riscv_dv_dev@google.com).
Please refer to CONTRIBUTING.md for license related questions.
- Handshake communication with testbench
- Support handcoded assembly test
- Co-simulation with multiple ISS : spike, riscv-ovpsim, whisper, sail-riscv
## Getting Started
@ -73,533 +62,18 @@ run --help
cov --help
```
### Setup RISCV-GCC compiler toolchain
## Document
- Install [riscv-gcc](https://github.com/riscv/riscv-gcc) toolchain
- Set environment variable RISCV_GCC to the RISC-V gcc executable
executable. (example: <install_dir>/bin/riscv32-unknown-elf-gcc)
- Set environment variable RISCV_OBJCOPY to RISC-v objcopy executable
executable. (example: <install_dir>/bin/riscv32-unknown-elf-objcopy)
To understand how to setup and customize the generator, please check the full document under docs directory. You can use the makefile to generate the document. [HTML preview](https://htmlpreview.github.io/?https://github.com/google/riscv-dv/blob/master/docs/build/singlehtml/index.html#document-index)
```bash
# Sample .bashrc setup
export RISCV_TOOLCHAIN=<riscv_gcc_install_path>
export RISCV_GCC="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-gcc"
export RISCV_OBJCOPY="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-objcopy"
```
## External contributions and collaborations
### Setup ISS (instruction set simulator)
This repository is still under active development. We hope the RISC-V processor
verification platform development to be a collaborative effort of the RISC-V
community. Free feel to submit issues, feature requests, pull requests through
Github. You can also send your private collaboration request to [riscv_dv_dev@google.com](riscv_dv_dev@google.com).
Please refer to CONTRIBUTING.md for license related questions.
Currently three ISS are supported, the default ISS is spike. You can install any
one of below to run ISS simulation.
- [spike](https://github.com/riscv/riscv-isa-sim#) setup
- Follow the [steps](https://github.com/riscv/riscv-isa-sim#build-steps) to build spike
- Build spike with "--enable-commitlog"
- Set environment variable SPIKE_PATH to the directory of the spike binary
- [riscv-ovpsim](https://github.com/riscv/riscv-ovpsim) setup
- Download the riscv-ovpsim binary
- Set environment variable OVPSIM_PATH to the directory of the ovpsim binary
- [whisper(swerv-ISS)](https://github.com/westerndigitalcorporation/swerv-ISS) setup
- Follow the instruction to install the ISS, and set WHISPER_ISS to the
whisper binary
- [sail-riscv](https://github.com/rems-project/sail-riscv) setup
- Follow the [steps](https://github.com/rems-project/sail-riscv/blob/master/README.md) to install sail-riscv
- Set environment variable SAIL_RISCV to the path of sail-riscv binary
```bash
export SPIKE_PATH=$RISCV_TOOLCHAIN/bin
export SAIL_RISCV="xx/xxx/ocaml_emulator"
export OVPSIM_PATH=/xx/xxx/riscv-ovpsim/bin/Linux64
export WHISPER_ISS="xx/xxx/swerv-ISS/build-Linux/whisper"
```
## Running the generator
A simple script "run.py" is provided for you to run a single test or a regression.
You can use --help to get the complete command reference:
```bash
run --help
```
Here is the command to run a single test:
```bash
run --test=riscv_arithmetic_basic_test
```
You can specify the simulator by "-simulator" option
```bash
run --test riscv_arithmetic_basic_test --simulator ius
run --test riscv_arithmetic_basic_test --simulator vcs
run --test riscv_arithmetic_basic_test --simulator questa
run --test riscv_arithmetic_basic_test --simulator dsim
run --test riscv_arithmetic_basic_test --simulator qrun
```
The complete test list can be found in [yaml/base_testlist.yaml](https://github.com/google/riscv-dv/blob/master/yaml/base_testlist.yaml). To run a full
regression, simply use below command
```bash
run
```
You can also run multiple generator jobs in parallel through LSF
```bash
run --lsf_cmd="bsub -Is"
```
Here's a few more examples of the run command:
```bash
# Run a single test 10 times
run --test riscv_arithmetic_basic_test --iterations 10
# Run multiple tests
run --test riscv_arithmetic_basic_test,riscv_rand_instr_test
# Run a test with verbose logging
run --test riscv_arithmetic_basic_test --verbose
# Run a test with a specified seed
run --test riscv_arithmetic_basic_test --seed 123
# Skip the generation, run ISS simulation with previously generated program
run --test riscv_arithmetic_basic_test --steps iss_sim
# Run the generator only, do not compile and simluation with ISS
run --test riscv_arithmetic_basic_test --steps gen
# Compile the generator only, do not simulate
run --test riscv_arithmetic_basic_test --co
....
```
### Run ISS simulation
You can use -iss to run with different ISS.
```bash
# Run ISS with spike
run --test riscv_arithmetic_basic_test --iss spike
# Run ISS with riscv-ovpsim
run --test riscv_rand_instr_test --iss ovpsim
# Run ISS with whisper (swerv-ISS)
run --test riscv_rand_instr_test --iss whisper
# Run ISS with sail-riscv
run --test riscv_rand_instr_test --iss sail
```
To run with ISS simulation for RV32IMC, you can specify ISA and ABI from command
line like this:
```bash
# Run a full regression with RV32IMC
run --isa rv32imc --mabi ilp32
```
We have added a flow to run ISS simulation with both spike and riscv-ovpsim,
the instruction trace from these runs will be cross compared. This could greatly
speed up your development of new test without the need to simulate against a
real RISC-V processor.
```bash
run --test=riscv_rand_instr_test --iss=spike,ovpsim
run --test=riscv_rand_instr_test --iss=ovpsim,whisper
run --test=riscv_rand_instr_test --iss=spike,sail
```
### Run directed assembly tests
Sometimes it might be useful to run some hand-coded assembly tests to hit some
corner cases:
```bash
# Run a single/multiple assembly test
run --asm_tests asm_test_path1/asm_test1.S,asm_test_path2/asm_test2.S
# Run regression with all assembly tests(*.S) under a given directory
run --asm_tests asm_test_path1,asm_test_path2
# Run mix between the assembly test and assembly tests under a directory
run --asm_tests asm_test_path1/asm_test1.S,asm_test_path2
```
You could also use this approach to integrate the assembly tests
from other sources to riscv-dv flow.
## Configuration
### Configure the generator to match your processor features
The default configuration of the instruction generator is **RV32IMC** (machine
mode only). A few pre-defined configurations can be found under "target" directory,
you can run with these targets if it matches your processor specification.
```bash
run # Default target rv32imc
run --target rv32i # rv32i, machine mode only
run --target rv32imc # rv32imc, machine mode only
run --target rv64imc # rv64imc, machine mode only
run --target rv64gc # rv64gc, SV39, M/S/U mode
```
If you want to have a custom setting for your processor, you can make a copy of
existing target directory as the template, and modify riscv_core_setting.sv to
match your processor capability.
```verilog
// Bit width of RISC-V GPR
parameter int XLEN = 64;
// Parameter for SATP mode, set to BARE if address translation is not supported
parameter satp_mode_t SATP_MODE = SV39;
// Supported Privileged mode
privileged_mode_t supported_privileged_mode[] = {USER_MODE,
SUPERVISOR_MODE,
MACHINE_MODE};
// Unsupported instructions
riscv_instr_name_t unsupported_instr[] = {};
// ISA supported by the processor
riscv_instr_group_t supported_isa[] = {RV32I, RV32M, RV64I, RV64M};
...
```
You can then run the generator with "--custom_target <target_dir>"
```bash
# You need to manually specify isa and mabi for your custom target
run --custom_target <target_dir> --isa <isa> --mabi <mabi>
...
```
### Setup the memory map
Here's a few cases that you might want to allocate the instruction and data
sections to match the actual memory map
- The processor has internal memories, and you want to test load/store from
various internal/externel memory regions
- The processor implments the PMP feature, and you want to configure the memory
map to match PMP setting.
- Virtual address translation is implmented and you want to test load/store from
sparse memory locations to verify data TLB replacement logic.
You can configure the memory map in [riscv_instr_gen_config.sv](https://github.com/google/riscv-dv/blob/master/src/riscv_instr_gen_config.sv)
```verilog
mem_region_t mem_region[$] = '{
'{name:"region_0", size_in_bytes: 4096, xwr: 3'b111},
'{name:"region_1", size_in_bytes: 4096 * 4, xwr: 3'b111},
'{name:"region_2", size_in_bytes: 4096 * 2, xwr: 3'b111},
'{name:"region_3", size_in_bytes: 512, xwr: 3'b111},
'{name:"region_4", size_in_bytes: 4096, xwr: 3'b111}
};
```
Each memory region belongs to a separate section in the generated assembly
program. You can modify the link script to link each section to the target
memory location. Please avoid setting a large memory range as it could takes a
long time to randomly initializing the memory. You can break down a large memory
region to a few representative small regions which covers all the boundary
conditions for the load/store testing.
### Setup regression test list
[Test list in YAML format](https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml)
```yaml
# test : Assembly test name
# description : Description of this test
# gen_opts : Instruction generator options
# iterations : Number of iterations of this test
# no_iss : Enable/disable ISS simulation (Optional)
# gen_test : Test name used by the instruction generator
# asm_tests : Path to directed, hand-coded assembly test file or directory
# rtl_test : RTL simulation test name
# cmp_opts : Compile options passed to the instruction generator
# sim_opts : Simulation options passed to the instruction generator
# no_post_compare : Enable/disable log comparison (Optional)
# compare_opts : Options for the RTL & ISS trace comparison
- test: riscv_arithmetic_basic_test
description: >
Arithmetic instruction test, no load/store/branch instructions
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=0
+no_fence=1
+no_data_page=1'b1
+no_branch_jump=1'b1
+boot_mode=m
iterations: 2
gen_test: riscv_instr_base_test
rtl_test: core_base_test
- test: riscv_csr_test
description: >
Stress CSR accesses on all implemented CSRs
iterations: 2
no_iss: 1
rtl_test: core_base_test
no_post_compare: 1
- test: riscv_directed_asm_test
description: >
Hand-coded assembly test to test corner case
iterations: 1
asm_tests: <asm_test_dir_path or asm_test_file path>
rtl_test: core_base_test
```
Note: To automatically generate CSR stress tests without having to explicitly run the
script, include a test entry `riscv_csr_test` in the testlist as shown in the
example YAML file above.
The generation flow now supports inclusion of handcoded assembly tests into the
overall regression. To do this, simply create a YAML entry in the appropriate
testlist as shown above in `riscv_directed_asm_test`, using the `asm_tests`
field to point to the location of the assembly test file or directory.
The run flow will then locate these file(s) and include them into the overall
regression run. These directed test targets can also be run individually from
the python script, as shown below:
```bash
# Run directed assembly test 10 times
python3 run.py --test riscv_directed_asm_test --iterations 10
```
Note: when using the `asm_tests` field to specify some directed/handcoded
assembly tests to the flow, make sure that the `gen_test` field is not defined,
as this will cause the flow to throw an error.
### Runtime options of the generator
| Option | Description | Default |
|:---------------------------:|:-------------------------------------------------:|:-------:|
| num_of_tests | Number of assembly tests to be generated | 1 |
| num_of_sub_program | Number of sub-program in one test | 5 |
| instr_cnt | Instruction count per test | 200 |
| enable_page_table_exception | Enable page table exception | 0 |
| enable_unaligned_load_store | Enable unaligned memory operations | 0 |
| no_ebreak | Disable ebreak instruction | 1 |
| no_wfi | Disable WFI instruction | 1 |
| no_dret | Disable dret instruction | 1 |
| no_branch_jump | Disable branch/jump instruction | 0 |
| no_load_store | Disable load/store instruction | 0 |
| no_csr_instr | Disable CSR instruction | 0 |
| no_fence | Disable fence instruction | 0 |
| illegal_instr_ratio | Number of illegal instructions every 1000 instr | 0 |
| hint_instr_ratio | Number of HINT instructions every 1000 instr | 0 |
| boot_mode | m:Machine mode, s:Supervisor mode, u:User mode | m |
| no_directed_instr | Disable directed instruction stream | 0 |
| require_signature_addr | Set to 1 if test needs to talk to testbench | 0 |
| signature_addr | Write to this addr to send data to testbench | 0 |
| enable_interrupt | Enable MStatus.MIE, used in interrupt test | 0 |
| gen_debug_section | Disables randomized debug_rom section | 0 |
| num_debug_sub_program | Number of debug sub-programs in test | 0 |
| enable_ebreak_in_debug_rom | Generate ebreak instructions inside debug ROM | 0 |
| set_dcsr_ebreak | Randomly enable dcsr.ebreak(m/s/u) | 0 |
| randomize_csr | Fully randomize main CSRs (xSTATUS, xIE) | 0 |
### Setup Privileged CSR description (optional)
This YAML description file of all CSRs is only required for the privileged CSR
test. All other standard tests do not use this description.
[CSR descriptions in YAML
format](https://github.com/google/riscv-dv/blob/master/yaml/csr_template.yaml)
```yaml
- csr: CSR_NAME
description: >
BRIEF_DESCRIPTION
address: 0x###
privilege_mode: MODE (D/M/S/H/U)
rv32:
- MSB_FIELD_NAME:
- description: >
BRIEF_DESCRIPTION
- type: TYPE (WPRI/WLRL/WARL/R)
- reset_val: RESET_VAL
- msb: MSB_POS
- lsb: LSB_POS
- ...
- ...
- LSB_FIELD_NAME:
- description: ...
- type: ...
- ...
rv64:
- MSB_FIELD_NAME:
- description: >
BRIEF_DESCRIPTION
- type: TYPE (WPRI/WLRL/WARL/R)
- reset_val: RESET_VAL
- msb: MSB_POS
- lsb: LSB_POS
- ...
- ...
- LSB_FIELD_NAME:
- description: ...
- type: ...
- ...
```
To specify what ISA width should be generated in the test, simply include the
matching rv32/rv64/rv128 entry and fill in the appropriate CSR field entries.
### Privileged CSR Test Generation (optional)
The CSR generation script is located at
[scripts/gen_csr_test.py](https://github.com/google/riscv-dv/blob/master/scripts/gen_csr_test.py).
The CSR test code that this script generates will execute every CSR instruction
on every processor implemented CSR, writing values to the CSR and then using a
prediction function to calculate a reference value that will be written into
another GPR. The reference value will then be compared to the value actually
stored in the CSR to determine whether to jump to the failure condition or
continue executing, allowing it to be completely self checking. This script has
been integrated with run.py. If you want to run it separately, you can get the
command reference with --help:
```bash
python3 scripts/gen_csr_test.py --help
```
### Adding new instruction stream and test
Please refer to src/src/riscv_load_store_instr_lib.sv for an example on how to
add a new instruction stream.
After the new instruction stream is created, you can use a runtime option to mix
it with random instructions
```bash
//+directed_instr_n=instr_sequence_name,frequency(number of insertions per 1000 instructions)
+directed_instr_5=riscv_multi_page_load_store_instr_stream,4
// An alternative command line options for directed instruction stream
+stream_name_0=riscv_multi_page_load_store_instr_stream
+stream_freq_0=4
```
## Integrate a new ISS
You can add a new entry in [iss.yaml](https://github.com/google/riscv-dv/blob/master/yaml/iss.yaml)
```yaml
- iss: new_iss_name
path_var: ISS_PATH
cmd: >
<path_var>/iss_executable --isa=<variant> -l <elf>
```
Simulate with the new ISS
```bash
run --test riscv_arithmetic_basic_test --iss new_iss_name
```
## End-to-end RTL and ISS co-simulation flow
We have collaborated with LowRISC to apply this flow for [IBEX RISC-V core
verification](https://github.com/lowRISC/ibex/blob/master/doc/verification.rst). You can use
it as a reference to setup end-to-end co-simulation flow.
This repo is still under active development, this is the recommended approach to
customize the instruction generator while keeping the effort of merging
upstream changes to a minimum.
- Do not modify the upstream classes directly. When possible, extend from
the upstream classses and implement your own functionalities.
- Add your extensions under user_extension directory, and add the files to
user_extension/user_extension.svh. If you prefer to put your extensions in a
different directory, you can use "-ext <user_extension_path>" to override the
user extension path.
- Create a new target directory and customize the setting and testlist
- Run the generator with `--custom_target <target_dir> --isa <isa> --mabi <mabi>`
- Use command line type override to use your extended classes.
`--sim_opts="+uvm_set_type_override=<upstream_class>,<extended_class>"`
- If extending `riscv_asm_program_gen` class is desired, must use this command
line override:
`--sim_opts="+uvm_set_inst_override=riscv_asm_program_gen,<extended
class>,'uvm_test_top.asm_gen'"`
You can refer to [riscv-dv extension for ibex](https://github.com/lowRISC/ibex/blob/master/dv/uvm/Makefile#L68) for a working example.
We have plan to open-source the end-to-end environments of other advanced RISC-V
processors. Stay tuned!
## Handshaking Mechanism
This mechanism allows the generator to generate small, directed sequences of
instructions that write critical information to a specified address in memory,
that the testbench monitors for write accesses to.
This allows for more in-depth verification of scenarios that involve external
stimulus to the core, such as interrupts and debug requests.
For more information, detailed documentation of this mechanism can be found in
[HANDSHAKE.md](./HANDSHAKE.md).
## Functional coverage (work in progress)
This flow extracts functional coverage information from the
instruction trace generated by ISS. It's independent of the instruction generation
flow and does not require a tracer implementation in the RTL. You can use this
flow as long as your program can be run with an ISS supported in this flow. The
flow parses the instruction trace log and converts it to a CSV trace format. After
that, a SV test is run to process the CSV trace files and sample functional
coverage from there.
The functional covergroup is defined in [riscv_instr_cover_group.sv](https://github.com/google/riscv-dv/blob/master/src/riscv_instr_cover_group.sv). It includes below major categories:
- Cover all operands for each instruction
- Hazard conditions
- Corner cases like overflow, underflow, divide by zero
- Aligned/unaligned load/store
- Positive/negative immediate value
- Forward/backward branches, branch hit history
- Hint instruction
- Illegal instruction
- All compressed and non-compressed opcode
- Access to all implemened privileged CSR
- Exception and interrupt
The functional covergroup is still under active development. Please feel free to
add anything you are interested or file a bug for any feature request.
Before start, please check the you have modified [riscv_core_setting.sv](https://github.com/google/riscv-dv/blob/master/setting/riscv_core_setting.sv) to reflect your processor capabilities. The covergroup is selectively instantiated based on this setting so that you don't need to deal with excluding unrelated coverpoints later. You also need to get the Spike ISS or riscvOVPsim ISS (riscv-ovpsim) setup before running this flow.
```bash
# Process spike simulation log and collect functional coverage
cov --dir out/spike_sim
# Get the command reference
cov --help
# Run the coverage flow with predefined targets
cov --dir out/spike_sim --target rv32imc
```
The coverage sampling from the CSV could be time consuming if you have a large
number of log to process. You can split them to small batches and run with LSF
in parallel.
```
# Split the run to process 5 CSV at a time, and run with LSF
cov --dir out/spike_sim --lsf_cmd "bsub ....." -bz 5
```
## Supporting model
Please file an issue under this repository for any bug report / integration

View file

@ -53,7 +53,7 @@ def build_cov(out, cfg, cwd, opts_vec, opts_cov):
build_cmd += (" --custom_target %s" % argv.custom_target)
if argv.stop_on_first_error:
build_cmd += (" --stop_on_first_error")
run_cmd(build_cmd)
run_cmd(build_cmd, debug_cmd = argv.debug)
def sim_cov(out, cfg, cwd, opts_vec, opts_cov, csv_list):
"""Simulation the coverage collection
@ -101,7 +101,7 @@ def sim_cov(out, cfg, cwd, opts_vec, opts_cov, csv_list):
sim_cmd += (" --log_suffix _%d" % file_idx)
if argv.lsf_cmd == "":
logging.info("Processing batch %0d/%0d" % (file_idx+1, batch_cnt))
run_cmd(sim_cmd)
run_cmd(sim_cmd, debug_cmd = argv.debug)
else:
sim_cmd += (" --lsf_cmd \"%s\"" % argv.lsf_cmd)
sim_cmd_list.append(sim_cmd)
@ -127,8 +127,9 @@ def collect_cov(out, cfg, cwd):
sys.exit(RET_FAIL)
logging.info("Processing trace log under %s" % argv.dir)
if not os.path.isdir(argv.dir) or not os.listdir(argv.dir):
logging.error("Cannot find %s directory, or it is empty", argv.dir)
sys.exit(RET_FAIL)
if not argv.debug:
logging.error("Cannot find %s directory, or it is empty", argv.dir)
sys.exit(RET_FAIL)
if argv.core:
"""
If functional coverage is being collected from an RTL core implementation,
@ -239,6 +240,8 @@ def setup_parser():
help="Controlling coverage coverpoints")
parser.add_argument("--exp", action="store_true", default=False,
help="Run generator with experimental features")
parser.add_argument("-d", "--debug", type=str, default="",
help="Generate debug command log file")
return parser
def load_config(args, cwd):
@ -250,6 +253,8 @@ def load_config(args, cwd):
Returns:
Loaded configuration dictionary.
"""
if args.debug:
args.debug = open(args.debug, "w")
if args.verbose:
args.opts += "-v"

View file

@ -9,6 +9,7 @@ if "%SPHINXBUILD%" == "" (
)
set SOURCEDIR=source
set BUILDDIR=build
set SPHINXOPTS="-html_theme classic"
if "%1" == "" goto help

View file

@ -0,0 +1,49 @@
Appendix
========
Trace CSV format
----------------
A standard CSV format is defined for the instruction execution trace. It's used for co-simulation result comparison and functional coverage collection.
.. image:: trace_csv.png
**The CSV format includes the following fields:**
- pc : Program counter (instruction memory address)
- instr: Instruction name
- gpr: General purpose register updated by the instruction (rd, fd, vd etc.)
- Format: <GPR name>:<Value>
- GPR can be any integer/floating point/vector register
- If more than one general purpose registers are updated, separate them with semicolon
- csr: Privileged CSR updated by the instruction
- The same format as the GPR field
- binary: Instruction binary
- instr_str: Instruction in assmebly format
- operand: Instruction operands
- pad: Unused
**Here's a sample of the CSV trace file:**
.. code-block:: verilog
pc,instr,gpr,csr,binary,mode,instr_str,operand,pad
ffffffff8000000c,c.addi,ra:daab700e,,000000b9,3,"c.addi ra, 14","ra,14",
ffffffff8000000e,lui,sp:ff8e6000,,ff8e6137,3,"lui sp, 0xff8e6","sp,0xff8e6",
ffffffff80000012,addi,sp:ff8e6541,,54110113,3,"addi sp, sp, 1345","sp,sp,1345",
ffffffff80000016,c.li,gp:00000000,,00004181,3,"c.li gp, 0","gp,0",
ffffffff80000018,lui,tp:80000000,,80000237,3,"lui tp, 0x80000","tp,0x80000",
ffffffff8000001c,lui,t0:f999d000,,f999d2b7,3,"lui t0, 0xf999d","t0,0xf999d",
ffffffff80000020,addi,t0:f999cbf0,,bf028293,3,"addi t0, t0, -1040","t0,t0,-1040",
ffffffff80000024,lui,t1:0416b000,,0416b337,3,"lui t1, 0x416b","t1,0x416b",
ffffffff80000028,addi,t1:0416b6ee,,6ee30313,3,"addi t1, t1, 1774","t1,t1,1774",
ffffffff8000002c,lui,t2:e6420000,,e64203b7,3,"lui t2, 0xe6420","t2,0xe6420",
...
To integrate a new ISS or processor with the co-simualtion or coverage flow, user must implement a
python script to convert the custom trace log format to this CSV format. You can find a sample
script `here`_.
.. _here: https://github.com/google/riscv-dv/blob/master/scripts/spike_log_to_trace_csv.py

View file

@ -14,6 +14,7 @@
# import sys
# sys.path.insert(0, os.path.abspath('.'))
from pallets_sphinx_themes import ProjectLink
import sphinx_rtd_theme
# -- Project information -----------------------------------------------------
@ -35,6 +36,7 @@ extensions = [
"sphinxcontrib.log_cabinet",
"sphinx_issues",
"rst2pdf.pdfbuilder",
'sphinx_rtd_theme',
]
# Add any paths that contain templates here, relative to this directory.
@ -51,20 +53,20 @@ exclude_patterns = []
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = "jinja"
html_theme_options = {"index_sidebar_logo": False}
html_context = {
"project_links": [
ProjectLink("Source Code", "https://github.com/google/riscv-dv.git"),
ProjectLink("Issue Tracker", "https://github.com/google/riscv-dv/issues"),
]
}
html_sidebars = {
"index": ["project.html", "localtoc.html", "searchbox.html"],
"**": ["localtoc.html", "relations.html", "searchbox.html"],
}
html_theme = "sphinx_rtd_theme"
#html_theme_options = {"index_sidebar_logo": False}
#
#html_context = {
# "project_links": [
# ProjectLink("Source Code", "https://github.com/google/riscv-dv.git"),
# ProjectLink("Issue Tracker", "https://github.com/google/riscv-dv/issues"),
# ]
#}
#
#html_sidebars = {
# "index": ["project.html", "localtoc.html", "searchbox.html"],
# "**": ["localtoc.html", "relations.html", "searchbox.html"],
#}
# -- For PDF output ---------------------------------------------------------
pdf_documents = [('index', u'riscv-dv', u'RISCV-DV', u'Google, Inc'),]

View file

@ -108,7 +108,7 @@ Test list in `YAML format`_
gen_test: riscv_instr_base_test
rtl_test: core_base_test
.. _YAML format: https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml
.. _YAML format: https://github.com/google/riscv-dv/blob/master/yaml/base_testlist.yaml
.. note:: To automatically generate CSR tests without having to explicitly run the
script, include `riscv_csr_test` in the testlist as shown in the example YAML

View file

@ -1,2 +1,29 @@
Customize and Extend Generator
==============================
Add custom instructions
-----------------------
1. Add the new instruction enum to `riscv_custom_instr_enum.sv`_
.. code-block:: verilog
CUSTOM_ADD,
CUSTOM_SUB,
...
2. Add custom instruction definition to `rv32x_instr.sv`_/`rv64x_instr.sv`_
.. code-block:: verilog
`DEFINE_CUSTOM_INSTR(CUSTOM_ADD, R_FORMAT, ARITHMETIC, RV32X)
`DEFINE_CUSTOM_INSTR(CUSTOM_SUB, R_FORMAT, ARITHMETIC, RV32X)
...
3. Extend `riscv_custom_instr.sv`_ and implement key functions like get_instr_name, convert2asm
4. Add RV32X/RV64X to supported_isa in riscv_core_setting.sv
.. _riscv_custom_instr_enum.sv: https://github.com/google/riscv-dv/blob/master/src/isa/custom/riscv_custom_instr_enum.sv
.. _riscv_custom_instr.sv: https://github.com/google/riscv-dv/blob/master/src/isa/custom/riscv_custom_instr.sv
.. _rv32x_instr.sv: https://github.com/google/riscv-dv/blob/master/src/isa/custom/rv32x_instr.sv
.. _rv64x_instr.sv: https://github.com/google/riscv-dv/blob/master/src/isa/custom/rv64x_instr.sv

View file

@ -19,6 +19,7 @@ Welcome to riscv-dv's documentation!
customize_extend_generator
class_reference
cmd_line_reference
appendix

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -4,4 +4,5 @@ Sphinx
Pallets-Sphinx-Themes
sphinxcontrib-log-cabinet
sphinx-issues
sphinx_rtd_theme
rst2pdf

View file

@ -33,7 +33,7 @@ from types import SimpleNamespace
LOGGER = logging.getLogger()
def get_generator_cmd(simulator, simulator_yaml, cov, exp):
def get_generator_cmd(simulator, simulator_yaml, cov, exp, debug_cmd):
""" Setup the compile and simulation command for the generator
Args:
@ -41,6 +41,7 @@ def get_generator_cmd(simulator, simulator_yaml, cov, exp):
simulator_yaml : RTL simulator configuration file in YAML format
cov : Enable functional coverage
exp : Use experimental version
debug_cmd : Produce the debug cmd log without running
Returns:
compile_cmd : RTL simulator command to compile the instruction generator
@ -69,14 +70,15 @@ def get_generator_cmd(simulator, simulator_yaml, cov, exp):
if 'env_var' in entry:
for env_var in entry['env_var'].split(','):
for i in range(len(compile_cmd)):
compile_cmd[i] = re.sub("<"+env_var+">", get_env_var(env_var), compile_cmd[i])
sim_cmd = re.sub("<"+env_var+">", get_env_var(env_var), sim_cmd)
compile_cmd[i] = re.sub("<"+env_var+">", get_env_var(env_var, debug_cmd = debug_cmd),
compile_cmd[i])
sim_cmd = re.sub("<"+env_var+">", get_env_var(env_var, debug_cmd = debug_cmd), sim_cmd)
return compile_cmd, sim_cmd
logging.error("Cannot find RTL simulator %0s" % simulator)
sys.exit(RET_FAIL)
def parse_iss_yaml(iss, iss_yaml, isa, setting_dir):
def parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd):
"""Parse ISS YAML to get the simulation command
Args:
@ -84,6 +86,7 @@ def parse_iss_yaml(iss, iss_yaml, isa, setting_dir):
iss_yaml : ISS configuration file in YAML format
isa : ISA variant passed to the ISS
setting_dir : Generator setting directory
debug_cmd : Produce the debug cmd log without running
Returns:
cmd : ISS run command
@ -95,7 +98,7 @@ def parse_iss_yaml(iss, iss_yaml, isa, setting_dir):
if entry['iss'] == iss:
logging.info("Found matching ISS: %s" % entry['iss'])
cmd = entry['cmd'].rstrip()
cmd = re.sub("\<path_var\>", get_env_var(entry['path_var']), cmd)
cmd = re.sub("\<path_var\>", get_env_var(entry['path_var'], debug_cmd = debug_cmd), cmd)
m = re.search(r"rv(?P<xlen>[0-9]+?)(?P<variant>[a-z]+?)$", isa)
if m:
cmd = re.sub("\<xlen\>", m.group('xlen'), cmd)
@ -130,7 +133,8 @@ def get_iss_cmd(base_cmd, elf, log):
cmd += (" &> %s" % log)
return cmd
def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir, cmp_opts, output_dir):
def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir,
cmp_opts, output_dir, debug_cmd):
"""Compile the instruction generator
Args:
@ -141,6 +145,7 @@ def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir, cmp_opts,
ext_dir : User extension directory
cmd_opts : Compile options for the generator
output_dir : Output directory of the ELF files
debug_cmd : Produce the debug cmd log without running
"""
if (not((len(test_list) == 1) and (test_list[0]['test'] == 'riscv_csr_test'))):
logging.info("Building RISC-V instruction generator")
@ -155,10 +160,10 @@ def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir, cmp_opts,
cmd = re.sub("<cmp_opts>", cmp_opts, cmd)
logging.debug("Compile command: %s" % cmd)
run_cmd(cmd)
run_cmd(cmd, debug_cmd = debug_cmd)
def run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
end_signature_addr, timeout_s, output_dir):
end_signature_addr, timeout_s, output_dir, debug_cmd):
"""Run CSR test
It calls a separate python script to generate directed CSR test code,
located at scripts/gen_csr_test.py.
@ -172,11 +177,11 @@ def run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
if lsf_cmd:
cmd_list.append(cmd)
else:
run_cmd(cmd, timeout_s)
run_cmd(cmd, timeout_s, debug_cmd = debug_cmd)
def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
isa, end_signature_addr, lsf_cmd, timeout_s, log_suffix,
batch_size, output_dir, verbose, check_return_code):
batch_size, output_dir, verbose, check_return_code, debug_cmd):
"""Run the instruction generator
Args:
@ -195,6 +200,7 @@ def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
batch_size : Number of tests to generate per run
output_dir : Output directory of the ELF files
check_return_code : Check return code of the command
debug_cmd : Produce the debug cmd log without running
"""
cmd_list = []
sim_cmd = re.sub("<out>", os.path.abspath(output_dir), sim_cmd)
@ -212,7 +218,7 @@ def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
# Running a CSR test
if test['test'] == 'riscv_csr_test':
run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
end_signature_addr, timeout_s, output_dir)
end_signature_addr, timeout_s, output_dir, debug_cmd)
else:
batch_cnt = 1
if batch_size > 0:
@ -247,12 +253,13 @@ def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
else:
logging.info("Running %s, batch %0d/%0d, test_cnt:%0d" %
(test['test'], i+1, batch_cnt, test_cnt))
run_cmd(cmd, timeout_s, check_return_code = check_return_code)
run_cmd(cmd, timeout_s, check_return_code = check_return_code, debug_cmd = debug_cmd)
if sim_seed:
with open(('%s/seed.yaml' % os.path.abspath(output_dir)) , 'w') as outfile:
yaml.dump(sim_seed, outfile, default_flow_style=False)
if lsf_cmd:
run_parallel_cmd(cmd_list, timeout_s, check_return_code = check_return_code)
run_parallel_cmd(cmd_list, timeout_s, check_return_code = check_return_code,
debug_cmd = debug_cmd)
def gen(test_list, cfg, output_dir, cwd):
@ -281,19 +288,20 @@ def gen(test_list, cfg, output_dir, cwd):
# Setup the compile and simulation command for the generator
compile_cmd = []
sim_cmd = ""
compile_cmd, sim_cmd = get_generator_cmd(argv.simulator, argv.simulator_yaml, argv.cov, argv.exp);
compile_cmd, sim_cmd = get_generator_cmd(argv.simulator, argv.simulator_yaml, argv.cov,
argv.exp, argv.debug);
# Compile the instruction generator
if not argv.so:
do_compile(compile_cmd, test_list, argv.core_setting_dir, cwd, argv.user_extension_dir,
argv.cmp_opts, output_dir)
argv.cmp_opts, output_dir, argv.debug)
# Run the instruction generator
if not argv.co:
do_simulate(sim_cmd, test_list, cwd, argv.sim_opts, argv.seed_yaml, argv.seed, argv.csr_yaml,
argv.isa, argv.end_signature_addr, argv.lsf_cmd, argv.gen_timeout, argv.log_suffix,
argv.batch_size, output_dir, argv.verbose, check_return_code)
argv.batch_size, output_dir, argv.verbose, check_return_code, argv.debug)
def gcc_compile(test_list, output_dir, isa, mabi, opts):
def gcc_compile(test_list, output_dir, isa, mabi, opts, debug_cmd):
"""Use riscv gcc toolchain to compile the assembly program
Args:
@ -301,6 +309,7 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts):
output_dir : Output directory of the ELF files
isa : ISA variant passed to GCC
mabi : MABI variant passed to GCC
debug_cmd : Produce the debug cmd log without running
"""
cwd = os.path.dirname(os.path.realpath(__file__))
for test in test_list:
@ -312,7 +321,7 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts):
elf = prefix + ".o"
binary = prefix + ".bin"
test_isa = isa
if not os.path.isfile(asm):
if not os.path.isfile(asm) and not debug_cmd:
logging.error("Cannot find assembly test: %s\n", asm)
sys.exit(RET_FAIL)
# gcc comilation
@ -321,7 +330,7 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts):
-nostartfiles %s \
-I%s/user_extension \
-T%s/scripts/link.ld %s -o %s " % \
(get_env_var("RISCV_GCC"), asm, cwd, cwd, opts, elf))
(get_env_var("RISCV_GCC", debug_cmd = debug_cmd), asm, cwd, cwd, opts, elf))
if 'gcc_opts' in test:
cmd += test['gcc_opts']
if 'gen_opts' in test:
@ -335,15 +344,16 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts):
if not re.search('mabi', cmd):
cmd += (" -mabi=%s" % mabi)
logging.info("Compiling %s" % asm)
run_cmd_output(cmd.split())
run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
# Convert the ELF to plain binary, used in RTL sim
logging.info("Converting to %s" % binary)
cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY"), elf, binary))
run_cmd_output(cmd.split())
cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY", debug_cmd = debug_cmd),
elf, binary))
run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
def run_assembly(asm_test, iss_yaml, isa, mabi, gcc_opts, iss_opts, output_dir,
setting_dir):
setting_dir, debug_cmd):
"""Run a directed assembly test with ISS
Args:
@ -355,6 +365,7 @@ def run_assembly(asm_test, iss_yaml, isa, mabi, gcc_opts, iss_opts, output_dir,
iss_opts : Instruction set simulators
output_dir : Output directory of compiled test files
setting_dir : Generator setting directory
debug_cmd : Produce the debug cmd log without running
"""
if not asm_test.endswith(".S"):
logging.error("%s is not an assembly .S file" % asm_test)
@ -377,30 +388,31 @@ def run_assembly(asm_test, iss_yaml, isa, mabi, gcc_opts, iss_opts, output_dir,
-nostartfiles %s \
-I%s/user_extension \
-T%s/scripts/link.ld %s -o %s " % \
(get_env_var("RISCV_GCC"), asm_test, cwd, cwd, gcc_opts, elf))
(get_env_var("RISCV_GCC", debug_cmd = debug_cmd), asm_test, cwd,
cwd, gcc_opts, elf))
cmd += (" -march=%s" % isa)
cmd += (" -mabi=%s" % mabi)
run_cmd_output(cmd.split())
run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
# Convert the ELF to plain binary, used in RTL sim
logging.info("Converting to %s" % binary)
cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY"), elf, binary))
run_cmd_output(cmd.split())
cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY", debug_cmd = debug_cmd), elf, binary))
run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
log_list = []
# ISS simulation
for iss in iss_list:
run_cmd("mkdir -p %s/%s_sim" % (output_dir, iss))
log = ("%s/%s_sim/%s.log" % (output_dir, iss, asm))
log_list.append(log)
base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir)
base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd)
logging.info("[%0s] Running ISS simulation: %s" % (iss, elf))
cmd = get_iss_cmd(base_cmd, elf, log)
run_cmd(cmd, 10)
run_cmd(cmd, 10, debug_cmd = debug_cmd)
logging.info("[%0s] Running ISS simulation: %s ...done" % (iss, elf))
if len(iss_list) == 2:
compare_iss_log(iss_list, log_list, report)
def run_assembly_from_dir(asm_test_dir, iss_yaml, isa, mabi, gcc_opts, iss,
output_dir, setting_dir):
output_dir, setting_dir, debug_cmd):
"""Run a directed assembly test from a directory with spike
Args:
@ -412,6 +424,7 @@ def run_assembly_from_dir(asm_test_dir, iss_yaml, isa, mabi, gcc_opts, iss,
iss : Instruction set simulators
output_dir : Output directory of compiled test files
setting_dir : Generator setting directory
debug_cmd : Produce the debug cmd log without running
"""
result = run_cmd("find %s -name \"*.S\"" % asm_test_dir)
if result:
@ -420,14 +433,102 @@ def run_assembly_from_dir(asm_test_dir, iss_yaml, isa, mabi, gcc_opts, iss,
(len(asm_list), asm_test_dir))
for asm_file in asm_list:
run_assembly(asm_file, iss_yaml, isa, mabi, gcc_opts, iss, output_dir,
setting_dir)
setting_dir, debug_cmd)
if "," in iss:
report = ("%s/iss_regr.log" % output_dir).rstrip()
save_regr_report(report)
else:
logging.error("No assembly test(*.S) found under %s" % asm_test_dir)
def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, setting_dir, timeout_s):
def run_c(c_test, iss_yaml, isa, mabi, gcc_opts, iss_opts, output_dir,
setting_dir, debug_cmd):
"""Run a directed c test with ISS
Args:
c_test : C test file
iss_yaml : ISS configuration file in YAML format
isa : ISA variant passed to the ISS
mabi : MABI variant passed to GCC
gcc_opts : User-defined options for GCC compilation
iss_opts : Instruction set simulators
output_dir : Output directory of compiled test files
setting_dir : Generator setting directory
debug_cmd : Produce the debug cmd log without running
"""
if not c_test.endswith(".c"):
logging.error("%s is not a .c file" % c_test)
return
cwd = os.path.dirname(os.path.realpath(__file__))
c_test = os.path.expanduser(c_test)
report = ("%s/iss_regr.log" % output_dir).rstrip()
c = re.sub(r"^.*\/", "", c_test)
c = re.sub(r"\.c$", "", c)
prefix = ("%s/directed_c_tests/%s" % (output_dir, c))
elf = prefix + ".o"
binary = prefix + ".bin"
iss_list = iss_opts.split(",")
run_cmd("mkdir -p %s/directed_c_tests" % output_dir)
logging.info("Compiling c test : %s" % c_test)
# gcc compilation
cmd = ("%s -mcmodel=medany -nostdlib \
-nostartfiles %s \
-I%s/user_extension \
-T%s/scripts/link.ld %s -o %s " % \
(get_env_var("RISCV_GCC", debug_cmd = debug_cmd), c_test, cwd,
cwd, gcc_opts, elf))
cmd += (" -march=%s" % isa)
cmd += (" -mabi=%s" % mabi)
run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
# Convert the ELF to plain binary, used in RTL sim
logging.info("Converting to %s" % binary)
cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY", debug_cmd = debug_cmd), elf, binary))
run_cmd_output(cmd.split(), debug_cmd = debug_cmd)
log_list = []
# ISS simulation
for iss in iss_list:
run_cmd("mkdir -p %s/%s_sim" % (output_dir, iss))
log = ("%s/%s_sim/%s.log" % (output_dir, iss, c))
log_list.append(log)
base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd)
logging.info("[%0s] Running ISS simulation: %s" % (iss, elf))
cmd = get_iss_cmd(base_cmd, elf, log)
run_cmd(cmd, 10, debug_cmd = debug_cmd)
logging.info("[%0s] Running ISS simulation: %s ...done" % (iss, elf))
if len(iss_list) == 2:
compare_iss_log(iss_list, log_list, report)
def run_c_from_dir(c_test_dir, iss_yaml, isa, mabi, gcc_opts, iss,
output_dir, setting_dir, debug_cmd):
"""Run a directed assembly test from a directory with spike
Args:
c_test_dir : C test file directory
iss_yaml : ISS configuration file in YAML format
isa : ISA variant passed to the ISS
mabi : MABI variant passed to GCC
gcc_opts : User-defined options for GCC compilation
iss : Instruction set simulators
output_dir : Output directory of compiled test files
setting_dir : Generator setting directory
debug_cmd : Produce the debug cmd log without running
"""
result = run_cmd("find %s -name \"*.c\"" % c_test_dir)
if result:
c_list = result.splitlines()
logging.info("Found %0d c tests under %s" %
(len(c_list), c_test_dir))
for c_file in c_list:
run_c(c_file, iss_yaml, isa, mabi, gcc_opts, iss, output_dir,
setting_dir, debug_cmd)
if "," in iss:
report = ("%s/iss_regr.log" % output_dir).rstrip()
save_regr_report(report)
else:
logging.error("No c test(*.c) found under %s" % c_test_dir)
def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa,
setting_dir, timeout_s, debug_cmd):
"""Run ISS simulation with the generated test program
Args:
@ -438,10 +539,11 @@ def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, setting_dir, timeout
isa : ISA variant passed to the ISS
setting_dir : Generator setting directory
timeout_s : Timeout limit in seconds
debug_cmd : Produce the debug cmd log without running
"""
for iss in iss_list.split(","):
log_dir = ("%s/%s_sim" % (output_dir, iss))
base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir)
base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd)
logging.info("%s sim log dir: %s" % (iss, log_dir))
run_cmd_output(["mkdir", "-p", log_dir])
for test in test_list:
@ -455,13 +557,13 @@ def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, setting_dir, timeout
cmd = get_iss_cmd(base_cmd, elf, log)
logging.info("Running %s sim: %s" % (iss, elf))
if iss == "ovpsim":
run_cmd(cmd, timeout_s, check_return_code=False)
run_cmd(cmd, timeout_s, check_return_code=False, debug_cmd = debug_cmd)
else:
run_cmd(cmd, timeout_s)
run_cmd(cmd, timeout_s, debug_cmd = debug_cmd)
logging.debug(cmd)
def iss_cmp(test_list, iss, output_dir, stop_on_first_error, exp):
def iss_cmp(test_list, iss, output_dir, stop_on_first_error, exp, debug_cmd):
"""Compare ISS simulation reult
Args:
@ -470,7 +572,10 @@ def iss_cmp(test_list, iss, output_dir, stop_on_first_error, exp):
output_dir : Output directory of the ELF files
stop_on_first_error : will end run on first error detected
exp : Use experimental version
debug_cmd : Produce the debug cmd log without running
"""
if debug_cmd:
return
iss_list = iss.split(",")
if len(iss_list) != 2:
return
@ -593,6 +698,8 @@ def setup_parser():
help="Path for the user extension directory")
parser.add_argument("--asm_tests", type=str, default="",
help="Directed assembly tests")
parser.add_argument("--c_tests", type=str, default="",
help="Directed c tests")
parser.add_argument("--log_suffix", type=str, default="",
help="Simulation log name suffix")
parser.add_argument("--exp", action="store_true", default=False,
@ -605,6 +712,8 @@ def setup_parser():
help="Stop on detecting first error")
parser.add_argument("--noclean", action="store_true", default=True,
help="Do not clean the output of the previous runs")
parser.add_argument("-d", "--debug", type=str, default="",
help="Generate debug command log file")
return parser
def load_config(args, cwd):
@ -615,6 +724,8 @@ def load_config(args, cwd):
Returns:
Loaded configuration dictionary.
"""
if args.debug:
args.debug = open(args.debug, "w")
if not args.csr_yaml:
args.csr_yaml = cwd + "/yaml/csr_template.yaml"
@ -687,11 +798,31 @@ def main():
# path_asm_test is a directory
if os.path.isdir(full_path):
run_assembly_from_dir(full_path, args.iss_yaml, args.isa, args.mabi,
args.gcc_opts, args.iss, output_dir, args.core_setting_dir)
args.gcc_opts, args.iss, output_dir,
args.core_setting_dir, args.debug)
# path_asm_test is an assembly file
elif os.path.isfile(full_path):
elif os.path.isfile(full_path) or args.debug:
run_assembly(full_path, args.iss_yaml, args.isa, args.mabi, args.gcc_opts,
args.iss, output_dir, args.core_setting_dir)
args.iss, output_dir, args.core_setting_dir, args.debug)
else:
logging.error('%s does not exist' % full_path)
sys.exit(RET_FAIL)
return
# Run any handcoded/directed c tests specified by args.c_tests
if args.c_tests != "":
c_test = args.c_tests.split(',')
for path_c_test in c_test:
full_path = os.path.expanduser(path_c_test)
# path_c_test is a directory
if os.path.isdir(full_path):
run_c_from_dir(full_path, args.iss_yaml, args.isa, args.mabi,
args.gcc_opts, args.iss, output_dir,
args.core_setting_dir, args.debug)
# path_c_test is a c file
elif os.path.isfile(full_path) or args.debug:
run_c(full_path, args.iss_yaml, args.isa, args.mabi, args.gcc_opts,
args.iss, output_dir, args.core_setting_dir, args.debug)
else:
logging.error('%s does not exist' % full_path)
sys.exit(RET_FAIL)
@ -729,30 +860,34 @@ def main():
# path_asm_test is a directory
if os.path.isdir(path_asm_test):
run_assembly_from_dir(path_asm_test, args.iss_yaml, args.isa, args.mabi,
gcc_opts, args.iss, output_dir, args.core_setting_dir)
gcc_opts, args.iss, output_dir,
args.core_setting_dir, args.debug)
# path_asm_test is an assembly file
elif os.path.isfile(path_asm_test):
run_assembly(path_asm_test, args.iss_yaml, args.isa, args.mabi, gcc_opts,
args.iss, output_dir, args.core_setting_dir)
args.iss, output_dir, args.core_setting_dir, args.debug)
else:
logging.error('%s does not exist' % path_asm_test)
sys.exit(RET_FAIL)
if not args.debug:
logging.error('%s does not exist' % path_asm_test)
sys.exit(RET_FAIL)
# Run remaining tests using the instruction generator
gen(matched_list, cfg, output_dir, cwd)
if not args.co:
# Compile the assembly program to ELF, convert to plain binary
if args.steps == "all" or re.match(".*gcc_compile.*", args.steps):
gcc_compile(matched_list, output_dir, args.isa, args.mabi, args.gcc_opts)
gcc_compile(matched_list, output_dir, args.isa, args.mabi,
args.gcc_opts, args.debug)
# Run ISS simulation
if args.steps == "all" or re.match(".*iss_sim.*", args.steps):
iss_sim(matched_list, output_dir, args.iss, args.iss_yaml,
args.isa, args.core_setting_dir, args.iss_timeout)
args.isa, args.core_setting_dir, args.iss_timeout, args.debug)
# Compare ISS simulation result
if args.steps == "all" or re.match(".*iss_cmp.*", args.steps):
iss_cmp(matched_list, args.iss, output_dir, args.stop_on_first_error, args.exp)
iss_cmp(matched_list, args.iss, output_dir, args.stop_on_first_error,
args.exp, args.debug)
sys.exit(RET_SUCCESS)
except KeyboardInterrupt:

View file

@ -65,7 +65,7 @@ def read_yaml(yaml_file):
return yaml_data
def get_env_var(var):
def get_env_var(var, debug_cmd = None):
"""Get the value of environment variable
Args:
@ -77,8 +77,11 @@ def get_env_var(var):
try:
val = os.environ[var]
except KeyError:
logging.warning("Please set the environment variable %0s" % var)
sys.exit(RET_FAIL)
if debug_cmd:
return var
else:
logging.warning("Please set the environment variable %0s" % var)
sys.exit(RET_FAIL)
return val
@ -96,7 +99,7 @@ def get_seed(seed):
return random.getrandbits(32)
def run_cmd(cmd, timeout_s = 999, exit_on_error = 1, check_return_code = True):
def run_cmd(cmd, timeout_s = 999, exit_on_error = 1, check_return_code = True, debug_cmd = None):
"""Run a command and return output
Args:
@ -106,6 +109,10 @@ def run_cmd(cmd, timeout_s = 999, exit_on_error = 1, check_return_code = True):
command output
"""
logging.debug(cmd)
if debug_cmd:
debug_cmd.write(cmd)
debug_cmd.write("\n\n")
return
try:
ps = subprocess.Popen("exec " + cmd,
shell=True,
@ -135,7 +142,8 @@ def run_cmd(cmd, timeout_s = 999, exit_on_error = 1, check_return_code = True):
return output
def run_parallel_cmd(cmd_list, timeout_s = 999, exit_on_error = 0, check_return_code = True):
def run_parallel_cmd(cmd_list, timeout_s = 999, exit_on_error = 0,
check_return_code = True, debug_cmd = None):
"""Run a list of commands in parallel
Args:
@ -144,6 +152,11 @@ def run_parallel_cmd(cmd_list, timeout_s = 999, exit_on_error = 0, check_return_
Returns:
command output
"""
if debug_cmd:
for cmd in cmd_list:
debug_cmd.write(cmd)
debug_cmd.write("\n\n")
return
children = []
for cmd in cmd_list:
ps = subprocess.Popen("exec " + cmd,
@ -174,12 +187,16 @@ def run_parallel_cmd(cmd_list, timeout_s = 999, exit_on_error = 0, check_return_
os.system("stty sane")
logging.debug(output)
def run_cmd_output(cmd):
def run_cmd_output(cmd, debug_cmd = None):
"""Run a command and return output
Args:
cmd : Command line to execute
"""
logging.debug(" ".join(cmd))
if debug_cmd:
debug_cmd.write(" ".join(cmd))
debug_cmd.write("\n\n")
return
try:
output = subprocess.check_output(cmd)
except subprocess.CalledProcessError as exc:

View file

@ -0,0 +1,51 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Custom instruction class
class riscv_custom_instr extends riscv_instr;
// TODO: Add custom operands here, example:
// rand riscv_reg_t rs3;
`uvm_object_utils(riscv_custom_instr)
`uvm_object_new
virtual function string get_instr_name();
get_instr_name = instr_name.name();
// TODO: Add custom instruction name encoding here
return get_instr_name;
endfunction : get_instr_name
// Convert the instruction to assembly code
virtual function string convert2asm(string prefix = "");
string asm_str;
asm_str = format_string("nop", MAX_INSTR_STR_LEN);
/* TODO: Convert custom instruction to assembly format. Example:
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
case (instr_name)
CUSTOM_1: asm_str = $sformatf("%0s %0s, (%0s)", asm_str, rd.name(), rs1.name());
CUSTOM_2: asm_str = $sformatf("%0s %0s", asm_str, r3.name());
endcase
*/
comment = {get_instr_name(), " ", comment};
if (comment != "") begin
asm_str = {asm_str, " #",comment};
end
return asm_str.tolower();
endfunction : convert2asm
endclass : riscv_custom_instr

View file

@ -0,0 +1,2 @@
// TODO: Add custom instruction name enum
CUSTOM_1,

View file

@ -0,0 +1,18 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// TODO: Add custom RV32X instruction. Example:
`DEFINE_CUSTOM_INSTR(CUSTOM_1, R_FORMAT, ARITHMETIC, RV32X)

View file

@ -0,0 +1,18 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// TODO: Add custom RV32X instruction. Example:
// `DEFINE_CUSTOM_INSTR(CUSTOM1, R_FORMAT, LOAD, RV64X)

View file

@ -362,6 +362,7 @@ class riscv_asm_program_gen extends uvm_object;
RV32F, RV64F, RV32FC : misa[MISA_EXT_F] = 1'b1;
RV32D, RV64D, RV32DC : misa[MISA_EXT_D] = 1'b1;
RV32V, RV64V : misa[MISA_EXT_V] = 1'b1;
RV32X, RV64X : misa[MISA_EXT_X] = 1'b1;
default : `uvm_fatal(`gfn, $sformatf("%0s is not yet supported",
supported_isa[i].name()))
endcase
@ -820,21 +821,6 @@ class riscv_asm_program_gen extends uvm_object;
for (int i = 1; i < max_interrupt_vector_num; i++) begin
string intr_handler[$];
push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, intr_handler);
// If nested interrupts are enabled, set xSTATUS.xIE in the interrupt handler
// to re-enable interrupt handling capabilities
if (cfg.enable_nested_interrupt) begin
case (status)
MSTATUS: begin
intr_handler.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 8));
end
SSTATUS: begin
intr_handler.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 2));
end
USTATUS: begin
intr_handler.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 1));
end
endcase
end
gen_signature_handshake(.instr(intr_handler), .signature_type(CORE_STATUS), .core_status(HANDLING_IRQ));
intr_handler = {intr_handler,
$sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause.name()),
@ -845,7 +831,7 @@ class riscv_asm_program_gen extends uvm_object;
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(cause));
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(ie));
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(ip));
// Jump to commmon interrupt handling routine
// Jump to commmon interrupt handling routine
intr_handler = {intr_handler,
$sformatf("j %0smode_intr_handler", mode),
"1: j test_done"};
@ -1022,6 +1008,25 @@ class riscv_asm_program_gen extends uvm_object;
end
default: `uvm_fatal(get_full_name(), $sformatf("Unsupported mode: %0s", mode.name()))
endcase
// If nested interrupts are enabled, set xSTATUS.xIE in the interrupt handler
// to re-enable interrupt handling capabilities
if (cfg.enable_nested_interrupt) begin
interrupt_handler_instr.push_back($sformatf("csrr x%0d, 0x%0x", cfg.gpr[0], scratch));
interrupt_handler_instr.push_back($sformatf("bgtz x%0d, 1f", cfg.gpr[0]));
interrupt_handler_instr.push_back($sformatf("csrwi 0x%0x, 0x1", scratch));
case (status)
MSTATUS: begin
interrupt_handler_instr.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 8));
end
SSTATUS: begin
interrupt_handler_instr.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 2));
end
USTATUS: begin
interrupt_handler_instr.push_back($sformatf("csrsi 0x%0x, 0x%0x", status, 1));
end
endcase
interrupt_handler_instr.push_back($sformatf("1: csrwi 0x%0x,0", scratch));
end
// Read back interrupt related privileged CSR
// The value of these CSR are checked by comparing with spike simulation result.
interrupt_handler_instr = {

View file

@ -93,3 +93,8 @@
`define DEFINE_VA_INSTR(instr_n, instr_format, instr_category, instr_group, vav = {}, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_vector_instr; \
`VA_INSTR_BODY(instr_n, instr_format, instr_category, instr_group, vav, imm_tp)
// Custom extension instruction
`define DEFINE_CUSTOM_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_custom_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)

View file

@ -90,7 +90,9 @@ package riscv_instr_pkg;
RV32V,
RV32B,
RV64V,
RV64B
RV64B,
RV32X,
RV64X
} riscv_instr_group_t;
typedef enum {
@ -491,6 +493,8 @@ package riscv_instr_pkg;
SRET,
WFI,
SFENCE_VMA,
// Custom instructions
`include "isa/custom/riscv_custom_instr_enum.sv"
// You can add other instructions here
INVALID_INSTR
} riscv_instr_name_t;
@ -1106,6 +1110,9 @@ package riscv_instr_pkg;
`include "isa/rv64m_instr.sv"
`include "isa/rv128c_instr.sv"
`include "isa/rv32v_instr.sv"
`include "isa/custom/riscv_custom_instr.sv"
`include "isa/custom/rv32x_instr.sv"
`include "isa/custom/rv64x_instr.sv"
`endif
`include "riscv_pseudo_instr.sv"

View file

@ -31,7 +31,7 @@ riscv_instr_name_t unsupported_instr[];
// ISA supported by the processor
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C, RV32A, RV64A,
RV32F, RV64F, RV32D, RV64D};
RV32F, RV64F, RV32D, RV64D, RV32X};
// Interrupt mode support
mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};