Update google_riscv-dv to google/riscv-dv@46ec4bc (#417)

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

* Incorrect deletion (google/riscv-dv#249) (eroom)
* Updated OVPsim log processing for coverage (google/riscv-dv#248)
  (eroom)
* Improve illegal/hint test coverage (google/riscv-dv#247) (taoliug)
* Coverage model fixes (google/riscv-dv#246) (taoliug)
* Add back-to-back jump instruction test (google/riscv-dv#244)
  (taoliug)
* Functional coverage improvement (google/riscv-dv#243) (taoliug)
* Functional coverage improvement (google/riscv-dv#242) (taoliug)
* Support c.jr,c.jalr, fix coverage sampling issues (google/riscv-
  dv#241) (taoliug)
* allow select a random GPR for JALR op (google/riscv-dv#240)
  (taoliug)
* Fix coverage definition/sampling issue (google/riscv-dv#239)
  (taoliug)
* Testlist clean up, add RV32I target (google/riscv-dv#238) (taoliug)
* Consolidate the coverage collection script (google/riscv-dv#234)
  (taoliug)
* Fixed default values, and trailing blank lines (google/riscv-dv#233)
  (eroom)
* Refine README structure (google/riscv-dv#231) (taoliug)
* Add pre-defined target: RV32IMC, RV64IMC (google/riscv-dv#230)
  (taoliug)
This commit is contained in:
udinator 2019-10-23 10:46:31 -07:00 committed by GitHub
parent 023b7b6856
commit c89e431937
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 2113 additions and 666 deletions

View file

@ -3,3 +3,7 @@
out_*/
work/
*.pyc
/.cproject
/.project
/outdir/
ucli.key

View file

@ -41,8 +41,40 @@ setup script, or run only one of the below commands:
2) pip install bitstring
```
### Running the generator
### Setup RISCV-GCC compiler toolchain
- 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)
```
// Sample .bashrc setup
export RISCV_TOOLCHAIN=<riscv_gcc_install_path>
export RISCV_GCC="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-gcc"
export RISCV_OBJCOPY="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-objcopy"
export SPIKE_PATH=$RISCV_TOOLCHAIN/bin
```
### Setup ISS (instruction set simulator)
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
- Install 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
- [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 sail-riscv binary
## Running the generator
A simple script "run.py" is provided for you to run a single test or a regression.
@ -102,25 +134,109 @@ python3 run.py --test riscv_arithmetic_basic_test --co
....
```
### Privileged CSR Test Generation
### Run ISS simulation
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:
You can use -iss to run with different ISS.
```
python3 scripts/gen_csr_test.py --help
// Run ISS with spike
python3 run.py --test riscv_arithmetic_basic_test --iss spike
// Run ISS with riscv-ovpsim
python3 run.py --test riscv_rand_instr_test --iss ovpsim
// Run ISS with sail-riscv
python3 run.py --test riscv_rand_instr_test --iss sail
```
To run with ISS simulation for RV32IMC, you can specify ISA and ABI from command
line like this:
```
// Run a full regression with RV32IMC
python3 run.py --isa rv32imc --mabi ilp32
```
We have added a flow to run ISS simulation with both spike and riscv-ovpsim,
the instruction trace from these runs will be cross compared. This could greatly
speed up your development of new test without the need to simulate against a
real RISC-V processor.
```
python3 run.py --test=riscv_rand_instr_test --iss=spike,ovpsim
python3 run.py --test=riscv_rand_instr_test --iss=spike,sail
```
## Configuration
### Configure the generator to match your processor features
The default configuration of the instruction generator is for **RV64GC** RISC-V
processors with address translation capability. You might want to configure the
generator according the feature of your processor.
The static setting of the processor src/riscv_core_setting.sv
```
// 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};
...
```
A few pre-defined configurations can be found under "target" directory, you can
run with these targets if it matches your processor specification.
```
// Run regression with RV32IMC configuration
python3 run.py --target rv32imc
```
### 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)
```
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)
@ -159,65 +275,6 @@ 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
processors with address translation capability. You might want to configure the
generator according the feature of your processor.
The static setting of the processor src/riscv_core_setting.sv
```
// Bit width of RISC-V GPR
parameter int XLEN = 64;
// Parameter for SATP mode, set to BARE if address translation is not supported
parameter satp_mode_t SATP_MODE = SV39;
// Supported Privileged mode
privileged_mode_t supported_privileged_mode[] = {USER_MODE,
SUPERVISOR_MODE,
MACHINE_MODE};
// Unsupported instructions
riscv_instr_name_t unsupported_instr[] = {};
// ISA supported by the processor
riscv_instr_group_t supported_isa[] = {RV32I, RV32M, RV64I, RV64M};
...
```
### 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)
```
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.
### Runtime options of the generator
@ -296,6 +353,22 @@ format](https://github.com/google/riscv-dv/blob/master/yaml/csr_template.yaml)
To specify what ISA width should be generated in the test, simply include the
matching rv32/rv64/rv128 entry and fill in the appropriate CSR field entries.
### Privileged CSR Test Generation
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:
```
python3 scripts/gen_csr_test.py --help
```
### Adding new instruction stream and test
@ -309,62 +382,7 @@ it with random instructions
+directed_instr_5=riscv_multi_page_load_store_instr_stream,4
```
## Compile generated programs with GCC
- 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)
## Run ISS (Instruction Set Simulator) simulation
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
- Install 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
- [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 sail-riscv binary
You can use -iss to run with different ISS.
```
// Run ISS with spike
python3 run.py --test riscv_arithmetic_basic_test --iss spike
// Run ISS with riscv-ovpsim
python3 run.py --test riscv_rand_instr_test --iss ovpsim
// Run ISS with sail-riscv
python3 run.py --test riscv_rand_instr_test --iss sail
```
To run with ISS simulation for RV32IMC, you can specify ISA and ABI from command
line like this:
```
// Run a full regression with RV32IMC
python3 run.py --isa rv32imc --mabi ilp32
```
We have added a flow to run ISS simulation with both spike and riscv-ovpsim,
the instruction trace from these runs will be cross compared. This could greatly
speed up your development of new test without the need to simulate against a
real RISC-V processor.
```
python3 run.py --test=riscv_rand_instr_test --iss=spike,ovpsim
python3 run.py --test=riscv_rand_instr_test --iss=spike,sail
```
### Integrate a new ISS
## Integrate a new ISS
You can add a new entry in [iss.yaml](https://github.com/google/riscv-dv/blob/master/yaml/iss.yaml)

View file

@ -31,20 +31,23 @@ from scripts.sail_log_to_trace_csv import *
LOGGER = logging.getLogger()
def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, opts, timeout, si):
def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, \
opts, timeout, simulator, simulator_yaml, core_setting_dir):
"""Collect functional coverage from the instruction trace
Args:
log_dir : ISS log directory
out : Output directory
iss : Instruction set simulator
test_list : Testlist of the coverage test
batch_size : Number of trace CSV to process per test
lsf_cmd : LSF command used to run the instruction generator
steps : csv:log to CSV, cov:sample coverage
opts : Additional options to the instruction generator
timeout : Timeout limit in seconds
si : Simulator used to run
log_dir : ISS log directory
out : Output directory
iss : Instruction set simulator
test_list : Testlist of the coverage test
batch_size : Number of trace CSV to process per test
lsf_cmd : LSF command used to run the instruction generator
steps : csv:log to CSV, cov:sample coverage
opts : Additional options to the instruction generator
timeout : Timeout limit in seconds
simulator : RTL simulator used to run
simulator_yaml : RTL simulator configuration file in YAML format
core_setting_dir : Path for riscv_core_setting.sv
"""
log_list = []
csv_list = []
@ -64,15 +67,19 @@ def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, opts, t
logging.info("Process %0s log[%0d/%0d] : %s" % (iss, i+1, len(log_list), log))
if iss == "spike":
process_spike_sim_log(log, csv, 1)
elif iss == "ovpsim":
process_ovpsim_sim_log(log, csv, 1)
else:
logging.error("Full trace for %s is not supported yet" % iss)
sys.exit(1)
if steps == "all" or re.match("cov", steps):
build_cmd = ("python3 run.py -si %s --co -o %s --cov -tl %s %s" %
(si, out, testlist, opts))
base_sim_cmd = ("python3 run.py -si %s --so -o %s --cov -tl %s %s "
build_cmd = ("python3 run.py --simulator %s --simulator_yaml %s "
"--core_setting_dir %s --co -o %s --cov -tl %s %s " %
(simulator, simulator_yaml, core_setting_dir, out, testlist, opts))
base_sim_cmd = ("python3 run.py --simulator %s --simulator_yaml %s "
"--core_setting_dir %s --so -o %s --cov -tl %s %s "
"-tn riscv_instr_cov_test --steps gen --sim_opts \"<trace_csv_opts>\"" %
(si, out, testlist, opts))
(simulator, simulator_yaml, core_setting_dir, out, testlist, opts))
logging.info("Building the coverage collection framework")
run_cmd(build_cmd)
file_idx = 0
@ -107,28 +114,33 @@ def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, opts, t
logging.info("Collecting functional coverage from %0d trace CSV...done" % len(csv_list))
def run_cov_debug_test(out, instr_cnt, testlist, batch_size, opts, lsf_cmd, timeout, si):
def run_cov_debug_test(out, instr_cnt, testlist, batch_size, opts, lsf_cmd,\
timeout, simulator, simulator_yaml, core_setting_dir):
"""Collect functional coverage from the instruction trace
Args:
out : Output directory
instr_cnt : Number of instruction to randomize
test_list : Testlist of the coverage test
batch_size : Number of trace CSV to process per test
lsf_cmd : LSF command used to run the instruction generator
opts : Additional options to the instruction generator
timeout : Timeout limit in seconds
si : Simulator used to run
out : Output directory
instr_cnt : Number of instruction to randomize
test_list : Testlist of the coverage test
batch_size : Number of trace CSV to process per test
lsf_cmd : LSF command used to run the instruction generator
opts : Additional options to the instruction generator
timeout : Timeout limit in seconds
simulator : RTL simulator used to run
simulator_yaml : RTL simulator configuration file in YAML format
core_setting_dir : Path for riscv_core_setting.sv
"""
sim_cmd_list = []
logging.info("Building the coverage collection framework")
build_cmd = ("python3 run.py -si %s --co -o %s --cov -tl %s %s" %
(si, out, testlist, opts))
build_cmd = ("python3 run.py --simulator %s --simulator_yaml %s "
"--core_setting_dir %s --co -o %s --cov -tl %s %s" %
(simulator, simulator_yaml, core_setting_dir, out, testlist, opts))
run_cmd(build_cmd)
base_sim_cmd = ("python3 run.py -si %s --so -o %s --cov -tl %s %s "
base_sim_cmd = ("python3 run.py --simulator %s --simulator_yaml %s "
"--core_setting_dir %s --so -o %s --cov -tl %s %s "
"-tn riscv_instr_cov_debug_test --steps gen "
"--sim_opts \"+num_of_iterations=<instr_cnt>\"" %
(si, out, testlist, opts))
(simulator, simulator_yaml, core_setting_dir, out, testlist, opts))
if batch_size > 0:
batch_cnt = int((instr_cnt+batch_size-1)/batch_size)
logging.info("Batch size: %0d, Batch cnt:%0d" % (batch_size, batch_cnt))
@ -188,8 +200,15 @@ def setup_parser():
parser.add_argument("--lsf_cmd", type=str, default="",
help="LSF command. Run in local sequentially if lsf \
command is not specified")
parser.add_argument("--target", type=str, default="",
help="Run the generator with pre-defined targets: \
rv32imc, rv32i, rv64imc")
parser.add_argument("-si", "--simulator", type=str, default="vcs",
help="Simulator used to run the generator, default VCS", dest="simulator")
parser.add_argument("--simulator_yaml", type=str, default="",
help="RTL simulator setting YAML")
parser.add_argument("-cs", "--core_setting_dir", type=str, default="",
help="Path for the riscv_core_setting.sv")
parser.set_defaults(verbose=False)
parser.set_defaults(debug_mode=False)
return parser
@ -207,6 +226,14 @@ def main():
if not args.testlist:
args.testlist = cwd + "/yaml/cov_testlist.yaml"
if not args.simulator_yaml:
args.simulator_yaml = cwd + "/yaml/simulator.yaml"
if args.target:
args.core_setting_dir = cwd + "/target/"+ args.target
elif not args.core_setting_dir:
args.core_setting_dir = cwd + "/setting/"
# Create output directory
if args.o is None:
output_dir = "out_" + str(date.today())
@ -217,10 +244,12 @@ def main():
if args.debug_mode:
run_cov_debug_test(output_dir, args.instr_cnt, args.testlist,
args.batch_size, args.opts, args.lsf_cmd, args.timeout, args.simulator)
args.batch_size, args.opts, args.lsf_cmd, args.timeout,
args.simulator, args.simulator_yaml, args.core_setting_dir)
else:
collect_cov(args.dir, output_dir, args.iss, args.testlist, args.batch_size,
args.lsf_cmd, args.steps, args.opts, args.timeout, args.simulator)
args.lsf_cmd, args.steps, args.opts, args.timeout,
args.simulator, args.simulator_yaml, args.core_setting_dir)
if __name__ == "__main__":
main()

View file

@ -1 +1,2 @@
coverage save -onexit riscv.ucdb
run -all ; quit

View file

@ -92,7 +92,7 @@ def parse_iss_yaml(iss, iss_yaml, isa):
cmd = entry['cmd'].rstrip()
cmd = re.sub("\<path_var\>", get_env_var(entry['path_var']), cmd)
if iss == "ovpsim":
cmd = re.sub("\<variant\>", isa.upper(), cmd)
cmd = re.sub("\<variant\>", isa, cmd)
else:
cmd = re.sub("\<variant\>", isa, cmd)
return cmd
@ -466,6 +466,9 @@ def setup_parser():
help="Path for the user extension directory")
parser.add_argument("--asm_test", type=str, default="",
help="Directed assembly test")
parser.add_argument("--target", type=str, default="",
help="Run the generator with pre-defined targets: \
rv32imc, rv32i, rv64imc")
parser.add_argument("--log_suffix", type=str, default="",
help="Simulation log name suffix")
parser.add_argument("-bz", "--batch_size", type=int, default=0,
@ -495,7 +498,21 @@ def main():
if not args.simulator_yaml:
args.simulator_yaml = cwd + "/yaml/simulator.yaml"
if not args.testlist:
if args.target:
args.testlist = cwd + "/target/"+ args.target +"/testlist.yaml"
args.core_setting_dir = cwd + "/target/"+ args.target
if args.target == "rv32imc":
args.mabi = "ilp32"
args.isa = "rv32imc"
elif args.target == "rv32i":
args.mabi = "ilp32"
args.isa = "rv32i"
elif args.target == "rv64imc":
args.mabi = "lp64"
args.isa = "rv64imc"
else:
print ("Unsupported target: %0s" % args.target)
elif not args.testlist:
args.testlist = cwd + "/yaml/testlist.yaml"
if args.asm_test != "":

View file

@ -20,15 +20,63 @@ import os
import argparse
import logging
import sys
import pprint as pp
from riscv_trace_csv import *
def process_ovpsim_sim_log(ovpsim_log, csv):
"""Process SPIKE simulation log.
def convert_mode(pri, line):
if "Machine" in pri: return str(3)
logging.info("convert_mode = UNKNOWN PRIV MODE [%s]: %s" % (pri, line))
sys.exit(-1)
REGS = ["zero","ra","sp","gp","tp","t0","t1","t2","s0","s1",
"a0","a1","a2","a3","a4","a5","a6","a7",
"s2","s3","s4","s5","s6","s7","s8","s9","s10","s11",
"t3","t4","t5","t6"]
def process_jalr(trace, operands, gpr):
## jalr x3
## jalr 9(x3)
## jalr x2,x3
## jalr x2,4(x3)
if len(operands) == 1:
trace.rd = 'zero'
trace.rd_val = '0'
m = ADDR_RE.search(operands[0])
if m: # jalr 9(x3)
trace.rs1 = m.group('rs1')
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val(m.group('imm'))
else: # jalr x3
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('0')
elif len(operands) == 2:
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
m = ADDR_RE.search(operands[1])
if m: # jalr x2,4(x3)
trace.rs1 = m.group('rs1')
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val(m.group('imm'))
else: # jalr x2,x3
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('0')
def process_if_compressed(prev_trace):
if len(prev_trace.binary) == 4: # compressed are always 4 hex digits
prev_trace.instr = "c."+prev_trace.instr
# logging.debug("process_if_compressed(%s, %s)" % (prev_trace.instr, prev_trace.binary))
def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 0):
"""Process OVPsim simulation log.
Extract instruction and affected register information from ovpsim simulation
log and save to a list.
"""
logging.info("Processing ovpsim log : %s" % ovpsim_log)
logging.info("Processing ovpsim log [%d]: %s" % (full_trace, ovpsim_log))
instr_cnt = 0
trace_instr = ""
trace_bin = ""
@ -41,33 +89,113 @@ def process_ovpsim_sim_log(ovpsim_log, csv):
cmd = ("sed -i '/ecall/q' %s" % ovpsim_log)
os.system(cmd)
gpr = {}
for g in REGS:
gpr[g] = 0
with open(ovpsim_log, "r") as f, open(csv, "w") as csv_fd:
trace_csv = RiscvInstructiontTraceCsv(csv_fd)
trace_csv.start_new_trace()
prev_trace = 0
for line in f:
# Extract instruction infromation
m = re.search(r"riscvOVPsim.*, 0x(?P<addr>.*?)(?P<section>\(.*\): ?)" \
"(?P<bin>[a-f0-9]*?)\s+(?P<instr>.*?)$", line)
"(?P<mode>[A-Za-z]*?)\s+(?P<bin>[a-f0-9]*?)\s+(?P<instr>.*?)$", line)
if m:
if prev_trace: # if not yet written as it had no data following it
trace_csv.write_trace_entry(prev_trace)
prev_trace = 0
trace_bin = m.group("bin")
trace_instr = m.group("instr")
trace_instr_str = m.group("instr")
trace_addr = m.group("addr")
trace_section = m.group("section") # not yet used
#trace_mode = convert_mode(m.group("mode"), line)
instr_cnt += 1
prev_trace = RiscvInstructiontTraceEntry()
prev_trace.instr_str = trace_instr_str
prev_trace.binary = trace_bin
prev_trace.addr = trace_addr
#prev_trace.privileged_mode = trace_mode
prev_trace.instr = trace_instr # wrong
if 0:
print ("line ::"+line)
print ("bin ::"+trace_bin)
print ("instr::"+trace_instr_str)
print ("ins ::"+trace_instr)
print ("addr ::"+trace_addr)
print ("sect ::"+trace_section)
#print ("mode ::"+prev_trace.privileged_mode)
sys.exit(-1)
if full_trace:
i = re.search (r"(?P<instr>[a-z]*?)\s", trace_instr_str)
if i:
trace_instr = i.group("instr")
if trace_instr_str == "nop" or \
trace_instr_str == "mret" or \
trace_instr_str == "ecall" :
# this will probably need also doing for things like wfi too
trace_instr = trace_instr_str
prev_trace.instr = trace_instr
process_if_compressed(prev_trace)
o = re.search (r"(?P<instr>[a-z]*?)\s(?P<operand>.*)", trace_instr_str)
if o:
operand_str = o.group("operand").replace(" ", "")
operands = operand_str.split(",")
if (prev_trace.instr in ['jalr']):
process_jalr(prev_trace, operands, gpr)
else:
assign_operand(prev_trace, operands, gpr)
# sys.exit(-1)
else:
# print("no operand for [%s] in [%s]" % (trace_instr, trace_instr_str))
pass
else:
trace_instr = ""
else:
if 0:
print ("not ins line... [%s]" % (line))
# Extract register value information
n = re.search(r" (?P<rd>[a-z]{1,3}[0-9]{0,2}?) (?P<pre>[a-f0-9]+?)" \
" -> (?P<val>[a-f0-9]+?)$", line)
if n:
# Write the extracted instruction to a csvcol buffer file
# print("%0s %0s = %0s" % (trace_instr_str, m.group("rd"), m.group("val")))
if n.group("rd") != "frm":
rv_instr_trace = RiscvInstructiontTraceEntry()
rv_instr_trace.rd = n.group("rd")
rv_instr_trace.rd_val = n.group("val")
rv_instr_trace.instr_str = trace_instr
rv_instr_trace.rs1 = prev_trace.rs1
rv_instr_trace.rs1_val = prev_trace.rs1_val
rv_instr_trace.rs2 = prev_trace.rs2
rv_instr_trace.rs2_val = prev_trace.rs2_val
rv_instr_trace.instr_str = trace_instr_str
rv_instr_trace.instr = prev_trace.instr
rv_instr_trace.binary = trace_bin
rv_instr_trace.addr = trace_addr
#rv_instr_trace.privileged_mode = trace_mode
gpr[rv_instr_trace.rd] = rv_instr_trace.rd_val
if full_trace:
rv_instr_trace.instr = prev_trace.instr
trace_csv.write_trace_entry(rv_instr_trace)
prev_trace = 0 # we wrote out as it had data, so no need to write it next time round
if 0:
print ("write entry [[%d]]: rd[%s] val[%s] instr(%s) bin(%s) addr(%s)"
% (instr_cnt, rv_instr_trace.rd, rv_instr_trace.rd_val,
trace_instr_str, trace_bin, trace_addr))
print (rv_instr_trace.__dict__)
sys.exit(-1)
else:
if 0:
print ("write previous entry: [%s] %s " % (str(instr_cnt), line))
sys.exit(-1)
logging.info("Processed instruction count : %d" % instr_cnt)
if instr_cnt == 0:
logging.error ("No Instructions in logfile: %s" % ovpsim_log)
sys.exit(-1)
logging.info("CSV saved to : %s" % csv)
def main():
@ -76,9 +204,16 @@ def main():
parser = argparse.ArgumentParser()
parser.add_argument("--log", type=str, help="Input ovpsim simulation log")
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
parser.add_argument("-f", "--full_trace", dest="full_trace", action="store_true",
help="Generate the full trace")
parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
help="Verbose logging")
parser.set_defaults(full_trace=False)
parser.set_defaults(verbose=False)
args = parser.parse_args()
setup_logging(args.verbose)
# Process ovpsim log
process_ovpsim_sim_log(args.log, args.csv)
process_ovpsim_sim_log(args.log, args.csv, args.full_trace)
if __name__ == "__main__":

View file

@ -17,6 +17,8 @@ Class for RISC-V instruction trace CSV
"""
import csv
import re
import logging
class RiscvInstructiontTraceEntry(object):
"""RISC-V instruction trace entry"""
@ -159,3 +161,293 @@ def gpr_to_abi(gpr):
"f31" : "ft11",
}
return switcher.get(gpr, "na")
def sint_to_hex(val):
"""Signed integer to hex conversion"""
return str(hex((val + (1 << 32)) % (1 << 32)))
def get_imm_hex_val(imm):
"""Get the hex representation of the imm value"""
if imm[0] == '-':
is_negative = 1
imm = imm[1:]
else:
is_negative = 0
if len(imm) > 1 and imm[1] != 'x':
imm = "0x"+imm
imm_val = int(imm, 0)
if is_negative:
imm_val = -imm_val
hexstr = sint_to_hex(imm_val)
return hexstr[2:]
ADDR_RE = re.compile(r"(?P<imm>[\-0-9]+?)\((?P<rs1>.*)\)")
def assign_operand(trace, operands, gpr):
"""Assign the operand value of the instruction trace"""
if trace.instr in ['lb', 'lh', 'lw', 'lbu', 'lhu', 'ld', 'lq', 'lwu', 'ldu',
'c.lw', 'c.ld', 'c.lq', 'c.lwsp', 'c.ldsp', 'c.lqsp']:
# TODO: Support regular load/store format
m = ADDR_RE.search(operands[1])
# Load instruction
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
if m:
trace.imm = get_imm_hex_val(m.group('imm'))
trace.rs1 = m.group('rs1')
trace.rs1_val = gpr[trace.rs1]
else:
logging.info("Unexpected load address %0s", operands[1])
elif trace.instr in ['sb', 'sh', 'sw', 'sd', 'sq', 'c.sw', 'c.sd', 'c.sq',
'c.swsp', 'c.sdsp', 'c.sqsp']:
# Store instruction
m = ADDR_RE.search(operands[1])
# Load instruction
trace.rs2 = operands[0]
trace.rs2_val = gpr[trace.rs2]
if m:
trace.imm = get_imm_hex_val(m.group('imm'))
trace.rs1 = m.group('rs1')
trace.rs1_val = gpr[trace.rs1]
else:
logging.info("Unexpected store address %0s", operands[1])
elif trace.instr in ['mul', 'mulh', 'mulhsu', 'mulhu', 'div', 'divu', 'rem', 'remu',
'mulw', 'muld', 'divw', 'divuw', 'divd', 'remw', 'remd', 'remuw',
'remud', 'sll', 'srl', 'sra', 'add', 'sub', 'xor', 'or', 'and',
'slt', 'sltu', 'sllw', 'slld', 'srlw', 'srld', 'sraw', 'srad',
'addw', 'addd', 'subw', 'subd']:
# R type instruction
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = operands[2]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['c.add', 'c.addw', 'c.mv', 'c.sub', 'c.and', 'c.or', 'c.xor', 'c.subw']:
# CR type
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['c.jr']:
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = 'zero'
trace.rs2_val = '0'
trace.rd = 'zero'
trace.rd_val = '0'
elif trace.instr in ['c.jr', 'c.jalr']:
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = 'zero'
trace.rs2_val = '0'
elif trace.instr in ['slli', 'srli', 'srai', 'addi', 'xori', 'ori', 'andi', 'slti',
'sltiu', 'slliw', 'sllid', 'srliw', 'srlid', 'sraiw', 'sraid',
'addiw', 'addid']:
# I type instruction
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val(operands[2])
elif trace.instr in ['c.addi16sp', 'c.addi4spn']:
trace.rs1 = 'sp'
trace.rs1_val = gpr[trace.rs1]
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.imm = get_imm_hex_val(operands[-1])
elif trace.instr in ['c.addi', 'c.addiw', 'c.li', 'c.lui',
'c.slli', 'c.srai', 'c.srli', 'c.andi']:
# CI/CIW type
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val(operands[-1])
elif trace.instr in ['beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu']:
# SB type instruction
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
trace.imm = get_imm_hex_val(operands[2])
elif trace.instr in ['c.beqz', 'c.bnez']:
# CB type instruction
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['csrrw', 'csrrs', 'csrrc']:
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.csr = operands[1]
trace.rs1 = operands[2]
trace.rs1_val = gpr[trace.rs1]
elif trace.instr in ['csrrwi', 'csrrsi', 'csrrci']:
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.csr = operands[1]
trace.imm = get_imm_hex_val(operands[2])
elif trace.instr in ['scall', 'sbreak', 'fence', 'fence.i', 'ecall', 'ebreak', 'wfi',
'sfence.vma', 'c.ebreak', 'nop', 'c.nop']:
trace.rd = 'zero'
trace.rs1 = 'zero'
trace.rs2 = 'zero'
trace.rd_val = '0'
trace.rs1_val = '0'
trace.rs2_val = '0'
trace.imm = get_imm_hex_val('0')
elif trace.instr in ['lui', 'auipc']:
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['jal']:
if len(operands) == 1:
trace.imm = get_imm_hex_val(operands[0])
else:
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['jalr']:
if len(operands) == 1:
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('0')
else:
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val(operands[2])
elif trace.instr in ['c.j', 'c.jal']:
trace.imm = get_imm_hex_val(operands[0])
# Pseudo instruction convertion below
elif trace.instr in ['mv']:
trace.instr = 'addi'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('0')
elif trace.instr in ['not']:
trace.instr = 'xori'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('-1')
elif trace.instr in ['neg']:
trace.instr = 'sub'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['negw']:
trace.instr = 'subw'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['sext.w']:
trace.instr = 'addiw'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('0')
elif trace.instr in ['seqz']:
trace.instr = 'sltiu'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('1')
elif trace.instr in ['snez']:
trace.instr = 'sltu'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['sltz']:
trace.instr = 'slt'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = 'zero'
trace.rs2_val = '0'
elif trace.instr in ['sgtz']:
trace.instr = 'slt'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['beqz', 'bnez', 'bgez', 'bltz']:
trace.instr = trace.instr[0:3]
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = 'zero'
trace.rs2_val = '0'
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['blez']:
trace.instr = 'bge'
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[0]
trace.rs2_val = gpr[trace.rs2]
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['bgtz']:
trace.instr = 'blt'
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[0]
trace.rs2_val = gpr[trace.rs2]
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['csrr']:
trace.instr = 'csrrw'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.csr = operands[1]
trace.rs1 = 'zero'
trace.rs1_val = '0'
elif trace.instr in ['csrw', 'csrs', 'csrc']:
trace.instr = 'csrr' + trace.instr[-1]
trace.csr = operands[0]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.rd = 'zero'
trace.rd_val = '0'
elif trace.instr in ['csrwi', 'csrsi', 'csrci']:
trace.instr = 'csrr' + trace.instr[-2:]
trace.rd = 'zero'
trace.rd_val = '0'
trace.csr = operands[0]
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['j']:
trace.instr = 'jal'
trace.rd = 'zero'
trace.rd_val = '0'
trace.imm = get_imm_hex_val(operands[0])
elif trace.instr in ['jr']:
trace.instr = 'jal'
trace.rd = 'zero'
trace.rd_val = '0'
trace.rs1 = operands[0]
if trace.rs1 in gpr:
trace.rs1_val = gpr[trace.rs1]
elif trace.instr in ['li']:
trace.instr = 'li'
elif trace.instr[0:2] in ['lr', 'am', 'sc']:
# TODO: Support A-extension
pass
else:
# TODO: Support other instructions
logging.info("Unsupported instr : %s" % trace.instr)

View file

@ -33,7 +33,6 @@ CORE_RE = re.compile(r"core.*0x(?P<addr>[a-f0-9]+?) \(0x(?P<bin>.*?)\) (?P<inst
INSTR_RE = re.compile(r"(?P<instr>[a-z\.0-9]+?)(\s+?)(?P<operand>.*)")
GPR_RE = re.compile(r"^[a-z][0-9a-z]$")
ILLE_RE = re.compile(r"trap_illegal_instruction")
ADDR_RE = re.compile(r"(?P<imm>[\-0-9]+?)\((?P<rs1>.*)\)")
PC_RE = re.compile(r"pc+")
HEX_RE = re.compile(r"^0x")
@ -79,6 +78,8 @@ def process_spike_sim_log(spike_log, csv, full_trace = 0):
if nextline != "":
if ILLE_RE.search(nextline):
if full_trace:
logging.debug("Illegal instruction: %s, opcode:%s" %
(rv_instr_trace.instr_str, rv_instr_trace.binary))
trace_csv.write_trace_entry(rv_instr_trace)
continue
m = RD_RE.search(nextline)
@ -110,272 +111,6 @@ def process_spike_sim_log(spike_log, csv, full_trace = 0):
logging.info("CSV saved to : %s" % csv)
def sint_to_hex(val):
"""Signed integer to hex conversion"""
return str(hex((val + (1 << 32)) % (1 << 32)))
def get_imm_hex_val(imm):
"""Get the hex representation of the imm value"""
if imm[0] == '-':
is_negative = 1
imm = imm[1:]
else:
is_negative = 0
imm_val = int(imm, 0)
if is_negative:
imm_val = -imm_val
hexstr = sint_to_hex(imm_val)
return hexstr[2:]
def assign_operand(trace, operands, gpr):
#logging.debug("-> [%0s] %0s" % (trace.instr, trace.instr_str))
if trace.instr in ['lb', 'lh', 'lw', 'lbu', 'lhu', 'ld', 'lq', 'lwu', 'ldu',
'c.lw', 'c.ld', 'c.lq', 'c.lwsp', 'c.ldsp', 'c.lqsp']:
# TODO: Support regular load/store format
m = ADDR_RE.search(operands[1])
# Load instruction
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
if m:
trace.imm = get_imm_hex_val(m.group('imm'))
trace.rs1 = m.group('rs1')
trace.rs1_val = gpr[trace.rs1]
else:
logging.info("Unexpected load address %0s", operands[1])
elif trace.instr in ['sb', 'sh', 'sw', 'sd', 'sq', 'c.sw', 'c.sd', 'c.sq',
'c.swsp', 'c.sdsp', 'c.sqsp']:
# Store instruction
m = ADDR_RE.search(operands[1])
# Load instruction
trace.rs2 = operands[0]
trace.rs2_val = gpr[trace.rs2]
if m:
trace.imm = get_imm_hex_val(m.group('imm'))
trace.rs1 = m.group('rs1')
trace.rs1_val = gpr[trace.rs1]
else:
logging.info("Unexpected store address %0s", operands[1])
elif trace.instr in ['mul', 'mulh', 'mulhsu', 'mulhu', 'div', 'divu', 'rem', 'remu',
'mulw', 'muld', 'divw', 'divuw', 'divd', 'remw', 'remd', 'remuw',
'remud', 'sll', 'srl', 'sra', 'add', 'sub', 'xor', 'or', 'and',
'slt', 'sltu', 'sllw', 'slld', 'srlw', 'srld', 'sraw', 'srad',
'addw', 'addd', 'subw', 'subd']:
# R type instruction
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = operands[2]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['c.add', 'c.addw', 'c.mv', 'c.sub', 'c.jr', 'c.and', 'c.or',
'c.xor', 'c.subw']:
# CR type
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['slli', 'srli', 'srai', 'addi', 'xori', 'ori', 'andi', 'slti',
'sltiu', 'slliw', 'sllid', 'srliw', 'srlid', 'sraiw', 'sraid',
'addiw', 'addid']:
# I type instruction
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val(operands[2])
elif trace.instr in ['c.addi', 'c.addiw', 'c.addi16sp', 'c.addi4spn', 'c.li', 'c.lui',
'c.slli', 'c.srai', 'c.srli', 'c.andi']:
# CI/CIW type
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.imm = get_imm_hex_val(operands[-1])
elif trace.instr in ['beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu']:
# SB type instruction
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
trace.imm = get_imm_hex_val(operands[2])
elif trace.instr in ['c.beqz', 'c.bnez']:
# CB type instruction
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['csrrw', 'csrrs', 'csrrc']:
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.csr = operands[1]
trace.rs1 = operands[2]
trace.rs1_val = gpr[trace.rs1]
elif trace.instr in ['csrrwi', 'csrrsi', 'csrrci']:
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.csr = operands[1]
trace.imm = get_imm_hex_val(operands[2])
elif trace.instr in ['scall', 'sbreak', 'fence', 'fence.i', 'ecall', 'ebreak', 'wfi',
'sfence.vma', 'c.ebreak', 'nop', 'c.nop']:
trace.rd = 'zero'
trace.rs1 = 'zero'
trace.rs2 = 'zero'
trace.rd_val = '0'
trace.rs1_val = '0'
trace.rs2_val = '0'
trace.imm = get_imm_hex_val('0')
elif trace.instr in ['lui', 'auipc']:
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['jal']:
if len(operands) == 1:
trace.imm = get_imm_hex_val(operands[0])
else:
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['jalr']:
if len(operands) == 1:
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('0')
else:
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val(operands[2])
elif trace.instr in ['c.j', 'c.jal']:
trace.imm = get_imm_hex_val(operands[0])
# Pseudo instruction convertion below
elif trace.instr in ['mv']:
trace.instr = 'addi'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('0')
elif trace.instr in ['not']:
trace.instr = 'xori'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('-1')
elif trace.instr in ['neg']:
trace.instr = 'sub'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
elif trace.instr in ['negw']:
trace.instr = 'subw'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['sext.w']:
trace.instr = 'addiw'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('0')
elif trace.instr in ['seqz']:
trace.instr = 'sltiu'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.imm = get_imm_hex_val('1')
elif trace.instr in ['snez']:
trace.instr = 'sltu'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['sltz']:
trace.instr = 'slt'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = 'zero'
trace.rs2_val = '0'
elif trace.instr in ['sgtz']:
trace.instr = 'slt'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[1]
trace.rs2_val = gpr[trace.rs2]
elif trace.instr in ['beqz', 'bnez', 'bgez', 'bltz']:
trace.instr = trace.instr[0:3]
trace.rs1 = operands[0]
trace.rs1_val = gpr[trace.rs1]
trace.rs2 = 'zero'
trace.rs2_val = '0'
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['blez']:
trace.instr = 'bge'
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[0]
trace.rs2_val = gpr[trace.rs2]
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['bgtz']:
trace.instr = 'blt'
trace.rs1 = 'zero'
trace.rs1_val = '0'
trace.rs2 = operands[0]
trace.rs2_val = gpr[trace.rs2]
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['csrr']:
trace.instr = 'csrrw'
trace.rd = operands[0]
trace.rd_val = gpr[trace.rd]
trace.csr = operands[1]
trace.rs1 = 'zero'
trace.rs1_val = '0'
elif trace.instr in ['csrw', 'csrs', 'csrc']:
trace.instr = 'csrr' + trace.instr[-1]
trace.csr = operands[0]
trace.rs1 = operands[1]
trace.rs1_val = gpr[trace.rs1]
trace.rd = 'zero'
trace.rd_val = '0'
elif trace.instr in ['csrwi', 'csrsi', 'csrci']:
trace.instr = 'csrr' + trace.instr[-2:]
trace.rd = 'zero'
trace.rd_val = '0'
trace.csr = operands[0]
trace.imm = get_imm_hex_val(operands[1])
elif trace.instr in ['j']:
trace.instr = 'jal'
trace.rd = 'zero'
trace.rd_val = '0'
trace.imm = get_imm_hex_val(operands[0])
elif trace.instr in ['jr']:
trace.instr = 'jal'
trace.rd = 'zero'
trace.rd_val = '0'
trace.rs1 = operands[0]
if trace.rs1 in gpr:
trace.rs1_val = gpr[trace.rs1]
elif trace.instr in ['li']:
trace.instr = 'li'
elif trace.instr[0:2] in ['lr', 'am', 'sc']:
# TODO: Support A-extension
pass
else:
# TODO: Support other instructions
logging.info("Unsupported instr : %s" % trace.instr)
def main():
instr_trace = []
# Parse input arguments

View file

@ -35,12 +35,12 @@ class riscv_asm_program_gen extends uvm_object;
// These programs are called in the interrupt/exception handling routine based on the privileged
// mode settings. For example, when the interrupt/exception is delegated to S-mode, if both SUM
// and MPRV equal 1, kernel program can fetch/load/store from U-mode pages,
// smode_accessible_umode_program is designed for this purpose. There can be other cases that
// umode_program is designed for this purpose. There can be other cases that
// instruction can only be fetched from S-mode pages but load/store can access U-mode pages, or
// everything needs to be in S-mode pages.
riscv_instr_sequence smode_accessible_umode_program;
riscv_instr_sequence umode_program;
riscv_instr_sequence smode_program;
riscv_instr_sequence smode_ls_umem_program;
riscv_instr_sequence smode_lsu_program;
riscv_instr_stream directed_instr[];
string instr_stream[$];
riscv_callstack_gen callstack_gen;
@ -141,13 +141,12 @@ class riscv_asm_program_gen extends uvm_object;
instr_stream.push_back(".text");
// Kernel programs
if (cfg.virtual_addr_translation_on) begin
smode_accessible_umode_program = riscv_instr_sequence::type_id::
create("smode_accessible_umode_program");
gen_kernel_program(smode_accessible_umode_program);
umode_program = riscv_instr_sequence::type_id::create("umode_program");
gen_kernel_program(umode_program);
smode_program = riscv_instr_sequence::type_id::create("smode_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);
smode_lsu_program = riscv_instr_sequence::type_id::create("smode_lsu_program");
gen_kernel_program(smode_lsu_program);
end
// All trap/interrupt handling is in the kernel region
// Trap/interrupt delegation to user mode is not supported now
@ -1155,7 +1154,7 @@ class riscv_asm_program_gen extends uvm_object;
end
if($cast(new_instr_stream, object_h)) begin
new_instr_stream.cfg = cfg;
new_instr_stream.label = $sformatf("%0s_instr_%0d", label, idx);
new_instr_stream.label = $sformatf("%0s_%0d", label, idx);
new_instr_stream.kernel_mode = kernel_mode;
`DV_CHECK_RANDOMIZE_FATAL(new_instr_stream)
instr_stream = {instr_stream, new_instr_stream};

View file

@ -85,55 +85,12 @@ class riscv_mem_access_stream extends riscv_directed_instr_stream;
endclass
// Create a infinte zero instruction loop, test if we can interrupt or
// enter debug mode while core is executing this loop
class riscv_infinte_loop_instr extends riscv_directed_instr_stream;
string label_prefix = "";
string label_name;
`uvm_object_utils(riscv_infinte_loop_instr)
constraint instr_c {
foreach(instr_list[i]) {
instr_list[i].imm == 0;
instr_list[i].category inside {JUMP, BRANCH};
instr_list[i].instr_name != JALR;
}
}
function new(string name = "");
super.new(name);
endfunction
function void pre_randomize();
riscv_rand_instr instr;
initialize_instr_list(5);
foreach(instr_list[i]) begin
$cast(instr, instr_list[i]);
instr.constraint_cfg_knob_c.constraint_mode(0);
end
endfunction
function void post_randomize();
foreach(instr_list[i]) begin
label_name = $sformatf("%0s_inf_loop_%0d", label_prefix, i);
instr_list[i].atomic = 1'b1;
instr_list[i].label = label_name;
instr_list[i].imm_str = label_name;
instr_list[i].has_label = 1'b1;
instr_list[i].branch_assigned = 1'b1;
end
endfunction
endclass
// Jump instruction (JAL, JALR)
// la rd0, jump_tagert_label
// addi rd1, offset, rd0
// jalr rd, offset, rd1
// For JAL, restore the stack before doing the jump
class riscv_jump_instr extends riscv_rand_instr_stream;
class riscv_jump_instr extends riscv_directed_instr_stream;
riscv_instr_base jump;
riscv_instr_base addi;
@ -168,8 +125,11 @@ class riscv_jump_instr extends riscv_rand_instr_stream;
riscv_instr_base instr[];
`DV_CHECK_RANDOMIZE_WITH_FATAL(jump,
(use_jalr) -> (instr_name == JALR);
instr_name dist {JAL := 1, JALR := 9};
rd == RA;
instr_name dist {JAL := 2, JALR := 6, C_JALR := 2};
if (cfg.disable_compressed_instr || (cfg.ra != RA)) {
instr_name != C_JALR;
}
rd == cfg.ra;
rs1 == gpr;
)
`DV_CHECK_RANDOMIZE_WITH_FATAL(addi,
@ -198,6 +158,8 @@ class riscv_jump_instr extends riscv_rand_instr_stream;
end
if(jump.instr_name == JAL) begin
jump.imm_str = target_program_label;
end else if (jump.instr_name == C_JALR) begin
instr = {la, instr};
end else begin
instr = {la, addi, instr};
end
@ -215,6 +177,78 @@ class riscv_jump_instr extends riscv_rand_instr_stream;
endfunction
endclass
// Stress back to back jump instruction
class riscv_jal_instr extends riscv_rand_instr_stream;
riscv_instr_base jump[];
riscv_instr_base jump_start;
riscv_instr_base jump_end;
rand int unsigned num_of_jump_instr;
riscv_instr_name_t jal[];
constraint instr_c {
num_of_jump_instr inside {[10:30]};
}
`uvm_object_utils(riscv_jal_instr)
function new(string name = "");
super.new(name);
endfunction
function void post_randomize();
int order[];
order = new[num_of_jump_instr];
jump = new[num_of_jump_instr];
foreach (order[i]) begin
order[i] = i;
end
order.shuffle();
setup_allowed_instr(1, 1);
jal = {JAL};
if (!cfg.disable_compressed_instr) begin
jal = (XLEN == 32) ? {jal, C_J, C_JAL} : {jal, C_J};
end
// First instruction
jump_start = riscv_instr_base::type_id::create("jump_start");
`DV_CHECK_RANDOMIZE_WITH_FATAL(jump_start,
instr_name == JAL;
rd == cfg.ra;
)
jump_start.imm_str = $sformatf("%0df", order[0]);
jump_start.label = label;
// Last instruction
jump_end = riscv_instr_base::type_id::create("jump_end");
randomize_instr(jump_end);
jump_end.label = $sformatf("%0d", num_of_jump_instr);
foreach (jump[i]) begin
jump[i] = riscv_instr_base::type_id::create($sformatf("jump_%0d", i));
`DV_CHECK_RANDOMIZE_WITH_FATAL(jump[i],
instr_name inside {jal};
rd dist {RA := 5, T1 := 2, [SP:T0] :/ 1, [T2:T6] :/ 2};
!(rd inside {cfg.reserved_regs});
)
jump[i].label = $sformatf("%0d", i);
end
foreach (order[i]) begin
if (i == num_of_jump_instr - 1) begin
jump[order[i]].imm_str = $sformatf("%0df", num_of_jump_instr);
end else begin
if (order[i+1] > order[i]) begin
jump[order[i]].imm_str = $sformatf("%0df", order[i+1]);
end else begin
jump[order[i]].imm_str = $sformatf("%0db", order[i+1]);
end
end
end
instr_list = {jump_start, jump, jump_end};
foreach (instr_list[i]) begin
instr_list[i].has_label = 1'b1;
instr_list[i].atomic = 1'b1;
end
endfunction
endclass
// Push stack instruction stream
class riscv_push_stack_instr extends riscv_rand_instr_stream;
@ -235,8 +269,8 @@ class riscv_push_stack_instr extends riscv_rand_instr_stream;
function void init();
// Save RA, T0
reserved_rd = {RA, T0};
saved_regs = {RA, T0};
reserved_rd = {cfg.ra};
saved_regs = {cfg.ra};
num_of_reg_to_save = saved_regs.size();
if(num_of_reg_to_save * (XLEN/8) > stack_len) begin
`uvm_fatal(get_full_name(), $sformatf("stack len [%0d] is not enough to store %d regs",
@ -317,7 +351,7 @@ class riscv_pop_stack_instr extends riscv_rand_instr_stream;
endfunction
function void init();
reserved_rd = {RA, T0};
reserved_rd = {cfg.ra};
num_of_reg_to_save = saved_regs.size();
if(num_of_reg_to_save * 4 > stack_len) begin
`uvm_fatal(get_full_name(), $sformatf("stack len [%0d] is not enough to store %d regs",

View file

@ -25,6 +25,7 @@ class riscv_illegal_instr extends uvm_object;
typedef enum bit [2:0] {
kIllegalOpcode,
kIllegalCompressedOpcode,
kIllegalFunc3,
kIllegalFunc7,
kReservedCompressedInstr,
@ -44,6 +45,15 @@ class riscv_illegal_instr extends uvm_object;
7'b1110011,
7'b1101111};
// Default legal opcode for RV32C instructions
bit [2:0] legal_c00_opcode[$] = '{3'b000,
3'b010,
3'b110};
bit [2:0] legal_c10_opcode[$] = '{3'b000,
3'b010,
3'b100,
3'b110};
rand illegal_instr_type_e exception;
rand bit [31:0] instr_bin;
rand bit [6:0] opcode;
@ -56,6 +66,17 @@ class riscv_illegal_instr extends uvm_object;
rand bit [2:0] c_msb;
riscv_instr_gen_config cfg;
constraint exception_dist_c {
exception dist {
kIllegalOpcode := 4,
kIllegalCompressedOpcode := 1,
kIllegalFunc3 := 1,
kIllegalFunc7 := 1,
kReservedCompressedInstr := 1,
kHintInstr := 3
};
}
constraint instr_bit_assignment_c {
solve opcode before instr_bin;
solve func3 before instr_bin;
@ -76,9 +97,19 @@ class riscv_illegal_instr extends uvm_object;
}
}
constraint legal_rv32_c_slli {
if ((c_msb == 3'b000) && (c_op == 2'b10) && (XLEN == 32)) {
if (exception == kReservedCompressedInstr) {
instr_bin[12] == 1;
} else {
instr_bin[12] == 0;
}
}
}
constraint exception_type_c {
if (compressed) {
exception inside {kReservedCompressedInstr, kHintInstr};
exception inside {kReservedCompressedInstr, kIllegalCompressedOpcode, kHintInstr};
} else {
exception inside {kIllegalOpcode, kIllegalFunc3, kIllegalFunc7};
}
@ -94,14 +125,31 @@ class riscv_illegal_instr extends uvm_object;
c_op != 2'b11;
}
constraint illegal_compressed_op_c {
if (exception == kIllegalCompressedOpcode) {
c_op != 2'b01;
if (legal_c00_opcode.size() == 8) {
c_op != 2'b00;
} else {
!(c_msb inside {legal_c00_opcode});
}
if (legal_c10_opcode.size() == 8) {
c_op != 2'b10;
} else {
!(c_msb inside {legal_c10_opcode});
}
}
}
constraint reserved_compressed_instr_c {
if (exception == kReservedCompressedInstr) {
((instr_bin[15:5] == '0) && (c_op == 2'b00)) ||
((c_msb == 3'b100) && (c_op == 2'b00)) ||
((instr_bin[15:10] == 6'b100111) && (instr_bin[6:5] == 2'b10) && (c_op == 2'b01)) ||
((instr_bin[15:10] == 6'b100111) && (instr_bin[6:5] == 2'b11) && (c_op == 2'b01)) ||
((c_msb == 3'b001) && (c_op == 2'b01) && (instr_bin[11:7] == 5'b0) && (XLEN == 64)) ||
((c_msb == 3'b011) && (c_op == 2'b01) && (instr_bin[12:2] == 11'h40)) ||
// C_LUI, imm = 0
((c_msb == 3'b011) && (c_op == 2'b01) && !instr_bin[12] && (instr_bin[6:2] == 0)) ||
((c_msb == 3'b001) && (c_op == 2'b10) && (instr_bin[11:7] == 5'b0)) ||
((c_msb == 3'b010) && (c_op == 2'b10) && (instr_bin[11:7] == 5'b0)) ||
((c_msb == 3'b011) && (c_op == 2'b10) && (instr_bin[11:7] == 5'b0)) ||
@ -118,6 +166,9 @@ class riscv_illegal_instr extends uvm_object;
// C.SRAI64, C.SRLI64
((c_msb == 3'b100) && (c_op == 2'b01) && (instr_bin[12:11] == 2'b00) &&
(instr_bin[6:2] == 5'b0)) ||
// C.MV
((c_msb == 3'b100) && (c_op == 2'b10) && (instr_bin[11:7] == 0) &&
(instr_bin[6:2] != 0)) ||
// C.LUI
((c_msb == 3'b011) && (c_op == 2'b01) && (instr_bin[11:7] == 5'b0) &&
({instr_bin[12], instr_bin[6:2]} != 6'b0)) ||
@ -133,6 +184,7 @@ class riscv_illegal_instr extends uvm_object;
}
constraint illegal_opcode_c {
solve opcode before instr_bin;
if (exception == kIllegalOpcode) {
!(opcode inside {legal_opcode});
opcode[1:0] == 2'b11;
@ -233,6 +285,10 @@ class riscv_illegal_instr extends uvm_object;
riscv_instr_pkg::RV64M inside {riscv_instr_pkg::supported_isa}) begin
legal_opcode = {legal_opcode, 7'b0111011};
end
if (riscv_instr_pkg::RV64I inside {riscv_instr_pkg::supported_isa}) begin
legal_c00_opcode = {legal_c00_opcode, 3'b011, 3'b111};
legal_c10_opcode = {legal_c10_opcode, 3'b011, 3'b111};
end
endfunction
function string get_bin_str();

View file

@ -132,16 +132,6 @@ class riscv_instr_base extends uvm_object;
}
}
// Registers specified by the three-bit rs1, rs2, and rd fields of the CIW, CL, CS,
// and CB formats
constraint compressed_three_bits_csr_c {
if(format inside {CIW_FORMAT, CL_FORMAT, CS_FORMAT, CB_FORMAT}) {
rs1 inside {[S0:A5]};
rs2 inside {[S0:A5]};
rd inside {[S0:A5]};
}
}
// Cannot shift more than the width of the bus
constraint shift_imm_val_c {
solve category before imm;
@ -177,16 +167,21 @@ class riscv_instr_base extends uvm_object;
}
constraint rvc_csr_c {
// Registers specified by the three-bit rs1, rs2, and rd fields of the CIW, CL, CS,
// and CB formats
if(format inside {CIW_FORMAT, CL_FORMAT, CS_FORMAT, CB_FORMAT}) {
// Registers specified by the three-bit rs1, rs2, and rd
if(format inside {CIW_FORMAT, CL_FORMAT, CS_FORMAT, CB_FORMAT, CA_FORMAT}) {
rs1 inside {[S0:A5]};
rs2 inside {[S0:A5]};
rd inside {[S0:A5]};
}
// C_ADDI16SP is only valid when rd == SP
if(instr_name == C_ADDI16SP) {
rd == SP;
rd == SP;
rs1 == SP;
}
if(instr_name inside {C_JR, C_JALR}) {
rs2 == ZERO;
rs1 != ZERO;
}
}
@ -363,21 +358,21 @@ class riscv_instr_base extends uvm_object;
// RV32IC
`add_instr(C_LW, CL_FORMAT, LOAD, RV32C, UIMM)
`add_instr(C_SW, CS_FORMAT, STORE, RV32C, UIMM)
`add_instr(C_LWSP, CI_FORMAT, LOAD, RV64C, UIMM)
`add_instr(C_SWSP, CSS_FORMAT, STORE, RV64C, UIMM)
`add_instr(C_LWSP, CI_FORMAT, LOAD, RV32C, UIMM)
`add_instr(C_SWSP, CSS_FORMAT, STORE, RV32C, UIMM)
`add_instr(C_ADDI4SPN, CIW_FORMAT, ARITHMETIC, RV32C, NZUIMM)
`add_instr(C_ADDI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM)
`add_instr(C_ADDI16SP, CI_FORMAT, ARITHMETIC, RV32C, NZIMM)
`add_instr(C_LI, CI_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_LUI, CI_FORMAT, ARITHMETIC, RV32C, NZUIMM)
`add_instr(C_SUB, CS_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_SUB, CA_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_ADD, CR_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_NOP, CI_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_MV, CR_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_ANDI, CB_FORMAT, LOGICAL, RV32C)
`add_instr(C_XOR, CS_FORMAT, LOGICAL, RV32C)
`add_instr(C_OR, CS_FORMAT, LOGICAL, RV32C)
`add_instr(C_AND, CS_FORMAT, LOGICAL, RV32C)
`add_instr(C_XOR, CA_FORMAT, LOGICAL, RV32C)
`add_instr(C_OR, CA_FORMAT, LOGICAL, RV32C)
`add_instr(C_AND, CA_FORMAT, LOGICAL, RV32C)
`add_instr(C_BEQZ, CB_FORMAT, BRANCH, RV32C)
`add_instr(C_BNEZ, CB_FORMAT, BRANCH, RV32C)
`add_instr(C_SRLI, CB_FORMAT, SHIFT, RV32C, NZUIMM)
@ -391,8 +386,8 @@ class riscv_instr_base extends uvm_object;
// RV64C
`add_instr(C_ADDIW, CI_FORMAT, ARITHMETIC, RV64C)
`add_instr(C_SUBW, CS_FORMAT, ARITHMETIC, RV64C)
`add_instr(C_ADDW, CS_FORMAT, ARITHMETIC, RV64C)
`add_instr(C_SUBW, CA_FORMAT, ARITHMETIC, RV64C)
`add_instr(C_ADDW, CA_FORMAT, ARITHMETIC, RV64C)
`add_instr(C_LD, CL_FORMAT, LOAD, RV64C, UIMM)
`add_instr(C_SD, CS_FORMAT, STORE, RV64C, UIMM)
`add_instr(C_LDSP, CI_FORMAT, LOAD, RV64C, UIMM)
@ -461,10 +456,14 @@ class riscv_instr_base extends uvm_object;
update_imm_str();
end
end
if (format inside {R_FORMAT, S_FORMAT, B_FORMAT, CSS_FORMAT, CS_FORMAT, CR_FORMAT}) begin
if (format inside {R_FORMAT, S_FORMAT, B_FORMAT, CSS_FORMAT,
CS_FORMAT, CR_FORMAT, CA_FORMAT}) begin
has_rs2 = 1'b1;
end
if (!(format inside {J_FORMAT, U_FORMAT, CJ_FORMAT, CSS_FORMAT, CR_FORMAT, CI_FORMAT})) begin
if (!(format inside {J_FORMAT, U_FORMAT, CJ_FORMAT, CSS_FORMAT,
CA_FORMAT, CR_FORMAT, CI_FORMAT})) begin
has_rs1 = 1'b1;
end else if (instr_name inside {C_JR, C_JALR}) begin
has_rs1 = 1'b1;
end
if (!(format inside {CJ_FORMAT, CB_FORMAT, CS_FORMAT, CSS_FORMAT, B_FORMAT, S_FORMAT})) begin
@ -557,18 +556,24 @@ class riscv_instr_base extends uvm_object;
riscv_reg_t legal_gpr[$];
if (included_reg.size() > 0) begin
legal_gpr = included_reg;
while (is_compressed && (i < legal_gpr.size())) begin
if (legal_gpr[i] < S0 || legal_gpr[i] > A5) begin
legal_gpr.delete(i);
end else begin
i++;
if (is_compressed && !(format inside {CR_FORMAT, CI_FORMAT, CSS_FORMAT})) begin
while (i < legal_gpr.size()) begin
if (legal_gpr[i] < S0 || legal_gpr[i] > A5) begin
legal_gpr.delete(i);
end else begin
i++;
end
end
end
end else if (is_compressed) begin
end else if (is_compressed &&
!(format inside {CR_FORMAT, CI_FORMAT, CSS_FORMAT})) begin
legal_gpr = riscv_instr_pkg::compressed_gpr;
end else begin
legal_gpr = riscv_instr_pkg::all_gpr;
end
if (format inside {CR_FORMAT, CI_FORMAT}) begin
excluded_reg = {excluded_reg, ZERO};
end
if (excluded_reg.size() > 0) begin
i = 0;
while (i < legal_gpr.size()) begin
@ -710,6 +715,8 @@ class riscv_instr_base extends uvm_object;
CI_FORMAT, CIW_FORMAT:
if(instr_name == C_NOP)
asm_str = "c.nop";
else if(instr_name == C_ADDI16SP)
asm_str = $sformatf("%0ssp, %0s", asm_str, get_imm());
else
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm());
CL_FORMAT:
@ -719,12 +726,18 @@ class riscv_instr_base extends uvm_object;
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name());
else
asm_str = $sformatf("%0s%0s, %0s", asm_str, rs1.name(), rs2.name());
CA_FORMAT:
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name());
CB_FORMAT:
asm_str = $sformatf("%0s%0s, %0s", asm_str, rs1.name(), get_imm());
CSS_FORMAT:
asm_str = $sformatf("%0s%0s, %0s", asm_str, rs2.name(), get_imm());
CR_FORMAT:
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name());
if (instr_name inside {C_JR, C_JALR}) begin
asm_str = $sformatf("%0s%0s", asm_str, rs1.name());
end else begin
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name());
end
CJ_FORMAT:
asm_str = $sformatf("%0s%0s", asm_str, get_imm());
endcase
@ -738,7 +751,7 @@ class riscv_instr_base extends uvm_object;
// For EBREAK,C.EBREAK, making sure pc+4 is a valid instruction boundary
// This is needed to resume execution from epc+4 after ebreak handling
if(instr_name == EBREAK) begin
asm_str = ".option norvc;ebreak;.option rvc;";
asm_str = ".4byte 0x00100073 # ebreak";
end else if(instr_name == C_EBREAK) begin
asm_str = "c.ebreak;c.nop;";
end

View file

@ -67,7 +67,7 @@ class riscv_instr_cov_item extends riscv_instr_base;
if (category inside {LOAD, STORE}) begin
unaligned_mem_access = is_unaligned_mem_access();
if (unaligned_mem_access) begin
`uvm_info(`gfn, $sformatf("Unaligned: %0s, mem_addr:%0x", instr_name.name(), mem_addr), UVM_LOW)
`uvm_info(`gfn, $sformatf("Unaligned: %0s, mem_addr:%0x", instr_name.name(), mem_addr), UVM_HIGH)
end
end
if (category == LOGICAL) begin

View file

@ -26,7 +26,7 @@
cp_rs1_sign : coverpoint instr.rs1_sign; \
cp_rs2_sign : coverpoint instr.rs2_sign; \
cp_rd_sign : coverpoint instr.rd_sign; \
cp_gpr_harzard : coverpoint instr.gpr_hazard; \
cp_gpr_hazard : coverpoint instr.gpr_hazard; \
`define CMP_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
@ -34,7 +34,7 @@
cp_rd : coverpoint instr.rd; \
cp_rs1_sign : coverpoint instr.rs1_sign; \
cp_result : coverpoint instr.rd_value[0]; \
cp_gpr_harzard : coverpoint instr.gpr_hazard; \
cp_gpr_hazard : coverpoint instr.gpr_hazard; \
`define SB_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
@ -44,30 +44,34 @@
cp_rs2_sign : coverpoint instr.rs2_sign; \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_branch_hit : coverpoint instr.branch_hit; \
cp_sign_cross : cross cp_rs1_sign, cp_rs2_sign, cp_imm_sign; \
cp_gpr_harzard : coverpoint instr.gpr_hazard { \
cp_sign_cross : cross cp_rs1_sign, cp_rs2_sign; \
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
}
`define STORE_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rs1 : coverpoint instr.rs1; \
cp_rs1 : coverpoint instr.rs1 { \
ignore_bins zero = {ZERO}; \
} \
cp_rs2 : coverpoint instr.rs2; \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_gpr_harzard : coverpoint instr.gpr_hazard { \
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
} \
cp_lsu_harzard : coverpoint instr.lsu_hazard { \
cp_lsu_hazard : coverpoint instr.lsu_hazard { \
bins valid_hazard[] = {NO_HAZARD, WAR_HAZARD, WAW_HAZARD}; \
}
`define LOAD_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rs1 : coverpoint instr.rs1; \
cp_rs1 : coverpoint instr.rs1 { \
ignore_bins zero = {ZERO}; \
} \
cp_rd : coverpoint instr.rd; \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_gpr_harzard : coverpoint instr.gpr_hazard; \
cp_lsu_harzard : coverpoint instr.lsu_hazard { \
cp_gpr_hazard : coverpoint instr.gpr_hazard; \
cp_lsu_hazard : coverpoint instr.lsu_hazard { \
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
}
@ -78,41 +82,39 @@
cp_rs1_sign : coverpoint instr.rs1_sign; \
cp_rd_sign : coverpoint instr.rd_sign; \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_gpr_harzard : coverpoint instr.gpr_hazard;
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`define U_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rd : coverpoint instr.rd; \
cp_rd_sign : coverpoint instr.rd_sign; \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_gpr_harzard : coverpoint instr.gpr_hazard;
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`define J_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_imm_lsb : coverpoint instr.imm[1:0]; \
cp_rd : coverpoint instr.rd; \
cp_rd_align : coverpoint instr.rd_value[1];
`define CSR_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rs1 : coverpoint instr.rs1; \
cp_rd : coverpoint instr.rd; \
cp_gpr_harzard : coverpoint instr.gpr_hazard;
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`define CR_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rs2 : coverpoint instr.rs2; \
cp_rd : coverpoint instr.rd; \
cp_rs2_sign : coverpoint instr.rs2_sign; \
cp_gpr_harzard : coverpoint instr.gpr_hazard;
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`define CI_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rd : coverpoint instr.rd; \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_gpr_harzard : coverpoint instr.gpr_hazard { \
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
bins valid_hazard[] = {NO_HAZARD, WAR_HAZARD, WAW_HAZARD}; \
}
@ -121,7 +123,7 @@
cp_rs2 : coverpoint instr.rs2; \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_rs2_sign : coverpoint instr.rs2_sign; \
cp_gpr_harzard : coverpoint instr.gpr_hazard { \
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
}
@ -129,50 +131,69 @@
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_rd : coverpoint instr.rd { \
bins gpr[] = cp_rd with (is_compressed_gpr(riscv_reg_t'(item))); \
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
} \
cp_gpr_harzard : coverpoint instr.gpr_hazard { \
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
bins valid_hazard[] = {NO_HAZARD, WAR_HAZARD, WAW_HAZARD}; \
}
`define CL_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_rs1 : coverpoint instr.rs1 { \
bins gpr[] = cp_rs1 with (is_compressed_gpr(riscv_reg_t'(item))); \
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
} \
cp_rd : coverpoint instr.rd { \
bins gpr[] = cp_rd with (is_compressed_gpr(riscv_reg_t'(item))); \
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
} \
cp_gpr_harzard : coverpoint instr.gpr_hazard; \
cp_lsu_harzard : coverpoint instr.lsu_hazard { \
cp_gpr_hazard : coverpoint instr.gpr_hazard; \
cp_lsu_hazard : coverpoint instr.lsu_hazard { \
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
}
`define CL_SP_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rd : coverpoint instr.rd { \
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
}
`define CS_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_rs1 : coverpoint instr.rs1 { \
bins gpr[] = cp_rs1 with (is_compressed_gpr(riscv_reg_t'(item))); \
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
} \
cp_rs2 : coverpoint instr.rs2 { \
bins gpr[] = cp_rs2 with (is_compressed_gpr(riscv_reg_t'(item))); \
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
} \
cp_gpr_harzard : coverpoint instr.gpr_hazard { \
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
} \
cp_lsu_harzard : coverpoint instr.lsu_hazard { \
cp_lsu_hazard : coverpoint instr.lsu_hazard { \
bins valid_hazard[] = {NO_HAZARD, WAR_HAZARD, WAW_HAZARD}; \
}
`define CS_SP_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rs2 : coverpoint instr.rs2 { \
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
}
`define CA_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rd : coverpoint instr.rd { \
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
} \
cp_rs2 : coverpoint instr.rs2 { \
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
} \
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`define CB_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_imm_sign : coverpoint instr.imm_sign; \
cp_rs1 : coverpoint instr.rs1 { \
bins gpr[] = cp_rs1 with (is_compressed_gpr(riscv_reg_t'(item))); \
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
} \
cp_gpr_harzard : coverpoint instr.gpr_hazard { \
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
}
@ -208,11 +229,9 @@ class riscv_instr_cover_group;
`CG_END
`U_INSTR_CG_BEGIN(lui)
cp_sign_cross: cross cp_imm_sign, cp_rd_sign;
`CG_END
`U_INSTR_CG_BEGIN(auipc)
cp_sign_cross: cross cp_imm_sign, cp_rd_sign;
`CG_END
// Shift instructions
@ -233,7 +252,7 @@ class riscv_instr_cover_group;
cp_rd : coverpoint instr.rd;
cp_rs1_sign : coverpoint instr.rs1_sign;
cp_rd_sign : coverpoint instr.rd_sign;
cp_gpr_harzard : coverpoint instr.gpr_hazard;
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`CG_END
`INSTR_CG_BEGIN(slli)
@ -241,7 +260,7 @@ class riscv_instr_cover_group;
cp_rd : coverpoint instr.rd;
cp_rs1_sign : coverpoint instr.rs1_sign;
cp_rd_sign : coverpoint instr.rd_sign;
cp_gpr_harzard : coverpoint instr.gpr_hazard;
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`CG_END
`INSTR_CG_BEGIN(srli)
@ -249,7 +268,7 @@ class riscv_instr_cover_group;
cp_rd : coverpoint instr.rd;
cp_rs1_sign : coverpoint instr.rs1_sign;
cp_rd_sign : coverpoint instr.rd_sign;
cp_gpr_harzard : coverpoint instr.gpr_hazard;
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`CG_END
// Logical instructions
@ -361,33 +380,39 @@ class riscv_instr_cover_group;
`CG_END
`J_INSTR_CG_BEGIN(jalr)
cp_rs1_eq_rd : coverpoint instr.rs1 iff (instr.rs1 == instr.rd);
cp_rs1_ne_rd : coverpoint instr.rs1 iff (instr.rs1 != instr.rd);
cp_rs1_link : coverpoint instr.rs1 {
bins ra = {RA};
bins t1 = {T1};
bins non_link = default;
}
cp_rd_link : coverpoint instr.rd {
bins ra = {RA};
bins t1 = {T1};
bins non_link = default;
}
cp_ras : cross cp_rs1_link, cp_rd_link;
`CG_END
// CSR instructions
`CSR_INSTR_CG_BEGIN(csrrw)
cp_rs2 : coverpoint instr.rs1;
cp_rs1 : coverpoint instr.rs1;
`CG_END
`CSR_INSTR_CG_BEGIN(csrrs)
cp_rs2 : coverpoint instr.rs1;
cp_rs1 : coverpoint instr.rs1;
`CG_END
`CSR_INSTR_CG_BEGIN(csrrc)
cp_rs2 : coverpoint instr.rs1;
cp_rs1 : coverpoint instr.rs1;
`CG_END
`CSR_INSTR_CG_BEGIN(csrrwi)
cp_imm_sign : coverpoint instr.imm_sign;
`CG_END
`CSR_INSTR_CG_BEGIN(csrrsi)
cp_imm_sign : coverpoint instr.imm_sign;
`CG_END
`CSR_INSTR_CG_BEGIN(csrrci)
cp_imm_sign : coverpoint instr.imm_sign;
`CG_END
covergroup rv32i_misc_cg with function sample(riscv_instr_cov_item instr);
@ -521,7 +546,7 @@ class riscv_instr_cover_group;
cp_rd : coverpoint instr.rd;
cp_rs1_sign : coverpoint instr.rs1_sign;
cp_rd_sign : coverpoint instr.rd_sign;
cp_gpr_harzard : coverpoint instr.gpr_hazard;
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`CG_END
`INSTR_CG_BEGIN(slliw)
@ -529,7 +554,7 @@ class riscv_instr_cover_group;
cp_rd : coverpoint instr.rd;
cp_rs1_sign : coverpoint instr.rs1_sign;
cp_rd_sign : coverpoint instr.rd_sign;
cp_gpr_harzard : coverpoint instr.gpr_hazard;
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`CG_END
`INSTR_CG_BEGIN(srliw)
@ -537,7 +562,7 @@ class riscv_instr_cover_group;
cp_rd : coverpoint instr.rd;
cp_rs1_sign : coverpoint instr.rs1_sign;
cp_rd_sign : coverpoint instr.rd_sign;
cp_gpr_harzard : coverpoint instr.gpr_hazard;
cp_gpr_hazard : coverpoint instr.gpr_hazard;
`CG_END
`R_INSTR_CG_BEGIN(addw)
@ -557,13 +582,13 @@ class riscv_instr_cover_group;
`CL_INSTR_CG_BEGIN(c_lw)
`CG_END
`CL_INSTR_CG_BEGIN(c_lwsp)
`CL_SP_INSTR_CG_BEGIN(c_lwsp)
`CG_END
`CS_INSTR_CG_BEGIN(c_sw)
`CG_END
`CS_INSTR_CG_BEGIN(c_swsp)
`CS_SP_INSTR_CG_BEGIN(c_swsp)
`CG_END
`CIW_INSTR_CG_BEGIN(c_addi4spn)
@ -572,16 +597,23 @@ class riscv_instr_cover_group;
`CI_INSTR_CG_BEGIN(c_addi)
`CG_END
`CI_INSTR_CG_BEGIN(c_addi16sp)
`INSTR_CG_BEGIN(c_addi16sp)
cp_imm_sign : coverpoint instr.imm_sign;
cp_gpr_hazard : coverpoint instr.gpr_hazard {
bins valid_hazard[] = {NO_HAZARD, WAR_HAZARD, WAW_HAZARD};
}
`CG_END
`CI_INSTR_CG_BEGIN(c_li)
`CG_END
`CI_INSTR_CG_BEGIN(c_lui)
`INSTR_CG_BEGIN(c_lui)
cp_rd : coverpoint instr.rd {
ignore_bins bin = {ZERO, SP};
}
`CG_END
`CS_INSTR_CG_BEGIN(c_sub)
`CA_INSTR_CG_BEGIN(c_sub)
`CG_END
`CR_INSTR_CG_BEGIN(c_add)
@ -591,46 +623,35 @@ class riscv_instr_cover_group;
`CG_END
`CB_INSTR_CG_BEGIN(c_andi)
cp_imm_sign : coverpoint instr.imm_sign;
`CG_END
`CS_INSTR_CG_BEGIN(c_xor)
`CA_INSTR_CG_BEGIN(c_xor)
`CG_END
`CS_INSTR_CG_BEGIN(c_or)
`CA_INSTR_CG_BEGIN(c_or)
`CG_END
`CS_INSTR_CG_BEGIN(c_and)
`CA_INSTR_CG_BEGIN(c_and)
`CG_END
`CB_INSTR_CG_BEGIN(c_beqz)
cp_imm_sign : coverpoint instr.imm_sign;
`CG_END
`CB_INSTR_CG_BEGIN(c_bnez)
cp_imm_sign : coverpoint instr.imm_sign;
`CG_END
`INSTR_CG_BEGIN(c_srli)
cp_rs1 : coverpoint instr.rs1 {
bins gpr[] = cp_rs1 with (is_compressed_gpr(riscv_reg_t'(item)));
}
cp_gpr_harzard : coverpoint instr.gpr_hazard {
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD};
}
`CB_INSTR_CG_BEGIN(c_srli)
`CG_END
`INSTR_CG_BEGIN(c_srai)
cp_rs1 : coverpoint instr.rs1 {
bins gpr[] = cp_rs1 with (is_compressed_gpr(riscv_reg_t'(item)));
}
cp_gpr_harzard : coverpoint instr.gpr_hazard {
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD};
}
`CB_INSTR_CG_BEGIN(c_srai)
`CG_END
`INSTR_CG_BEGIN(c_slli)
cp_rs1 : coverpoint instr.rs1 {
bins gpr[] = cp_rs1 with (is_compressed_gpr(riscv_reg_t'(item)));
}
cp_gpr_harzard : coverpoint instr.gpr_hazard {
cp_rd : coverpoint instr.rd;
cp_gpr_hazard : coverpoint instr.gpr_hazard {
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD};
}
`CG_END
@ -641,10 +662,17 @@ class riscv_instr_cover_group;
`CJ_INSTR_CG_BEGIN(c_jal)
`CG_END
`CR_INSTR_CG_BEGIN(c_jr)
`INSTR_CG_BEGIN(c_jr)
cp_rs1 : coverpoint instr.rs1 {
ignore_bins zero = {ZERO};
}
`CG_END
`CR_INSTR_CG_BEGIN(c_jalr)
`INSTR_CG_BEGIN(c_jalr)
cp_rs1 : coverpoint instr.rs1 {
ignore_bins zero = {ZERO};
}
cp_rd_align : coverpoint instr.rd_value[1];
`CG_END
// RV64C
@ -652,22 +680,22 @@ class riscv_instr_cover_group;
`CL_INSTR_CG_BEGIN(c_ld)
`CG_END
`CL_INSTR_CG_BEGIN(c_ldsp)
`CL_SP_INSTR_CG_BEGIN(c_ldsp)
`CG_END
`CS_INSTR_CG_BEGIN(c_sd)
`CG_END
`CS_INSTR_CG_BEGIN(c_sdsp)
`CS_SP_INSTR_CG_BEGIN(c_sdsp)
`CG_END
`CI_INSTR_CG_BEGIN(c_addiw)
`CG_END
`CS_INSTR_CG_BEGIN(c_subw)
`CA_INSTR_CG_BEGIN(c_subw)
`CG_END
`CR_INSTR_CG_BEGIN(c_addw)
`CA_INSTR_CG_BEGIN(c_addw)
`CG_END
`INSTR_CG_BEGIN(hint)
@ -697,10 +725,9 @@ class riscv_instr_cover_group;
`CG_END
// Cover all illegal instruction
covergroup illegal_cg with function sample(bit [31:0] binary);
covergroup illegal_compressed_instr_cg with function sample(bit [31:0] binary);
cp_point : coverpoint binary {
wildcard bins c_addi4spn = {32'bxxxx_xxxxx_0000_0000_000x_xx00};
wildcard bins c_addiw = {32'bxxxx_xxxxx_001x_0000_0xxx_xx01};
wildcard bins c_addi16sp = {32'bxxxx_xxxxx_0110_0001_0000_0001};
wildcard bins c_lui = {32'bxxxx_xxxxx_0110_xxxx_1000_0001,
32'bxxxx_xxxxx_0110_xx1x_x000_0001,
@ -766,7 +793,7 @@ class riscv_instr_cover_group;
}
endgroup
covergroup mepc_cg with function sample(bit [XLEN-1:0] val);
covergroup mepc_alignment_cg with function sample(bit [XLEN-1:0] val);
cp_align: coverpoint val[1:0] {
bins alignment[] = {2'b00, 2'b10};
}
@ -783,7 +810,6 @@ class riscv_instr_cover_group;
cur_instr = riscv_instr_cov_item::type_id::create("cur_instr");
pre_instr = riscv_instr_cov_item::type_id::create("pre_instr");
build_instr_list();
hint_cg = new();
// RV32I instruction functional coverage instantiation
add_cg = new();
sub_cg = new();
@ -831,9 +857,14 @@ class riscv_instr_cover_group;
// instr_trans_cg = new();
branch_hit_history_cg = new();
rv32i_misc_cg = new();
illegal_cg = new();
if (!cfg.disable_compressed_instr) begin
illegal_compressed_instr_cg = new();
end
opcode_cg = new();
compressed_opcode_cg = new();
if (RV32C inside {supported_isa}) begin
compressed_opcode_cg = new();
hint_cg = new();
end
if (RV32M inside {supported_isa}) begin
mul_cg = new();
mulh_cg = new();
@ -842,6 +873,7 @@ class riscv_instr_cover_group;
div_cg = new();
divu_cg = new();
rem_cg = new();
remu_cg = new();
end
if (RV64M inside {supported_isa}) begin
mulw_cg = new();
@ -890,7 +922,9 @@ class riscv_instr_cover_group;
c_srai_cg = new();
c_slli_cg = new();
c_j_cg = new();
c_jal_cg = new();
if (XLEN == 32) begin
c_jal_cg = new();
end
c_jr_cg = new();
c_jalr_cg = new();
end
@ -906,7 +940,9 @@ class riscv_instr_cover_group;
privileged_csr_cg = new();
mcause_exception_cg = new();
mcause_interrupt_cg = new();
mepc_cg = new();
if (!cfg.disable_compressed_instr) begin
mepc_alignment_cg = new();
end
mstatus_m_cg = new();
endfunction
@ -915,10 +951,11 @@ class riscv_instr_cover_group;
if (instr_cnt > 1) begin
instr.check_hazard_condition(pre_instr);
end
if (instr.binary[1:0] != 2'b11) begin
if ((instr.binary[1:0] != 2'b11) && (RV32C inside {supported_isa})) begin
hint_cg.sample(instr);
compressed_opcode_cg.sample(instr.binary[15:0]);
end else begin
end
if (instr.binary[1:0] == 2'b11) begin
opcode_cg.sample(instr.binary[6:2]);
end
case (instr.instr_name)
@ -943,13 +980,11 @@ class riscv_instr_cover_group;
end
end
SRAI : begin
slli_cg.sample(instr);
srai_cg.sample(instr);
if (RV64I inside {supported_isa}) begin
slli64_cg.sample(instr);
srai64_cg.sample(instr);
end
end
SRLI : srli_cg.sample(instr);
SRAI : srai_cg.sample(instr);
AND : and_cg.sample(instr);
OR : or_cg.sample(instr);
XOR : xor_cg.sample(instr);
@ -989,6 +1024,7 @@ class riscv_instr_cover_group;
DIV : div_cg.sample(instr);
DIVU : divu_cg.sample(instr);
REM : rem_cg.sample(instr);
REMU : remu_cg.sample(instr);
MULW : mulw_cg.sample(instr);
DIVW : divw_cg.sample(instr);
DIVUW : divuw_cg.sample(instr);
@ -1039,7 +1075,9 @@ class riscv_instr_cover_group;
C_ADDW : c_addw_cg.sample(instr);
C_ADDIW : c_addiw_cg.sample(instr);
default: begin
illegal_cg.sample(instr.binary);
if (!cfg.disable_compressed_instr) begin
illegal_compressed_instr_cg.sample(instr.binary);
end
if (instr.group == RV32I) begin
rv32i_misc_cg.sample(instr);
end
@ -1068,7 +1106,11 @@ class riscv_instr_cover_group;
end
end
end
MEPC: mepc_cg.sample(instr.rd_value);
MEPC: begin
if (!cfg.disable_compressed_instr) begin
mepc_alignment_cg.sample(instr.rd_value);
end
end
MSTATUS: begin
mstatus_m_cg.sample(instr.rd_value);
end

View file

@ -76,6 +76,7 @@ class riscv_instr_gen_config extends uvm_object;
// Use a random register for stack pointer/thread pointer
rand riscv_reg_t sp;
rand riscv_reg_t tp;
rand riscv_reg_t ra;
// Options for privileged mode CSR checking
// Below checking can be made optional as the ISS implementation could be different with the
@ -324,8 +325,16 @@ class riscv_instr_gen_config extends uvm_object;
}
}
constraint ra_c {
ra dist {RA := 5, T1 := 2, [SP:T0] :/ 1, [T2:T6] :/ 2};
ra != sp;
ra != tp;
ra != ZERO;
}
constraint sp_tp_c {
sp != tp;
sp dist {SP := 6, RA := 1, [GP:T6] :/ 3};
!(sp inside {GP, RA, ZERO});
!(tp inside {GP, RA, ZERO});
}
@ -437,6 +446,9 @@ class riscv_instr_gen_config extends uvm_object;
end
end
end
if (!(RV32C inside {supported_isa})) begin
disable_compressed_instr = 1;
end
endfunction
// Initialize the exception/interrupt delegation associate array, set all delegation default to 0

View file

@ -348,6 +348,7 @@ package riscv_instr_pkg;
CB_FORMAT,
CJ_FORMAT,
CR_FORMAT,
CA_FORMAT,
CL_FORMAT,
CS_FORMAT,
CSS_FORMAT,

View file

@ -278,7 +278,11 @@ class riscv_instr_sequence extends uvm_sequence;
insert_illegal_hint_instr();
prefix = format_string($sformatf("%0d:", i), LABEL_STR_LEN);
if(!is_main_program) begin
str = {prefix, "ret"};
if (!cfg.disable_compressed_instr) begin
str = {prefix, $sformatf("c.jr x%0d", cfg.ra)};
end else begin
str = {prefix, $sformatf("jalr x0, x%0d, 0", cfg.ra)};
end
instr_string_list.push_back(str);
end
endfunction

View file

@ -116,10 +116,10 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
// Assign the allowed load/store instructions based on address alignment
// This is done separately rather than a constraint to improve the randomization performance
allowed_instr = {LB, LBU, SB};
if (addr[i][0] == 1'b0) begin
allowed_instr = {LH, LHU, SH, allowed_instr};
end
if (!cfg.enable_unaligned_load_store) begin
if (addr[i][0] == 1'b0) begin
allowed_instr = {LH, LHU, SH, allowed_instr};
end
if (addr[i] % 4 == 0) begin
allowed_instr = {LW, SW, allowed_instr};
if (cfg.enable_floating_point) begin
@ -149,7 +149,7 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
end
end
end else begin
allowed_instr = {LW, SW, allowed_instr};
allowed_instr = {LW, SW, LH, LHU, SH, allowed_instr};
if ((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0) &&
(RV32C inside {riscv_instr_pkg::supported_isa}) &&
enable_compressed_load_store) begin

View file

@ -44,7 +44,6 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
}
}
foreach (loop_limit_reg[i]) {
loop_limit_reg[i] != ZERO;
foreach (cfg.reserved_regs[j]) {
loop_limit_reg[i] != cfg.reserved_regs[j];
}
@ -58,34 +57,54 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
solve num_of_nested_loop before loop_init_val;
solve num_of_nested_loop before loop_step_val;
solve num_of_nested_loop before loop_limit_val;
num_of_instr_in_loop inside {[1:200]};
solve loop_limit_val before loop_limit_reg;
solve branch_type before loop_init_val;
solve branch_type before loop_step_val;
solve branch_type before loop_limit_val;
num_of_instr_in_loop inside {[1:25]};
num_of_nested_loop inside {[1:2]};
loop_init_val.size() == num_of_nested_loop;
loop_step_val.size() == num_of_nested_loop;
loop_limit_val.size() == num_of_nested_loop;
branch_type.size() == num_of_nested_loop;
foreach (branch_type[i]) {
if (!cfg.disable_compressed_instr) {
branch_type[i] inside {C_BNEZ, C_BEQZ, BEQ, BNE, BLTU, BLT, BGEU, BGE};
} else {
branch_type[i] inside {BEQ, BNE, BLTU, BLT, BGEU, BGE};
}
}
foreach(loop_init_val[i]) {
if (branch_type[i] inside {C_BNEZ, C_BEQZ}) {
loop_limit_val[i] == 0;
loop_limit_reg[i] == ZERO;
loop_cnt_reg[i] inside {riscv_instr_pkg::compressed_gpr};
} else {
loop_limit_val[i] inside {[-20:20]};
loop_limit_reg[i] != ZERO;
}
if (branch_type[i] inside {C_BNEZ, C_BEQZ, BEQ, BNE}) {
((loop_limit_val[i] - loop_init_val[i]) % loop_step_val[i] == 0) &&
(loop_limit_val[i] != loop_init_val[i]);
} else if (branch_type[i] == BGE) {
loop_step_val[i] < 0;
} else if (branch_type[i] == BGEU) {
loop_step_val[i] < 0;
loop_init_val[i] > 0;
// Avoid count to negative
loop_step_val[i] + loop_limit_val[i] > 0;
} else if (branch_type[i] == BLT) {
loop_step_val[i] > 0;
} else if (branch_type[i] == BLTU) {
loop_step_val[i] > 0;
loop_limit_val[i] > 0;
}
loop_init_val[i] inside {[-10:10]};
loop_limit_val[i] inside {[-20:20]};
loop_step_val[i] inside {[-10:10]};
loop_step_val[i] != 0;
if(loop_init_val[i] < loop_limit_val[i]) {
loop_step_val[i] > 0;
loop_step_val[i] > 0;
} else {
loop_step_val[i] < 0;
}
// Select a reasonable branch instruction to avoid inifint loop
if(loop_init_val[i] < 0 || (loop_limit_val[i] + loop_step_val[i]) < 0) {
!(branch_type[i] inside {BLTU, BGEU});
}
if(((loop_limit_val[i] - loop_init_val[i]) % loop_step_val[i] != 0) ||
(loop_limit_val[i] == loop_init_val[i])) {
!(branch_type[i] inside {BEQ, BNE});
}
if(loop_step_val[i] > 0) {
branch_type[i] inside {BLTU, BNE, BLT, BEQ};
} else {
branch_type[i] inside {BGEU, BNE, BGE, BEQ};
loop_step_val[i] < 0;
}
}
}
@ -148,7 +167,9 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_branch_instr[i],
instr_name == branch_type[i];
rs1 == loop_cnt_reg[i];
rs2 == loop_limit_reg[i];,
if (!(branch_type[i] inside {C_BEQZ, C_BNEZ})) {
rs2 == loop_limit_reg[i];
},
"Cannot randomize backward branch instruction")
loop_branch_instr[i].comment = $sformatf("branch for loop %0d", i);
loop_branch_instr[i].imm_str = loop_branch_target_instr[i].label;

View file

@ -390,7 +390,7 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
instr.push_back($sformatf("csrr x%0d, 0x%0x", tmp_reg, MSTATUS));
instr.push_back($sformatf("and x%0d, x%0d, x%0d", tmp_reg, tmp_reg, mask_reg));
instr.push_back($sformatf("beqz x%0d, j_smode", tmp_reg));
instr.push_back("jal ra, smode_ls_umem_program");
instr.push_back("jal ra, smode_lsu_program");
instr.push_back("j fix_pte_ret");
instr.push_back("j_smode: jal ra, smode_program");
instr.push_back("fix_pte_ret:");

View file

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

View file

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

View file

@ -0,0 +1,197 @@
# Copyright Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ================================================================================
# Regression test list format
# --------------------------------------------------------------------------------
# test : Assembly test name
# description : Description of this test
# gen_opts : Instruction generator options
# iterations : Number of iterations of this test
# no_iss : Enable/disable ISS simulator (Optional)
# gen_test : Test name used by the instruction generator
# rtl_test : RTL simulation test name
# cmp_opts : Compile options passed to the instruction generator
# sim_opts : Simulation options passed to the instruction generator
# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional)
# compare_opts : Options for the RTL & ISS trace comparison
# gcc_opts : gcc compile options
# --------------------------------------------------------------------------------
- test: riscv_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
+no_branch_jump=1
+boot_mode=m
+no_csr_instr=1
iterations: 2
gen_test: riscv_instr_base_test
rtl_test: core_base_test
- test: riscv_rand_instr_test
description: >
Random instruction stress test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,4
+directed_instr_1=riscv_loop_instr,4
+directed_instr_2=riscv_hazard_instr_stream,4
+directed_instr_3=riscv_load_store_hazard_instr_stream,4
+directed_instr_4=riscv_multi_page_load_store_instr_stream,4
+directed_instr_5=riscv_mem_region_stress_test,4
+directed_instr_6=riscv_jal_instr,4
rtl_test: core_base_test
- test: riscv_jump_stress_test
description: >
Stress back-to-back jump instruction test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=5000
+num_of_sub_program=5
+directed_instr_1=riscv_jal_instr,20
rtl_test: core_base_test
- test: riscv_loop_test
description: >
Random instruction stress test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+directed_instr_1=riscv_loop_instr,20
rtl_test: core_base_test
- test: riscv_rand_jump_test
description: >
Jump among large number of sub-programs, stress testing iTLB operations.
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=20
+directed_instr_0=riscv_load_store_rand_instr_stream,8
rtl_test: core_base_test
- test: riscv_mmu_stress_test
description: >
Test with different patterns of load/store instructions, stress test MMU
operations.
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=5000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,40
+directed_instr_1=riscv_load_store_hazard_instr_stream,40
+directed_instr_2=riscv_multi_page_load_store_instr_stream,10
+directed_instr_3=riscv_mem_region_stress_test,10
rtl_test: core_base_test
- test: riscv_no_fence_test
description: >
Random instruction with FENCE disabled, used to test processor pipeline with
less stall/flush operations caused by FENCE instruction.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+no_fence=1
rtl_test: core_base_test
- test: riscv_illegal_instr_test
description: >
Illegal instruction test, verify the processor can detect illegal
instruction and handle corresponding exception properly. An exception
handling routine is designed to resume execution after illegal
instruction exception.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+illegal_instr_ratio=5
rtl_test: core_base_test
- test: riscv_ebreak_test
description: >
Random instruction test with ebreak instruction enabled. Debug mode is not
enabled for this test, processor should raise ebreak exception.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=6000
+no_ebreak=0
rtl_test: core_base_test
- test: riscv_ebreak_debug_mode_test
description: >
Ebreak instruction test with debug mode enabled.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=6000
+no_ebreak=0
rtl_test: core_base_test
sim_opts: >
+require_signature_addr=1
+enable_debug_seq=1
compare_opts: >
+compare_final_value_only=1
- test: riscv_full_interrupt_test
description: >
Random instruction test with complete interrupt handling
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+enable_interrupt=1
rtl_test: core_base_test
sim_opts: >
+enable_irq_seq=1
compare_opts: >
+compare_final_value_only=1
# Please enable this test for your RTL simulation
- test: riscv_csr_test
description: >
Test all CSR instructions on all implemented CSR registers
iterations: 0
no_iss: 1
rtl_test: core_csr_test
no_post_compare: 1
- test: riscv_unaligned_load_store_test
description: >
Unaligned load/store test
iterations: 1
gen_test: riscv_instr_base_test
gcc_opts: >
-mno-strict-align
gen_opts: >
+instr_cnt=6000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,20
+directed_instr_1=riscv_load_store_hazard_instr_stream,20
+directed_instr_2=riscv_multi_page_load_store_instr_stream,5
+directed_instr_3=riscv_mem_region_stress_test,5
+enable_unaligned_load_store=1
rtl_test: core_base_test

View file

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

View file

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

View file

@ -0,0 +1,218 @@
# Copyright Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ================================================================================
# Regression test list format
# --------------------------------------------------------------------------------
# test : Assembly test name
# description : Description of this test
# gen_opts : Instruction generator options
# iterations : Number of iterations of this test
# no_iss : Enable/disable ISS simulator (Optional)
# gen_test : Test name used by the instruction generator
# rtl_test : RTL simulation test name
# cmp_opts : Compile options passed to the instruction generator
# sim_opts : Simulation options passed to the instruction generator
# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional)
# compare_opts : Options for the RTL & ISS trace comparison
# gcc_opts : gcc compile options
# --------------------------------------------------------------------------------
- test: riscv_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
+no_branch_jump=1
+boot_mode=m
+no_csr_instr=1
iterations: 2
gen_test: riscv_instr_base_test
rtl_test: core_base_test
- test: riscv_rand_instr_test
description: >
Random instruction stress test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,4
+directed_instr_1=riscv_loop_instr,4
+directed_instr_2=riscv_hazard_instr_stream,4
+directed_instr_3=riscv_load_store_hazard_instr_stream,4
+directed_instr_4=riscv_multi_page_load_store_instr_stream,4
+directed_instr_5=riscv_mem_region_stress_test,4
+directed_instr_6=riscv_jal_instr,4
rtl_test: core_base_test
- test: riscv_jump_stress_test
description: >
Back to back jump instruction test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=5000
+num_of_sub_program=5
+directed_instr_1=riscv_jal_instr,20
rtl_test: core_base_test
- test: riscv_loop_test
description: >
Random instruction stress test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+directed_instr_1=riscv_loop_instr,20
rtl_test: core_base_test
- test: riscv_non_compressed_instr_test
description: >
Random instruction test without compressed instructions
iterations: 1
gen_test: riscv_rand_instr_test
gen_opts: >
+disable_compressed_instr=1
gcc_opts: >
-march=rv32im
rtl_test: core_base_test
- test: riscv_rand_jump_test
description: >
Jump among large number of sub-programs, stress testing iTLB operations.
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=20
+directed_instr_0=riscv_load_store_rand_instr_stream,8
rtl_test: core_base_test
- test: riscv_mmu_stress_test
description: >
Test with different patterns of load/store instructions, stress test MMU
operations.
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=5000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,40
+directed_instr_1=riscv_load_store_hazard_instr_stream,40
+directed_instr_2=riscv_multi_page_load_store_instr_stream,10
+directed_instr_3=riscv_mem_region_stress_test,10
rtl_test: core_base_test
- test: riscv_no_fence_test
description: >
Random instruction with FENCE disabled, used to test processor pipeline with
less stall/flush operations caused by FENCE instruction.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+no_fence=1
rtl_test: core_base_test
- test: riscv_illegal_instr_test
description: >
Illegal instruction test, verify the processor can detect illegal
instruction and handle corresponding exception properly. An exception
handling routine is designed to resume execution after illegal
instruction exception.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+illegal_instr_ratio=5
rtl_test: core_base_test
- test: riscv_hint_instr_test
description: >
HINT instruction test, verify the processor can detect HINT instruction
treat it as NOP. No illegal instruction exception is expected
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+hint_instr_ratio=5
rtl_test: core_base_test
- test: riscv_ebreak_test
description: >
Random instruction test with ebreak instruction enabled. Debug mode is not
enabled for this test, processor should raise ebreak exception.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=6000
+no_ebreak=0
rtl_test: core_base_test
- test: riscv_ebreak_debug_mode_test
description: >
Ebreak instruction test with debug mode enabled.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=6000
+no_ebreak=0
rtl_test: core_base_test
sim_opts: >
+require_signature_addr=1
+enable_debug_seq=1
compare_opts: >
+compare_final_value_only=1
- test: riscv_full_interrupt_test
description: >
Random instruction test with complete interrupt handling
iterations: 2
gen_test: riscv_rand_instr_test
+enable_interrupt=1
gen_opts: >
rtl_test: core_base_test
sim_opts: >
+enable_irq_seq=1
compare_opts: >
+compare_final_value_only=1
# Please enable this test for your RTL simulation
- test: riscv_csr_test
description: >
Test all CSR instructions on all implemented CSR registers
iterations: 0
no_iss: 1
rtl_test: core_csr_test
no_post_compare: 1
- test: riscv_unaligned_load_store_test
description: >
Unaligned load/store test
iterations: 1
gen_test: riscv_instr_base_test
gcc_opts: >
-mno-strict-align
gen_opts: >
+instr_cnt=6000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,20
+directed_instr_1=riscv_load_store_hazard_instr_stream,20
+directed_instr_2=riscv_multi_page_load_store_instr_stream,5
+directed_instr_3=riscv_mem_region_stress_test,5
+enable_unaligned_load_store=1
rtl_test: core_base_test

View file

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

View file

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

View file

@ -0,0 +1,219 @@
# Copyright Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ================================================================================
# Regression test list format
# --------------------------------------------------------------------------------
# test : Assembly test name
# description : Description of this test
# gen_opts : Instruction generator options
# iterations : Number of iterations of this test
# no_iss : Enable/disable ISS simulator (Optional)
# gen_test : Test name used by the instruction generator
# rtl_test : RTL simulation test name
# cmp_opts : Compile options passed to the instruction generator
# sim_opts : Simulation options passed to the instruction generator
# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional)
# compare_opts : Options for the RTL & ISS trace comparison
# gcc_opts : gcc compile options
# --------------------------------------------------------------------------------
- test: riscv_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
+no_branch_jump=1
+boot_mode=m
+no_csr_instr=1
iterations: 2
gen_test: riscv_instr_base_test
rtl_test: core_base_test
- test: riscv_rand_instr_test
description: >
Random instruction stress test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,4
+directed_instr_1=riscv_loop_instr,4
+directed_instr_2=riscv_hazard_instr_stream,4
+directed_instr_3=riscv_load_store_hazard_instr_stream,4
+directed_instr_4=riscv_multi_page_load_store_instr_stream,4
+directed_instr_5=riscv_mem_region_stress_test,4
+directed_instr_6=riscv_jal_instr,4
rtl_test: core_base_test
- test: riscv_jump_stress_test
description: >
Stress back-to-back jump instruction test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=5000
+num_of_sub_program=5
+directed_instr_1=riscv_jal_instr,20
rtl_test: core_base_test
- test: riscv_loop_test
description: >
Random instruction stress test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+directed_instr_1=riscv_loop_instr,20
rtl_test: core_base_test
- test: riscv_non_compressed_instr_test
description: >
Random instruction test without compressed instructions
iterations: 1
gen_test: riscv_rand_instr_test
gen_opts: >
+disable_compressed_instr=1
gcc_opts: >
-march=rv64im
rtl_test: core_base_test
- test: riscv_rand_jump_test
description: >
Jump among large number of sub-programs, stress testing iTLB operations.
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=20
+directed_instr_0=riscv_load_store_rand_instr_stream,8
rtl_test: core_base_test
- test: riscv_mmu_stress_test
description: >
Test with different patterns of load/store instructions, stress test MMU
operations.
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=5000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,40
+directed_instr_1=riscv_load_store_hazard_instr_stream,40
+directed_instr_2=riscv_multi_page_load_store_instr_stream,10
+directed_instr_3=riscv_mem_region_stress_test,10
rtl_test: core_base_test
- test: riscv_no_fence_test
description: >
Random instruction with FENCE disabled, used to test processor pipeline with
less stall/flush operations caused by FENCE instruction.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+no_fence=1
rtl_test: core_base_test
- test: riscv_illegal_instr_test
description: >
Illegal instruction test, verify the processor can detect illegal
instruction and handle corresponding exception properly. An exception
handling routine is designed to resume execution after illegal
instruction exception.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+illegal_instr_ratio=5
rtl_test: core_base_test
- test: riscv_hint_instr_test
description: >
HINT instruction test, verify the processor can detect HINT instruction
treat it as NOP. No illegal instruction exception is expected
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+hint_instr_ratio=5
rtl_test: core_base_test
- test: riscv_ebreak_test
description: >
Random instruction test with ebreak instruction enabled. Debug mode is not
enabled for this test, processor should raise ebreak exception.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=6000
+no_ebreak=0
rtl_test: core_base_test
- test: riscv_ebreak_debug_mode_test
description: >
Ebreak instruction test with debug mode enabled.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=6000
+no_ebreak=0
rtl_test: core_base_test
sim_opts: >
+require_signature_addr=1
+enable_debug_seq=1
compare_opts: >
+compare_final_value_only=1
- test: riscv_full_interrupt_test
description: >
Random instruction test with complete interrupt handling
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+enable_interrupt=1
rtl_test: core_base_test
sim_opts: >
+enable_irq_seq=1
compare_opts: >
+compare_final_value_only=1
# Please enable this test for your RTL simulation
- test: riscv_csr_test
description: >
Test all CSR instructions on all implemented CSR registers
iterations: 0
no_iss: 1
rtl_test: core_csr_test
no_post_compare: 1
- test: riscv_unaligned_load_store_test
description: >
Unaligned load/store test
iterations: 1
gen_test: riscv_instr_base_test
gcc_opts: >
-mno-strict-align
gen_opts: >
+instr_cnt=6000
+num_of_sub_program=5
+directed_instr_0=riscv_load_store_rand_instr_stream,20
+directed_instr_1=riscv_load_store_hazard_instr_stream,20
+directed_instr_2=riscv_multi_page_load_store_instr_stream,5
+directed_instr_3=riscv_mem_region_stress_test,5
+enable_unaligned_load_store=1
rtl_test: core_base_test

View file

@ -76,7 +76,7 @@ class riscv_instr_cov_test extends uvm_test;
continue;
end
if (!sample()) begin
`uvm_info(`gfn, $sformatf("Skipping illegal instr name: %0s [%0s]",
`uvm_info(`gfn, $sformatf("Found illegal instr: %0s [%0s]",
trace["instr"], line), UVM_LOW)
end
end
@ -105,6 +105,7 @@ class riscv_instr_cov_test extends uvm_test;
function bit sample();
riscv_instr_name_t instr_name;
bit [XLEN-1:0] val;
if (instr_enum::from_name(process_instr_name(trace["instr"]), instr_name)) begin
if (cfg.instr_template.exists(instr_name)) begin
instr.copy_base_instr(cfg.instr_template[instr_name]);
@ -113,11 +114,16 @@ class riscv_instr_cov_test extends uvm_test;
instr_cg.sample(instr);
return 1'b1;
end
end else if (trace["instr"] == "") begin
bit [XLEN-1:0] val;
get_val(trace["binary"], val);
instr_cg.illegal_cg.sample(val);
return 1'b1;
end
get_val(trace["binary"], val);
if ((val[1:0] != 2'b11) && (RV32C inside {supported_isa})) begin
instr_cg.compressed_opcode_cg.sample(val[15:0]);
instr_cg.illegal_compressed_instr_cg.sample(val);
end
if (val[1:0] == 2'b11) begin
`uvm_info("DBG", $sformatf("Sample illegal opcode: %0x [%0s]",
val[6:2], trace["instr_str"]), UVM_LOW)
instr_cg.opcode_cg.sample(val[6:2]);
end
illegal_instr_cnt++;
return 1'b0;
@ -128,7 +134,7 @@ class riscv_instr_cov_test extends uvm_test;
privileged_reg_t preg;
get_val(trace["addr"], instr.pc);
get_val(trace["binary"], instr.binary);
instr.trace = trace["instr_str"];
instr.trace = trace["str"];
if (instr.instr_name inside {ECALL, EBREAK, FENCE, FENCE_I, NOP,
C_NOP, WFI, MRET, C_EBREAK}) begin
return;
@ -152,7 +158,8 @@ class riscv_instr_cov_test extends uvm_test;
end
end
if (instr.has_rs1) begin
if (instr.format inside {CI_FORMAT, CR_FORMAT, CB_FORMAT}) begin
if (instr.format inside {CI_FORMAT, CR_FORMAT} &&
!(instr.instr_name inside {C_JR, C_JALR})) begin
instr.rs1 = instr.rd;
end else begin
if (get_gpr(trace["rs1"], gpr)) begin

View file

@ -32,6 +32,7 @@ class riscv_rand_instr_test extends riscv_instr_base_test;
// Mix below directed instructino streams with the random instructions
asm_gen.add_directed_instr_stream("riscv_load_store_rand_instr_stream", 4);
asm_gen.add_directed_instr_stream("riscv_loop_instr", 4);
asm_gen.add_directed_instr_stream("riscv_jal_instr", 4);
asm_gen.add_directed_instr_stream("riscv_hazard_instr_stream", 4);
asm_gen.add_directed_instr_stream("riscv_load_store_hazard_instr_stream", 4);
asm_gen.add_directed_instr_stream("riscv_multi_page_load_store_instr_stream", 4);

View file

@ -21,10 +21,11 @@
path_var: OVPSIM_PATH
cmd: >
<path_var>/riscvOVPsim.exe
--variant <variant>
--controlfile ../riscv-dv/target/<variant>/riscvOVPsim.ic
--objfilenoentry <elf>
--override riscvOVPsim/cpu/PMP_registers=0
--override riscvOVPsim/cpu/simulateexceptions=T
--trace --tracechange --traceshowicount --program <elf>
--trace --tracechange --traceshowicount --tracemode --traceregs
--finishafter 1000000
- iss: sail

View file

@ -39,6 +39,7 @@
+no_data_page=1
+no_branch_jump=1
+boot_mode=m
+no_csr_instr=1
iterations: 2
gen_test: riscv_instr_base_test
rtl_test: core_base_test
@ -78,6 +79,18 @@
+directed_instr_3=riscv_load_store_hazard_instr_stream,4
+directed_instr_4=riscv_multi_page_load_store_instr_stream,4
+directed_instr_5=riscv_mem_region_stress_test,4
+directed_instr_6=riscv_jal_instr,4
rtl_test: core_base_test
- test: riscv_jump_stress_test
description: >
Stress back-to-back jump instruction test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=5000
+num_of_sub_program=5
+directed_instr_1=riscv_jal_instr,20
rtl_test: core_base_test
- test: riscv_loop_test
@ -212,6 +225,7 @@
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+enable_interrupt=1
rtl_test: core_base_test
sim_opts: >
+enable_irq_seq=1
@ -224,12 +238,12 @@
Test all CSR instructions on all implemented CSR registers
iterations: 0
no_iss: 1
rtl_test: core_ibex_csr_test
rtl_test: core_csr_test
no_post_compare: 1
- test: riscv_unaligned_load_store_test
description: >
Unaligned load/store test, ibex should handle it correctly without raising any exception
Unaligned load/store test
iterations: 1
gen_test: riscv_instr_base_test
gcc_opts: >
@ -242,7 +256,7 @@
+directed_instr_2=riscv_multi_page_load_store_instr_stream,5
+directed_instr_3=riscv_mem_region_stress_test,5
+enable_unaligned_load_store=1
rtl_test: core_ibex_base_test
rtl_test: core_base_test
- test: riscv_amo_test
description: >