mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 21:07:34 -04:00
Update google_riscv-dv to google/riscv-dv@5b1dd4e (#523)
Update code from upstream repository https://github.com/google/riscv- dv to revision 5b1dd4e2eb11d49d3275da80953efc0c50f90447 * Add compliance mode to coverage model (google/riscv-dv#361) (taoliug) * Revert " Make assign_operand become a method of class RiscvInstructionTraceEntry (google/riscv-dv#357)" (google/riscv- dv#360) (taoliug) * Fix script issue (google/riscv-dv#358) (taoliug) * Make assign_operand become a method of class RiscvInstructionTraceEntry (google/riscv-dv#357) (Hai Hoang Dang) * Remove unused variable (google/riscv-dv#348) (Hai Hoang Dang) * Functional coverage improvement (google/riscv-dv#356) (taoliug) * Fix list access exception thrown when parsing ovpsim illegal instruction (Udi Jonnalagadda) * Add compliance mode and RTL mode to the coverage model (google/riscv-dv#354) (taoliug) * Fix lr/sc sequence (google/riscv-dv#353) (taoliug) * Fix minor illegal instruction issue (google/riscv-dv#351) (taoliug) * Migrate to new instruction class (google/riscv-dv#350) (taoliug) * misc issue fixes (google/riscv-dv#349) (taoliug) * Update README to add contact info for the collaboration request (google/riscv-dv#347) (taoliug) * Support running specific multiple tests (google/riscv-dv#346) (Hai Hoang Dang) * Fix rv64 coverage model issue (google/riscv-dv#344) (taoliug) * Fix the link for yaml/base_testlist.yaml (google/riscv-dv#343) (Hai Hoang Dang) * refactor debug ROM generation (Udi Jonnalagadda) * Add a runtime option to run with experimental features (google/riscv-dv#341) (taoliug) * Fix a few issues with the new instruction class (google/riscv- dv#340) (taoliug) * Improve performance of new experimental instruction class (google/riscv-dv#339) (taoliug) * Fix CSR randomization bug when generating loops (google/riscv- dv#337) (udinator) * Add support coverage flow for qrun, and minor fix for cov.py (google/riscv-dv#335) (Hai Hoang Dang) * [ovpsim] Coding style fixes, fix floating point compare mismatch (google/riscv-dv#334) (taoliug) * Fix ius flow issue (google/riscv-dv#333) (taoliug) * Fix a few new instruction class issues (google/riscv-dv#332) (taoliug) * Added two includes and starting variables for adding bitmanip extension (google/riscv-dv#328) (simond-imperas) * Integrate experimental instruction class (google/riscv-dv#331) (taoliug) * Minor fixes to run.py (google/riscv-dv#330) (taoliug) * Run.py: minor refactor the code for compile, and simulate (google/riscv-dv#326) (Hai Hoang Dang) * Add requirements for install dependencies (google/riscv-dv#325) (Hai Hoang Dang) * Adding support qrun simulator (google/riscv-dv#324) (Hai Hoang Dang) * Add new experimental instruction class (google/riscv-dv#323) (taoliug) * Added command line control of coverage and added hooks for vector coverage development (google/riscv-dv#317) (simond-imperas) * Fix compilation issue (google/riscv-dv#322) (taoliug) Signed-off-by: Udi <udij@google.com>
This commit is contained in:
parent
8568e6b3b5
commit
0d6ccbf1f6
72 changed files with 5763 additions and 1403 deletions
2
vendor/google_riscv-dv.lock.hjson
vendored
2
vendor/google_riscv-dv.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/google/riscv-dv
|
||||
rev: d69190682078470bc6d5661d72f873ae9850ae53
|
||||
rev: 5b1dd4e2eb11d49d3275da80953efc0c50f90447
|
||||
}
|
||||
}
|
||||
|
|
4
vendor/google_riscv-dv/.gitignore
vendored
4
vendor/google_riscv-dv/.gitignore
vendored
|
@ -7,3 +7,7 @@ work/
|
|||
/.project
|
||||
/outdir/
|
||||
ucli.key
|
||||
qrun.out/
|
||||
qrun.log
|
||||
*.ucdb
|
||||
*.vstf
|
||||
|
|
45
vendor/google_riscv-dv/README.md
vendored
45
vendor/google_riscv-dv/README.md
vendored
|
@ -23,6 +23,14 @@ A CSR test generation script written in Python is also provided, to generate a
|
|||
directed test suite that stresses all CSR instructions on all of the CSRs that
|
||||
the core implements.
|
||||
|
||||
## External contributions and collaborations
|
||||
|
||||
This repository is still under active development. We hope the RISC-V processor
|
||||
verification platform development to be a collaborative effort of the RISC-V
|
||||
community. Free feel to submit issues, feature requests, pull requests through
|
||||
Github. You can also send your private collaboration request to [riscv_dv_dev@google.com](riscv_dv_dev@google.com).
|
||||
Please refer to CONTRIBUTING.md for license related questions.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
@ -32,10 +40,10 @@ which supports SystemVerilog and UVM 1.2. This generator has been verified with
|
|||
Synopsys VCS, Cadence Incisive/Xcelium, and Mentor Questa simulators. Please
|
||||
make sure the EDA tool environment is properly setup before running the generator.
|
||||
|
||||
Install YAML python package:
|
||||
Install dependencies needed for running:
|
||||
|
||||
```bash
|
||||
pip3 install PyYAML
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
### Setup RISCV-GCC compiler toolchain
|
||||
|
@ -101,8 +109,9 @@ python3 run.py --test riscv_arithmetic_basic_test --simulator ius
|
|||
python3 run.py --test riscv_arithmetic_basic_test --simulator vcs
|
||||
python3 run.py --test riscv_arithmetic_basic_test --simulator questa
|
||||
python3 run.py --test riscv_arithmetic_basic_test --simulator dsim
|
||||
python3 run.py --test riscv_arithmetic_basic_test --simulator qrun
|
||||
```
|
||||
The complete test list can be found in [yaml/testlist.yaml](https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml). To run a full
|
||||
The complete test list can be found in [yaml/base_testlist.yaml](https://github.com/google/riscv-dv/blob/master/yaml/base_testlist.yaml). To run a full
|
||||
regression, simply use below command
|
||||
|
||||
```bash
|
||||
|
@ -121,6 +130,9 @@ Here's a few more examples of the run command:
|
|||
# Run a single test 10 times
|
||||
python3 run.py --test riscv_arithmetic_basic_test --iterations 10
|
||||
|
||||
# Run multiple tests
|
||||
python3 run.py --test riscv_arithmetic_basic_test,riscv_rand_instr_test
|
||||
|
||||
# Run a test with verbose logging
|
||||
python3 run.py --test riscv_arithmetic_basic_test --verbose
|
||||
|
||||
|
@ -373,16 +385,6 @@ matching rv32/rv64/rv128 entry and fill in the appropriate CSR field entries.
|
|||
|
||||
### Privileged CSR Test Generation (optional)
|
||||
|
||||
To be able to run the CSR generation script, the open-source `bitstring`
|
||||
Python library is required ([bitstring](https://github.com/scott-griffiths/bitstring)).
|
||||
To install this library, either clone the repository and run the `setup.py`
|
||||
setup script, or run only one of the below commands:
|
||||
|
||||
```bash
|
||||
sudo apt-get install python3-bitstring (or your OS-specific package manager)
|
||||
pip install bitstring
|
||||
```
|
||||
|
||||
The CSR generation script is located at
|
||||
[scripts/gen_csr_test.py](https://github.com/google/riscv-dv/blob/master/scripts/gen_csr_test.py).
|
||||
The CSR test code that this script generates will execute every CSR instruction
|
||||
|
@ -446,9 +448,13 @@ upstream changes to a minimum.
|
|||
different directory, you can use "-ext <user_extension_path>" to override the
|
||||
user extension path.
|
||||
- Create a new target directory and customize the setting and testlist
|
||||
- Run the generator with "--custom_target <target_dir> --isa <isa> --mabi <mabi>"
|
||||
- Run the generator with `--custom_target <target_dir> --isa <isa> --mabi <mabi>`
|
||||
- Use command line type override to use your extended classes.
|
||||
--sim_opts="+uvm_set_type_override=<upstream_class>,<extended_class>"
|
||||
`--sim_opts="+uvm_set_type_override=<upstream_class>,<extended_class>"`
|
||||
- If extending `riscv_asm_program_gen` class is desired, must use this command
|
||||
line override:
|
||||
`--sim_opts="+uvm_set_inst_override=riscv_asm_program_gen,<extended
|
||||
class>,'uvm_test_top.asm_gen'"`
|
||||
|
||||
You can refer to [riscv-dv extension for ibex](https://github.com/lowRISC/ibex/blob/master/dv/uvm/Makefile#L68) for a working example.
|
||||
|
||||
|
@ -521,7 +527,7 @@ implmentation.
|
|||
|
||||
```bash
|
||||
# Randomly generate 100000 instructions, split to 20000 instructions per batch
|
||||
python3 cov.py -d -i 100000 -bz 20000
|
||||
python3 cov.py -d -i 100000 -bz 20000 --isa rv32imc
|
||||
```
|
||||
|
||||
|
||||
|
@ -531,13 +537,6 @@ Please file an issue under this repository for any bug report / integration
|
|||
issue / feature request. We are looking forward to knowing your experience of
|
||||
using this flow and how we can make it better together.
|
||||
|
||||
## External contributions
|
||||
|
||||
We definitely welcome external contributions. We hope it could be a
|
||||
collaborative effort to build a strong open source RISC-V processor
|
||||
verification platform. Free feel to submit your pull request for review.
|
||||
Please refer to CONTRIBUTING.md for license related questions.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This is not an officially supported Google product.
|
||||
|
|
100
vendor/google_riscv-dv/cov.py
vendored
100
vendor/google_riscv-dv/cov.py
vendored
|
@ -23,7 +23,6 @@ import re
|
|||
import sys
|
||||
import logging
|
||||
|
||||
from datetime import date
|
||||
from scripts.lib import *
|
||||
from scripts.spike_log_to_trace_csv import *
|
||||
from scripts.ovpsim_log_to_trace_csv import *
|
||||
|
@ -31,11 +30,13 @@ from scripts.sail_log_to_trace_csv import *
|
|||
|
||||
LOGGER = logging.getLogger()
|
||||
|
||||
|
||||
def collect_cov(log_dir, out, core, iss, testlist, batch_size, lsf_cmd, steps, \
|
||||
opts, timeout, simulator, simulator_yaml, custom_target, \
|
||||
isa, target, stop_on_first_error):
|
||||
isa, target, stop_on_first_error,
|
||||
dont_truncate_after_first_ecall,
|
||||
vector_options, coverage_options, compliance_mode):
|
||||
"""Collect functional coverage from the instruction trace
|
||||
|
||||
Args:
|
||||
log_dir : Trace log directory
|
||||
out : Output directory
|
||||
|
@ -53,6 +54,9 @@ def collect_cov(log_dir, out, core, iss, testlist, batch_size, lsf_cmd, steps, \
|
|||
isa : RISC-V ISA variant
|
||||
target : Predefined target
|
||||
stop_on_first_error : will end run on first error detected
|
||||
vector_options : Enable Vectors and set vector config options
|
||||
coverage_options : Set coverage config options
|
||||
compliance_mode : Run coverage model for compliance test
|
||||
"""
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
log_list = []
|
||||
|
@ -87,28 +91,40 @@ def collect_cov(log_dir, out, core, iss, testlist, batch_size, lsf_cmd, steps, \
|
|||
if iss == "spike":
|
||||
process_spike_sim_log(log, csv, 1)
|
||||
elif iss == "ovpsim":
|
||||
process_ovpsim_sim_log(log, csv, 1, stop_on_first_error)
|
||||
process_ovpsim_sim_log(log, csv, 1, stop_on_first_error,
|
||||
dont_truncate_after_first_ecall)
|
||||
else:
|
||||
logging.error("Full trace for %s is not supported yet" % iss)
|
||||
sys.exit(1)
|
||||
sys.exit(RET_FAIL)
|
||||
if steps == "all" or re.match("cov", steps):
|
||||
opts_vec = ""
|
||||
opts_cov = ""
|
||||
if vector_options:
|
||||
opts_vec = ("%0s" % vector_options)
|
||||
if coverage_options:
|
||||
opts_cov = ("%0s" % coverage_options)
|
||||
if compliance_mode:
|
||||
opts_cov += " +define+COMPLIANCE_MODE"
|
||||
build_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s "
|
||||
" --co -o %s --cov -tl %s %s " %
|
||||
(cwd, simulator, simulator_yaml, out, testlist, opts))
|
||||
" --co -o %s --cov -tl %s %s --cmp_opts \"%s %s\" " %
|
||||
(cwd, simulator, simulator_yaml, out, testlist, opts,
|
||||
opts_vec, opts_cov))
|
||||
base_sim_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s "
|
||||
"--so -o %s --cov -tl %s %s "
|
||||
"-tn riscv_instr_cov_test --steps gen --sim_opts \"<trace_csv_opts>\"" %
|
||||
(cwd, simulator, simulator_yaml, out, testlist, opts))
|
||||
"-tn riscv_instr_cov_test --steps gen --sim_opts \"<trace_csv_opts> %s %s\" " %
|
||||
(cwd, simulator, simulator_yaml, out, testlist, opts,
|
||||
opts_vec, opts_cov))
|
||||
if target:
|
||||
build_cmd += (" --target %s" % target)
|
||||
if custom_target:
|
||||
build_cmd += (" --custom_target %s" % custom_target)
|
||||
if target:
|
||||
base_sim_cmd += (" --target %s" % target)
|
||||
if custom_target:
|
||||
build_cmd += (" --custom_target %s" % custom_target)
|
||||
base_sim_cmd += (" --custom_target %s" % custom_target)
|
||||
if stop_on_first_error:
|
||||
build_cmd += (" --stop_on_first_error")
|
||||
base_sim_cmd += (" --stop_on_first_error")
|
||||
logging.info("Building the coverage collection framework")
|
||||
output = run_cmd(build_cmd)
|
||||
run_cmd(build_cmd)
|
||||
file_idx = 0
|
||||
trace_idx = 0
|
||||
trace_csv_opts = ""
|
||||
|
@ -119,12 +135,11 @@ def collect_cov(log_dir, out, core, iss, testlist, batch_size, lsf_cmd, steps, \
|
|||
batch_cnt = (len(csv_list)+batch_size-1)/batch_size;
|
||||
logging.info("Batch size: %0d, Batch cnt:%0d" % (batch_size, batch_cnt))
|
||||
for i in range(len(csv_list)):
|
||||
file_idx = 0
|
||||
trace_idx = i
|
||||
if batch_size > 0:
|
||||
file_idx = i / batch_size;
|
||||
trace_idx = i % batch_size;
|
||||
else:
|
||||
file_idx = 0
|
||||
trace_idx = i
|
||||
trace_csv_opts += (" +trace_csv_%0d=%s" % (trace_idx, csv_list[i]))
|
||||
if ((i == len(csv_list)-1) or ((batch_size > 0) and (trace_idx == batch_size-1))):
|
||||
sim_cmd = base_sim_cmd.replace("<trace_csv_opts>", trace_csv_opts)
|
||||
|
@ -165,34 +180,30 @@ def run_cov_debug_test(out, instr_cnt, testlist, batch_size, opts, lsf_cmd,\
|
|||
build_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s "
|
||||
"--co -o %s --cov -tl %s %s" %
|
||||
(cwd, simulator, simulator_yaml, out, testlist, opts))
|
||||
if target:
|
||||
build_cmd += (" --target %s" % target)
|
||||
if custom_target:
|
||||
build_cmd += (" --custom_target %s" % custom_target)
|
||||
run_cmd(build_cmd)
|
||||
base_sim_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s "
|
||||
"--so -o %s --cov -tl %s --isa %s%s "
|
||||
"--so -o %s --cov -tl %s --isa %s %s "
|
||||
"-tn riscv_instr_cov_debug_test --steps gen "
|
||||
"--sim_opts \"+num_of_iterations=<instr_cnt>\"" %
|
||||
(cwd, simulator, simulator_yaml, out, testlist, isa, opts))
|
||||
if target:
|
||||
build_cmd += (" --target %s" % target)
|
||||
base_sim_cmd += (" --target %s" % target)
|
||||
if custom_target:
|
||||
build_cmd += (" --custom_target %s" % custom_target)
|
||||
base_sim_cmd += (" --custom_target %s" % custom_target)
|
||||
logging.info("Building the coverage collection framework")
|
||||
run_cmd(build_cmd)
|
||||
batch_cnt = 1
|
||||
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))
|
||||
else:
|
||||
batch_cnt = 1
|
||||
logging.info("Randomizing %0d instructions in %0d batches", instr_cnt, batch_cnt)
|
||||
for i in range(batch_cnt):
|
||||
batch_instr_cnt = instr_cnt
|
||||
if batch_size > 0:
|
||||
batch_instr_cnt = batch_size
|
||||
if i == batch_cnt - 1:
|
||||
batch_instr_cnt = instr_cnt - batch_size * (batch_cnt - 1)
|
||||
else:
|
||||
batch_instr_cnt = batch_size
|
||||
else:
|
||||
batch_instr_cnt = instr_cnt
|
||||
sim_cmd = base_sim_cmd.replace("<instr_cnt>", str(batch_instr_cnt))
|
||||
sim_cmd += (" --log_suffix _%d" % i)
|
||||
if lsf_cmd == "":
|
||||
|
@ -223,6 +234,8 @@ def setup_parser():
|
|||
help="Number of CSV to process per run")
|
||||
parser.add_argument("-d", "--debug_mode", dest="debug_mode", action="store_true",
|
||||
help="Debug mode, randomize and sample the coverage directly")
|
||||
parser.add_argument("--compliance_mode", action="store_true",
|
||||
help="Run the coverage model in compliance test mode")
|
||||
parser.add_argument("-i", "--instr_cnt", dest="instr_cnt", type=int, default=0,
|
||||
help="Random instruction count for debug mode")
|
||||
parser.add_argument("-to", "--timeout", dest="timeout", type=int, default=1000,
|
||||
|
@ -256,11 +269,21 @@ def setup_parser():
|
|||
help="Path for the riscv_core_setting.sv")
|
||||
parser.add_argument("--stop_on_first_error", dest="stop_on_first_error",
|
||||
action="store_true", help="Stop on detecting first error")
|
||||
parser.set_defaults(verbose=False)
|
||||
parser.set_defaults(debug_mode=False)
|
||||
parser.set_defaults(stop_on_first_error=False)
|
||||
parser.add_argument("--dont_truncate_after_first_ecall", dest="dont_truncate_after_first_ecall",
|
||||
action="store_true", help="Do not truncate log and csv file on first ecall")
|
||||
parser.add_argument("--noclean", action="store_true",
|
||||
help="Do not clean the output of the previous runs")
|
||||
parser.add_argument("--vector_options", type=str, default="",
|
||||
help="Enable Vectors and set options")
|
||||
parser.add_argument("--coverage_options", type=str, default="",
|
||||
help="Controlling coverage coverpoints")
|
||||
parser.set_defaults(verbose=False)
|
||||
parser.set_defaults(debug_mode=False)
|
||||
parser.set_defaults(compliance_mode=False)
|
||||
parser.set_defaults(stop_on_first_error=False)
|
||||
parser.set_defaults(dont_truncate_after_first_ecall=False)
|
||||
parser.set_defaults(vector_options="")
|
||||
parser.set_defaults(coverage_options="")
|
||||
return parser
|
||||
|
||||
def main():
|
||||
|
@ -273,9 +296,6 @@ def main():
|
|||
if args.verbose:
|
||||
args.opts += "-v"
|
||||
|
||||
if not args.testlist:
|
||||
args.testlist = cwd + "/yaml/cov_testlist.yaml"
|
||||
|
||||
if not args.simulator_yaml:
|
||||
args.simulator_yaml = cwd + "/yaml/simulator.yaml"
|
||||
|
||||
|
@ -301,14 +321,12 @@ def main():
|
|||
args.testlist = cwd + "/yaml/cov_testlist.yaml" ## needed if need to force
|
||||
|
||||
# Create output directory
|
||||
if args.o is None:
|
||||
output_dir = "cov_out_" + str(date.today())
|
||||
else:
|
||||
output_dir = args.o
|
||||
output_dir = create_output(args.o, "cov_out_")
|
||||
|
||||
if args.noclean is False:
|
||||
os.system("rm -rf %s" % output_dir)
|
||||
|
||||
logging.info("Creating output directory: %s" % output_dir)
|
||||
subprocess.run(["mkdir", "-p", output_dir])
|
||||
|
||||
if args.debug_mode:
|
||||
|
@ -320,7 +338,11 @@ def main():
|
|||
collect_cov(args.dir, output_dir, args.core, args.iss, args.testlist,
|
||||
args.batch_size, args.lsf_cmd, args.steps, args.opts, args.timeout,
|
||||
args.simulator, args.simulator_yaml, args.custom_target,
|
||||
args.isa, args.target, args.stop_on_first_error)
|
||||
args.isa, args.target, args.stop_on_first_error,
|
||||
args.dont_truncate_after_first_ecall,
|
||||
args.vector_options,
|
||||
args.coverage_options,
|
||||
args.compliance_mode)
|
||||
logging.info("Coverage results are saved to %s" % output_dir)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
10
vendor/google_riscv-dv/qrun_option.f
vendored
Normal file
10
vendor/google_riscv-dv/qrun_option.f
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
-64
|
||||
-uvmhome uvm-1.2
|
||||
-sv
|
||||
-mfcu
|
||||
-cuname design_cuname
|
||||
+define+UVM_REGEX_NO_DPI
|
||||
-debug
|
||||
+designfile
|
||||
-o design_opt
|
||||
-optimize
|
2
vendor/google_riscv-dv/requirements.txt
vendored
Normal file
2
vendor/google_riscv-dv/requirements.txt
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
PyYAML
|
||||
bitstring
|
267
vendor/google_riscv-dv/run.py
vendored
267
vendor/google_riscv-dv/run.py
vendored
|
@ -23,7 +23,6 @@ import re
|
|||
import sys
|
||||
import logging
|
||||
|
||||
from datetime import date
|
||||
from scripts.lib import *
|
||||
from scripts.spike_log_to_trace_csv import *
|
||||
from scripts.ovpsim_log_to_trace_csv import *
|
||||
|
@ -33,13 +32,14 @@ from scripts.instr_trace_compare import *
|
|||
|
||||
LOGGER = logging.getLogger()
|
||||
|
||||
def get_generator_cmd(simulator, simulator_yaml, cov):
|
||||
def get_generator_cmd(simulator, simulator_yaml, cov, exp):
|
||||
""" Setup the compile and simulation command for the generator
|
||||
|
||||
Args:
|
||||
simulator : RTL simulator used to run instruction generator
|
||||
simulator_yaml : RTL simulator configuration file in YAML format
|
||||
cov : Enable functional coverage
|
||||
exp : Use experimental version
|
||||
|
||||
Returns:
|
||||
compile_cmd : RTL simulator command to compile the instruction generator
|
||||
|
@ -58,6 +58,8 @@ def get_generator_cmd(simulator, simulator_yaml, cov):
|
|||
compile_cmd[i] = re.sub('<cov_opts>', compile_spec['cov_opts'].rstrip(), compile_cmd[i])
|
||||
else:
|
||||
compile_cmd[i] = re.sub('<cov_opts>', '', compile_cmd[i])
|
||||
if exp:
|
||||
compile_cmd[i] += " +define+EXPERIMENTAL "
|
||||
sim_cmd = entry['sim']['cmd']
|
||||
if ('cov_opts' in entry['sim']) and cov:
|
||||
sim_cmd = re.sub('<cov_opts>', entry['sim']['cov_opts'].rstrip(), sim_cmd)
|
||||
|
@ -70,7 +72,7 @@ def get_generator_cmd(simulator, simulator_yaml, cov):
|
|||
sim_cmd = re.sub("<"+env_var+">", get_env_var(env_var), sim_cmd)
|
||||
return compile_cmd, sim_cmd
|
||||
logging.error("Cannot find RTL simulator %0s" % simulator)
|
||||
sys.exit(1)
|
||||
sys.exit(RET_FAIL)
|
||||
|
||||
|
||||
def parse_iss_yaml(iss, iss_yaml, isa, setting_dir):
|
||||
|
@ -87,7 +89,6 @@ def parse_iss_yaml(iss, iss_yaml, isa, setting_dir):
|
|||
"""
|
||||
logging.info("Processing ISS setup file : %s" % iss_yaml)
|
||||
yaml_data = read_yaml(iss_yaml)
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
# Search for matched ISS
|
||||
for entry in yaml_data:
|
||||
if entry['iss'] == iss:
|
||||
|
@ -110,7 +111,7 @@ def parse_iss_yaml(iss, iss_yaml, isa, setting_dir):
|
|||
cmd = re.sub("\<variant\>", isa, cmd)
|
||||
return cmd
|
||||
logging.error("Cannot find ISS %0s" % iss)
|
||||
sys.exit(1)
|
||||
sys.exit(RET_FAIL)
|
||||
|
||||
|
||||
def get_iss_cmd(base_cmd, elf, log):
|
||||
|
@ -128,17 +129,142 @@ def get_iss_cmd(base_cmd, elf, log):
|
|||
cmd += (" &> %s" % log)
|
||||
return cmd
|
||||
|
||||
def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir, cmp_opts, output_dir):
|
||||
"""Compile the instruction generator
|
||||
|
||||
Args:
|
||||
compile_cmd : Compile command for the generator
|
||||
test_list : List of assembly programs to be compiled
|
||||
core_setting_dir : Path for riscv_core_setting.sv
|
||||
cwd : Filesystem path to RISCV-DV repo
|
||||
ext_dir : User extension directory
|
||||
cmd_opts : Compile options for the generator
|
||||
output_dir : Output directory of the ELF files
|
||||
"""
|
||||
if (not((len(test_list) == 1) and (test_list[0]['test'] == 'riscv_csr_test'))):
|
||||
logging.info("Building RISC-V instruction generator")
|
||||
for cmd in compile_cmd:
|
||||
cmd = re.sub("<out>", os.path.abspath(output_dir), cmd)
|
||||
cmd = re.sub("<setting>", core_setting_dir, cmd)
|
||||
if ext_dir == "":
|
||||
cmd = re.sub("<user_extension>", "<cwd>/user_extension", cmd)
|
||||
else:
|
||||
cmd = re.sub("<user_extension>", ext_dir, cmd)
|
||||
cmd = re.sub("<cwd>", cwd, cmd)
|
||||
cmd = re.sub("<cmp_opts>", cmp_opts, cmd)
|
||||
|
||||
logging.debug("Compile command: %s" % cmd)
|
||||
run_cmd(cmd)
|
||||
|
||||
def run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
|
||||
end_signature_addr, timeout_s, output_dir):
|
||||
"""Run CSR test
|
||||
It calls a separate python script to generate directed CSR test code,
|
||||
located at scripts/gen_csr_test.py.
|
||||
"""
|
||||
cmd = "python3 " + cwd + "/scripts/gen_csr_test.py" + \
|
||||
(" --csr_file %s" % csr_file) + \
|
||||
(" --xlen %s" % re.search(r"(?P<xlen>[0-9]+)", isa).group("xlen")) + \
|
||||
(" --iterations %i" % iterations) + \
|
||||
(" --out %s/asm_tests" % output_dir) + \
|
||||
(" --end_signature_addr %s" % end_signature_addr)
|
||||
if lsf_cmd:
|
||||
cmd_list.append(cmd)
|
||||
else:
|
||||
run_cmd(cmd, timeout_s)
|
||||
|
||||
def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
|
||||
isa, end_signature_addr, lsf_cmd, timeout_s, log_suffix,
|
||||
batch_size, output_dir, verbose, check_return_code):
|
||||
"""Run the instruction generator
|
||||
|
||||
Args:
|
||||
sim_cmd : Simulate command for the generator
|
||||
test_list : List of assembly programs to be compiled
|
||||
cwd : Filesystem path to RISCV-DV repo
|
||||
sim_opts : Simulation options for the generator
|
||||
seed_yaml : Seed specification from a prior regression
|
||||
seed : Seed to the instruction generator
|
||||
csr_file : YAML file containing description of all CSRs
|
||||
isa : Processor supported ISA subset
|
||||
end_signature_addr : Address that tests will write pass/fail signature to at end of test
|
||||
lsf_cmd : LSF command used to run the instruction generator
|
||||
timeout_s : Timeout limit in seconds
|
||||
log_suffix : Simulation log file name suffix
|
||||
batch_size : Number of tests to generate per run
|
||||
output_dir : Output directory of the ELF files
|
||||
check_return_code : Check return code of the command
|
||||
"""
|
||||
cmd_list = []
|
||||
sim_cmd = re.sub("<out>", os.path.abspath(output_dir), sim_cmd)
|
||||
sim_cmd = re.sub("<cwd>", cwd, sim_cmd)
|
||||
sim_cmd = re.sub("<sim_opts>", sim_opts, sim_cmd)
|
||||
rerun_seed = {}
|
||||
if seed_yaml:
|
||||
rerun_seed = read_yaml(seed_yaml)
|
||||
logging.info("Running RISC-V instruction generator")
|
||||
sim_seed = {}
|
||||
for test in test_list:
|
||||
iterations = test['iterations']
|
||||
logging.info("Generating %d %s" % (iterations, test['test']))
|
||||
if iterations > 0:
|
||||
# Running a CSR test
|
||||
if test['test'] == 'riscv_csr_test':
|
||||
run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
|
||||
end_signature_addr, timeout_s, output_dir)
|
||||
else:
|
||||
batch_cnt = 1
|
||||
if batch_size > 0:
|
||||
batch_cnt = int((iterations + batch_size - 1) / batch_size);
|
||||
logging.info("Running %s with %0d batches" % (test['test'], batch_cnt))
|
||||
for i in range(0, batch_cnt):
|
||||
test_id = '%0s_%0d' % (test['test'], i)
|
||||
if test_id in rerun_seed:
|
||||
rand_seed = rerun_seed[test_id]
|
||||
else:
|
||||
rand_seed = get_seed(seed)
|
||||
if i < batch_cnt - 1:
|
||||
test_cnt = batch_size
|
||||
else:
|
||||
test_cnt = iterations - i * batch_size;
|
||||
cmd = lsf_cmd + " " + sim_cmd.rstrip() + \
|
||||
(" +UVM_TESTNAME=%s " % test['gen_test']) + \
|
||||
(" +num_of_tests=%i " % test_cnt) + \
|
||||
(" +start_idx=%d " % (i*batch_size)) + \
|
||||
(" +asm_file_name=%s/asm_tests/%s " % (output_dir, test['test'])) + \
|
||||
(" -l %s/sim_%s_%d%s.log " % (output_dir, test['test'], i, log_suffix))
|
||||
if verbose:
|
||||
cmd += "+UVM_VERBOSITY=UVM_HIGH "
|
||||
cmd = re.sub("<seed>", str(rand_seed), cmd)
|
||||
sim_seed[test_id] = str(rand_seed)
|
||||
if "gen_opts" in test:
|
||||
cmd += test['gen_opts']
|
||||
if not re.search("c", isa):
|
||||
cmd += "+disable_compressed_instr=1 ";
|
||||
if lsf_cmd:
|
||||
cmd_list.append(cmd)
|
||||
else:
|
||||
logging.info("Running %s, batch %0d/%0d, test_cnt:%0d" %
|
||||
(test['test'], i+1, batch_cnt, test_cnt))
|
||||
run_cmd(cmd, timeout_s, check_return_code = check_return_code)
|
||||
if sim_seed:
|
||||
with open(('%s/seed.yaml' % os.path.abspath(output_dir)) , 'w') as outfile:
|
||||
yaml.dump(sim_seed, outfile, default_flow_style=False)
|
||||
if lsf_cmd:
|
||||
run_parallel_cmd(cmd_list, timeout_s, check_return_code = check_return_code)
|
||||
|
||||
|
||||
|
||||
def gen(test_list, csr_file, end_signature_addr, isa, simulator,
|
||||
simulator_yaml, output_dir, sim_only, compile_only, lsf_cmd, seed,
|
||||
cwd, cmp_opts, sim_opts, timeout_s, core_setting_dir, ext_dir, cov,
|
||||
log_suffix, batch_size, seed_yaml, stop_on_first_error, verbose=False):
|
||||
log_suffix, batch_size, seed_yaml, verbose, exp):
|
||||
"""Run the instruction generator
|
||||
|
||||
Args:
|
||||
test_list : List of assembly programs to be compiled
|
||||
csr_file : YAML file containing description of all CSRs
|
||||
end_signature_addr : Address that tests will write pass/fail signature to at end of test
|
||||
end_signature_addr : Address that tests will write pass/fail signature to
|
||||
isa : Processor supported ISA subset
|
||||
simulator : RTL simulator used to run instruction generator
|
||||
simulator_yaml : RTL simulator configuration file in YAML format
|
||||
|
@ -157,105 +283,30 @@ def gen(test_list, csr_file, end_signature_addr, isa, simulator,
|
|||
log_suffix : Simulation log file name suffix
|
||||
batch_size : Number of tests to generate per run
|
||||
seed_yaml : Seed specification from a prior regression
|
||||
stop_on_first_error : will end run on first error detected
|
||||
exp : Enable experimental features
|
||||
"""
|
||||
check_return_code = True
|
||||
if simulator == "ius":
|
||||
# Incisive return non-zero return code even test passes
|
||||
check_return_code = False
|
||||
logging.debug("Disable return_code checking for %s" % simulator)
|
||||
# Mutually exclusive options between compile_only and sim_only
|
||||
if compile_only and sim_only:
|
||||
logging.error("argument -co is not allowed with argument -so")
|
||||
if ((compile_only == 0) and (len(test_list) == 0)):
|
||||
return
|
||||
# Setup the compile and simulation command for the generator
|
||||
compile_cmd = []
|
||||
sim_cmd = ""
|
||||
compile_cmd, sim_cmd = get_generator_cmd(simulator, simulator_yaml, cov);
|
||||
if ((compile_only == 0) and (len(test_list) == 0)):
|
||||
return
|
||||
compile_cmd, sim_cmd = get_generator_cmd(simulator, simulator_yaml, cov, exp);
|
||||
# Compile the instruction generator
|
||||
if not sim_only:
|
||||
if (not((len(test_list) == 1) and (test_list[0]['test'] == 'riscv_csr_test'))):
|
||||
logging.info("Building RISC-V instruction generator")
|
||||
for cmd in compile_cmd:
|
||||
cmd = re.sub("<out>", os.path.abspath(output_dir), cmd)
|
||||
cmd = re.sub("<setting>", core_setting_dir, cmd)
|
||||
if ext_dir == "":
|
||||
cmd = re.sub("<user_extension>", "<cwd>/user_extension", cmd)
|
||||
else:
|
||||
cmd = re.sub("<user_extension>", ext_dir, cmd)
|
||||
cmd = re.sub("<cwd>", cwd, cmd)
|
||||
cmd = re.sub("<cmp_opts>", cmp_opts, cmd)
|
||||
|
||||
logging.debug("Compile command: %s" % cmd)
|
||||
output = run_cmd(cmd)
|
||||
do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir, cmp_opts, output_dir)
|
||||
# Run the instruction generator
|
||||
if not compile_only:
|
||||
cmd_list = []
|
||||
sim_cmd = re.sub("<out>", os.path.abspath(output_dir), sim_cmd)
|
||||
sim_cmd = re.sub("<cwd>", cwd, sim_cmd)
|
||||
sim_cmd = re.sub("<sim_opts>", sim_opts, sim_cmd)
|
||||
if seed_yaml:
|
||||
rerun_seed = read_yaml(seed_yaml)
|
||||
else:
|
||||
rerun_seed = {}
|
||||
logging.info("Running RISC-V instruction generator")
|
||||
sim_seed = {}
|
||||
for test in test_list:
|
||||
iterations = test['iterations']
|
||||
logging.info("Generating %d %s" % (iterations, test['test']))
|
||||
if iterations > 0:
|
||||
"""
|
||||
If we are running a CSR test, need to call a separate python script
|
||||
to generate directed CSR test code, located at scripts/gen_csr_test.py.
|
||||
"""
|
||||
if test['test'] == 'riscv_csr_test':
|
||||
cmd = "python3 " + cwd + "/scripts/gen_csr_test.py" + \
|
||||
(" --csr_file %s" % csr_file) + \
|
||||
(" --xlen %s" % re.search(r"(?P<xlen>[0-9]+)", isa).group("xlen")) + \
|
||||
(" --iterations %i" % iterations) + \
|
||||
(" --out %s/asm_tests" % output_dir) + \
|
||||
(" --end_signature_addr %s" % end_signature_addr)
|
||||
if lsf_cmd:
|
||||
cmd_list.append(cmd)
|
||||
else:
|
||||
output = run_cmd(cmd, timeout_s)
|
||||
else:
|
||||
if batch_size > 0:
|
||||
batch_cnt = int((iterations + batch_size - 1) / batch_size);
|
||||
else:
|
||||
batch_cnt = 1
|
||||
logging.info("Running %s with %0d batches" % (test['test'], batch_cnt))
|
||||
for i in range(0, batch_cnt):
|
||||
test_id = '%0s_%0d' % (test['test'], i)
|
||||
if test_id in rerun_seed:
|
||||
rand_seed = rerun_seed[test_id]
|
||||
else:
|
||||
rand_seed = get_seed(seed)
|
||||
if i < batch_cnt - 1:
|
||||
test_cnt = batch_size
|
||||
else:
|
||||
test_cnt = iterations - i * batch_size;
|
||||
cmd = lsf_cmd + " " + sim_cmd.rstrip() + \
|
||||
(" +UVM_TESTNAME=%s " % test['gen_test']) + \
|
||||
(" +num_of_tests=%i " % test_cnt) + \
|
||||
(" +start_idx=%d " % (i*batch_size)) + \
|
||||
(" +asm_file_name=%s/asm_tests/%s " % (output_dir, test['test'])) + \
|
||||
(" -l %s/sim_%s_%d%s.log " % (output_dir, test['test'], i, log_suffix))
|
||||
if verbose:
|
||||
cmd += "+UVM_VERBOSITY=UVM_HIGH "
|
||||
cmd = re.sub("<seed>", str(rand_seed), cmd)
|
||||
sim_seed[test_id] = str(rand_seed)
|
||||
if "gen_opts" in test:
|
||||
cmd += test['gen_opts']
|
||||
if not re.search("c", isa):
|
||||
cmd += "+disable_compressed_instr=1 ";
|
||||
if lsf_cmd:
|
||||
cmd_list.append(cmd)
|
||||
else:
|
||||
logging.info("Running %s, batch %0d/%0d, test_cnt:%0d" %
|
||||
(test['test'], i+1, batch_cnt, test_cnt))
|
||||
output = run_cmd(cmd, timeout_s)
|
||||
if sim_seed:
|
||||
with open(('%s/seed.yaml' % os.path.abspath(output_dir)) , 'w') as outfile:
|
||||
yaml.dump(sim_seed, outfile, default_flow_style=False)
|
||||
if lsf_cmd:
|
||||
run_parallel_cmd(cmd_list, timeout_s)
|
||||
do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
|
||||
isa, end_signature_addr, lsf_cmd, timeout_s, log_suffix,
|
||||
batch_size, output_dir, verbose, check_return_code)
|
||||
|
||||
|
||||
def gcc_compile(test_list, output_dir, isa, mabi, opts):
|
||||
|
@ -377,14 +428,13 @@ def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, setting_dir, timeout
|
|||
logging.debug(cmd)
|
||||
|
||||
|
||||
def iss_cmp(test_list, iss, output_dir, isa, stop_on_first_error):
|
||||
def iss_cmp(test_list, iss, output_dir, stop_on_first_error):
|
||||
"""Compare ISS simulation reult
|
||||
|
||||
Args:
|
||||
test_list : List of assembly programs to be compiled
|
||||
iss : List of instruction set simulators
|
||||
output_dir : Output directory of the ELF files
|
||||
isa : ISA
|
||||
stop_on_first_error : will end run on first error detected
|
||||
"""
|
||||
iss_list = iss.split(",")
|
||||
|
@ -406,14 +456,14 @@ def iss_cmp(test_list, iss, output_dir, isa, stop_on_first_error):
|
|||
if iss == "spike":
|
||||
process_spike_sim_log(log, csv)
|
||||
elif iss == "ovpsim":
|
||||
process_ovpsim_sim_log(log, csv, 1, stop_on_first_error)
|
||||
process_ovpsim_sim_log(log, csv, 0, stop_on_first_error)
|
||||
elif iss == "sail":
|
||||
process_sail_sim_log(log, csv)
|
||||
elif iss == "whisper":
|
||||
process_whisper_sim_log(log, csv)
|
||||
else:
|
||||
logging.error("Unsupported ISS" % iss)
|
||||
sys.exit(1)
|
||||
sys.exit(RET_FAIL)
|
||||
compare_trace_csv(csv_list[0], csv_list[1], iss_list[0], iss_list[1], report)
|
||||
passed_cnt = run_cmd("grep PASSED %s | wc -l" % report).strip()
|
||||
failed_cnt = run_cmd("grep FAILED %s | wc -l" % report).strip()
|
||||
|
@ -496,6 +546,8 @@ def setup_parser():
|
|||
help="Directed assembly test")
|
||||
parser.add_argument("--log_suffix", type=str, default="",
|
||||
help="Simulation log name suffix")
|
||||
parser.add_argument("--exp", action="store_true",
|
||||
help="Run generator with experimental features")
|
||||
parser.add_argument("-bz", "--batch_size", type=int, default=0,
|
||||
help="Number of tests to generate per run. You can split a big"
|
||||
" job to small batches with this option")
|
||||
|
@ -505,6 +557,7 @@ def setup_parser():
|
|||
parser.set_defaults(so=False)
|
||||
parser.set_defaults(verbose=False)
|
||||
parser.set_defaults(cov=False)
|
||||
parser.set_defaults(exp=False)
|
||||
parser.set_defaults(stop_on_first_error=False)
|
||||
return parser
|
||||
|
||||
|
@ -553,8 +606,11 @@ def main():
|
|||
elif args.target == "ml":
|
||||
args.mabi = "lp64"
|
||||
args.isa = "rv64imc"
|
||||
elif args.target == "exp":
|
||||
args.mabi = "lp64"
|
||||
args.isa = "rv64gc"
|
||||
else:
|
||||
print ("Unsupported pre-defined target: %0s" % args.target)
|
||||
sys.exit("Unsupported pre-defined target: %0s" % args.target)
|
||||
else:
|
||||
if re.match(".*gcc_compile.*", args.steps) or re.match(".*iss_sim.*", args.steps):
|
||||
if (not args.mabi) or (not args.isa):
|
||||
|
@ -567,11 +623,8 @@ def main():
|
|||
return
|
||||
|
||||
# Create output directory
|
||||
if args.o is None:
|
||||
output_dir = "out_" + str(date.today())
|
||||
else:
|
||||
output_dir = args.o
|
||||
|
||||
output_dir = create_output(args.o)
|
||||
logging.info("Creating output directory: %s" % output_dir)
|
||||
subprocess.run(["mkdir", "-p", output_dir])
|
||||
subprocess.run(["mkdir", "-p", ("%s/asm_tests" % output_dir)])
|
||||
|
||||
|
@ -590,7 +643,7 @@ def main():
|
|||
args.co, args.lsf_cmd, args.seed, cwd, args.cmp_opts,
|
||||
args.sim_opts, args.gen_timeout, args.core_setting_dir,
|
||||
args.user_extension_dir, args.cov, args.log_suffix, args.batch_size,
|
||||
args.seed_yaml, args.stop_on_first_error, args.verbose)
|
||||
args.seed_yaml, args.verbose, args.exp)
|
||||
|
||||
if not args.co:
|
||||
# Compile the assembly program to ELF, convert to plain binary
|
||||
|
@ -604,7 +657,7 @@ def main():
|
|||
|
||||
# Compare ISS simulation result
|
||||
if args.steps == "all" or re.match(".*iss_cmp.*", args.steps):
|
||||
iss_cmp(matched_list, args.iss, output_dir, args.isa, args.stop_on_first_error)
|
||||
iss_cmp(matched_list, args.iss, output_dir, args.stop_on_first_error)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
10
vendor/google_riscv-dv/scripts/gen_csr_test.py
vendored
10
vendor/google_riscv-dv/scripts/gen_csr_test.py
vendored
|
@ -32,12 +32,13 @@ import yaml
|
|||
import argparse
|
||||
import random
|
||||
import copy
|
||||
from lib import *
|
||||
|
||||
try:
|
||||
from bitstring import BitArray as bitarray
|
||||
except ImportError as e:
|
||||
logging.error("Please install bitstring package: sudo apt-get install python3-bitstring")
|
||||
sys.exit(1)
|
||||
sys.exit(RET_FAIL)
|
||||
|
||||
"""
|
||||
Defines the test's success/failure values, one of which will be written to
|
||||
|
@ -176,25 +177,20 @@ def predict_csr_val(csr_op, rs1_val, csr_val, csr_write_mask, csr_read_mask):
|
|||
prediction = None
|
||||
# create a zero bitarray to zero extend immediates
|
||||
zero = bitarray(uint=0, length=csr_val.len - 5)
|
||||
prediction = csr_read(csr_val, csr_read_mask)
|
||||
if csr_op == 'csrrw':
|
||||
prediction = csr_read(csr_val, csr_read_mask)
|
||||
csr_write(rs1_val, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrs':
|
||||
prediction = csr_read(csr_val, csr_read_mask)
|
||||
csr_write(rs1_val | prediction, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrc':
|
||||
prediction = csr_read(csr_val, csr_read_mask)
|
||||
csr_write((~rs1_val) & prediction, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrwi':
|
||||
prediction = csr_read(csr_val, csr_read_mask)
|
||||
zero.append(rs1_val[-5:])
|
||||
csr_write(zero, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrsi':
|
||||
prediction = csr_read(csr_val, csr_read_mask)
|
||||
zero.append(rs1_val[-5:])
|
||||
csr_write(zero | prediction, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrci':
|
||||
prediction = csr_read(csr_val, csr_read_mask)
|
||||
zero.append(rs1_val[-5:])
|
||||
csr_write((~zero) & prediction, csr_val, csr_write_mask)
|
||||
return f"0x{prediction.hex}"
|
||||
|
|
60
vendor/google_riscv-dv/scripts/lib.py
vendored
60
vendor/google_riscv-dv/scripts/lib.py
vendored
|
@ -25,6 +25,12 @@ import time
|
|||
import yaml
|
||||
import logging
|
||||
|
||||
from datetime import date
|
||||
|
||||
RET_SUCCESS = 0
|
||||
RET_FAIL = 1
|
||||
RET_FATAL = -1
|
||||
|
||||
def setup_logging(verbose):
|
||||
"""Setup the root logger.
|
||||
|
||||
|
@ -55,7 +61,7 @@ def read_yaml(yaml_file):
|
|||
yaml_data = yaml.safe_load(f)
|
||||
except yaml.YAMLError as exc:
|
||||
logging.error(exc)
|
||||
sys.exit(1)
|
||||
sys.exit(RET_FAIL)
|
||||
return yaml_data
|
||||
|
||||
|
||||
|
@ -72,7 +78,7 @@ def get_env_var(var):
|
|||
val = os.environ[var]
|
||||
except KeyError:
|
||||
logging.warning("Please set the environment variable %0s" % var)
|
||||
sys.exit(1)
|
||||
sys.exit(RET_FAIL)
|
||||
return val
|
||||
|
||||
|
||||
|
@ -87,11 +93,10 @@ def get_seed(seed):
|
|||
"""
|
||||
if seed >= 0:
|
||||
return seed
|
||||
else:
|
||||
return random.getrandbits(32)
|
||||
return random.getrandbits(32)
|
||||
|
||||
|
||||
def run_cmd(cmd, timeout_s = 999, exit_on_error = 1):
|
||||
def run_cmd(cmd, timeout_s = 999, exit_on_error = 1, check_return_code = True):
|
||||
"""Run a command and return output
|
||||
|
||||
Args:
|
||||
|
@ -108,9 +113,9 @@ def run_cmd(cmd, timeout_s = 999, exit_on_error = 1):
|
|||
universal_newlines=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
except subprocess.CalledProcessError:
|
||||
logging.error(ps.communicate()[0])
|
||||
sys.exit(1)
|
||||
sys.exit(RET_FAIL)
|
||||
try:
|
||||
output = ps.communicate(timeout = timeout_s)[0]
|
||||
except subprocess.TimeoutExpired:
|
||||
|
@ -118,17 +123,16 @@ def run_cmd(cmd, timeout_s = 999, exit_on_error = 1):
|
|||
output = ""
|
||||
ps.kill()
|
||||
rc = ps.returncode
|
||||
if rc:
|
||||
if rc > 0:
|
||||
logging.info(output)
|
||||
logging.error("ERROR return code: %d, cmd:%s" % (rc, cmd))
|
||||
if exit_on_error:
|
||||
sys.exit(1)
|
||||
if rc and check_return_code and rc > 0:
|
||||
logging.info(output)
|
||||
logging.error("ERROR return code: %d/%d, cmd:%s" % (check_return_code, rc, cmd))
|
||||
if exit_on_error:
|
||||
sys.exit(RET_FAIL)
|
||||
logging.debug(output)
|
||||
return output
|
||||
|
||||
|
||||
def run_parallel_cmd(cmd_list, timeout_s = 999, exit_on_error = 0):
|
||||
def run_parallel_cmd(cmd_list, timeout_s = 999, exit_on_error = 0, check_return_code = True):
|
||||
"""Run a list of commands in parallel
|
||||
|
||||
Args:
|
||||
|
@ -155,12 +159,11 @@ def run_parallel_cmd(cmd_list, timeout_s = 999, exit_on_error = 0):
|
|||
logging.error("Timeout[%ds]: %s" % (timeout_s, cmd))
|
||||
children[i].kill()
|
||||
rc = children[i].returncode
|
||||
if rc:
|
||||
if rc > 0:
|
||||
logging.info(output)
|
||||
logging.error("ERROR return code: %d, cmd:%s" % (rc, cmd))
|
||||
if exit_on_error:
|
||||
sys.exit(1)
|
||||
if rc and check_return_code and rc > 0:
|
||||
logging.info(output)
|
||||
logging.error("ERROR return code: %d, cmd:%s" % (rc, cmd))
|
||||
if exit_on_error:
|
||||
sys.exit(RET_FAIL)
|
||||
# Restore stty setting otherwise the terminal may go crazy
|
||||
os.system("stty sane")
|
||||
logging.debug(output)
|
||||
|
@ -180,15 +183,30 @@ def process_regression_list(testlist, test, iterations, matched_list, riscv_dv_r
|
|||
"""
|
||||
logging.info("Processing regression test list : %s, test: %s" % (testlist, test))
|
||||
yaml_data = read_yaml(testlist)
|
||||
mult_test = test.split(',')
|
||||
for entry in yaml_data:
|
||||
if 'import' in entry:
|
||||
sub_list = re.sub('<riscv_dv_root>', riscv_dv_root, entry['import'])
|
||||
process_regression_list(sub_list, test, iterations, matched_list, riscv_dv_root)
|
||||
else:
|
||||
if (entry['test'] == test) or (test == "all"):
|
||||
if (entry['test'] in mult_test) or (test == "all"):
|
||||
if (iterations > 0 and entry['iterations'] > 0):
|
||||
entry['iterations'] = iterations
|
||||
if entry['iterations'] > 0:
|
||||
logging.info("Found matched tests: %s, iterations:%0d" %
|
||||
(entry['test'], entry['iterations']))
|
||||
matched_list.append(entry)
|
||||
|
||||
def create_output(output, prefix = "out_"):
|
||||
""" Create output directory
|
||||
|
||||
Args:
|
||||
output : Name of specified output directory
|
||||
|
||||
Returns:
|
||||
Output directory
|
||||
"""
|
||||
# Create output directory
|
||||
if output is None:
|
||||
return prefix + str(date.today())
|
||||
return output
|
||||
|
|
|
@ -27,46 +27,54 @@ from lib import *
|
|||
from riscv_trace_csv import *
|
||||
|
||||
try:
|
||||
from ovpsim_log_to_trace_csv_vectors import *
|
||||
from ovpsim_log_to_trace_csv_vectors import *
|
||||
except:
|
||||
def assign_operand_vector(a,b,c,d):
|
||||
""" stub version when no vector processing included """
|
||||
logging.info("No OVPsim vector instruction processing included")
|
||||
if stop_on_first_error:
|
||||
sys.exit(-1)
|
||||
def assign_operand_vector(a,b,c,d):
|
||||
""" stub version when no vector processing included """
|
||||
logging.info("No OVPsim vector instruction processing included")
|
||||
if stop_on_first_error:
|
||||
sys.exit(RET_FATAL)
|
||||
def is_an_extension_instruction(instr):
|
||||
if instr and 'v' in instr[0]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
stop_on_first_error = 0
|
||||
|
||||
def fatal (s):
|
||||
""" ensure we end if a problem """
|
||||
logging.fatal("ERROR: "+s)
|
||||
sys.exit(-1)
|
||||
""" ensure we end if a problem """
|
||||
logging.fatal("ERROR: "+s)
|
||||
sys.exit(RET_FATAL)
|
||||
|
||||
def convert_mode(pri, line):
|
||||
""" OVPsim uses text string, convert to numeric """
|
||||
if "Machine" in pri: return str(3)
|
||||
if "Supervisor" in pri: return str(1)
|
||||
if "User" in pri: return str(0)
|
||||
logging.error("convert_mode = UNKNOWN PRIV MODE [%s]: %s" % (pri, line))
|
||||
if stop_on_first_error:
|
||||
sys.exit(-1)
|
||||
""" OVPsim uses text string, convert to numeric """
|
||||
if "Machine" in pri: return str(3)
|
||||
if "Supervisor" in pri: return str(1)
|
||||
if "User" in pri: return str(0)
|
||||
logging.error("convert_mode = UNKNOWN PRIV MODE [%s]: %s" % (pri, line))
|
||||
if stop_on_first_error:
|
||||
sys.exit(RET_FATAL)
|
||||
|
||||
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"]
|
||||
FREGS = ["ft0","ft1","ft2","ft3","ft4","ft5","ft6","ft7","fs0","fs1","fa0",
|
||||
"fa1","fa2","fa3","fa4","fa5","fa6","fa7","fs2","fs3","fs4","fs5",
|
||||
"fs6","fs7","fs8","fs9","fs10","fs11","ft8","ft9","ft10","ft11"]
|
||||
|
||||
def process_jal(trace, operands, gpr):
|
||||
""" correctly process jal """
|
||||
# TODO need to merge with jalr
|
||||
## jal rd, imm
|
||||
if len(operands) == 2:
|
||||
trace.rd = operands[0]
|
||||
trace.rd_val = gpr[trace.rd]
|
||||
trace.imm = get_imm_hex_val("0x" + operands[1])
|
||||
else:
|
||||
fatal("process_jal(%s) wrong num operands (%d)" %
|
||||
(trace.instr, len(operands)))
|
||||
""" correctly process jal """
|
||||
# TODO need to merge with jalr
|
||||
## jal rd, imm
|
||||
if len(operands) == 2:
|
||||
trace.rd = operands[0]
|
||||
trace.rd_val = gpr[trace.rd]
|
||||
trace.imm = get_imm_hex_val("0x" + operands[1])
|
||||
else:
|
||||
fatal("process_jal(%s) wrong num operands (%d)" %
|
||||
(trace.instr, len(operands)))
|
||||
|
||||
def process_jalr(trace, operands, gpr):
|
||||
""" process jalr """
|
||||
|
@ -134,64 +142,69 @@ pseudos={
|
|||
}
|
||||
|
||||
def check_conversion(entry):
|
||||
""" after conversion check that the entry was converted correctly """
|
||||
instr_str_0 =entry.instr_str.split(" ")[0]
|
||||
instr =entry.instr.split(" ")[0]
|
||||
if "c." in instr[0:2]:
|
||||
instr = instr[2:]
|
||||
if instr in instr_str_0:
|
||||
return # same
|
||||
#logging.debug("converted pseudo %10s -> %s" % (instr_str_0, instr))
|
||||
if instr_str_0 in pseudos:
|
||||
p_instr = pseudos[instr_str_0]
|
||||
if p_instr in instr:
|
||||
return # is pseudo, converted ok
|
||||
logging.error(
|
||||
"converted %10s -> %s <<-- not correct pseudo (%s)" %
|
||||
(instr_str_0, instr, p_instr))
|
||||
if stop_on_first_error:
|
||||
sys.exit(-1)
|
||||
logging.error("converted %10s -> %s <<-- not correct at all" %
|
||||
(instr_str_0, instr))
|
||||
""" after conversion check that the entry was converted correctly """
|
||||
instr_str_0 =entry.instr_str.split(" ")[0]
|
||||
instr =entry.instr.split(" ")[0]
|
||||
if "c." in instr[0:2]:
|
||||
instr = instr[2:]
|
||||
if instr in instr_str_0:
|
||||
return # same
|
||||
#logging.debug("converted pseudo %10s -> %s" % (instr_str_0, instr))
|
||||
if instr_str_0 in pseudos:
|
||||
p_instr = pseudos[instr_str_0]
|
||||
if p_instr in instr:
|
||||
return # is pseudo, converted ok
|
||||
logging.error(
|
||||
"converted %10s -> %s <<-- not correct pseudo (%s)" %
|
||||
(instr_str_0, instr, p_instr))
|
||||
if stop_on_first_error:
|
||||
sys.exit(-1)
|
||||
sys.exit(RET_FATAL)
|
||||
logging.error("converted %10s -> %s <<-- not correct at all" %
|
||||
(instr_str_0, instr))
|
||||
if stop_on_first_error:
|
||||
sys.exit(RET_FATAL)
|
||||
|
||||
operands_list = ["rd","rs1","rs2","vd","vs1","vs2","vs3","fd","fs1","fs2"]
|
||||
|
||||
def update_operands_values(trace, gpr):
|
||||
""" ensure operands have been updated """
|
||||
for op in operands_list:
|
||||
exec("if trace.%0s in gpr: trace.%0s_val = gpr[trace.%0s]" % (op, op, op))
|
||||
|
||||
def show_line_instr(line, i):
|
||||
""" show line """
|
||||
if i.instr_str[0] in ['v']:
|
||||
logging.debug("%s" % (line.strip()))
|
||||
logging.debug(
|
||||
" -->> instr_str(%s) binary(%s) addr(%s) mode(%s) instr(%s)"
|
||||
% ( i.instr_str, i.binary, i.addr, i.privileged_mode,
|
||||
i.instr))
|
||||
""" show line """
|
||||
if is_an_extension_instruction(i.instr):
|
||||
logging.debug("%s" % (line.strip()))
|
||||
logging.debug(
|
||||
" -->> instr_str(%s) binary(%s) addr(%s) mode(%s) instr(%s)"
|
||||
% ( i.instr_str, i.binary, i.addr, i.privileged_mode,i.instr))
|
||||
|
||||
def check_num_operands(instr_str, num_operands, n):
|
||||
""" ensure consistency """
|
||||
if n != num_operands:
|
||||
fatal("%s: num operands wrong, expected (%d) got (%d)" % (instr_str,
|
||||
n, num_operands))
|
||||
""" ensure consistency """
|
||||
if n != num_operands:
|
||||
fatal("%s: num operands wrong, expected (%d) got (%d)" % (instr_str,
|
||||
n, num_operands))
|
||||
|
||||
def is_csr(r):
|
||||
""" see if r is a csr """
|
||||
|
||||
# add more as needed
|
||||
if r in ["mtvec","pmpaddr0","pmpcfg0","mstatus","mepc","mscratch","mcause",
|
||||
"mtval","vl","vtype"]:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
""" see if r is a csr """
|
||||
# TODO add more as needed - could look in the enum privileged_reg_t or the cores settings: implemented_csr[]
|
||||
if r in ["mtvec","pmpaddr0","pmpcfg0","mstatus","mepc","mscratch","mcause",
|
||||
"mtval","vl","vtype"]:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def process_branch_offset (opn, operands, prev_trace):
|
||||
""" convert from ovpsim logs branch offsets as absolute to relative """
|
||||
addr = operands[opn]
|
||||
pc = prev_trace.addr
|
||||
offset_dec = int(addr, 16) - int(pc, 16)
|
||||
offset = hex(offset_dec)
|
||||
operands[opn] = offset
|
||||
""" convert from ovpsim logs branch offsets as absolute to relative """
|
||||
addr = operands[opn]
|
||||
pc = prev_trace.addr
|
||||
offset_dec = int(addr, 16) - int(pc, 16)
|
||||
offset = hex(offset_dec)
|
||||
operands[opn] = offset
|
||||
|
||||
def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 1, stop = 0,
|
||||
dont_truncate_after_first_ecall = 0,
|
||||
verbose2 = False):
|
||||
dont_truncate_after_first_ecall = 0,
|
||||
verbose2 = False):
|
||||
"""Process OVPsim simulation log.
|
||||
|
||||
Extract instruction and affected register information from ovpsim simulation
|
||||
|
@ -200,10 +213,12 @@ def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 1, stop = 0,
|
|||
|
||||
stop_on_first_error = stop
|
||||
|
||||
logging.info("Processing ovpsim log [%s %s %s]: %s" %
|
||||
("full_trace" if full_trace else "", "stop_on_first_error" if stop else "",
|
||||
"dont_truncate_after_first_ecall" if dont_truncate_after_first_ecall else
|
||||
"", ovpsim_log))
|
||||
logging.info("Processing ovpsim log : %s" % ovpsim_log)
|
||||
|
||||
logging.debug("Flags [%s %s %s]" %
|
||||
("full_trace" if full_trace else "",
|
||||
"stop_on_first_error" if stop else "",
|
||||
"dont_truncate_after_first_ecall" if dont_truncate_after_first_ecall else ""))
|
||||
|
||||
# Remove the header part of ovpsim log
|
||||
cmd = ("sed -i '/Info 1:/,$!d' %s" % ovpsim_log)
|
||||
|
@ -217,14 +232,16 @@ def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 1, stop = 0,
|
|||
os.system(cmd)
|
||||
|
||||
# storage and initial values of gpr and csr
|
||||
|
||||
gpr = {}
|
||||
csr = {}
|
||||
|
||||
for g in REGS: # base base isa gprs
|
||||
for g in REGS: # base isa gprs
|
||||
gpr[g] = 0
|
||||
|
||||
for i in range(32): # add in v0-v31 gprs
|
||||
gpr["v"+str(i)] = 0
|
||||
for f in FREGS: # floating point gprs
|
||||
gpr[f] = 0
|
||||
|
||||
csr["vl"] = 0
|
||||
csr["vtype"] = 0
|
||||
|
@ -238,22 +255,22 @@ def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 1, stop = 0,
|
|||
for line in f:
|
||||
# Extract instruction infromation
|
||||
m = re.search(r"riscvOVPsim.*, 0x(?P<addr>.*?)(?P<section>\(.*\): ?)" \
|
||||
"(?P<mode>[A-Za-z]*?)\s+(?P<bin>[a-f0-9]*?)\s+(?P<instr_str>.*?)$",
|
||||
line)
|
||||
"(?P<mode>[A-Za-z]*?)\s+(?P<bin>[a-f0-9]*?)\s+(?P<instr_str>.*?)$", line)
|
||||
if m:
|
||||
# its instruction disassembly line
|
||||
if prev_trace: # write out the previous one when find next one
|
||||
check_conversion(prev_trace)
|
||||
instr_cnt += 1
|
||||
trace_csv.write_trace_entry(prev_trace)
|
||||
if verbose2:
|
||||
logging.debug("prev_trace:: "+str(prev_trace.__dict__))
|
||||
logging.debug("csr :: "+str(csr))
|
||||
logging.debug("gpr :: "+str(gpr))
|
||||
if logit:
|
||||
# fatal ("stop for now")
|
||||
pass
|
||||
prev_trace = 0
|
||||
check_conversion(prev_trace)
|
||||
update_operands_values(prev_trace, gpr)
|
||||
instr_cnt += 1
|
||||
trace_csv.write_trace_entry(prev_trace)
|
||||
if verbose2:
|
||||
logging.debug("prev_trace:: "+str(prev_trace.__dict__))
|
||||
logging.debug("csr :: "+str(csr))
|
||||
logging.debug("gpr :: "+str(gpr))
|
||||
if logit:
|
||||
# fatal ("stop for now")
|
||||
pass
|
||||
prev_trace = 0
|
||||
prev_trace = RiscvInstructionTraceEntry()
|
||||
prev_trace.instr_str = m.group("instr_str")
|
||||
prev_trace.instr = prev_trace.instr_str.split(" ")[0]
|
||||
|
@ -263,127 +280,119 @@ def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 1, stop = 0,
|
|||
prev_trace.privileged_mode = convert_mode(m.group("mode"), line)
|
||||
prev_trace.updated_csr = []
|
||||
prev_trace.updated_gpr = []
|
||||
|
||||
#if prev_trace.instr in ["vsetvli"]:
|
||||
#if prev_trace.instr in ["vlh.v"]:
|
||||
#if prev_trace.instr in ["vmul.vx"]:
|
||||
if prev_trace.instr in ["vmul.vx_XXX"]:
|
||||
logit = 1
|
||||
verbose2 = True
|
||||
if prev_trace.instr in ["vsetvl"]:
|
||||
logit = 1
|
||||
verbose2 = True
|
||||
|
||||
show_line_instr(line, prev_trace)
|
||||
|
||||
if full_trace:
|
||||
# TODO - when got full ins decode remove this
|
||||
if "fsriw" in line or \
|
||||
"fsw" in line or \
|
||||
"fsd" in line or \
|
||||
"fnmsub.d" in line or \
|
||||
"flw" in line:
|
||||
logging.debug ("Ignoring ins...(%s) " % (line))
|
||||
continue
|
||||
logging.debug("Processing [%s]: %s" %
|
||||
(prev_trace.instr, prev_trace.instr_str))
|
||||
process_if_compressed(prev_trace)
|
||||
o = re.search (r"(?P<instr>[a-z]*?)\s(?P<operand>.*)",
|
||||
prev_trace.instr_str)
|
||||
if o:
|
||||
operand_str = o.group("operand").replace(" ", "")
|
||||
operands = operand_str.split(",")
|
||||
if (prev_trace.instr in ['jalr', 'c.jalr']):
|
||||
process_jalr(prev_trace, operands, gpr)
|
||||
elif (prev_trace.instr in ['jal','c.jal']):
|
||||
process_jal(prev_trace, operands, gpr)
|
||||
else:
|
||||
if 'v' in prev_trace.instr[0]:
|
||||
assign_operand_vector(prev_trace, operands, gpr, stop_on_first_error)
|
||||
elif 'f' in prev_trace.instr[0] or "c.f" in prev_trace.instr[0:3]:
|
||||
pass # ignore floating point. TODO include them
|
||||
else:
|
||||
if prev_trace.instr in [
|
||||
'beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu']:
|
||||
process_branch_offset (2, operands, prev_trace)
|
||||
elif prev_trace.instr in [
|
||||
'c.beqz', 'c.bnez', 'beqz', 'bnez', 'bgez',
|
||||
'bltz', 'blez', 'bgtz']:
|
||||
process_branch_offset (1, operands, prev_trace)
|
||||
if prev_trace.instr in ['j', 'c.j']:
|
||||
operands[0] = "0x" + operands[0]
|
||||
assign_operand(prev_trace, operands, gpr, stop_on_first_error)
|
||||
# TODO - when got full ins decode remove this
|
||||
if "fsw" in line or \
|
||||
"fnmsub.d" in line or \
|
||||
"fsd" in line:
|
||||
# "fsriw" in line or \
|
||||
# "flw" in line or \
|
||||
logging.debug ("Ignoring ins...(%s) " % (line))
|
||||
continue
|
||||
process_if_compressed(prev_trace)
|
||||
o = re.search (r"(?P<instr>[a-z]*?)\s(?P<operand>.*)",
|
||||
prev_trace.instr_str)
|
||||
if o:
|
||||
operand_str = o.group("operand").replace(" ", "")
|
||||
operands = operand_str.split(",")
|
||||
if (prev_trace.instr in ['jalr', 'c.jalr']):
|
||||
process_jalr(prev_trace, operands, gpr)
|
||||
elif (prev_trace.instr in ['jal','c.jal']):
|
||||
process_jal(prev_trace, operands, gpr)
|
||||
else:
|
||||
# logging.debug("no operand for [%s] in [%s]" % (trace_instr,
|
||||
# trace_instr_str))
|
||||
pass
|
||||
if is_an_extension_instruction(prev_trace.instr):
|
||||
assign_operand_vector(prev_trace, operands, gpr, stop_on_first_error)
|
||||
elif 'f' in prev_trace.instr[0] or "c.f" in prev_trace.instr[0:3]:
|
||||
pass # ignore floating point. TODO include them
|
||||
else:
|
||||
if prev_trace.instr in ['beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu']:
|
||||
process_branch_offset (2, operands, prev_trace)
|
||||
elif prev_trace.instr in [
|
||||
'c.beqz', 'c.bnez', 'beqz', 'bnez', 'bgez', 'bltz', 'blez', 'bgtz']:
|
||||
process_branch_offset (1, operands, prev_trace)
|
||||
if prev_trace.instr in ['j', 'c.j']:
|
||||
operands[0] = "0x" + operands[0] # ovpsim has no '0x' so need to add it.
|
||||
assign_operand(prev_trace, operands, gpr, stop_on_first_error)
|
||||
else:
|
||||
# logging.debug("no operand for [%s] in [%s]" % (trace_instr,
|
||||
# trace_instr_str))
|
||||
pass
|
||||
else:
|
||||
# its a csr, gpr new value or report
|
||||
if 0: logging.debug ("reg change... [%s]" % (line.strip()))
|
||||
if verbose2:
|
||||
logging.debug ("reg change... [%s]" % (line.strip()))
|
||||
# Extract register change value information
|
||||
c = re.search(r" (?P<r>[a-z]*[0-9]{0,2}?) (?P<pre>[a-f0-9]+?)" \
|
||||
" -> (?P<val>[a-f0-9]+?)$", line)
|
||||
if c and is_csr (c.group("r")):
|
||||
csr[c.group("r")] = c.group("val")
|
||||
if verbose2: logging.debug("c:csr %0s = %0s" %
|
||||
(c.group("r"), c.group("val")))
|
||||
csr[c.group("r")] = c.group("val")
|
||||
# prev_trace.updated_csr.append(c.group("r"))
|
||||
prev_trace.updated_csr.append([c.group("r"), c.group("val")])
|
||||
continue
|
||||
csr[c.group("r")] = c.group("val")
|
||||
if verbose2:
|
||||
logging.debug("c:csr %0s = %0s" % (c.group("r"), c.group("val")))
|
||||
csr[c.group("r")] = c.group("val")
|
||||
# prev_trace.updated_csr.append(c.group("r"))
|
||||
prev_trace.updated_csr.append([c.group("r"), c.group("val")])
|
||||
continue
|
||||
n = re.search(r" (?P<r>[a-z]{1,3}[0-9]{0,2}?) (?P<pre>[a-f0-9]+?)" \
|
||||
" -> (?P<val>[a-f0-9]+?)$", line)
|
||||
if n: # gpr
|
||||
if verbose2: logging.debug(("n:gpr %0s = %0s" %
|
||||
(n.group("r"), n.group("val"))))
|
||||
if verbose2:
|
||||
logging.debug(("n:gpr %0s = %0s" % (n.group("r"), n.group("val"))))
|
||||
if n.group("r") != "frm":
|
||||
# prev_trace.updated_gpr.append(n.group("r"))
|
||||
prev_trace.updated_gpr.append([n.group("r"), n.group("val")])
|
||||
if 'v' in prev_trace.instr[0]:
|
||||
gpr[n.group("r")] = n.group("val")
|
||||
if is_an_extension_instruction(prev_trace.instr):
|
||||
gpr[n.group("r")] = n.group("val")
|
||||
else:
|
||||
# backwards compatible
|
||||
prev_trace.rd = n.group("r")
|
||||
prev_trace.rd_val = n.group("val")
|
||||
gpr[prev_trace.rd] = prev_trace.rd_val
|
||||
# backwards compatible
|
||||
prev_trace.rd = n.group("r")
|
||||
prev_trace.rd_val = n.group("val")
|
||||
gpr[prev_trace.rd] = prev_trace.rd_val
|
||||
if 0:
|
||||
print (
|
||||
"write entry [[%d]]: rd[%s] val[%s] instr(%s) bin(%s) addr(%s)"
|
||||
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, prev_trace.binary, prev_trace.addr))
|
||||
trace_instr_str, prev_trace.binary, prev_trace.addr))
|
||||
print (rv_instr_trace.__dict__)
|
||||
sys.exit(-1)
|
||||
sys.exit(RET_FATAL)
|
||||
else:
|
||||
line = line.strip()
|
||||
if verbose2: logging.debug("ignoring line: [%s] %s " %
|
||||
(str(instr_cnt), line))
|
||||
line = re.sub(' +', ' ', line)
|
||||
split = line.split(" ")
|
||||
if len(split) == 1: continue
|
||||
item = split[1]
|
||||
if "----" in item: continue
|
||||
if "REPORT" in line or item in [ # TODO sort csrs
|
||||
"mtvec","pmpaddr0","pmpcfg0","mstatus","mepc","mscratch",
|
||||
"mcause","mtval","vl","vtype","sstatus"]:
|
||||
logging.debug("Ignoring: [%d] [[%s]]" % (instr_cnt, line))
|
||||
pass
|
||||
elif "Warning (RISCV_" in line:
|
||||
logging.debug("Skipping: [%d] (%s) [[%s]]" %
|
||||
(instr_cnt, prev_trace.instr_str, line))
|
||||
prev_trace.instr = "nop"
|
||||
prev_trace.instr_str = "nop"
|
||||
else:
|
||||
logging.debug("<unknown> (%s) in line: [%s] %s " %
|
||||
(item, str(instr_cnt), line))
|
||||
if stop_on_first_error:
|
||||
fatal ("")
|
||||
line = line.strip()
|
||||
if verbose2: logging.debug("ignoring line: [%s] %s " %
|
||||
(str(instr_cnt), line))
|
||||
line = re.sub(' +', ' ', line)
|
||||
split = line.split(" ")
|
||||
if len(split) == 1: continue
|
||||
item = split[1]
|
||||
if "----" in item: continue
|
||||
if "REPORT" in line or item in [ # TODO sort csrs
|
||||
"mtvec","pmpaddr0","pmpcfg0","mstatus","mepc","mscratch",
|
||||
"mcause","mtval","vl","vtype","sstatus"]:
|
||||
logging.debug("Ignoring: [%d] [[%s]]" % (instr_cnt, line))
|
||||
pass
|
||||
elif "Warning (RISCV_" in line:
|
||||
logging.debug("Skipping: [%d] (%s) [[%s]]" %
|
||||
(instr_cnt, prev_trace.instr_str, line))
|
||||
prev_trace.instr = "nop"
|
||||
prev_trace.instr_str = "nop"
|
||||
else:
|
||||
logging.debug("<unknown> (%s) in line: [%s] %s " %
|
||||
(item, str(instr_cnt), line))
|
||||
if stop_on_first_error:
|
||||
fatal ("")
|
||||
logging.info("Processed instruction count : %d " % instr_cnt)
|
||||
if instr_cnt == 0:
|
||||
logging.error ("No Instructions in logfile: %s" % ovpsim_log)
|
||||
sys.exit(-1)
|
||||
sys.exit(RET_FATAL)
|
||||
logging.info("CSV saved to : %s" % csv)
|
||||
|
||||
|
||||
def main():
|
||||
""" if used standalone set up for testing """
|
||||
instr_trace = []
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input ovpsim simulation log")
|
||||
|
|
|
@ -20,6 +20,7 @@ import csv
|
|||
import re
|
||||
import logging
|
||||
import sys
|
||||
from lib import *
|
||||
|
||||
class RiscvInstructionTraceEntry(object):
|
||||
"""RISC-V instruction trace entry"""
|
||||
|
@ -46,12 +47,20 @@ class RiscvInstructionTraceEntry(object):
|
|||
self.vs2_val = ""
|
||||
self.vs3 = ""
|
||||
self.vs3_val = ""
|
||||
self.vtype_e = ""
|
||||
self.vtype_m = ""
|
||||
self.vtype_d = ""
|
||||
self.rs3 = ""
|
||||
self.rs3_val = ""
|
||||
self.vtype_vsew = ""
|
||||
self.vtype_vmul = ""
|
||||
self.vtype_vediv = ""
|
||||
self.vm = ""
|
||||
self.updated_csr = ""
|
||||
self.updated_gpr = ""
|
||||
self.fd = ""
|
||||
self.fd_val = ""
|
||||
self.fs1 = ""
|
||||
self.fs1_val = ""
|
||||
self.fs2 = ""
|
||||
self.fs2_val = ""
|
||||
|
||||
def get_trace_string(self):
|
||||
"""Return a short string of the trace entry"""
|
||||
|
@ -73,9 +82,10 @@ class RiscvInstructionTraceCsv(object):
|
|||
"""Create a CSV file handle for a new trace"""
|
||||
fields = [
|
||||
"instr", "rd", "rd_val", "rs1", "rs1_val", "rs2", "rs2_val",
|
||||
"imm", "str", "addr", "binary", "csr", "mode",
|
||||
"rs3", "rs3_val", "imm", "str", "addr", "binary", "csr", "mode",
|
||||
"vd", "vd_val", "vs1", "vs1_val","vs2", "vs2_val","vs3", "vs3_val",
|
||||
"vtype_e", "vtype_m", "vtype_d", "vm", "updated_csr", "updated_gpr"]
|
||||
"vtype_vsew", "vtype_vmul", "vtype_vediv", "vm", "updated_csr", "updated_gpr",
|
||||
"fd", "fd_val", "fs1", "fs1_val","fs2", "fs2_val"]
|
||||
self.csv_writer = csv.DictWriter(self.csv_fd, fieldnames=fields)
|
||||
self.csv_writer.writeheader()
|
||||
|
||||
|
@ -96,33 +106,41 @@ class RiscvInstructionTraceCsv(object):
|
|||
def write_trace_entry(self, entry):
|
||||
"""Write a new trace entry to CSV"""
|
||||
self.gpr[entry.rd] = entry.rd_val
|
||||
self.csv_writer.writerow({'str' : entry.instr_str,
|
||||
'rd' : entry.rd,
|
||||
'rd_val' : entry.rd_val,
|
||||
'rs1' : entry.rs1,
|
||||
'rs1_val' : entry.rs1_val,
|
||||
'rs2' : entry.rs2,
|
||||
'rs2_val' : entry.rs2_val,
|
||||
'addr' : entry.addr,
|
||||
'instr' : entry.instr,
|
||||
'imm' : entry.imm,
|
||||
'csr' : entry.csr,
|
||||
'binary' : entry.binary,
|
||||
'mode' : entry.privileged_mode,
|
||||
'vd' : entry.vd,
|
||||
'vd_val' : entry.vd_val,
|
||||
'vs1' : entry.vs1,
|
||||
'vs1_val' : entry.vs1_val,
|
||||
'vs2' : entry.vs2,
|
||||
'vs2_val' : entry.vs2_val,
|
||||
'vs3' : entry.vs3,
|
||||
'vs3_val' : entry.vs3_val,
|
||||
'vtype_e' : entry.vtype_e,
|
||||
'vtype_m' : entry.vtype_m,
|
||||
'vtype_d' : entry.vtype_d,
|
||||
'vm' : entry.vm,
|
||||
'updated_csr': entry.updated_csr,
|
||||
'updated_gpr': entry.updated_gpr,
|
||||
self.csv_writer.writerow({'str' : entry.instr_str,
|
||||
'rd' : entry.rd,
|
||||
'rd_val' : entry.rd_val,
|
||||
'rs1' : entry.rs1,
|
||||
'rs1_val' : entry.rs1_val,
|
||||
'rs2' : entry.rs2,
|
||||
'rs2_val' : entry.rs2_val,
|
||||
'rs3' : entry.rs3,
|
||||
'rs3_val' : entry.rs3_val,
|
||||
'addr' : entry.addr,
|
||||
'instr' : entry.instr,
|
||||
'imm' : entry.imm,
|
||||
'csr' : entry.csr,
|
||||
'binary' : entry.binary,
|
||||
'mode' : entry.privileged_mode,
|
||||
'vd' : entry.vd,
|
||||
'vd_val' : entry.vd_val,
|
||||
'vs1' : entry.vs1,
|
||||
'vs1_val' : entry.vs1_val,
|
||||
'vs2' : entry.vs2,
|
||||
'vs2_val' : entry.vs2_val,
|
||||
'vs3' : entry.vs3,
|
||||
'vs3_val' : entry.vs3_val,
|
||||
'vtype_vsew' : entry.vtype_vsew,
|
||||
'vtype_vmul' : entry.vtype_vmul,
|
||||
'vtype_vediv' : entry.vtype_vediv,
|
||||
'vm' : entry.vm,
|
||||
'updated_csr' : entry.updated_csr,
|
||||
'updated_gpr' : entry.updated_gpr,
|
||||
'fd' : entry.fd,
|
||||
'fd_val' : entry.fd_val,
|
||||
'fs1' : entry.fs1,
|
||||
'fs1_val' : entry.fs1_val,
|
||||
'fs2' : entry.fs2,
|
||||
'fs2_val' : entry.fs2_val,
|
||||
})
|
||||
|
||||
|
||||
|
@ -493,4 +511,4 @@ def assign_operand(trace, operands, gpr, stop_on_first_error = 0):
|
|||
logging.debug("Unsupported instr : %s (%s)" %
|
||||
(trace.instr, trace.instr_str))
|
||||
if stop_on_first_error:
|
||||
sys.exit(-1)
|
||||
sys.exit(RET_FATAL)
|
||||
|
|
|
@ -40,7 +40,6 @@ def process_sail_sim_log(sail_log, csv):
|
|||
"""
|
||||
logging.info("Processing sail log : %s" % sail_log)
|
||||
instr_cnt = 0
|
||||
sail_instr = ""
|
||||
|
||||
with open(sail_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
search_start = 0
|
||||
|
@ -84,7 +83,6 @@ def process_sail_sim_log(sail_log, csv):
|
|||
|
||||
|
||||
def main():
|
||||
instr_trace = []
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input sail simulation log")
|
||||
|
|
|
@ -112,7 +112,6 @@ def process_spike_sim_log(spike_log, csv, full_trace = 0):
|
|||
|
||||
|
||||
def main():
|
||||
instr_trace = []
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input spike simulation log")
|
||||
|
|
|
@ -72,7 +72,6 @@ def process_whisper_sim_log(whisper_log, csv, full_trace = 0):
|
|||
|
||||
|
||||
def main():
|
||||
instr_trace = []
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input whisper simulation log")
|
||||
|
|
142
vendor/google_riscv-dv/src/deprecated/riscv_amo_instr_lib.sv
vendored
Normal file
142
vendor/google_riscv-dv/src/deprecated/riscv_amo_instr_lib.sv
vendored
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Base class for AMO instruction stream
|
||||
class riscv_amo_base_instr_stream extends riscv_mem_access_stream;
|
||||
|
||||
rand int unsigned num_amo;
|
||||
rand int unsigned num_mixed_instr;
|
||||
rand int base;
|
||||
rand riscv_reg_t rs1_reg;
|
||||
rand int unsigned data_page_id;
|
||||
rand int max_load_store_offset;
|
||||
|
||||
// User can specify a small group of available registers to generate various hazard condition
|
||||
rand riscv_reg_t avail_regs[];
|
||||
|
||||
`uvm_object_utils(riscv_amo_base_instr_stream)
|
||||
|
||||
constraint rs1_c {
|
||||
!(rs1_reg inside {cfg.reserved_regs, reserved_rd, ZERO});
|
||||
}
|
||||
|
||||
constraint addr_range_c {
|
||||
data_page_id < max_data_page_id;
|
||||
base inside {[0 : max_load_store_offset-1]};
|
||||
}
|
||||
|
||||
constraint aligned_amo_c {
|
||||
if (XLEN == 32) {
|
||||
base % 4 == 0;
|
||||
} else {
|
||||
base % 8 == 0;
|
||||
}
|
||||
}
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
gen_amo_instr();
|
||||
// rs1 cannot be modified by other instructions
|
||||
if(!(rs1_reg inside {reserved_rd})) begin
|
||||
reserved_rd = {reserved_rd, rs1_reg};
|
||||
end
|
||||
add_mixed_instr(num_mixed_instr);
|
||||
add_rs1_init_la_instr(rs1_reg, data_page_id);
|
||||
super.post_randomize();
|
||||
endfunction
|
||||
|
||||
// AMO instruction generation
|
||||
virtual function void gen_amo_instr();
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// A pair of LR/SC instruction
|
||||
class riscv_lr_sc_instr_stream extends riscv_amo_base_instr_stream;
|
||||
|
||||
riscv_rand_instr lr_instr;
|
||||
riscv_rand_instr sc_instr;
|
||||
|
||||
constraint legal_c {
|
||||
num_amo == 1;
|
||||
num_mixed_instr inside {[0:15]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_lr_sc_instr_stream)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
lr_instr = riscv_rand_instr::type_id::create("lr_instr");
|
||||
sc_instr = riscv_rand_instr::type_id::create("sc_instr");
|
||||
endfunction
|
||||
|
||||
virtual function void gen_amo_instr();
|
||||
lr_instr.cfg = cfg;
|
||||
sc_instr.cfg = cfg;
|
||||
lr_instr.disable_a_extension_c.constraint_mode(0);
|
||||
sc_instr.disable_a_extension_c.constraint_mode(0);
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(lr_instr,
|
||||
rs1 == rs1_reg;
|
||||
rd != rs1_reg;
|
||||
instr_name inside {LR_W, LR_D};)
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(sc_instr,
|
||||
rs1 == rs1_reg;
|
||||
rd != rs1_reg;
|
||||
instr_name inside {SC_W, SC_D};)
|
||||
instr_list.push_front(lr_instr);
|
||||
instr_list.push_front(sc_instr);
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
class riscv_amo_instr_stream extends riscv_amo_base_instr_stream;
|
||||
|
||||
riscv_rand_instr amo_instr[];
|
||||
|
||||
constraint reasonable_c {
|
||||
solve num_amo before num_mixed_instr;
|
||||
num_amo inside {[1:10]};
|
||||
num_mixed_instr inside {[0:2*num_amo]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_amo_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
virtual function void gen_amo_instr();
|
||||
amo_instr = new[num_amo];
|
||||
foreach (amo_instr[i]) begin
|
||||
amo_instr[i] = riscv_rand_instr::type_id::create($sformatf("amo_instr_%0d", i));
|
||||
amo_instr[i].cfg = cfg;
|
||||
amo_instr[i].disable_a_extension_c.constraint_mode(0);
|
||||
`ifdef DSIM
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(amo_instr[i],
|
||||
rs1 == rs1_reg;
|
||||
rd != rs1_reg;
|
||||
instr_name inside {[AMOSWAP_W:AMOMAXU_D]};)
|
||||
`else
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(amo_instr[i],
|
||||
rs1 == rs1_reg;
|
||||
rd != rs1_reg;
|
||||
category == AMO;)
|
||||
`endif
|
||||
instr_list.push_front(amo_instr[i]);
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
531
vendor/google_riscv-dv/src/deprecated/riscv_directed_instr_lib.sv
vendored
Normal file
531
vendor/google_riscv-dv/src/deprecated/riscv_directed_instr_lib.sv
vendored
Normal file
|
@ -0,0 +1,531 @@
|
|||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Base class for directed instruction stream
|
||||
class riscv_directed_instr_stream extends riscv_rand_instr_stream;
|
||||
|
||||
`uvm_object_utils(riscv_directed_instr_stream)
|
||||
|
||||
string label;
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
foreach(instr_list[i]) begin
|
||||
instr_list[i].has_label = 1'b0;
|
||||
instr_list[i].atomic = 1'b1;
|
||||
end
|
||||
instr_list[0].comment = $sformatf("Start %0s", get_name());
|
||||
instr_list[$].comment = $sformatf("End %0s", get_name());
|
||||
if(label!= "") begin
|
||||
instr_list[0].label = label;
|
||||
instr_list[0].has_label = 1'b1;
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Base class for memory access stream
|
||||
class riscv_mem_access_stream extends riscv_directed_instr_stream;
|
||||
|
||||
int max_data_page_id;
|
||||
mem_region_t data_page[$];
|
||||
|
||||
`uvm_object_utils(riscv_mem_access_stream)
|
||||
`uvm_object_new
|
||||
|
||||
function void pre_randomize();
|
||||
if(kernel_mode) begin
|
||||
data_page = cfg.s_mem_region;
|
||||
end else begin
|
||||
data_page = cfg.mem_region;
|
||||
end
|
||||
max_data_page_id = data_page.size();
|
||||
endfunction
|
||||
|
||||
// Use "la" instruction to initialize the base regiseter
|
||||
virtual function void add_rs1_init_la_instr(riscv_reg_t gpr, int id, int base = 0);
|
||||
riscv_pseudo_instr la_instr;
|
||||
la_instr = riscv_pseudo_instr::type_id::create("la_instr");
|
||||
la_instr.pseudo_instr_name = LA;
|
||||
la_instr.rd = gpr;
|
||||
if(kernel_mode) begin
|
||||
la_instr.imm_str = $sformatf("%s+%0d", cfg.s_mem_region[id].name, base);
|
||||
end else begin
|
||||
la_instr.imm_str = $sformatf("%s+%0d", cfg.mem_region[id].name, base);
|
||||
end
|
||||
instr_list.push_front(la_instr);
|
||||
endfunction
|
||||
|
||||
// Insert some other instructions to mix with mem_access instruction
|
||||
virtual function void add_mixed_instr(int instr_cnt);
|
||||
riscv_instr_base instr;
|
||||
setup_allowed_instr(1, 1);
|
||||
for(int i = 0; i < instr_cnt; i ++) begin
|
||||
instr = riscv_instr_base::type_id::create("instr");
|
||||
randomize_instr(instr);
|
||||
insert_instr(instr);
|
||||
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_directed_instr_stream;
|
||||
|
||||
riscv_instr_base jump;
|
||||
riscv_instr_base addi;
|
||||
riscv_pseudo_instr la;
|
||||
riscv_instr_base branch;
|
||||
rand riscv_reg_t gpr;
|
||||
rand int imm;
|
||||
rand bit enable_branch;
|
||||
rand int mixed_instr_cnt;
|
||||
riscv_instr_base stack_exit_instr[];
|
||||
string target_program_label;
|
||||
int idx;
|
||||
bit use_jalr;
|
||||
|
||||
constraint instr_c {
|
||||
!(gpr inside {cfg.reserved_regs, ZERO});
|
||||
imm inside {[-1023:1023]};
|
||||
mixed_instr_cnt inside {[5:10]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_jump_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
jump = riscv_instr_base::type_id::create("jump");
|
||||
la = riscv_pseudo_instr::type_id::create("la");
|
||||
addi = riscv_instr_base::type_id::create("addi");
|
||||
branch = riscv_instr_base::type_id::create("branch");
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
riscv_instr_base instr[];
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(jump,
|
||||
(use_jalr) -> (instr_name == JALR);
|
||||
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,
|
||||
rs1 == gpr;
|
||||
instr_name == ADDI;
|
||||
rd == gpr;
|
||||
)
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(branch,
|
||||
instr_name inside {BEQ, BNE, BLT, BGE, BLTU, BGEU};)
|
||||
la.pseudo_instr_name = LA;
|
||||
la.imm_str = target_program_label;
|
||||
la.rd = gpr;
|
||||
// Generate some random instructions to mix with jump instructions
|
||||
reserved_rd = {gpr};
|
||||
initialize_instr_list(mixed_instr_cnt);
|
||||
gen_instr(1'b1);
|
||||
addi.imm_str = $sformatf("%0d", imm);
|
||||
jump.imm_str = $sformatf("%0d", -imm);
|
||||
// The branch instruction is always inserted right before the jump instruction to avoid
|
||||
// skipping other required instructions like restore stack, load jump base etc.
|
||||
// The purse of adding the branch instruction here is to cover branch -> jump scenario.
|
||||
if(enable_branch) instr = {branch};
|
||||
// Restore stack before unconditional jump
|
||||
if(jump.rd == ZERO) begin
|
||||
instr= {stack_exit_instr, instr};
|
||||
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
|
||||
mix_instr_stream(instr);
|
||||
instr_list = {instr_list, jump};
|
||||
foreach(instr_list[i]) begin
|
||||
instr_list[i].has_label = 1'b0;
|
||||
instr_list[i].atomic = 1'b1;
|
||||
end
|
||||
jump.has_label = 1'b1;
|
||||
jump.label = $sformatf("j_%0s_%0s_%0d", label, target_program_label, idx);
|
||||
branch.imm_str = jump.label;
|
||||
branch.comment = "branch to jump instr";
|
||||
branch.branch_assigned = 1'b1;
|
||||
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.push_back(C_J);
|
||||
if (XLEN == 32) begin
|
||||
jal.push_back(C_JAL);
|
||||
end
|
||||
end
|
||||
// First instruction
|
||||
jump_start = riscv_instr_base::type_id::create("jump_start");
|
||||
`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;
|
||||
|
||||
int stack_len;
|
||||
int num_of_reg_to_save;
|
||||
int num_of_redudant_instr;
|
||||
riscv_instr_base push_stack_instr[];
|
||||
riscv_reg_t saved_regs[];
|
||||
rand riscv_rand_instr branch_instr;
|
||||
rand bit enable_branch;
|
||||
string push_start_label;
|
||||
|
||||
`uvm_object_utils(riscv_push_stack_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
function void init();
|
||||
// Save 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",
|
||||
stack_len, num_of_reg_to_save))
|
||||
end
|
||||
num_of_redudant_instr = $urandom_range(3,10);
|
||||
initialize_instr_list(num_of_redudant_instr);
|
||||
endfunction
|
||||
|
||||
virtual function void gen_push_stack_instr(int stack_len, bit allow_branch = 1);
|
||||
this.stack_len = stack_len;
|
||||
init();
|
||||
gen_instr(1'b1);
|
||||
push_stack_instr = new[num_of_reg_to_save+1];
|
||||
foreach(push_stack_instr[i]) begin
|
||||
push_stack_instr[i] = riscv_instr_base::type_id::
|
||||
create($sformatf("push_stack_instr_%0d", i));
|
||||
end
|
||||
// addi sp,sp,-imm
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[0],
|
||||
instr_name == ADDI; rd == cfg.sp; rs1 == cfg.sp;
|
||||
imm == (~stack_len + 1);)
|
||||
push_stack_instr[0].imm_str = $sformatf("-%0d", stack_len);
|
||||
foreach(saved_regs[i]) begin
|
||||
if(XLEN == 32) begin
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[i+1],
|
||||
instr_name == SW; rs2 == saved_regs[i]; rs1 == cfg.sp; imm == 4 * (i+1);)
|
||||
end else begin
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[i+1],
|
||||
instr_name == SD; rs2 == saved_regs[i]; rs1 == cfg.sp; imm == 8 * (i+1);)
|
||||
end
|
||||
push_stack_instr[i+1].process_load_store = 0;
|
||||
end
|
||||
if (allow_branch) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_FATAL(enable_branch)
|
||||
end else begin
|
||||
enable_branch = 0;
|
||||
end
|
||||
if(enable_branch) begin
|
||||
// Cover jal -> branch scenario, the branch is added before push stack operation
|
||||
branch_instr = riscv_rand_instr::type_id::create("branch_instr");
|
||||
branch_instr.cfg = cfg;
|
||||
`ifdef DSIM
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(branch_instr,
|
||||
instr_name inside {[BEQ:BGEU], C_BEQZ, C_BNEZ};)
|
||||
`else
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(branch_instr, category == BRANCH;)
|
||||
`endif
|
||||
branch_instr.imm_str = push_start_label;
|
||||
branch_instr.branch_assigned = 1'b1;
|
||||
push_stack_instr[0].label = push_start_label;
|
||||
push_stack_instr[0].has_label = 1'b1;
|
||||
push_stack_instr = {branch_instr, push_stack_instr};
|
||||
end
|
||||
mix_instr_stream(push_stack_instr);
|
||||
foreach(instr_list[i]) begin
|
||||
instr_list[i].atomic = 1'b1;
|
||||
if(instr_list[i].label == "")
|
||||
instr_list[i].has_label = 1'b0;
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Pop stack instruction stream
|
||||
class riscv_pop_stack_instr extends riscv_rand_instr_stream;
|
||||
|
||||
int stack_len;
|
||||
int num_of_reg_to_save;
|
||||
int num_of_redudant_instr;
|
||||
riscv_instr_base pop_stack_instr[];
|
||||
riscv_reg_t saved_regs[];
|
||||
|
||||
`uvm_object_utils(riscv_pop_stack_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
function void init();
|
||||
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",
|
||||
stack_len, num_of_reg_to_save))
|
||||
end
|
||||
num_of_redudant_instr = $urandom_range(3,10);
|
||||
initialize_instr_list(num_of_redudant_instr);
|
||||
endfunction
|
||||
|
||||
virtual function void gen_pop_stack_instr(int stack_len, riscv_reg_t saved_regs[]);
|
||||
this.stack_len = stack_len;
|
||||
this.saved_regs = saved_regs;
|
||||
init();
|
||||
gen_instr(1'b1);
|
||||
pop_stack_instr = new[num_of_reg_to_save+1];
|
||||
foreach(pop_stack_instr[i]) begin
|
||||
pop_stack_instr[i] = riscv_instr_base::type_id::
|
||||
create($sformatf("pop_stack_instr_%0d", i));
|
||||
end
|
||||
foreach(saved_regs[i]) begin
|
||||
if(XLEN == 32) begin
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[i],
|
||||
instr_name == LW; rd == saved_regs[i]; rs1 == cfg.sp; imm == 4 * (i+1);)
|
||||
end else begin
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[i],
|
||||
instr_name == LD; rd == saved_regs[i]; rs1 == cfg.sp; imm == 8 * (i+1);)
|
||||
end
|
||||
pop_stack_instr[i].process_load_store = 0;
|
||||
end
|
||||
// addi sp,sp,imm
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[num_of_reg_to_save],
|
||||
instr_name == ADDI; rd == cfg.sp; rs1 == cfg.sp; imm == stack_len;)
|
||||
pop_stack_instr[num_of_reg_to_save].imm_str = $sformatf("%0d", stack_len);
|
||||
mix_instr_stream(pop_stack_instr);
|
||||
foreach(instr_list[i]) begin
|
||||
instr_list[i].atomic = 1'b1;
|
||||
instr_list[i].has_label = 1'b0;
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Cover the long fprward and backward jump
|
||||
class riscv_long_branch_instr extends riscv_rand_instr_stream;
|
||||
|
||||
int branch_instr_stream_len = 100;
|
||||
int branch_instr_offset = 999;
|
||||
riscv_rand_instr_stream forward_branch_instr_stream;
|
||||
riscv_rand_instr_stream backward_branch_instr_stream;
|
||||
riscv_instr_base jump_instr;
|
||||
|
||||
`uvm_object_utils(riscv_long_branch_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
forward_branch_instr_stream = riscv_rand_instr_stream::type_id::
|
||||
create("forward_branch_instr_stream");
|
||||
backward_branch_instr_stream = riscv_rand_instr_stream::type_id::
|
||||
create("backward_branch_instr_stream");
|
||||
jump_instr = riscv_instr_base::type_id::create("jump_instr");
|
||||
endfunction
|
||||
|
||||
function void init(int instr_len);
|
||||
branch_instr_stream_len = instr_len;
|
||||
initialize_instr_list(branch_instr_offset-branch_instr_stream_len);
|
||||
forward_branch_instr_stream.cfg = cfg;
|
||||
backward_branch_instr_stream.cfg = cfg;
|
||||
forward_branch_instr_stream.initialize_instr_list(branch_instr_stream_len);
|
||||
backward_branch_instr_stream.initialize_instr_list(branch_instr_stream_len);
|
||||
endfunction
|
||||
|
||||
virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1,
|
||||
bit is_debug_program = 1'b0);
|
||||
int branch_offset;
|
||||
super.gen_instr(1'b1);
|
||||
forward_branch_instr_stream.gen_instr();
|
||||
backward_branch_instr_stream.gen_instr();
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(jump_instr, instr_name == JAL;)
|
||||
jump_instr.imm_str = "test_done";
|
||||
instr_list = {forward_branch_instr_stream.instr_list, instr_list,
|
||||
jump_instr, backward_branch_instr_stream.instr_list};
|
||||
foreach(instr_list[i]) begin
|
||||
instr_list[i].atomic = 1'b1;
|
||||
if(!instr_list[i].is_branch_target) begin
|
||||
instr_list[i].has_label = 1'b0;
|
||||
end
|
||||
if(instr_list[i].category == BRANCH) begin
|
||||
if(i < branch_instr_stream_len)
|
||||
branch_offset = branch_instr_offset;
|
||||
else
|
||||
branch_offset = -branch_instr_offset;
|
||||
instr_list[i].imm_str = $sformatf("target_%0d", i);
|
||||
instr_list[i].branch_assigned = 1'b1;
|
||||
// Avoid dead loop
|
||||
if(((instr_list[i+branch_offset].category == BRANCH) ||
|
||||
instr_list[i+branch_offset].is_branch_target) && (branch_offset < 0))
|
||||
branch_offset = branch_offset + 1;
|
||||
`uvm_info(get_full_name(), $sformatf("Branch [%0d] %0s -> [%0d] %0s", i,
|
||||
instr_list[i].convert2asm(), i+branch_offset,
|
||||
instr_list[i+branch_offset].convert2asm()), UVM_LOW)
|
||||
if(i < -branch_offset)
|
||||
`uvm_fatal(get_name(), $sformatf("Unexpected branch instr at %0d", i))
|
||||
instr_list[i+branch_offset].label = $sformatf("target_%0d", i);
|
||||
instr_list[i+branch_offset].has_label = 1'b1;
|
||||
instr_list[i+branch_offset].is_branch_target = 1;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
class riscv_sw_interrupt_instr extends riscv_directed_instr_stream;
|
||||
|
||||
rand bit usip;
|
||||
rand bit ssip;
|
||||
rand bit msip;
|
||||
rand privileged_reg_t ip_reg;
|
||||
rand riscv_pseudo_instr li_instr;
|
||||
rand riscv_instr_base csr_instr;
|
||||
riscv_privil_reg ip;
|
||||
rand riscv_reg_t rs1_reg;
|
||||
|
||||
constraint ip_reg_c {
|
||||
if(cfg.init_privileged_mode == MACHINE_MODE) {
|
||||
ip_reg == MIP;
|
||||
} else {
|
||||
ip_reg == SIP;
|
||||
}
|
||||
(ip_reg == MIP) -> (usip || ssip || msip);
|
||||
(ip_reg == SIP) -> (usip || ssip);
|
||||
}
|
||||
|
||||
constraint instr_c {
|
||||
!(rs1_reg inside {cfg.reserved_regs});
|
||||
rs1_reg != ZERO;
|
||||
li_instr.pseudo_instr_name == LI;
|
||||
li_instr.rd == rs1_reg;
|
||||
csr_instr.instr_name == CSRRW;
|
||||
csr_instr.rs1 == rs1_reg;
|
||||
// TODO: Support non-zero rd for SIP, MIP
|
||||
// csr_instr.rd inside {cfg.avail_regs};
|
||||
csr_instr.rd == ZERO;
|
||||
csr_instr.csr == ip_reg;
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_sw_interrupt_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
li_instr = riscv_pseudo_instr::type_id::create("li_instr");
|
||||
csr_instr = riscv_instr_base::type_id::create("csr_instr");
|
||||
ip = riscv_privil_reg::type_id::create("ip");
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
// TODO: Support UIP
|
||||
if(cfg.init_privileged_mode == USER_MODE) return;
|
||||
ip.init_reg(ip_reg);
|
||||
if(ip_reg == SIP) begin
|
||||
ip.set_field("USIP", usip);
|
||||
ip.set_field("SSIP", ssip);
|
||||
end else begin
|
||||
ip.set_field("USIP", usip);
|
||||
ip.set_field("SSIP", ssip);
|
||||
ip.set_field("MSIP", msip);
|
||||
end
|
||||
li_instr.imm_str = $sformatf("0x%0x", ip.get_val());
|
||||
csr_instr.comment = ip_reg.name();
|
||||
instr_list = {li_instr, csr_instr};
|
||||
super.post_randomize();
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
@ -32,9 +32,9 @@ class riscv_instr_base extends uvm_object;
|
|||
rand bit [31:0] imm;
|
||||
rand imm_t imm_type;
|
||||
rand bit [4:0] imm_len;
|
||||
rand bit is_pseudo_instr;
|
||||
rand bit aq;
|
||||
rand bit rl;
|
||||
bit is_pseudo_instr;
|
||||
bit is_branch_target;
|
||||
bit has_label = 1'b1;
|
||||
bit atomic = 0;
|
||||
|
@ -58,11 +58,11 @@ class riscv_instr_base extends uvm_object;
|
|||
string label;
|
||||
bit is_local_numeric_label;
|
||||
int idx = -1;
|
||||
`VECTOR_INCLUDE("riscv_instr_base_inc_riscv_instr_base_declares.sv")
|
||||
|
||||
`uvm_object_utils(riscv_instr_base)
|
||||
|
||||
constraint default_c {
|
||||
soft is_pseudo_instr == 0;
|
||||
instr_name != INVALID_INSTR;
|
||||
}
|
||||
|
||||
|
@ -369,6 +369,7 @@ class riscv_instr_base extends uvm_object;
|
|||
`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, CA_FORMAT, ARITHMETIC, RV32C)
|
||||
|
@ -449,6 +450,8 @@ class riscv_instr_base extends uvm_object;
|
|||
// Supervisor Instructions
|
||||
`add_instr(SFENCE_VMA, R_FORMAT,SYNCH,RV32I)
|
||||
|
||||
`VECTOR_INCLUDE("riscv_instr_base_inc_add_instr.sv")
|
||||
|
||||
function void post_randomize();
|
||||
if (group inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) begin
|
||||
is_compressed = 1'b1;
|
||||
|
@ -519,6 +522,9 @@ class riscv_instr_base extends uvm_object;
|
|||
has_rs1 = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
`VECTOR_INCLUDE("riscv_instr_base_inc_post_randomize.sv")
|
||||
|
||||
endfunction
|
||||
|
||||
function void mask_imm();
|
||||
|
@ -758,6 +764,7 @@ class riscv_instr_base extends uvm_object;
|
|||
end else begin
|
||||
asm_str = $sformatf("%0s %0s, %0s, (%0s)", asm_str, rd.name(), rs2.name(), rs1.name());
|
||||
end
|
||||
`VECTOR_INCLUDE("riscv_instr_base_inc_convert2asm.sv")
|
||||
end else begin
|
||||
// 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
|
||||
|
@ -1202,42 +1209,7 @@ class riscv_instr_base extends uvm_object;
|
|||
this.has_fs3 = obj.has_fs3;
|
||||
this.has_fd = obj.has_fd;
|
||||
this.is_floating_point = obj.is_floating_point;
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Psuedo instructions are used to simplify assembly program writing
|
||||
class riscv_pseudo_instr extends riscv_instr_base;
|
||||
|
||||
rand riscv_pseudo_instr_name_t pseudo_instr_name;
|
||||
|
||||
constraint default_c {
|
||||
is_pseudo_instr == 1'b1;
|
||||
}
|
||||
|
||||
`add_pseudo_instr(LI, I_FORMAT, LOAD, RV32I)
|
||||
`add_pseudo_instr(LA, I_FORMAT, LOAD, RV32I)
|
||||
|
||||
`uvm_object_utils(riscv_pseudo_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
process_load_store = 0;
|
||||
endfunction
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2asm(string prefix = "");
|
||||
string asm_str;
|
||||
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
|
||||
// instr rd,imm
|
||||
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm());
|
||||
if(comment != "")
|
||||
asm_str = {asm_str, " #",comment};
|
||||
return asm_str.tolower();
|
||||
endfunction
|
||||
|
||||
virtual function string get_instr_name();
|
||||
return pseudo_instr_name.name();
|
||||
endfunction
|
||||
`VECTOR_INCLUDE("riscv_instr_base_inc_copy_base_instr.sv")
|
||||
endfunction
|
||||
|
||||
endclass
|
700
vendor/google_riscv-dv/src/deprecated/riscv_instr_gen_config.sv
vendored
Normal file
700
vendor/google_riscv-dv/src/deprecated/riscv_instr_gen_config.sv
vendored
Normal file
|
@ -0,0 +1,700 @@
|
|||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RISC-V assembly program generator configuration class
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class riscv_instr_gen_config extends uvm_object;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Random instruction generation settings
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Instruction count of the main program
|
||||
rand int main_program_instr_cnt;
|
||||
|
||||
// Instruction count of each sub-program
|
||||
rand int sub_program_instr_cnt[];
|
||||
|
||||
// Instruction count of the debug rom
|
||||
rand int debug_program_instr_cnt;
|
||||
|
||||
// Instruction count of debug sub-programs
|
||||
rand int debug_sub_program_instr_cnt[];
|
||||
|
||||
// Pattern of data section: RAND_DATA, ALL_ZERO, INCR_VAL
|
||||
rand data_pattern_t data_page_pattern;
|
||||
|
||||
// Associate array for delegation configuration for each exception and interrupt
|
||||
// When the bit is 1, the corresponding delegation is enabled.
|
||||
rand bit m_mode_exception_delegation[exception_cause_t];
|
||||
rand bit s_mode_exception_delegation[exception_cause_t];
|
||||
rand bit m_mode_interrupt_delegation[interrupt_cause_t];
|
||||
rand bit s_mode_interrupt_delegation[interrupt_cause_t];
|
||||
|
||||
// Priviledged mode after boot
|
||||
rand privileged_mode_t init_privileged_mode;
|
||||
|
||||
rand bit[XLEN-1:0] mstatus, mie,
|
||||
sstatus, sie,
|
||||
ustatus, uie;
|
||||
|
||||
// Key fields in xSTATUS
|
||||
// Memory protection bits
|
||||
rand bit mstatus_mprv;
|
||||
rand bit mstatus_mxr;
|
||||
rand bit mstatus_sum;
|
||||
rand bit mstatus_tvm;
|
||||
rand bit [1:0] mstatus_fs;
|
||||
rand mtvec_mode_t mtvec_mode;
|
||||
|
||||
// Floating point rounding mode
|
||||
rand f_rounding_mode_t fcsr_rm;
|
||||
|
||||
// Enable sfence.vma instruction
|
||||
rand bit enable_sfence;
|
||||
|
||||
// Reserved register
|
||||
// Reserved for various hardcoded routines
|
||||
rand riscv_reg_t gpr[4];
|
||||
// Used by any DCSR operations inside of the debug rom
|
||||
rand riscv_reg_t scratch_reg;
|
||||
// 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
|
||||
// processor.
|
||||
bit check_misa_init_val = 1'b0;
|
||||
bit check_xstatus = 1'b1;
|
||||
|
||||
// Virtual address translation is on for this test
|
||||
rand bit virtual_addr_translation_on;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// User space memory region and stack setting
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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}
|
||||
};
|
||||
|
||||
// Stack section word length
|
||||
int stack_len = 5000;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Kernel section setting, used by supervisor mode programs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
mem_region_t s_mem_region[$] = '{
|
||||
'{name:"s_region_0", size_in_bytes: 4096, xwr: 3'b111},
|
||||
'{name:"s_region_1", size_in_bytes: 4096, xwr: 3'b111}};
|
||||
|
||||
// Kernel Stack section word length
|
||||
int kernel_stack_len = 4000;
|
||||
|
||||
// Number of instructions for each kernel program
|
||||
int kernel_program_instr_cnt = 400;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Instruction list based on the config, generate by build_instruction_template
|
||||
//-----------------------------------------------------------------------------
|
||||
riscv_instr_base instr_template[riscv_instr_name_t];
|
||||
riscv_instr_name_t basic_instr[$];
|
||||
riscv_instr_name_t instr_group[riscv_instr_group_t][$];
|
||||
riscv_instr_name_t instr_category[riscv_instr_category_t][$];
|
||||
|
||||
// Queue of all the main implemented CSRs that the boot privilege mode cannot access
|
||||
// e.g. these CSRs are in higher privilege modes - access should raise an exception
|
||||
privileged_reg_t invalid_priv_mode_csrs[$];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Command line options or control knobs
|
||||
//-----------------------------------------------------------------------------
|
||||
// Main options for RISC-V assembly program generation
|
||||
// Number of sub-programs per test
|
||||
int num_of_sub_program = 5;
|
||||
int instr_cnt = 200;
|
||||
int num_of_tests = 1;
|
||||
// For tests doesn't involve load/store, the data section generation could be skipped
|
||||
bit no_data_page;
|
||||
// Options to turn off some specific types of instructions
|
||||
bit no_branch_jump; // No branch/jump instruction
|
||||
bit no_load_store; // No load/store instruction
|
||||
bit no_csr_instr; // No csr instruction
|
||||
bit no_ebreak = 1; // No ebreak instruction
|
||||
bit no_dret = 1; // No dret instruction
|
||||
bit no_fence; // No fence instruction
|
||||
bit no_wfi = 1; // No WFI instruction
|
||||
bit enable_unaligned_load_store;
|
||||
int illegal_instr_ratio;
|
||||
int hint_instr_ratio;
|
||||
// Directed boot privileged mode, u, m, s
|
||||
string boot_mode_opts;
|
||||
int enable_page_table_exception;
|
||||
bit no_directed_instr;
|
||||
// A name suffix for the generated assembly program
|
||||
string asm_test_suffix;
|
||||
// Enable interrupt bit in MSTATUS (MIE, SIE, UIE)
|
||||
bit enable_interrupt;
|
||||
// We need a separate control knob for enabling timer interrupts, as Spike
|
||||
// throws an exception if xIE.xTIE is enabled
|
||||
bit enable_timer_irq;
|
||||
// Generate a bare program without any init/exit/error handling/page table routines
|
||||
// The generated program can be integrated with a larger program.
|
||||
// Note that the bare mode program is not expected to run in standalone mode
|
||||
bit bare_program_mode;
|
||||
// Enable accessing illegal CSR instruction
|
||||
// - Accessing non-existence CSR
|
||||
// - Accessing CSR with wrong privileged mode
|
||||
bit enable_illegal_csr_instruction;
|
||||
// Enable accessing CSRs at an invalid privilege level
|
||||
bit enable_access_invalid_csr_level;
|
||||
// Enable some dummy writes to main system CSRs (xSTATUS/xIE) at beginning of test
|
||||
// to check repeated writes
|
||||
bit enable_dummy_csr_write;
|
||||
bit randomize_csr = 0;
|
||||
// sfence support
|
||||
bit allow_sfence_exception = 0;
|
||||
// Interrupt/Exception Delegation
|
||||
bit no_delegation = 1;
|
||||
bit force_m_delegation = 0;
|
||||
bit force_s_delegation = 0;
|
||||
bit support_supervisor_mode;
|
||||
bit disable_compressed_instr;
|
||||
// "Memory mapped" address that when written to will indicate some event to
|
||||
// the testbench - testbench will take action based on the value written
|
||||
int signature_addr = 32'hdead_beef;
|
||||
bit require_signature_addr = 1'b0;
|
||||
// Enable a full or empty debug_rom section.
|
||||
// Full debug_rom will contain random instruction streams.
|
||||
// Empty debug_rom will contain just dret instruction and will return immediately.
|
||||
// Will be empty by default.
|
||||
bit gen_debug_section = 1'b0;
|
||||
// Enable generation of a directed sequence of instructions containing
|
||||
// ebreak inside the debug_rom.
|
||||
// Disabled by default.
|
||||
bit enable_ebreak_in_debug_rom = 1'b0;
|
||||
// Enable setting dcsr.ebreak(m/s/u)
|
||||
bit set_dcsr_ebreak = 1'b0;
|
||||
// Number of sub programs in the debug rom
|
||||
int num_debug_sub_program = 0;
|
||||
// Enable debug single stepping
|
||||
bit enable_debug_single_step = 0;
|
||||
// Number of single stepping iterations
|
||||
rand int single_step_iterations;
|
||||
// Enable mstatus.tw bit - causes u-mode WFI to raise illegal instruction exceptions
|
||||
bit set_mstatus_tw;
|
||||
// Stack space allocated to each program, need to be enough to store necessary context
|
||||
// Example: RA, SP, T0
|
||||
int min_stack_len_per_program = 10 * (XLEN/8);
|
||||
int max_stack_len_per_program = 16 * (XLEN/8);
|
||||
// Maximum branch distance, avoid skipping large portion of the code
|
||||
int max_branch_step = 20;
|
||||
// Maximum directed instruction stream sequence count
|
||||
int max_directed_instr_stream_seq = 20;
|
||||
// Reserved registers
|
||||
riscv_reg_t reserved_regs[];
|
||||
// Floating point support
|
||||
bit enable_floating_point;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Command line options for instruction distribution control
|
||||
//-----------------------------------------------------------------------------
|
||||
int dist_control_mode;
|
||||
int unsigned category_dist[riscv_instr_category_t];
|
||||
|
||||
uvm_cmdline_processor inst;
|
||||
|
||||
constraint default_c {
|
||||
sub_program_instr_cnt.size() == num_of_sub_program;
|
||||
debug_sub_program_instr_cnt.size() == num_debug_sub_program;
|
||||
main_program_instr_cnt inside {[10 : instr_cnt]};
|
||||
foreach(sub_program_instr_cnt[i]) {
|
||||
sub_program_instr_cnt[i] inside {[10 : instr_cnt]};
|
||||
}
|
||||
// Disable sfence if the program is not boot to supervisor mode
|
||||
// If sfence exception is allowed, we can enable sfence instruction in any priviledged mode.
|
||||
// When MSTATUS.TVM is set, executing sfence.vma will be treate as illegal instruction
|
||||
if(allow_sfence_exception) {
|
||||
enable_sfence == 1'b1;
|
||||
(init_privileged_mode != SUPERVISOR_MODE) || (mstatus_tvm == 1'b1);
|
||||
} else {
|
||||
(init_privileged_mode != SUPERVISOR_MODE || !riscv_instr_pkg::support_sfence || mstatus_tvm || no_fence)
|
||||
-> (enable_sfence == 1'b0);
|
||||
}
|
||||
}
|
||||
|
||||
constraint debug_mode_c {
|
||||
if (riscv_instr_pkg::support_debug_mode) {
|
||||
debug_program_instr_cnt inside {[100 : 300]};
|
||||
foreach(debug_sub_program_instr_cnt[i]) {
|
||||
debug_sub_program_instr_cnt[i] inside {[100 : 300]};
|
||||
}
|
||||
}
|
||||
`ifndef DSIM
|
||||
main_program_instr_cnt + sub_program_instr_cnt.sum() == instr_cnt;
|
||||
`else
|
||||
// dsim has some issue supporting sum(), use some approximate constraint to generate
|
||||
// instruction cnt
|
||||
if (num_of_sub_program > 0) {
|
||||
main_program_instr_cnt inside {[10:instr_cnt/2]};
|
||||
foreach (sub_program_instr_cnt[i]) {
|
||||
sub_program_instr_cnt[i] inside {[10:instr_cnt/num_of_sub_program]};
|
||||
}
|
||||
} else {
|
||||
main_program_instr_cnt == instr_cnt;
|
||||
}
|
||||
`endif
|
||||
}
|
||||
|
||||
// Keep the number of single step iterations relatively small
|
||||
constraint debug_single_step_c {
|
||||
if (enable_debug_single_step) {
|
||||
single_step_iterations inside {[10 : 50]};
|
||||
}
|
||||
}
|
||||
|
||||
// Boot privileged mode distribution
|
||||
constraint boot_privileged_mode_dist_c {
|
||||
// Boot to higher privileged mode more often
|
||||
if(riscv_instr_pkg::supported_privileged_mode.size() == 2) {
|
||||
init_privileged_mode dist {riscv_instr_pkg::supported_privileged_mode[0] := 6,
|
||||
riscv_instr_pkg::supported_privileged_mode[1] := 4};
|
||||
} else if (riscv_instr_pkg::supported_privileged_mode.size() == 3) {
|
||||
init_privileged_mode dist {riscv_instr_pkg::supported_privileged_mode[0] := 4,
|
||||
riscv_instr_pkg::supported_privileged_mode[1] := 3,
|
||||
riscv_instr_pkg::supported_privileged_mode[2] := 3};
|
||||
} else {
|
||||
init_privileged_mode == riscv_instr_pkg::supported_privileged_mode[0];
|
||||
}
|
||||
}
|
||||
|
||||
constraint mtvec_c {
|
||||
mtvec_mode inside {supported_interrupt_mode};
|
||||
}
|
||||
|
||||
constraint mstatus_c {
|
||||
// This is default disabled at setup phase. It can be enabled in the exception and interrupt
|
||||
// handling routine
|
||||
mstatus_mprv == 1'b0;
|
||||
}
|
||||
|
||||
// Exception delegation setting
|
||||
constraint exception_delegation_c {
|
||||
// Do not delegate instructino page fault to supervisor/user mode because this may introduce
|
||||
// dead loop. All the subsequent instruction fetches may fail and program cannot recover.
|
||||
m_mode_exception_delegation[INSTRUCTION_PAGE_FAULT] == 1'b0;
|
||||
if(force_m_delegation) {
|
||||
foreach(m_mode_exception_delegation[i]) {
|
||||
soft m_mode_exception_delegation[i] == 1'b1;
|
||||
}
|
||||
foreach(m_mode_interrupt_delegation[i]) {
|
||||
soft m_mode_interrupt_delegation[i] == 1'b1;
|
||||
}
|
||||
}
|
||||
if(force_s_delegation) {
|
||||
foreach(s_mode_exception_delegation[i]) {
|
||||
soft s_mode_exception_delegation[i] == 1'b1;
|
||||
}
|
||||
foreach(s_mode_interrupt_delegation[i]) {
|
||||
soft s_mode_interrupt_delegation[i] == 1'b1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spike only supports a subset of exception and interrupt delegation
|
||||
// You can modify this constraint if your ISS support different set of delegations
|
||||
constraint delegation_c {
|
||||
foreach(m_mode_exception_delegation[i]) {
|
||||
if(!support_supervisor_mode || no_delegation) {
|
||||
m_mode_exception_delegation[i] == 0;
|
||||
}
|
||||
if(!(i inside {INSTRUCTION_ADDRESS_MISALIGNED, BREAKPOINT, ECALL_UMODE,
|
||||
INSTRUCTION_PAGE_FAULT, LOAD_PAGE_FAULT, STORE_AMO_PAGE_FAULT})) {
|
||||
m_mode_exception_delegation[i] == 0;
|
||||
}
|
||||
}
|
||||
foreach(m_mode_interrupt_delegation[i]) {
|
||||
if(!support_supervisor_mode || no_delegation) {
|
||||
m_mode_interrupt_delegation[i] == 0;
|
||||
}
|
||||
if(!(i inside {S_SOFTWARE_INTR, S_TIMER_INTR, S_EXTERNAL_INTR})) {
|
||||
m_mode_interrupt_delegation[i] == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
|
||||
constraint reserve_scratch_reg_c {
|
||||
scratch_reg != ZERO;
|
||||
scratch_reg != sp;
|
||||
scratch_reg != tp;
|
||||
}
|
||||
|
||||
constraint gpr_c {
|
||||
foreach (gpr[i]) {
|
||||
!(gpr[i] inside {sp, tp, scratch_reg, ZERO, RA, GP});
|
||||
}
|
||||
unique {gpr};
|
||||
}
|
||||
|
||||
constraint addr_translaction_c {
|
||||
solve init_privileged_mode before virtual_addr_translation_on;
|
||||
if ((init_privileged_mode != MACHINE_MODE) && (SATP_MODE != BARE)) {
|
||||
virtual_addr_translation_on == 1'b1;
|
||||
} else {
|
||||
virtual_addr_translation_on == 1'b0;
|
||||
}
|
||||
}
|
||||
|
||||
constraint floating_point_c {
|
||||
if (enable_floating_point) {
|
||||
mstatus_fs == 2'b01;
|
||||
} else {
|
||||
mstatus_fs == 2'b00;
|
||||
}
|
||||
}
|
||||
|
||||
`uvm_object_utils_begin(riscv_instr_gen_config)
|
||||
`uvm_field_int(main_program_instr_cnt, UVM_DEFAULT)
|
||||
`uvm_field_sarray_int(sub_program_instr_cnt, UVM_DEFAULT)
|
||||
`uvm_field_int(debug_program_instr_cnt, UVM_DEFAULT)
|
||||
`uvm_field_enum(data_pattern_t, data_page_pattern, UVM_DEFAULT)
|
||||
`uvm_field_enum(privileged_mode_t, init_privileged_mode, UVM_DEFAULT)
|
||||
`uvm_field_array_enum(riscv_reg_t, reserved_regs, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
function new (string name = "");
|
||||
string s;
|
||||
super.new(name);
|
||||
init_delegation();
|
||||
inst = uvm_cmdline_processor::get_inst();
|
||||
get_int_arg_value("+num_of_tests=", num_of_tests);
|
||||
get_int_arg_value("+enable_page_table_exception=", enable_page_table_exception);
|
||||
get_bool_arg_value("+enable_interrupt=", enable_interrupt);
|
||||
get_bool_arg_value("+enable_timer_irq=", enable_timer_irq);
|
||||
get_int_arg_value("+num_of_sub_program=", num_of_sub_program);
|
||||
get_int_arg_value("+instr_cnt=", instr_cnt);
|
||||
get_bool_arg_value("+no_ebreak=", no_ebreak);
|
||||
get_bool_arg_value("+no_dret=", no_dret);
|
||||
get_bool_arg_value("+no_wfi=", no_wfi);
|
||||
get_bool_arg_value("+no_branch_jump=", no_branch_jump);
|
||||
get_bool_arg_value("+no_load_store=", no_load_store);
|
||||
get_bool_arg_value("+no_csr_instr=", no_csr_instr);
|
||||
get_bool_arg_value("+enable_illegal_csr_instruction=", enable_illegal_csr_instruction);
|
||||
get_bool_arg_value("+enable_access_invalid_csr_level=", enable_access_invalid_csr_level);
|
||||
get_bool_arg_value("+enable_dummy_csr_write=", enable_dummy_csr_write);
|
||||
get_bool_arg_value("+allow_sfence_exception=", allow_sfence_exception);
|
||||
get_bool_arg_value("+no_data_page=", no_data_page);
|
||||
get_bool_arg_value("+no_directed_instr=", no_directed_instr);
|
||||
get_bool_arg_value("+no_fence=", no_fence);
|
||||
get_bool_arg_value("+no_delegation=", no_delegation);
|
||||
get_int_arg_value("+illegal_instr_ratio=", illegal_instr_ratio);
|
||||
get_int_arg_value("+hint_instr_ratio=", hint_instr_ratio);
|
||||
get_bool_arg_value("+enable_unaligned_load_store=", enable_unaligned_load_store);
|
||||
get_bool_arg_value("+force_m_delegation=", force_m_delegation);
|
||||
get_bool_arg_value("+force_s_delegation=", force_s_delegation);
|
||||
get_bool_arg_value("+require_signature_addr=", require_signature_addr);
|
||||
get_bool_arg_value("+disable_compressed_instr=", disable_compressed_instr);
|
||||
get_bool_arg_value("+randomize_csr=", randomize_csr);
|
||||
if (this.require_signature_addr) begin
|
||||
get_hex_arg_value("+signature_addr=", signature_addr);
|
||||
end
|
||||
get_bool_arg_value("+gen_debug_section=", gen_debug_section);
|
||||
get_bool_arg_value("+bare_program_mode=", bare_program_mode);
|
||||
get_int_arg_value("+num_debug_sub_program=", num_debug_sub_program);
|
||||
get_bool_arg_value("+enable_ebreak_in_debug_rom=", enable_ebreak_in_debug_rom);
|
||||
get_bool_arg_value("+set_dcsr_ebreak=", set_dcsr_ebreak);
|
||||
get_bool_arg_value("+enable_debug_single_step=", enable_debug_single_step);
|
||||
get_bool_arg_value("+set_mstatus_tw=", set_mstatus_tw);
|
||||
get_bool_arg_value("+enable_floating_point=", enable_floating_point);
|
||||
if(inst.get_arg_value("+boot_mode=", boot_mode_opts)) begin
|
||||
`uvm_info(get_full_name(), $sformatf(
|
||||
"Got boot mode option - %0s", boot_mode_opts), UVM_LOW)
|
||||
case(boot_mode_opts)
|
||||
"m" : init_privileged_mode = MACHINE_MODE;
|
||||
"s" : init_privileged_mode = SUPERVISOR_MODE;
|
||||
"u" : init_privileged_mode = USER_MODE;
|
||||
default: `uvm_fatal(get_full_name(),
|
||||
$sformatf("Illegal boot mode option - %0s", boot_mode_opts))
|
||||
endcase
|
||||
init_privileged_mode.rand_mode(0);
|
||||
end
|
||||
`uvm_info(`gfn, $sformatf("riscv_instr_pkg::supported_privileged_mode = %0d",
|
||||
riscv_instr_pkg::supported_privileged_mode.size()), UVM_LOW)
|
||||
void'(inst.get_arg_value("+asm_test_suffix=", asm_test_suffix));
|
||||
// Directed march list from the runtime options, ex. RV32I, RV32M etc.
|
||||
void'(inst.get_arg_value("+march=", s));
|
||||
if(s != "") begin
|
||||
string cmdline_march_list[$];
|
||||
riscv_instr_group_t march;
|
||||
uvm_split_string(s, ",", cmdline_march_list);
|
||||
riscv_instr_pkg::supported_isa.delete();
|
||||
foreach(cmdline_march_list[i]) begin
|
||||
if(uvm_enum_wrapper#(riscv_instr_group_t)::from_name(
|
||||
cmdline_march_list[i].toupper(), march)) begin
|
||||
riscv_instr_pkg::supported_isa.push_back(march);
|
||||
end else begin
|
||||
`uvm_fatal(get_full_name(), $sformatf(
|
||||
"Invalid march %0s specified in command line", cmdline_march_list[i]))
|
||||
end
|
||||
end
|
||||
end
|
||||
if (!(RV32C inside {supported_isa})) begin
|
||||
disable_compressed_instr = 1;
|
||||
end
|
||||
setup_instr_distribution();
|
||||
get_invalid_priv_lvl_csr();
|
||||
endfunction
|
||||
|
||||
function void setup_instr_distribution();
|
||||
string opts;
|
||||
int val;
|
||||
get_int_arg_value("+dist_control_mode=", dist_control_mode);
|
||||
if (dist_control_mode == 1) begin
|
||||
riscv_instr_category_t category;
|
||||
category = category.first;
|
||||
do begin
|
||||
opts = {$sformatf("dist_%0s=", category.name()), "%d"};
|
||||
opts = opts.tolower();
|
||||
if ($value$plusargs(opts, val)) begin
|
||||
category_dist[category] = val;
|
||||
end else begin
|
||||
category_dist[category] = 10; // Default ratio
|
||||
end
|
||||
`uvm_info(`gfn, $sformatf("Set dist[%0s] = %0d",
|
||||
category.name(), category_dist[category]), UVM_LOW)
|
||||
category = category.next;
|
||||
end
|
||||
while(category != category.first);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Initialize the exception/interrupt delegation associate array, set all delegation default to 0
|
||||
virtual function void init_delegation();
|
||||
exception_cause_t cause;
|
||||
interrupt_cause_t intr_cause;
|
||||
cause = cause.first;
|
||||
// Init exception delegation array
|
||||
do begin
|
||||
m_mode_exception_delegation[cause] = 1'b0;
|
||||
s_mode_exception_delegation[cause] = 1'b0;
|
||||
cause = cause.next;
|
||||
end
|
||||
while(cause != cause.first);
|
||||
// Init interrupt delegation array
|
||||
intr_cause = intr_cause.first;
|
||||
do begin
|
||||
m_mode_interrupt_delegation[intr_cause] = 1'b0;
|
||||
s_mode_interrupt_delegation[intr_cause] = 1'b0;
|
||||
intr_cause = intr_cause.next;
|
||||
end
|
||||
while(intr_cause != intr_cause.first);
|
||||
endfunction
|
||||
|
||||
function void pre_randomize();
|
||||
foreach (riscv_instr_pkg::supported_privileged_mode[i]) begin
|
||||
if(riscv_instr_pkg::supported_privileged_mode[i] == SUPERVISOR_MODE)
|
||||
support_supervisor_mode = 1;
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void get_non_reserved_gpr();
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
// Setup the list all reserved registers
|
||||
reserved_regs = {tp, sp, scratch_reg};
|
||||
// Need to save all loop registers, and RA/T0
|
||||
min_stack_len_per_program = 2 * (XLEN/8);
|
||||
// Check if the setting is legal
|
||||
check_setting();
|
||||
// WFI is not supported in umode
|
||||
if (init_privileged_mode == USER_MODE) begin
|
||||
no_wfi = 1'b1;
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void check_setting();
|
||||
bit support_64b;
|
||||
bit support_128b;
|
||||
foreach (riscv_instr_pkg::supported_isa[i]) begin
|
||||
if (riscv_instr_pkg::supported_isa[i] inside {RV64I, RV64M, RV64A, RV64F, RV64D, RV64C}) begin
|
||||
support_64b = 1'b1;
|
||||
end else if (riscv_instr_pkg::supported_isa[i] inside {RV128I, RV128C}) begin
|
||||
support_128b = 1'b1;
|
||||
end
|
||||
end
|
||||
if (support_128b && XLEN != 128) begin
|
||||
`uvm_fatal(`gfn, "XLEN should be set to 128 based on riscv_instr_pkg::supported_isa setting")
|
||||
end
|
||||
if (!support_128b && support_64b && XLEN != 64) begin
|
||||
`uvm_fatal(`gfn, "XLEN should be set to 64 based on riscv_instr_pkg::supported_isa setting")
|
||||
end
|
||||
if (!(support_128b || support_64b) && XLEN != 32) begin
|
||||
`uvm_fatal(`gfn, "XLEN should be set to 32 based on riscv_instr_pkg::supported_isa setting")
|
||||
end
|
||||
if (!(support_128b || support_64b) && !(SATP_MODE inside {SV32, BARE})) begin
|
||||
`uvm_fatal(`gfn, $sformatf("SATP mode %0s is not supported for RV32G ISA", SATP_MODE.name()))
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Populate invalid_priv_mode_csrs with the main implemented CSRs for each supported privilege mode
|
||||
// TODO(udi) - include performance/pmp/trigger CSRs?
|
||||
virtual function void get_invalid_priv_lvl_csr();
|
||||
string invalid_lvl[$];
|
||||
string csr_name;
|
||||
privileged_reg_t csr;
|
||||
// Debug CSRs are inaccessible from all but Debug Mode, and we cannot boot into Debug Mode
|
||||
invalid_lvl.push_back("D");
|
||||
case (init_privileged_mode)
|
||||
MACHINE_MODE: begin
|
||||
end
|
||||
SUPERVISOR_MODE: begin
|
||||
invalid_lvl.push_back("M");
|
||||
end
|
||||
USER_MODE: begin
|
||||
invalid_lvl.push_back("S");
|
||||
invalid_lvl.push_back("M");
|
||||
end
|
||||
default: begin
|
||||
`uvm_fatal(`gfn, "Unsupported initialization privilege mode")
|
||||
end
|
||||
endcase
|
||||
foreach (implemented_csr[i]) begin
|
||||
privileged_reg_t csr = implemented_csr[i];
|
||||
csr_name = csr.name();
|
||||
if (csr_name[0] inside {invalid_lvl}) begin
|
||||
invalid_priv_mode_csrs.push_back(implemented_csr[i]);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Get an integer argument from comand line
|
||||
function void get_int_arg_value(string cmdline_str, ref int val);
|
||||
string s;
|
||||
if(inst.get_arg_value(cmdline_str, s)) begin
|
||||
val = s.atoi();
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Get a bool argument from comand line
|
||||
function void get_bool_arg_value(string cmdline_str, ref bit val);
|
||||
string s;
|
||||
if(inst.get_arg_value(cmdline_str, s)) begin
|
||||
val = s.atobin();
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Get a hex argument from command line
|
||||
function void get_hex_arg_value(string cmdline_str, ref int val);
|
||||
string s;
|
||||
if(inst.get_arg_value(cmdline_str, s)) begin
|
||||
val = s.atohex();
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Build instruction template
|
||||
virtual function void build_instruction_template(bit skip_instr_exclusion = 0);
|
||||
riscv_instr_name_t instr_name;
|
||||
riscv_instr_name_t excluded_instr[$];
|
||||
excluded_instr = {INVALID_INSTR};
|
||||
if (!skip_instr_exclusion) begin
|
||||
get_excluded_instr(excluded_instr);
|
||||
end
|
||||
instr_name = instr_name.first;
|
||||
do begin
|
||||
riscv_instr_base instr;
|
||||
if (!(instr_name inside {unsupported_instr, excluded_instr})) begin
|
||||
instr = riscv_instr_base::type_id::create("instr");
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(instr, instr_name == local::instr_name;)
|
||||
if ((instr.group inside {supported_isa}) &&
|
||||
!(disable_compressed_instr && instr.is_compressed) &&
|
||||
!(!enable_floating_point && (instr.group inside {RV32F, RV64F, RV32D, RV64D}))) begin
|
||||
`uvm_info(`gfn, $sformatf("Adding [%s] %s to the list",
|
||||
instr.group.name(), instr.instr_name.name()), UVM_HIGH)
|
||||
instr_group[instr.group].push_back(instr_name);
|
||||
instr_category[instr.category].push_back(instr_name);
|
||||
instr_template[instr_name] = instr;
|
||||
end
|
||||
end
|
||||
instr_name = instr_name.next;
|
||||
end
|
||||
while (instr_name != instr_name.first);
|
||||
endfunction
|
||||
|
||||
virtual function void build_instruction_list();
|
||||
basic_instr = {instr_category[SHIFT], instr_category[ARITHMETIC],
|
||||
instr_category[LOGICAL], instr_category[COMPARE]};
|
||||
basic_instr = {basic_instr, EBREAK};
|
||||
foreach(riscv_instr_pkg::supported_isa[i]) begin
|
||||
if (riscv_instr_pkg::supported_isa[i] inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) begin
|
||||
basic_instr = {basic_instr, C_EBREAK};
|
||||
break;
|
||||
end
|
||||
end
|
||||
if (no_dret == 0) begin
|
||||
basic_instr = {basic_instr, DRET};
|
||||
end
|
||||
if (no_fence == 0) begin
|
||||
basic_instr = {basic_instr, instr_category[SYNCH]};
|
||||
end
|
||||
// TODO: Support CSR instruction in other mode
|
||||
if ((no_csr_instr == 0) && (init_privileged_mode == MACHINE_MODE)) begin
|
||||
`uvm_info(`gfn, $sformatf("Adding CSR instr, mode: %0s", init_privileged_mode.name()), UVM_LOW)
|
||||
basic_instr = {basic_instr, instr_category[CSR]};
|
||||
end
|
||||
if (no_wfi == 0) begin
|
||||
basic_instr = {basic_instr, WFI};
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void get_excluded_instr(ref riscv_instr_name_t excluded[$]);
|
||||
// Below instrutions will modify stack pointer, not allowed in normal instruction stream.
|
||||
// It can be used in stack operation instruction stream.
|
||||
excluded = {excluded, C_SWSP, C_SDSP, C_ADDI16SP};
|
||||
if (!enable_sfence) begin
|
||||
excluded = {excluded, SFENCE_VMA};
|
||||
end
|
||||
if (no_fence) begin
|
||||
excluded = {excluded, FENCE, FENCE_I, SFENCE_VMA};
|
||||
end
|
||||
// TODO: Support C_ADDI4SPN
|
||||
excluded = {excluded, C_ADDI4SPN};
|
||||
endfunction
|
||||
|
||||
endclass
|
306
vendor/google_riscv-dv/src/deprecated/riscv_instr_stream.sv
vendored
Normal file
306
vendor/google_riscv-dv/src/deprecated/riscv_instr_stream.sv
vendored
Normal file
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Base class for RISC-V instruction stream
|
||||
// A instruction stream here is a queue of RISC-V basic instructions.
|
||||
// This class also provides some functions to manipulate the instruction stream, like insert a new
|
||||
// instruction, mix two instruction streams etc.
|
||||
class riscv_instr_stream extends uvm_object;
|
||||
|
||||
`INSTR instr_list[$];
|
||||
int unsigned instr_cnt;
|
||||
string label = "";
|
||||
// User can specify a small group of available registers to generate various hazard condition
|
||||
rand riscv_reg_t avail_regs[];
|
||||
// Some additional reserved registers that should not be used as rd register
|
||||
// by this instruction stream
|
||||
riscv_reg_t reserved_rd[];
|
||||
|
||||
`uvm_object_utils(riscv_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
// Initialize the instruction stream, create each instruction instance
|
||||
function void initialize_instr_list(int unsigned instr_cnt);
|
||||
instr_list = {};
|
||||
this.instr_cnt = instr_cnt;
|
||||
create_instr_instance();
|
||||
endfunction
|
||||
|
||||
virtual function void create_instr_instance();
|
||||
`INSTR instr;
|
||||
for(int i = 0; i < instr_cnt; i++) begin
|
||||
instr = `INSTR::type_id::create($sformatf("instr_%0d", i));
|
||||
instr_list.push_back(instr);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Insert an instruction to the existing instruction stream at the given index
|
||||
// When index is -1, the instruction is injected at a random location
|
||||
function void insert_instr(`INSTR instr, int idx = -1);
|
||||
int current_instr_cnt = instr_list.size();
|
||||
if(idx == -1) begin
|
||||
idx = $urandom_range(0, current_instr_cnt-1);
|
||||
while(instr_list[idx].atomic) begin
|
||||
idx += 1;
|
||||
if (idx == current_instr_cnt - 1) begin
|
||||
instr_list = {instr_list, instr};
|
||||
return;
|
||||
end
|
||||
end
|
||||
end else if((idx > current_instr_cnt) || (idx < 0)) begin
|
||||
`uvm_error(`gfn, $sformatf("Cannot insert instr:%0s at idx %0d",
|
||||
instr.convert2asm(), idx))
|
||||
end
|
||||
instr_list.insert(idx, instr);
|
||||
endfunction
|
||||
|
||||
// Insert an instruction to the existing instruction stream at the given index
|
||||
// When index is -1, the instruction is injected at a random location
|
||||
// When replace is 1, the original instruction at the inserted position will be replaced
|
||||
function void insert_instr_stream(`INSTR new_instr[], int idx = -1, bit replace = 1'b0);
|
||||
int current_instr_cnt = instr_list.size();
|
||||
int new_instr_cnt = new_instr.size();
|
||||
if(current_instr_cnt == 0) begin
|
||||
instr_list = new_instr;
|
||||
return;
|
||||
end
|
||||
if(idx == -1) begin
|
||||
idx = $urandom_range(0, current_instr_cnt-1);
|
||||
repeat(10) begin
|
||||
if (instr_list[idx].atomic) break;
|
||||
idx = $urandom_range(0, current_instr_cnt-1);
|
||||
end
|
||||
if (instr_list[idx].atomic) begin
|
||||
foreach (instr_list[i]) begin
|
||||
if (!instr_list[i].atomic) begin
|
||||
idx = i;
|
||||
break;
|
||||
end
|
||||
end
|
||||
if (instr_list[idx].atomic) begin
|
||||
`uvm_fatal(`gfn, $sformatf("Cannot inject the instruction"))
|
||||
end
|
||||
end
|
||||
end else if((idx > current_instr_cnt) || (idx < 0)) begin
|
||||
`uvm_error(`gfn, $sformatf("Cannot insert instr stream at idx %0d", idx))
|
||||
end
|
||||
// When replace is 1, the original instruction at this index will be removed. The label of the
|
||||
// original instruction will be copied to the head of inserted instruction stream.
|
||||
if(replace) begin
|
||||
new_instr[0].label = instr_list[idx].label;
|
||||
new_instr[0].has_label = instr_list[idx].has_label;
|
||||
if (idx == 0) begin
|
||||
instr_list = {new_instr, instr_list[idx+1:current_instr_cnt-1]};
|
||||
end else begin
|
||||
instr_list = {instr_list[0:idx-1], new_instr, instr_list[idx+1:current_instr_cnt-1]};
|
||||
end
|
||||
end else begin
|
||||
if (idx == 0) begin
|
||||
instr_list = {new_instr, instr_list[idx:current_instr_cnt-1]};
|
||||
end else begin
|
||||
instr_list = {instr_list[0:idx-1], new_instr, instr_list[idx:current_instr_cnt-1]};
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Mix the input instruction stream with the original instruction, the instruction order is
|
||||
// preserved. When 'contained' is set, the original instruction stream will be inside the
|
||||
// new instruction stream with the first and last instruction from the input instruction stream.
|
||||
function void mix_instr_stream(`INSTR new_instr[], bit contained = 1'b0);
|
||||
int current_instr_cnt = instr_list.size();
|
||||
int insert_instr_position[];
|
||||
int new_instr_cnt = new_instr.size();
|
||||
insert_instr_position = new[new_instr_cnt];
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(insert_instr_position,
|
||||
foreach(insert_instr_position[i]) {
|
||||
insert_instr_position[i] inside {[0:current_instr_cnt-1]};
|
||||
})
|
||||
if (insert_instr_position.size() > 0) begin
|
||||
insert_instr_position.sort();
|
||||
end
|
||||
if(contained) begin
|
||||
insert_instr_position[0] = 0;
|
||||
if(new_instr_cnt > 1)
|
||||
insert_instr_position[new_instr_cnt-1] = current_instr_cnt-1;
|
||||
end
|
||||
foreach(new_instr[i]) begin
|
||||
insert_instr(new_instr[i], insert_instr_position[i] + i);
|
||||
end
|
||||
endfunction
|
||||
|
||||
function string convert2string();
|
||||
string str;
|
||||
foreach(instr_list[i])
|
||||
str = {str, instr_list[i].convert2asm(), "\n"};
|
||||
return str;
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Generate a random instruction stream based on the configuration
|
||||
// There are two ways to use this class to generate instruction stream
|
||||
// 1. For short instruction stream, you can call randomize() directly.
|
||||
// 2. For long instruction stream (>1K), randomize() all instructions together might take a long
|
||||
// time for the constraint solver. In this case, you can call gen_instr to generate instructions
|
||||
// one by one. The time only grows linearly with the instruction count
|
||||
class riscv_rand_instr_stream extends riscv_instr_stream;
|
||||
|
||||
riscv_instr_gen_config cfg;
|
||||
bit kernel_mode;
|
||||
riscv_instr_name_t allowed_instr[$];
|
||||
int unsigned category_dist[riscv_instr_category_t];
|
||||
|
||||
`uvm_object_utils(riscv_rand_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
virtual function void create_instr_instance();
|
||||
`INSTR instr;
|
||||
for (int i = 0; i < instr_cnt; i++) begin
|
||||
instr = `INSTR::type_id::create($sformatf("instr_%0d", i));
|
||||
instr_list.push_back(instr);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void setup_allowed_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1);
|
||||
allowed_instr = cfg.basic_instr;
|
||||
if (no_branch == 0) begin
|
||||
allowed_instr = {allowed_instr, cfg.instr_category[BRANCH]};
|
||||
end
|
||||
if (no_load_store == 0) begin
|
||||
allowed_instr = {allowed_instr, cfg.instr_category[LOAD], cfg.instr_category[STORE]};
|
||||
end
|
||||
setup_instruction_dist(no_branch, no_load_store);
|
||||
endfunction
|
||||
|
||||
function void setup_instruction_dist(bit no_branch = 1'b0, bit no_load_store = 1'b1);
|
||||
if (cfg.dist_control_mode) begin
|
||||
category_dist = cfg.category_dist;
|
||||
if (no_branch) begin
|
||||
category_dist[BRANCH] = 0;
|
||||
end
|
||||
if (no_load_store) begin
|
||||
category_dist[LOAD] = 0;
|
||||
category_dist[STORE] = 0;
|
||||
end
|
||||
`uvm_info(`gfn, $sformatf("setup_instruction_dist: %0d", category_dist.size()), UVM_LOW)
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1,
|
||||
bit is_debug_program = 1'b0);
|
||||
setup_allowed_instr(no_branch, no_load_store);
|
||||
foreach(instr_list[i]) begin
|
||||
randomize_instr(instr_list[i], is_debug_program);
|
||||
end
|
||||
// Do not allow branch instruction as the last instruction because there's no
|
||||
// forward branch target
|
||||
while (instr_list[$].category == BRANCH) begin
|
||||
void'(instr_list.pop_back());
|
||||
if (instr_list.size() == 0) break;
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void randomize_instr(riscv_instr_base instr,
|
||||
bit is_in_debug = 1'b0,
|
||||
bit skip_rs1 = 1'b0,
|
||||
bit skip_rs2 = 1'b0,
|
||||
bit skip_rd = 1'b0,
|
||||
bit skip_imm = 1'b0,
|
||||
bit skip_csr = 1'b0,
|
||||
bit disable_dist = 1'b0);
|
||||
riscv_instr_name_t instr_name;
|
||||
if ((cfg.dist_control_mode == 1) && !disable_dist) begin
|
||||
riscv_instr_category_t category;
|
||||
int unsigned idx;
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(category,
|
||||
category dist {LOAD := category_dist[LOAD],
|
||||
STORE := category_dist[STORE],
|
||||
SHIFT := category_dist[SHIFT],
|
||||
ARITHMETIC := category_dist[ARITHMETIC],
|
||||
LOGICAL := category_dist[LOGICAL],
|
||||
COMPARE := category_dist[COMPARE],
|
||||
BRANCH := category_dist[BRANCH],
|
||||
SYNCH := category_dist[SYNCH],
|
||||
CSR := category_dist[CSR]};)
|
||||
idx = $urandom_range(0, cfg.instr_category[category].size() - 1);
|
||||
instr_name = cfg.instr_category[category][idx];
|
||||
// if set_dcsr_ebreak is set, we do not want to generate any ebreak
|
||||
// instructions inside the debug_rom
|
||||
end else if ((cfg.no_ebreak && !is_in_debug) ||
|
||||
(!cfg.enable_ebreak_in_debug_rom && is_in_debug)) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name,
|
||||
instr_name inside {allowed_instr};
|
||||
!(instr_name inside {EBREAK, C_EBREAK});)
|
||||
end else begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name,
|
||||
instr_name inside {allowed_instr};)
|
||||
end
|
||||
instr.copy_base_instr(cfg.instr_template[instr_name]);
|
||||
`uvm_info(`gfn, $sformatf("%s: rs1:%0d, rs2:%0d, rd:%0d, imm:%0d",
|
||||
instr.instr_name.name(),
|
||||
instr.has_rs1,
|
||||
instr.has_rs2,
|
||||
instr.has_rd,
|
||||
instr.has_imm), UVM_FULL)
|
||||
if (instr.has_imm && !skip_imm) begin
|
||||
instr.gen_rand_imm();
|
||||
end
|
||||
if (instr.has_rs1 && !skip_rs1) begin
|
||||
if (instr.is_compressed) begin
|
||||
// Compressed instruction could use the same register for rs1 and rd
|
||||
instr.rs1 = instr.gen_rand_gpr(
|
||||
.included_reg(avail_regs),
|
||||
.excluded_reg({reserved_rd, cfg.reserved_regs}));
|
||||
end else begin
|
||||
instr.rs1 = instr.gen_rand_gpr(.included_reg(avail_regs));
|
||||
end
|
||||
end
|
||||
if (instr.has_rs2 && !skip_rs2) begin
|
||||
instr.rs2 = instr.gen_rand_gpr(.included_reg(avail_regs));
|
||||
end
|
||||
if (instr.has_rd && !skip_rd) begin
|
||||
if (instr_name == C_LUI) begin
|
||||
instr.rd = instr.gen_rand_gpr(
|
||||
.included_reg(avail_regs),
|
||||
.excluded_reg({reserved_rd, cfg.reserved_regs, SP}));
|
||||
end else begin
|
||||
instr.rd = instr.gen_rand_gpr(
|
||||
.included_reg(avail_regs),
|
||||
.excluded_reg({reserved_rd, cfg.reserved_regs}));
|
||||
end
|
||||
end
|
||||
if ((instr.category == CSR) && !skip_csr) begin
|
||||
instr.gen_rand_csr(.privileged_mode(cfg.init_privileged_mode),
|
||||
.enable_floating_point(cfg.enable_floating_point),
|
||||
.illegal_csr_instr(cfg.enable_illegal_csr_instruction),
|
||||
.legal_invalid_csr_instr(cfg.enable_access_invalid_csr_level),
|
||||
.invalid_csrs(cfg.invalid_priv_mode_csrs));
|
||||
end
|
||||
if (instr.has_fs1) begin
|
||||
instr.fs1 = instr.gen_rand_fpr();
|
||||
end
|
||||
if (instr.has_fs2) begin
|
||||
instr.fs2 = instr.gen_rand_fpr();
|
||||
end
|
||||
if (instr.has_fs3) begin
|
||||
instr.fs3 = instr.gen_rand_fpr();
|
||||
end
|
||||
if (instr.has_fd) begin
|
||||
instr.fd = instr.gen_rand_fpr();
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
454
vendor/google_riscv-dv/src/deprecated/riscv_load_store_instr_lib.sv
vendored
Normal file
454
vendor/google_riscv-dv/src/deprecated/riscv_load_store_instr_lib.sv
vendored
Normal file
|
@ -0,0 +1,454 @@
|
|||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Base class for all load/store instruction stream
|
||||
|
||||
class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
||||
|
||||
typedef enum bit [1:0] {
|
||||
NARROW,
|
||||
HIGH,
|
||||
MEDIUM,
|
||||
SPARSE
|
||||
} locality_e;
|
||||
|
||||
rand int unsigned num_load_store;
|
||||
rand int unsigned num_mixed_instr;
|
||||
rand int base;
|
||||
int offset[];
|
||||
int addr[];
|
||||
riscv_instr_base load_store_instr[$];
|
||||
rand int unsigned data_page_id;
|
||||
rand riscv_reg_t rs1_reg;
|
||||
rand locality_e locality;
|
||||
rand int max_load_store_offset;
|
||||
|
||||
`uvm_object_utils(riscv_load_store_base_instr_stream)
|
||||
|
||||
constraint rs1_c {
|
||||
!(rs1_reg inside {cfg.reserved_regs, reserved_rd, ZERO});
|
||||
}
|
||||
|
||||
constraint addr_c {
|
||||
solve data_page_id before max_load_store_offset;
|
||||
solve max_load_store_offset before base;
|
||||
data_page_id < max_data_page_id;
|
||||
foreach (data_page[i]) {
|
||||
if (i == data_page_id) {
|
||||
max_load_store_offset == data_page[i].size_in_bytes;
|
||||
}
|
||||
}
|
||||
base inside {[0 : max_load_store_offset-1]};
|
||||
}
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
virtual function void randomize_offset();
|
||||
int offset_, addr_;
|
||||
offset = new[num_load_store];
|
||||
addr = new[num_load_store];
|
||||
for (int i=0; i<num_load_store; i++) begin
|
||||
if (!std::randomize(offset_, addr_) with {
|
||||
// Locality
|
||||
if (locality == NARROW) {
|
||||
soft offset_ inside {[-16:16]};
|
||||
} else if (locality == HIGH) {
|
||||
soft offset_ inside {[-64:64]};
|
||||
} else if (locality == MEDIUM) {
|
||||
soft offset_ inside {[-256:256]};
|
||||
} else if (locality == SPARSE) {
|
||||
soft offset_ inside {[-2048:2047]};
|
||||
}
|
||||
addr_ == base + offset_;
|
||||
addr_ inside {[0 : max_load_store_offset - 1]};
|
||||
}) begin
|
||||
`uvm_fatal(`gfn, "Cannot randomize load/store offset")
|
||||
end
|
||||
offset[i] = offset_;
|
||||
addr[i] = addr_;
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
randomize_offset();
|
||||
// rs1 cannot be modified by other instructions
|
||||
if(!(rs1_reg inside {reserved_rd})) begin
|
||||
reserved_rd = {reserved_rd, rs1_reg};
|
||||
end
|
||||
gen_load_store_instr();
|
||||
add_mixed_instr(num_mixed_instr);
|
||||
add_rs1_init_la_instr(rs1_reg, data_page_id, base);
|
||||
super.post_randomize();
|
||||
endfunction
|
||||
|
||||
// Generate each load/store instruction
|
||||
virtual function void gen_load_store_instr();
|
||||
bit enable_compressed_load_store;
|
||||
riscv_instr_base instr;
|
||||
if(avail_regs.size() > 0) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(avail_regs,
|
||||
unique{avail_regs};
|
||||
avail_regs[0] inside {[S0 : A5]};
|
||||
foreach(avail_regs[i]) {
|
||||
!(avail_regs[i] inside {cfg.reserved_regs, reserved_rd});
|
||||
},
|
||||
"Cannot randomize avail_regs")
|
||||
end
|
||||
if ((rs1_reg inside {[S0 : A5]}) && !cfg.disable_compressed_instr) begin
|
||||
enable_compressed_load_store = 1;
|
||||
end
|
||||
foreach(addr[i]) begin
|
||||
instr = riscv_instr_base::type_id::create("instr");
|
||||
// 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 (!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
|
||||
allowed_instr = {FLW, FSW, allowed_instr};
|
||||
end
|
||||
if((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0) &&
|
||||
(RV32C inside {riscv_instr_pkg::supported_isa}) &&
|
||||
enable_compressed_load_store) begin
|
||||
allowed_instr = {C_LW, C_SW, allowed_instr};
|
||||
if (cfg.enable_floating_point && (RV32FC inside {supported_isa})) begin
|
||||
allowed_instr = {C_FLW, C_FSW, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
if ((XLEN >= 64) && (addr[i] % 8 == 0)) begin
|
||||
allowed_instr = {LWU, LD, SD, allowed_instr};
|
||||
if (cfg.enable_floating_point && (RV32D inside {supported_isa})) begin
|
||||
allowed_instr = {FLD, FSD, allowed_instr};
|
||||
end
|
||||
if((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0) &&
|
||||
(RV64C inside {riscv_instr_pkg::supported_isa} &&
|
||||
enable_compressed_load_store)) begin
|
||||
allowed_instr = {C_LD, C_SD, allowed_instr};
|
||||
if (cfg.enable_floating_point && (RV32DC inside {supported_isa})) begin
|
||||
allowed_instr = {C_FLD, C_FSD, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
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
|
||||
allowed_instr = {C_LW, C_SW, allowed_instr};
|
||||
end
|
||||
if (XLEN >= 64) begin
|
||||
allowed_instr = {LWU, LD, SD, allowed_instr};
|
||||
if ((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0) &&
|
||||
(RV64C inside {riscv_instr_pkg::supported_isa}) &&
|
||||
enable_compressed_load_store) begin
|
||||
allowed_instr = {C_LD, C_SD, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
randomize_instr(instr, .skip_rs1(1'b1), .skip_imm(1'b1), .disable_dist(1'b1));
|
||||
instr.rs1 = rs1_reg;
|
||||
instr.set_imm(offset[i]);
|
||||
instr.process_load_store = 0;
|
||||
instr_list.push_back(instr);
|
||||
load_store_instr.push_back(instr);
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// A single load/store instruction
|
||||
class riscv_single_load_store_instr_stream extends riscv_load_store_base_instr_stream;
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store == 1;
|
||||
num_mixed_instr < 5;
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_single_load_store_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
endclass
|
||||
|
||||
// Back to back load/store instructions
|
||||
class riscv_load_store_stress_instr_stream extends riscv_load_store_base_instr_stream;
|
||||
|
||||
int unsigned max_instr_cnt = 30;
|
||||
int unsigned min_instr_cnt = 10;
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store inside {[min_instr_cnt:max_instr_cnt]};
|
||||
num_mixed_instr == 0;
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_load_store_stress_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
endclass
|
||||
|
||||
// Random load/store sequence
|
||||
// A random mix of load/store instructions and other instructions
|
||||
class riscv_load_store_rand_instr_stream extends riscv_load_store_base_instr_stream;
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store inside {[10:30]};
|
||||
num_mixed_instr inside {[10:30]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_load_store_rand_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
endclass
|
||||
|
||||
// Use a small set of GPR to create various WAW, RAW, WAR hazard scenario
|
||||
class riscv_hazard_instr_stream extends riscv_load_store_base_instr_stream;
|
||||
|
||||
int unsigned num_of_avail_regs = 6;
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store inside {[10:30]};
|
||||
num_mixed_instr inside {[10:30]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_hazard_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
function void pre_randomize();
|
||||
avail_regs = new[num_of_avail_regs];
|
||||
super.pre_randomize();
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Use a small set of address to create various load/store hazard sequence
|
||||
// This instruction stream focus more on hazard handling of load store unit.
|
||||
class riscv_load_store_hazard_instr_stream extends riscv_load_store_base_instr_stream;
|
||||
|
||||
rand int avail_addr[];
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store inside {[10:30]};
|
||||
num_mixed_instr inside {[10:30]};
|
||||
}
|
||||
|
||||
constraint avail_addr_c {
|
||||
avail_addr.size() inside {[1:3]};
|
||||
foreach(avail_addr[i]) {
|
||||
avail_addr[i] inside {[0 : max_load_store_offset - 1]};
|
||||
}
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_load_store_hazard_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
// Randomize each address in the post_randomize to reduce the complexity of solving everything
|
||||
// in one shot.
|
||||
function void post_randomize();
|
||||
int temp_addr;
|
||||
foreach(addr[i]) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(temp_addr,
|
||||
temp_addr inside {avail_addr};,
|
||||
"Cannot randomize address")
|
||||
addr[i] = temp_addr;
|
||||
end
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// Back to back access to multiple data pages
|
||||
// This is useful to test data TLB switch and replacement
|
||||
class riscv_multi_page_load_store_instr_stream extends riscv_mem_access_stream;
|
||||
|
||||
riscv_load_store_stress_instr_stream load_store_instr_stream[];
|
||||
rand int unsigned num_of_instr_stream;
|
||||
rand int unsigned data_page_id[];
|
||||
rand riscv_reg_t rs1_reg[];
|
||||
|
||||
constraint default_c {
|
||||
foreach(data_page_id[i]) {
|
||||
data_page_id[i] < max_data_page_id;
|
||||
}
|
||||
data_page_id.size() == num_of_instr_stream;
|
||||
rs1_reg.size() == num_of_instr_stream;
|
||||
unique {rs1_reg};
|
||||
foreach(rs1_reg[i]) {
|
||||
!(rs1_reg[i] inside {cfg.reserved_regs, ZERO});
|
||||
}
|
||||
}
|
||||
|
||||
constraint page_c {
|
||||
solve num_of_instr_stream before data_page_id;
|
||||
num_of_instr_stream inside {[1 : max_data_page_id]};
|
||||
unique {data_page_id};
|
||||
}
|
||||
|
||||
// Avoid accessing a large number of pages because we may run out of registers for rs1
|
||||
// Each page access needs a reserved register as the base address of load/store instruction
|
||||
constraint reasonable_c {
|
||||
num_of_instr_stream inside {[2:8]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_multi_page_load_store_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
// Generate each load/store seq, and mix them together
|
||||
function void post_randomize();
|
||||
load_store_instr_stream = new[num_of_instr_stream];
|
||||
foreach(load_store_instr_stream[i]) begin
|
||||
load_store_instr_stream[i] = riscv_load_store_stress_instr_stream::type_id::
|
||||
create($sformatf("load_store_instr_stream_%0d", i));
|
||||
load_store_instr_stream[i].min_instr_cnt = 5;
|
||||
load_store_instr_stream[i].max_instr_cnt = 10;
|
||||
load_store_instr_stream[i].cfg = cfg;
|
||||
// Make sure each load/store sequence doesn't override the rs1 of other sequences.
|
||||
foreach(rs1_reg[j]) begin
|
||||
if(i != j) begin
|
||||
load_store_instr_stream[i].reserved_rd =
|
||||
{load_store_instr_stream[i].reserved_rd, rs1_reg[j]};
|
||||
end
|
||||
end
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(load_store_instr_stream[i],
|
||||
rs1_reg == local::rs1_reg[i];
|
||||
data_page_id == local::data_page_id[i];,
|
||||
"Cannot randomize load/store instruction")
|
||||
// Mix the instruction stream of different page access, this could trigger the scenario of
|
||||
// frequent data TLB switch
|
||||
if(i == 0) begin
|
||||
instr_list = load_store_instr_stream[i].instr_list;
|
||||
end else begin
|
||||
mix_instr_stream(load_store_instr_stream[i].instr_list);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Access the different locations of the same memory regions
|
||||
class riscv_mem_region_stress_test extends riscv_multi_page_load_store_instr_stream;
|
||||
|
||||
`uvm_object_utils(riscv_mem_region_stress_test)
|
||||
`uvm_object_new
|
||||
|
||||
constraint page_c {
|
||||
num_of_instr_stream inside {[2:5]};
|
||||
foreach (data_page_id[i]) {
|
||||
if (i > 0) {
|
||||
data_page_id[i] == data_page_id[i-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endclass
|
||||
|
||||
// Random load/store sequence to full address range
|
||||
// The address range is not preloaded with data pages, use store instruction to initialize first
|
||||
class riscv_load_store_rand_addr_instr_stream extends riscv_load_store_base_instr_stream;
|
||||
|
||||
rand bit [XLEN-1:0] addr_offset;
|
||||
|
||||
// Find an unused 4K page from address 1M onward
|
||||
constraint addr_offset_c {
|
||||
|addr_offset[XLEN-1:20] == 1'b1;
|
||||
// TODO(taliu) Support larger address range
|
||||
addr_offset[XLEN-1:31] == 0;
|
||||
addr_offset[11:0] == 0;
|
||||
}
|
||||
|
||||
constraint legal_c {
|
||||
num_load_store inside {[5:10]};
|
||||
num_mixed_instr inside {[5:10]};
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_load_store_rand_addr_instr_stream)
|
||||
|
||||
virtual function void randomize_offset();
|
||||
int offset_, addr_;
|
||||
offset = new[num_load_store];
|
||||
addr = new[num_load_store];
|
||||
for (int i=0; i<num_load_store; i++) begin
|
||||
if (!std::randomize(offset_) with {
|
||||
offset_ inside {[-2048:2047]};
|
||||
}
|
||||
) begin
|
||||
`uvm_fatal(`gfn, "Cannot randomize load/store offset")
|
||||
end
|
||||
offset[i] = offset_;
|
||||
addr[i] = addr_offset + offset_;
|
||||
end
|
||||
endfunction `uvm_object_new
|
||||
|
||||
virtual function void add_rs1_init_la_instr(riscv_reg_t gpr, int id, int base = 0);
|
||||
riscv_instr_base instr[$];
|
||||
riscv_pseudo_instr li_instr;
|
||||
riscv_instr_base store_instr;
|
||||
riscv_instr_base add_instr;
|
||||
int min_offset[$];
|
||||
int max_offset[$];
|
||||
min_offset = offset.min();
|
||||
max_offset = offset.max();
|
||||
// Use LI to initialize the address offset
|
||||
li_instr = riscv_pseudo_instr::type_id::create("li_instr");
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(li_instr,
|
||||
pseudo_instr_name == LI;
|
||||
rd inside {cfg.gpr};
|
||||
rd != gpr;
|
||||
)
|
||||
li_instr.imm_str = $sformatf("0x%0x", addr_offset);
|
||||
// Add offset to the base address
|
||||
add_instr = riscv_instr_base::type_id::create("add_instr");
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(add_instr,
|
||||
instr_name == ADD;
|
||||
rs1 == gpr;
|
||||
rs2 == li_instr.rd;
|
||||
rd == gpr;
|
||||
)
|
||||
instr.push_back(li_instr);
|
||||
instr.push_back(add_instr);
|
||||
// Create SW instruction template
|
||||
store_instr = riscv_instr_base::type_id::create("store_instr");
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(store_instr,
|
||||
instr_name == SB;
|
||||
rs1 == gpr;
|
||||
)
|
||||
// Initialize the location which used by load instruction later
|
||||
foreach (load_store_instr[i]) begin
|
||||
if (load_store_instr[i].category == LOAD) begin
|
||||
riscv_instr_base store;
|
||||
store = riscv_instr_base::type_id::create("store");
|
||||
store.copy_base_instr(store_instr);
|
||||
store.rs2 = riscv_reg_t'(i % 32);
|
||||
store.imm_str = load_store_instr[i].imm_str;
|
||||
case (load_store_instr[i].instr_name) inside
|
||||
LB, LBU : store.instr_name = SB;
|
||||
LH, LHU : store.instr_name = SH;
|
||||
LW, C_LW, FLW, C_FLW : store.instr_name = SW;
|
||||
LD, C_LD, FLD, C_FLD, LWU : store.instr_name = SD;
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unexpected op: %0s",
|
||||
load_store_instr[i].convert2asm()))
|
||||
endcase
|
||||
instr.push_back(store);
|
||||
end
|
||||
end
|
||||
instr_list = {instr, instr_list};
|
||||
super.add_rs1_init_la_instr(gpr, id, 0);
|
||||
endfunction
|
||||
|
||||
endclass
|
212
vendor/google_riscv-dv/src/deprecated/riscv_loop_instr.sv
vendored
Normal file
212
vendor/google_riscv-dv/src/deprecated/riscv_loop_instr.sv
vendored
Normal file
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// TODO: Support other loop counter update instruction other than ADDI
|
||||
// TODO: Support forward branch inside the loop
|
||||
|
||||
class riscv_loop_instr extends riscv_rand_instr_stream;
|
||||
|
||||
rand riscv_reg_t loop_cnt_reg[];
|
||||
rand riscv_reg_t loop_limit_reg[];
|
||||
rand int loop_init_val[];
|
||||
rand int loop_step_val[];
|
||||
rand int loop_limit_val[];
|
||||
rand bit [2:0] num_of_nested_loop;
|
||||
rand int num_of_instr_in_loop;
|
||||
rand riscv_instr_name_t branch_type[];
|
||||
riscv_instr_base loop_init_instr[];
|
||||
riscv_instr_base loop_update_instr[];
|
||||
riscv_instr_base loop_branch_instr[];
|
||||
riscv_rand_instr loop_branch_target_instr[];
|
||||
// Aggregated loop instruction stream
|
||||
riscv_instr_base loop_instr[];
|
||||
|
||||
constraint legal_loop_regs_c {
|
||||
solve num_of_nested_loop before loop_cnt_reg;
|
||||
solve num_of_nested_loop before loop_limit_reg;
|
||||
foreach (loop_cnt_reg[i]) {
|
||||
loop_cnt_reg[i] != ZERO;
|
||||
foreach (cfg.reserved_regs[j]) {
|
||||
loop_cnt_reg[i] != cfg.reserved_regs[j];
|
||||
}
|
||||
}
|
||||
foreach (loop_limit_reg[i]) {
|
||||
foreach (cfg.reserved_regs[j]) {
|
||||
loop_limit_reg[i] != cfg.reserved_regs[j];
|
||||
}
|
||||
}
|
||||
unique {loop_cnt_reg, loop_limit_reg};
|
||||
loop_cnt_reg.size() == num_of_nested_loop;
|
||||
loop_limit_reg.size() == num_of_nested_loop;
|
||||
}
|
||||
|
||||
constraint loop_c {
|
||||
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;
|
||||
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_step_val[i] inside {[-10:10]};
|
||||
if(loop_init_val[i] < loop_limit_val[i]) {
|
||||
loop_step_val[i] > 0;
|
||||
} else {
|
||||
loop_step_val[i] < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_loop_instr)
|
||||
`uvm_object_new
|
||||
|
||||
function void post_randomize();
|
||||
reserved_rd = {loop_cnt_reg, loop_limit_reg};
|
||||
// Generate instructions that mixed with the loop instructions
|
||||
initialize_instr_list(num_of_instr_in_loop);
|
||||
gen_instr(1'b1);
|
||||
// Randomize the key loop instructions
|
||||
loop_init_instr = new[num_of_nested_loop*2];
|
||||
loop_update_instr = new[num_of_nested_loop];
|
||||
loop_branch_instr = new[num_of_nested_loop];
|
||||
loop_branch_target_instr = new[num_of_nested_loop];
|
||||
for(int i = 0; i < num_of_nested_loop; i++) begin
|
||||
// Instruction to init the loop counter
|
||||
loop_init_instr[2*i] = riscv_instr_base::type_id::create("loop_init_instr");
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_init_instr[2*i],
|
||||
instr_name == ADDI;
|
||||
rd == loop_cnt_reg[i];
|
||||
rs1 == ZERO;
|
||||
imm == loop_init_val[i];,
|
||||
"Cannot randomize loop init insturction")
|
||||
loop_init_instr[2*i].comment = $sformatf("init loop %0d counter", i);
|
||||
|
||||
// Instruction to init loop limit
|
||||
loop_init_instr[2*i+1] = riscv_instr_base::type_id::create("loop_init_instr");
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_init_instr[2*i+1],
|
||||
instr_name == ADDI;
|
||||
rd == loop_limit_reg[i];
|
||||
rs1 == ZERO;
|
||||
imm == loop_limit_val[i];,
|
||||
"Cannot randomize init loop instruction")
|
||||
loop_init_instr[2*i+1].comment = $sformatf("init loop %0d limit", i);
|
||||
|
||||
// Branch target instruction, can be anything
|
||||
loop_branch_target_instr[i] = riscv_rand_instr::type_id::create("loop_branch_target_instr");
|
||||
loop_branch_target_instr[i].cfg = cfg;
|
||||
loop_branch_target_instr[i].reserved_rd = reserved_rd;
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_branch_target_instr[i],
|
||||
!(category inside {LOAD, STORE, BRANCH, JUMP});
|
||||
// TODO: allow CSR instructions in all modes
|
||||
if (cfg.init_privileged_mode == MACHINE_MODE) {
|
||||
if (category == CSR) {
|
||||
csr == MSCRATCH;
|
||||
}
|
||||
} else {
|
||||
!(category == CSR);
|
||||
},
|
||||
"Cannot randomize branch target instruction")
|
||||
loop_branch_target_instr[i].label = $sformatf("%0s_%0d_t", label, i);
|
||||
|
||||
// Instruction to update loop counter
|
||||
loop_update_instr[i] = riscv_instr_base::type_id::create("loop_update_instr");
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_update_instr[i],
|
||||
instr_name == ADDI;
|
||||
rd == loop_cnt_reg[i];
|
||||
rs1== loop_cnt_reg[i];
|
||||
imm == loop_step_val[i];,
|
||||
"Cannot randomize loop update instruction")
|
||||
loop_update_instr[i].comment = $sformatf("update loop %0d counter", i);
|
||||
|
||||
// Backward branch instruction
|
||||
loop_branch_instr[i] = riscv_instr_base::type_id::create("loop_branch_instr");
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_branch_instr[i],
|
||||
instr_name == branch_type[i];
|
||||
rs1 == loop_cnt_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;
|
||||
loop_branch_instr[i].branch_assigned = 1'b1;
|
||||
end
|
||||
// Randomly distribute the loop instruction in the existing instruction stream
|
||||
build_loop_instr_stream();
|
||||
mix_instr_stream(loop_instr, 1'b1);
|
||||
foreach(instr_list[i]) begin
|
||||
if(instr_list[i].label != "")
|
||||
instr_list[i].has_label = 1'b1;
|
||||
else
|
||||
instr_list[i].has_label = 1'b0;
|
||||
instr_list[i].atomic = 1'b1;
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Build the whole loop structure from innermost loop to the outermost loop
|
||||
function void build_loop_instr_stream();
|
||||
loop_instr.delete;
|
||||
for(int i = 0; i < num_of_nested_loop; i++) begin
|
||||
loop_instr = {loop_init_instr[2*i],
|
||||
loop_init_instr[2*i+1],
|
||||
loop_branch_target_instr[i],
|
||||
loop_update_instr[i],
|
||||
loop_instr,
|
||||
loop_branch_instr[i]};
|
||||
end
|
||||
`uvm_info(get_full_name(), $sformatf("Totally %0d instructions have been added",
|
||||
loop_instr.size()), UVM_HIGH)
|
||||
endfunction
|
||||
endclass
|
8
vendor/google_riscv-dv/src/dv_defines.svh
vendored
8
vendor/google_riscv-dv/src/dv_defines.svh
vendored
|
@ -67,3 +67,11 @@
|
|||
`define DV_CHECK_STD_RANDOMIZE_WITH_FATAL(VAR_, WITH_C_,MSG_="Randomization failed!",ID_=`gfn) \
|
||||
`DV_CHECK_FATAL(std::randomize(VAR_), MSG_, ID_, with { WITH_C_ })
|
||||
`endif
|
||||
|
||||
// for vector processing
|
||||
`ifndef VECTOR_INCLUDE
|
||||
`define VECTOR_INCLUDE(VCE_INC) \
|
||||
`ifdef ENABLE_VECTORS \
|
||||
`include VCE_INC \
|
||||
`endif
|
||||
`endif
|
||||
|
|
60
vendor/google_riscv-dv/src/isa/riscv_amo_instr.sv
vendored
Normal file
60
vendor/google_riscv-dv/src/isa/riscv_amo_instr.sv
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
class riscv_amo_instr extends riscv_instr;
|
||||
|
||||
rand bit aq;
|
||||
rand bit rl;
|
||||
|
||||
constraint aq_rl_c {
|
||||
aq && rl == 0;
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_amo_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
virtual function string get_instr_name();
|
||||
get_instr_name = instr_name.name();
|
||||
if (group == RV32A) begin
|
||||
get_instr_name = {get_instr_name.substr(0, get_instr_name.len() - 3), ".w"};
|
||||
get_instr_name = aq ? {get_instr_name, ".aq"} :
|
||||
rl ? {get_instr_name, ".rl"} : get_instr_name;
|
||||
end else if (group == RV64A) begin
|
||||
get_instr_name = {get_instr_name.substr(0, get_instr_name.len() - 3), ".d"};
|
||||
get_instr_name = aq ? {get_instr_name, ".aq"} :
|
||||
rl ? {get_instr_name, ".rl"} : get_instr_name;
|
||||
end else begin
|
||||
`uvm_fatal(`gfn, $sformatf("Unexpected amo instr group: %0s / %0s",
|
||||
group.name(), instr_name.name()))
|
||||
end
|
||||
return get_instr_name;
|
||||
endfunction : get_instr_name
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2asm(string prefix = "");
|
||||
string asm_str;
|
||||
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
|
||||
if (group inside {RV32A, RV64A}) begin
|
||||
if (instr_name inside {LR_W, LR_D}) begin
|
||||
asm_str = $sformatf("%0s %0s, (%0s)", asm_str, rd.name(), rs1.name());
|
||||
end else begin
|
||||
asm_str = $sformatf("%0s %0s, %0s, (%0s)", asm_str, rd.name(), rs2.name(), rs1.name());
|
||||
end
|
||||
end else begin
|
||||
`uvm_fatal(`gfn, $sformatf("Unexpected amo instr group: %0s / %0s",
|
||||
group.name(), instr_name.name()))
|
||||
end
|
||||
if(comment != "")
|
||||
asm_str = {asm_str, " #",comment};
|
||||
return asm_str.tolower();
|
||||
endfunction : convert2asm
|
||||
|
||||
virtual function void do_copy(uvm_object rhs);
|
||||
riscv_amo_instr rhs_;
|
||||
super.copy(rhs);
|
||||
assert($cast(rhs_, rhs));
|
||||
this.aq = rhs_.aq;
|
||||
this.rl = rhs_.rl;
|
||||
endfunction : do_copy
|
||||
|
||||
endclass
|
384
vendor/google_riscv-dv/src/isa/riscv_compressed_instr.sv
vendored
Normal file
384
vendor/google_riscv-dv/src/isa/riscv_compressed_instr.sv
vendored
Normal file
|
@ -0,0 +1,384 @@
|
|||
class riscv_compressed_instr extends riscv_instr;
|
||||
|
||||
int imm_align;
|
||||
|
||||
constraint rvc_csr_c {
|
||||
// Registers specified by the three-bit rs1’, rs2’, and rd’
|
||||
if (format inside {CIW_FORMAT, CL_FORMAT, CS_FORMAT, CB_FORMAT, CA_FORMAT}) {
|
||||
if (has_rs1) {
|
||||
rs1 inside {[S0:A5]};
|
||||
}
|
||||
if (has_rs2) {
|
||||
rs2 inside {[S0:A5]};
|
||||
}
|
||||
if (has_rd) {
|
||||
rd inside {[S0:A5]};
|
||||
}
|
||||
}
|
||||
// C_ADDI16SP is only valid when rd == SP
|
||||
if (instr_name == C_ADDI16SP) {
|
||||
rd == SP;
|
||||
}
|
||||
if (instr_name inside {C_JR, C_JALR}) {
|
||||
rs2 == ZERO;
|
||||
rs1 != ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
constraint imm_val_c {
|
||||
if(imm_type inside {NZIMM, NZUIMM}) {
|
||||
imm[5:0] != 0;
|
||||
if (instr_name == C_LUI) {
|
||||
// TODO(taliu) Check why bit 6 cannot be zero
|
||||
imm[31:5] == 0;
|
||||
}
|
||||
if (instr_name inside {C_SRAI, C_SRLI, C_SLLI}) {
|
||||
imm[31:5] == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// C_JAL is RV32C only instruction
|
||||
constraint jal_c {
|
||||
if (XLEN != 32) {
|
||||
instr_name != C_JAL;
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid generating HINT or illegal instruction by default as it's not supported by the compiler
|
||||
constraint no_hint_illegal_instr_c {
|
||||
if (instr_name inside {C_ADDI, C_ADDIW, C_LI, C_LUI, C_SLLI, C_SLLI64,
|
||||
C_LQSP, C_LDSP, C_MV, C_ADD, C_LWSP}) {
|
||||
rd != ZERO;
|
||||
}
|
||||
if (instr_name == C_JR) {
|
||||
rs1 != ZERO;
|
||||
}
|
||||
if (instr_name inside {C_ADD, C_MV}) {
|
||||
rs2 != ZERO;
|
||||
}
|
||||
(instr_name == C_LUI) -> (rd != SP);
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_compressed_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
rs1 = S0;
|
||||
rs2 = S0;
|
||||
rd = S0;
|
||||
is_compressed = 1'b1;
|
||||
endfunction : new
|
||||
|
||||
virtual function void set_imm_len();
|
||||
if (format inside {CI_FORMAT, CSS_FORMAT}) begin
|
||||
imm_len = 6;
|
||||
end else if (format inside {CL_FORMAT, CS_FORMAT}) begin
|
||||
imm_len = 5;
|
||||
end else if (format inside {CJ_FORMAT}) begin
|
||||
imm_len = 11;
|
||||
end else if (format inside {CB_FORMAT}) begin
|
||||
if (instr_name == C_ANDI) begin
|
||||
imm_len = 6;
|
||||
end else begin
|
||||
imm_len = 7;
|
||||
end
|
||||
end else if (format inside {CB_FORMAT, CIW_FORMAT}) begin
|
||||
imm_len = 8;
|
||||
end
|
||||
if (instr_name inside {C_SQ, C_LQ, C_LQSP, C_SQSP, C_ADDI16SP}) begin
|
||||
imm_align = 4;
|
||||
end else if (instr_name inside {C_SD, C_LD, C_LDSP, C_SDSP}) begin
|
||||
imm_align = 3;
|
||||
end else if (instr_name inside {C_SW, C_LW, C_LWSP, C_SWSP, C_ADDI4SPN}) begin
|
||||
imm_align = 2;
|
||||
end else if (instr_name inside {C_LUI}) begin
|
||||
imm_align = 12;
|
||||
end else if (instr_name inside {C_J, C_JAL, C_BNEZ, C_BEQZ}) begin
|
||||
imm_align = 1;
|
||||
end
|
||||
endfunction : set_imm_len
|
||||
|
||||
virtual function void do_copy(uvm_object rhs);
|
||||
riscv_compressed_instr rhs_;
|
||||
super.copy(rhs);
|
||||
assert($cast(rhs_, rhs));
|
||||
this.imm_align = rhs_.imm_align;
|
||||
endfunction : do_copy
|
||||
|
||||
virtual function void extend_imm();
|
||||
if (instr_name != C_LUI) begin
|
||||
super.extend_imm();
|
||||
imm = imm << imm_align;
|
||||
end
|
||||
endfunction : extend_imm
|
||||
|
||||
virtual function void set_rand_mode();
|
||||
case (format) inside
|
||||
CR_FORMAT : begin
|
||||
if (category == JUMP) begin
|
||||
has_rd = 1'b0;
|
||||
end else begin
|
||||
has_rs1 = 1'b0;
|
||||
end
|
||||
has_imm = 1'b0;
|
||||
end
|
||||
CI_FORMAT : begin
|
||||
has_rs2 = 1'b0;
|
||||
has_rs1 = 1'b0;
|
||||
end
|
||||
CSS_FORMAT : begin
|
||||
has_rs1 = 1'b0;
|
||||
has_rd = 1'b0;
|
||||
end
|
||||
CL_FORMAT: begin
|
||||
has_rs2 = 1'b0;
|
||||
end
|
||||
CS_FORMAT : begin
|
||||
has_rd = 1'b0;
|
||||
end
|
||||
CA_FORMAT: begin
|
||||
has_rs1 = 1'b0;
|
||||
has_imm = 1'b0;
|
||||
end
|
||||
CIW_FORMAT: begin
|
||||
has_rs1 = 1'b0;
|
||||
has_rs2 = 1'b0;
|
||||
end
|
||||
CJ_FORMAT: begin
|
||||
has_rs1 = 1'b0;
|
||||
has_rs2 = 1'b0;
|
||||
has_rd = 1'b0;
|
||||
end
|
||||
CB_FORMAT: begin
|
||||
if (instr_name != C_ANDI) has_rd = 1'b0;
|
||||
has_rs2 = 1'b0;
|
||||
end
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2asm(string prefix = "");
|
||||
string asm_str;
|
||||
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
|
||||
if (category != SYSTEM) begin
|
||||
case(format)
|
||||
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 if (instr_name inside {C_LDSP, C_LWSP, C_LQSP})
|
||||
asm_str = $sformatf("%0s%0s, %0s(sp)", asm_str, rd.name(), get_imm());
|
||||
else
|
||||
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm());
|
||||
CL_FORMAT:
|
||||
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
|
||||
CS_FORMAT:
|
||||
if (category == STORE)
|
||||
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:
|
||||
if (category == STORE)
|
||||
asm_str = $sformatf("%0s%0s, %0s(sp)", asm_str, rs2.name(), get_imm());
|
||||
else
|
||||
asm_str = $sformatf("%0s%0s, %0s", asm_str, rs2.name(), get_imm());
|
||||
CR_FORMAT:
|
||||
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
|
||||
end else begin
|
||||
// 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 == C_EBREAK) begin
|
||||
asm_str = "c.ebreak;c.nop;";
|
||||
end
|
||||
end
|
||||
if (comment != "")
|
||||
asm_str = {asm_str, " #",comment};
|
||||
return asm_str.tolower();
|
||||
endfunction : convert2asm
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2bin(string prefix = "");
|
||||
string binary;
|
||||
case (instr_name) inside
|
||||
C_ADDI4SPN:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5:4], imm[9:6],
|
||||
imm[2], imm[3], get_c_gpr(rd), get_c_opcode()});
|
||||
C_LQ:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5:4], imm[8],
|
||||
get_c_gpr(rs1), imm[7:6], get_c_gpr(rd), get_c_opcode()});
|
||||
C_FLD, C_LD:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1),
|
||||
imm[7:6], get_c_gpr(rd), get_c_opcode()});
|
||||
C_LW, C_FLW:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1),
|
||||
imm[2], imm[6], get_c_gpr(rd), get_c_opcode()});
|
||||
C_SQ:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5:4], imm[8],
|
||||
get_c_gpr(rs1), imm[7:6], get_c_gpr(rs2), get_c_opcode()});
|
||||
C_FSD, C_SD:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1),
|
||||
imm[7:6], get_c_gpr(rs2), get_c_opcode()});
|
||||
C_SW, C_FSW:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1),
|
||||
imm[2], imm[6], get_c_gpr(rs2), get_c_opcode()});
|
||||
C_NOP, C_ADDI, C_LI, C_ADDIW:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:0], get_c_opcode()});
|
||||
C_JAL, C_J:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[11], imm[4], imm[9:8],
|
||||
imm[10], imm[6], imm[7], imm[3:1], imm[5], get_c_opcode()});
|
||||
C_ADDI16SP:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[9], 5'b10,
|
||||
imm[4], imm[6], imm[8:7], imm[5], get_c_opcode()});
|
||||
C_LUI:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:0], get_c_opcode()});
|
||||
C_SRLI:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5],
|
||||
2'b0, get_c_gpr(rd), imm[4:0], get_c_opcode()});
|
||||
C_SRLI64:
|
||||
binary = $sformatf("%4h", {get_func3(), 3'b0, get_c_gpr(rd), 5'b0, get_c_opcode()});
|
||||
C_SRAI:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5],
|
||||
2'b01, get_c_gpr(rd), imm[4:0], get_c_opcode()});
|
||||
C_SRAI64:
|
||||
binary = $sformatf("%4h", {get_func3(), 3'b001,
|
||||
get_c_gpr(rd), 5'b0, get_c_opcode()});
|
||||
C_ANDI:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5],
|
||||
2'b10, get_c_gpr(rd), imm[4:0], get_c_opcode()});
|
||||
C_SUB:
|
||||
binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd),
|
||||
2'b00, get_c_gpr(rs2), get_c_opcode()});
|
||||
C_XOR:
|
||||
binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd),
|
||||
2'b01, get_c_gpr(rs2), get_c_opcode()});
|
||||
C_OR:
|
||||
binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd),
|
||||
2'b10, get_c_gpr(rs2), get_c_opcode()});
|
||||
C_AND:
|
||||
binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd),
|
||||
2'b11, get_c_gpr(rs2), get_c_opcode()});
|
||||
C_SUBW:
|
||||
binary = $sformatf("%4h", {get_func3(), 3'b111, get_c_gpr(rd),
|
||||
2'b00, get_c_gpr(rs2), get_c_opcode()});
|
||||
C_ADDW:
|
||||
binary = $sformatf("%4h", {get_func3(), 3'b111, get_c_gpr(rd),
|
||||
2'b01, get_c_gpr(rs2), get_c_opcode()});
|
||||
C_BEQZ, C_BNEZ:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[8], imm[4:3],
|
||||
get_c_gpr(rs1), imm[7:6], imm[2:1], imm[5], get_c_opcode()});
|
||||
C_SLLI:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:0], get_c_opcode()});
|
||||
C_SLLI64:
|
||||
binary = $sformatf("%4h", {get_func3(), 1'b0, rd, 5'b0, get_c_opcode()});
|
||||
C_FLDSP, C_LDSP:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:3], imm[8:6], get_c_opcode()});
|
||||
C_LQSP:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4], imm[9:6], get_c_opcode()});
|
||||
C_LWSP, C_FLWSP:
|
||||
binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:2], imm[7:6], get_c_opcode()});
|
||||
C_JR:
|
||||
binary = $sformatf("%4h", {get_func3(), 1'b0, rs1, 5'b0, get_c_opcode()});
|
||||
C_MV:
|
||||
binary = $sformatf("%4h", {get_func3(), 1'b0, rd, rs2, get_c_opcode()});
|
||||
C_EBREAK:
|
||||
binary = $sformatf("%4h", {get_func3(), 1'b1, 10'b0, get_c_opcode()});
|
||||
C_JALR:
|
||||
binary = $sformatf("%4h", {get_func3(), 1'b1, 10'b0, get_c_opcode()});
|
||||
C_ADD:
|
||||
binary = $sformatf("%4h", {get_func3(), 1'b1, rd, rs2, get_c_opcode()});
|
||||
C_FSDSP, C_SDSP:
|
||||
binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:3], imm[8:6], rs2, get_c_opcode()});
|
||||
C_SQSP:
|
||||
binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:4], imm[9:6], rs2, get_c_opcode()});
|
||||
C_SWSP, C_FSWSP:
|
||||
binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:2], imm[7:6], rs2, get_c_opcode()});
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
|
||||
endcase
|
||||
return {prefix, binary};
|
||||
endfunction : convert2bin
|
||||
|
||||
// Get opcode for compressed instruction
|
||||
virtual function bit [1:0] get_c_opcode();
|
||||
case (instr_name) inside
|
||||
C_ADDI4SPN, C_FLD, C_FLD, C_LQ, C_LW, C_FLW,
|
||||
C_LD, C_FSD, C_SQ, C_SW, C_FSW, C_SD : get_c_opcode = 2'b00;
|
||||
C_NOP, C_ADDI, C_JAL, C_ADDIW, C_LI, C_ADDI16SP,
|
||||
C_LUI, C_SRLI, C_SRLI64, C_SRAI, C_SRAI64,
|
||||
C_ANDI, C_SUB, C_XOR, C_OR, C_AND, C_SUBW,
|
||||
C_ADDW, C_J, C_BEQZ, C_BNEZ : get_c_opcode = 2'b01;
|
||||
C_SLLI, C_SLLI64, C_FLDSP, C_LQSP, C_LWSP,
|
||||
C_FLWSP, C_LDSP, C_JR, C_MV, C_EBREAK, C_JALR,
|
||||
C_ADD, C_FSDSP, C_SQSP, C_SWSP, C_FSWSP, C_SDSP : get_c_opcode = 2'b10;
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
|
||||
endcase
|
||||
endfunction : get_c_opcode
|
||||
|
||||
virtual function bit [2:0] get_func3();
|
||||
case (instr_name) inside
|
||||
C_ADDI4SPN : get_func3 = 3'b000;
|
||||
C_FLD : get_func3 = 3'b001;
|
||||
C_LQ : get_func3 = 3'b001;
|
||||
C_LW : get_func3 = 3'b010;
|
||||
C_FLW : get_func3 = 3'b011;
|
||||
C_LD : get_func3 = 3'b011;
|
||||
C_FSD : get_func3 = 3'b101;
|
||||
C_SQ : get_func3 = 3'b101;
|
||||
C_SW : get_func3 = 3'b110;
|
||||
C_FSW : get_func3 = 3'b111;
|
||||
C_SD : get_func3 = 3'b111;
|
||||
C_NOP : get_func3 = 3'b000;
|
||||
C_ADDI : get_func3 = 3'b000;
|
||||
C_JAL : get_func3 = 3'b001;
|
||||
C_ADDIW : get_func3 = 3'b001;
|
||||
C_LI : get_func3 = 3'b010;
|
||||
C_ADDI16SP : get_func3 = 3'b011;
|
||||
C_LUI : get_func3 = 3'b011;
|
||||
C_SRLI : get_func3 = 3'b100;
|
||||
C_SRLI64 : get_func3 = 3'b100;
|
||||
C_SRAI : get_func3 = 3'b100;
|
||||
C_SRAI64 : get_func3 = 3'b100;
|
||||
C_ANDI : get_func3 = 3'b100;
|
||||
C_SUB : get_func3 = 3'b100;
|
||||
C_XOR : get_func3 = 3'b100;
|
||||
C_OR : get_func3 = 3'b100;
|
||||
C_AND : get_func3 = 3'b100;
|
||||
C_SUBW : get_func3 = 3'b100;
|
||||
C_ADDW : get_func3 = 3'b100;
|
||||
C_J : get_func3 = 3'b101;
|
||||
C_BEQZ : get_func3 = 3'b110;
|
||||
C_BNEZ : get_func3 = 3'b111;
|
||||
C_SLLI : get_func3 = 3'b000;
|
||||
C_SLLI64 : get_func3 = 3'b000;
|
||||
C_FLDSP : get_func3 = 3'b001;
|
||||
C_LQSP : get_func3 = 3'b001;
|
||||
C_LWSP : get_func3 = 3'b010;
|
||||
C_FLWSP : get_func3 = 3'b011;
|
||||
C_LDSP : get_func3 = 3'b011;
|
||||
C_JR : get_func3 = 3'b100;
|
||||
C_MV : get_func3 = 3'b100;
|
||||
C_EBREAK : get_func3 = 3'b100;
|
||||
C_JALR : get_func3 = 3'b100;
|
||||
C_ADD : get_func3 = 3'b100;
|
||||
C_FSDSP : get_func3 = 3'b101;
|
||||
C_SQSP : get_func3 = 3'b101;
|
||||
C_SWSP : get_func3 = 3'b110;
|
||||
C_FSWSP : get_func3 = 3'b111;
|
||||
C_SDSP : get_func3 = 3'b111;
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
|
||||
endcase
|
||||
endfunction : get_func3
|
||||
|
||||
endclass : riscv_compressed_instr
|
70
vendor/google_riscv-dv/src/isa/riscv_floating_point_instr.sv
vendored
Normal file
70
vendor/google_riscv-dv/src/isa/riscv_floating_point_instr.sv
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
class riscv_floating_point_instr extends riscv_instr;
|
||||
|
||||
rand riscv_fpr_t fs1;
|
||||
rand riscv_fpr_t fs2;
|
||||
rand riscv_fpr_t fs3;
|
||||
rand riscv_fpr_t fd;
|
||||
|
||||
`uvm_object_utils(riscv_floating_point_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
rs2.rand_mode(0);
|
||||
endfunction
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2asm(string prefix = "");
|
||||
string asm_str;
|
||||
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
|
||||
case (format)
|
||||
I_FORMAT:
|
||||
if (category == LOAD) begin
|
||||
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fd.name(), get_imm(), rs1.name());
|
||||
end else if (instr_name inside {FMV_X_W, FMV_X_D, FCVT_W_S, FCVT_WU_S,
|
||||
FCVT_L_S, FCVT_LU_S, FCVT_L_D, FCVT_LU_D, FCVT_LU_S,
|
||||
FCVT_W_D, FCVT_WU_D}) begin
|
||||
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), fs1.name());
|
||||
end else if (instr_name inside {FMV_W_X, FMV_D_X, FCVT_S_W, FCVT_S_WU,
|
||||
FCVT_S_L, FCVT_D_L, FCVT_S_LU, FCVT_D_W,
|
||||
FCVT_D_LU, FCVT_D_WU}) begin
|
||||
asm_str = $sformatf("%0s%0s, %0s", asm_str, fd.name(), rs1.name());
|
||||
end else begin
|
||||
asm_str = $sformatf("%0s%0s, %0s", asm_str, fd.name(), fs1.name());
|
||||
end
|
||||
S_FORMAT:
|
||||
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fs2.name(), get_imm(), rs1.name());
|
||||
R_FORMAT:
|
||||
if (category == COMPARE) begin
|
||||
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), fs1.name(), fs2.name());
|
||||
end else if (instr_name inside {FCLASS_S, FCLASS_D}) begin
|
||||
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), fs1.name());
|
||||
end else begin
|
||||
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, fd.name(), fs1.name(), fs2.name());
|
||||
end
|
||||
R4_FORMAT:
|
||||
asm_str = $sformatf("%0s%0s, %0s, %0s, %0s", asm_str, fd.name(), fs1.name(),
|
||||
fs2.name(), fs3.name());
|
||||
CL_FORMAT:
|
||||
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fd.name(), get_imm(), rs1.name());
|
||||
CS_FORMAT:
|
||||
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fs2.name(), get_imm(), rs1.name());
|
||||
default:
|
||||
`uvm_fatal(`gfn, $sformatf("Unsupported floating point format: %0s", format.name()))
|
||||
endcase
|
||||
if(comment != "")
|
||||
asm_str = {asm_str, " #",comment};
|
||||
return asm_str.tolower();
|
||||
endfunction
|
||||
|
||||
|
||||
virtual function void do_copy(uvm_object rhs);
|
||||
riscv_floating_point_instr rhs_;
|
||||
super.copy(rhs);
|
||||
assert($cast(rhs_, rhs));
|
||||
this.fs3 = rhs_.fs3;
|
||||
this.fs2 = rhs_.fs2;
|
||||
this.fs1 = rhs_.fs1;
|
||||
this.fd = rhs_.fd;
|
||||
endfunction : do_copy
|
||||
|
||||
endclass
|
622
vendor/google_riscv-dv/src/isa/riscv_instr.sv
vendored
Normal file
622
vendor/google_riscv-dv/src/isa/riscv_instr.sv
vendored
Normal file
|
@ -0,0 +1,622 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class riscv_instr extends uvm_object;
|
||||
|
||||
// All derived instructions
|
||||
static bit instr_registry[riscv_instr_name_t];
|
||||
|
||||
// Instruction list
|
||||
static riscv_instr_name_t instr_names[$];
|
||||
|
||||
// Categorized instruction list
|
||||
static riscv_instr_name_t instr_group[riscv_instr_group_t][$];
|
||||
static riscv_instr_name_t instr_category[riscv_instr_category_t][$];
|
||||
static riscv_instr_name_t basic_instr[$];
|
||||
static riscv_instr instr_template[riscv_instr_name_t];
|
||||
|
||||
// Privileged CSR filter
|
||||
static privileged_reg_t exclude_reg[];
|
||||
static privileged_reg_t include_reg[];
|
||||
|
||||
// Instruction attributes
|
||||
riscv_instr_group_t group;
|
||||
riscv_instr_format_t format;
|
||||
riscv_instr_category_t category;
|
||||
riscv_instr_name_t instr_name;
|
||||
imm_t imm_type;
|
||||
bit [4:0] imm_len;
|
||||
|
||||
// Operands
|
||||
rand bit [11:0] csr;
|
||||
rand riscv_reg_t rs2;
|
||||
rand riscv_reg_t rs1;
|
||||
rand riscv_reg_t rd;
|
||||
rand bit [31:0] imm;
|
||||
|
||||
// Helper fields
|
||||
bit [31:0] imm_mask = 32'hFFFF_FFFF;
|
||||
bit is_branch_target;
|
||||
bit has_label = 1'b1;
|
||||
bit atomic = 0;
|
||||
bit branch_assigned;
|
||||
bit process_load_store = 1'b1;
|
||||
bit is_compressed;
|
||||
bit is_illegal_instr;
|
||||
bit is_hint_instr;
|
||||
bit is_floating_point;
|
||||
string imm_str;
|
||||
string comment;
|
||||
string label;
|
||||
bit is_local_numeric_label;
|
||||
int idx = -1;
|
||||
bit has_rs1 = 1'b1;
|
||||
bit has_rs2 = 1'b1;
|
||||
bit has_rd = 1'b1;
|
||||
bit has_imm = 1'b1;
|
||||
|
||||
constraint imm_c {
|
||||
if (instr_name inside {SLLI, SRLI, SRAI, SLLIW, SRLIW, SRAIW}) {
|
||||
imm[11:5] == 0;
|
||||
}
|
||||
}
|
||||
|
||||
constraint csr_c {
|
||||
if (category == CSR) {
|
||||
if (include_reg.size() > 0) {
|
||||
csr inside {include_reg};
|
||||
}
|
||||
if (exclude_reg.size() > 0) {
|
||||
!(csr inside {exclude_reg});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_instr)
|
||||
`uvm_object_new
|
||||
|
||||
static function bit register(riscv_instr_name_t instr_name);
|
||||
`uvm_info("riscv_instr", $sformatf("Registering %0s", instr_name.name()), UVM_LOW)
|
||||
instr_registry[instr_name] = 1;
|
||||
return 1;
|
||||
endfunction : register
|
||||
|
||||
// Create the list of instructions based on the supported ISA extensions and configuration of the
|
||||
// generator.
|
||||
static function void create_instr_list(riscv_instr_gen_config cfg);
|
||||
instr_names.delete();
|
||||
instr_group.delete();
|
||||
instr_category.delete();
|
||||
foreach (instr_registry[instr_name]) begin
|
||||
riscv_instr instr_inst;
|
||||
instr_inst = create_instr(instr_name);
|
||||
instr_template[instr_name] = instr_inst;
|
||||
// C_JAL is RV32C only instruction
|
||||
if ((XLEN != 32) && (instr_name == C_JAL)) continue;
|
||||
if ((SP inside {cfg.reserved_regs}) && (instr_name inside {C_ADDI16SP})) begin
|
||||
continue;
|
||||
end
|
||||
if (!cfg.enable_sfence && instr_name == SFENCE_VMA) continue;
|
||||
if (cfg.no_fence && (instr_name inside {FENCE, FENCE_I, SFENCE_VMA})) continue;
|
||||
// TODO: gcc compile issue, support c.addi4spn later
|
||||
if (instr_name == C_ADDI4SPN) continue;
|
||||
if ((instr_inst.group inside {supported_isa}) &&
|
||||
!(cfg.disable_compressed_instr &&
|
||||
(instr_inst.group inside {RV32C, RV64C, RV32DC, RV32FC, RV128C})) &&
|
||||
!(!cfg.enable_floating_point &&
|
||||
(instr_inst.group inside {RV32F, RV64F, RV32D, RV64D}))) begin
|
||||
instr_category[instr_inst.category].push_back(instr_name);
|
||||
instr_group[instr_inst.group].push_back(instr_name);
|
||||
instr_names.push_back(instr_name);
|
||||
end
|
||||
end
|
||||
build_basic_instruction_list(cfg);
|
||||
create_csr_filter(cfg);
|
||||
endfunction : create_instr_list
|
||||
|
||||
static function void create_csr_filter(riscv_instr_gen_config cfg);
|
||||
include_reg.delete();
|
||||
exclude_reg.delete();
|
||||
if (cfg.enable_illegal_csr_instruction) begin
|
||||
exclude_reg = implemented_csr;
|
||||
end else if (cfg.enable_access_invalid_csr_level) begin
|
||||
include_reg = cfg.invalid_priv_mode_csrs;
|
||||
end else begin
|
||||
// Use scratch register to avoid the side effect of modifying other privileged mode CSR.
|
||||
if (cfg.init_privileged_mode == MACHINE_MODE) begin
|
||||
include_reg = {MSCRATCH};
|
||||
end else if (cfg.init_privileged_mode == SUPERVISOR_MODE) begin
|
||||
include_reg = {SSCRATCH};
|
||||
end else begin
|
||||
include_reg = {USCRATCH};
|
||||
end
|
||||
end
|
||||
endfunction : create_csr_filter
|
||||
|
||||
static function riscv_instr create_instr(riscv_instr_name_t instr_name);
|
||||
uvm_object obj;
|
||||
riscv_instr inst;
|
||||
string instr_class_name;
|
||||
uvm_coreservice_t coreservice = uvm_coreservice_t::get();
|
||||
uvm_factory factory = coreservice.get_factory();
|
||||
instr_class_name = {"riscv_", instr_name.name(), "_instr"};
|
||||
obj = factory.create_object_by_name(instr_class_name, "riscv_instr", instr_class_name);
|
||||
if (obj == null) begin
|
||||
`uvm_fatal("riscv_instr", $sformatf("Failed to create instr: %0s", instr_class_name))
|
||||
end
|
||||
if (!$cast(inst, obj)) begin
|
||||
`uvm_fatal("riscv_instr", $sformatf("Failed to cast instr: %0s", instr_class_name))
|
||||
end
|
||||
return inst;
|
||||
endfunction : create_instr
|
||||
|
||||
static function void build_basic_instruction_list(riscv_instr_gen_config cfg);
|
||||
basic_instr = {instr_category[SHIFT], instr_category[ARITHMETIC],
|
||||
instr_category[LOGICAL], instr_category[COMPARE]};
|
||||
if (!cfg.no_ebreak) begin
|
||||
basic_instr = {basic_instr, EBREAK};
|
||||
foreach (riscv_instr_pkg::supported_isa[i]) begin
|
||||
if (RV32C inside {riscv_instr_pkg::supported_isa[i]}) begin
|
||||
basic_instr = {basic_instr, C_EBREAK};
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
if (cfg.no_dret == 0) begin
|
||||
basic_instr = {basic_instr, DRET};
|
||||
end
|
||||
if (cfg.no_fence == 0) begin
|
||||
basic_instr = {basic_instr, instr_category[SYNCH]};
|
||||
end
|
||||
if ((cfg.no_csr_instr == 0) && (cfg.init_privileged_mode == MACHINE_MODE)) begin
|
||||
basic_instr = {basic_instr, instr_category[CSR]};
|
||||
end
|
||||
if (cfg.no_wfi == 0) begin
|
||||
basic_instr = {basic_instr, WFI};
|
||||
end
|
||||
endfunction : build_basic_instruction_list
|
||||
|
||||
static function riscv_instr get_rand_instr(riscv_instr instr_h = null,
|
||||
riscv_instr_name_t include_instr[] = {},
|
||||
riscv_instr_name_t exclude_instr[] = {},
|
||||
riscv_instr_category_t include_category[] = {},
|
||||
riscv_instr_category_t exclude_category[] = {},
|
||||
riscv_instr_group_t include_group[] = {},
|
||||
riscv_instr_group_t exclude_group[] = {});
|
||||
int unsigned idx;
|
||||
riscv_instr_name_t name;
|
||||
riscv_instr_name_t allowed_instr[];
|
||||
riscv_instr_name_t disallowed_instr[];
|
||||
riscv_instr_category_t allowed_categories[];
|
||||
foreach (include_category[i]) begin
|
||||
allowed_instr = {allowed_instr, instr_category[include_category[i]]};
|
||||
end
|
||||
foreach (exclude_category[i]) begin
|
||||
disallowed_instr = {disallowed_instr, instr_category[exclude_category[i]]};
|
||||
end
|
||||
foreach (include_group[i]) begin
|
||||
allowed_instr = {allowed_instr, instr_group[include_group[i]]};
|
||||
end
|
||||
foreach (exclude_group[i]) begin
|
||||
disallowed_instr = {disallowed_instr, instr_group[exclude_group[i]]};
|
||||
end
|
||||
disallowed_instr = {disallowed_instr, exclude_instr};
|
||||
if (disallowed_instr.size() == 0) begin
|
||||
if (include_instr.size() > 0) begin
|
||||
idx = $urandom_range(0, include_instr.size()-1);
|
||||
name = include_instr[idx];
|
||||
end else if (allowed_instr.size() > 0) begin
|
||||
idx = $urandom_range(0, allowed_instr.size()-1);
|
||||
name = allowed_instr[idx];
|
||||
end else begin
|
||||
idx = $urandom_range(0, instr_names.size()-1);
|
||||
name = instr_names[idx];
|
||||
end
|
||||
end else begin
|
||||
if (!std::randomize(name) with {
|
||||
name inside {instr_names};
|
||||
if (include_instr.size() > 0) {
|
||||
name inside {include_instr};
|
||||
}
|
||||
if (allowed_instr.size() > 0) {
|
||||
name inside {allowed_instr};
|
||||
}
|
||||
if (disallowed_instr.size() > 0) {
|
||||
!(name inside {disallowed_instr});
|
||||
}
|
||||
}) begin
|
||||
`uvm_fatal("riscv_instr", "Cannot generate random instruction")
|
||||
end
|
||||
end
|
||||
// Shallow copy for all relevant fields, avoid using create() to improve performance
|
||||
instr_h = new instr_template[name];
|
||||
return instr_h;
|
||||
endfunction : get_rand_instr
|
||||
|
||||
static function riscv_instr get_load_store_instr(riscv_instr_name_t load_store_instr[] = {});
|
||||
riscv_instr instr_h;
|
||||
int unsigned idx;
|
||||
riscv_instr_name_t name;
|
||||
if (load_store_instr.size() == 0) begin
|
||||
load_store_instr = {instr_category[LOAD], instr_category[STORE]};
|
||||
end
|
||||
idx = $urandom_range(0, load_store_instr.size()-1);
|
||||
name = load_store_instr[idx];
|
||||
// Shallow copy for all relevant fields, avoid using create() to improve performance
|
||||
instr_h = new instr_template[name];
|
||||
return instr_h;
|
||||
endfunction : get_load_store_instr
|
||||
|
||||
// Disable the rand mode for unused operands to randomization performance
|
||||
virtual function void set_rand_mode();
|
||||
case (format) inside
|
||||
R_FORMAT : has_imm = 1'b0;
|
||||
I_FORMAT : has_rs2 = 1'b0;
|
||||
S_FORMAT, B_FORMAT : has_rd = 1'b0;
|
||||
U_FORMAT, J_FORMAT : begin
|
||||
has_rs1 = 1'b0;
|
||||
has_rs2 = 1'b0;
|
||||
end
|
||||
endcase
|
||||
if (category == CSR) begin
|
||||
has_rs2 = 1'b0;
|
||||
if (format == I_FORMAT) begin
|
||||
has_rs1 = 1'b0;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void pre_randomize();
|
||||
rs1.rand_mode(has_rs1);
|
||||
rs2.rand_mode(has_rs2);
|
||||
rd.rand_mode(has_rd);
|
||||
imm.rand_mode(has_imm);
|
||||
if (category != CSR) begin
|
||||
csr.rand_mode(0);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void set_imm_len();
|
||||
if(format inside {U_FORMAT, J_FORMAT}) begin
|
||||
imm_len = 20;
|
||||
end else if(format inside {I_FORMAT, S_FORMAT, B_FORMAT}) begin
|
||||
if(imm_type == UIMM) begin
|
||||
imm_len = 5;
|
||||
end else begin
|
||||
imm_len = 11;
|
||||
end
|
||||
end
|
||||
imm_mask = imm_mask << imm_len;
|
||||
endfunction
|
||||
|
||||
virtual function void extend_imm();
|
||||
bit sign;
|
||||
imm = imm << (32 - imm_len);
|
||||
sign = imm[31];
|
||||
imm = imm >> (32 - imm_len);
|
||||
// Signed extension
|
||||
if (sign && !((format == U_FORMAT) || (imm_type inside {UIMM, NZUIMM}))) begin
|
||||
imm = imm_mask | imm;
|
||||
end
|
||||
endfunction : extend_imm
|
||||
|
||||
function void post_randomize();
|
||||
extend_imm();
|
||||
update_imm_str();
|
||||
endfunction : post_randomize
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2asm(string prefix = "");
|
||||
string asm_str;
|
||||
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
|
||||
if(category != SYSTEM) begin
|
||||
case(format)
|
||||
J_FORMAT, U_FORMAT : // instr rd,imm
|
||||
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm());
|
||||
I_FORMAT: // instr rd,rs1,imm
|
||||
if(instr_name == NOP)
|
||||
asm_str = "nop";
|
||||
else if(instr_name == WFI)
|
||||
asm_str = "wfi";
|
||||
else if(instr_name == FENCE)
|
||||
asm_str = $sformatf("fence"); // TODO: Support all fence combinations
|
||||
else if(instr_name == FENCE_I)
|
||||
asm_str = "fence.i";
|
||||
else if(category == LOAD) // Use psuedo instruction format
|
||||
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
|
||||
else if(category == CSR)
|
||||
asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, get_imm());
|
||||
else
|
||||
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), rs1.name(), get_imm());
|
||||
S_FORMAT, B_FORMAT: // instr rs1,rs2,imm
|
||||
if(category == STORE) // Use psuedo instruction format
|
||||
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name());
|
||||
else
|
||||
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rs1.name(), rs2.name(), get_imm());
|
||||
R_FORMAT: // instr rd,rs1,rs2
|
||||
if(category == CSR) begin
|
||||
asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, rs1.name());
|
||||
end else if(instr_name == SFENCE_VMA) begin
|
||||
asm_str = "sfence.vma x0, x0"; // TODO: Support all possible sfence
|
||||
end else begin
|
||||
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
|
||||
end
|
||||
endcase
|
||||
end else begin
|
||||
// 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 = ".4byte 0x00100073 # ebreak";
|
||||
end
|
||||
end
|
||||
if(comment != "")
|
||||
asm_str = {asm_str, " #",comment};
|
||||
return asm_str.tolower();
|
||||
endfunction
|
||||
|
||||
function bit [6:0] get_opcode();
|
||||
case (instr_name) inside
|
||||
LUI : get_opcode = 7'b0110111;
|
||||
AUIPC : get_opcode = 7'b0010111;
|
||||
JAL : get_opcode = 7'b1101111;
|
||||
JALR : get_opcode = 7'b1100111;
|
||||
BEQ, BNE, BLT, BGE, BLTU, BGEU : get_opcode = 7'b1100011;
|
||||
LB, LH, LW, LBU, LHU, LWU, LD : get_opcode = 7'b0000011;
|
||||
SB, SH, SW, SD : get_opcode = 7'b0100011;
|
||||
ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI, NOP : get_opcode = 7'b0010011;
|
||||
ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, MUL,
|
||||
MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU : get_opcode = 7'b0110011;
|
||||
ADDIW, SLLIW, SRLIW, SRAIW : get_opcode = 7'b0011011;
|
||||
MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU : get_opcode = 7'b0110011;
|
||||
FENCE, FENCE_I : get_opcode = 7'b0001111;
|
||||
ECALL, EBREAK, CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI : get_opcode = 7'b1110011;
|
||||
ADDW, SUBW, SLLW, SRLW, SRAW, MULW, DIVW, DIVUW, REMW, REMUW : get_opcode = 7'b0111011;
|
||||
ECALL, EBREAK, URET, SRET, MRET, DRET, WFI, SFENCE_VMA : get_opcode = 7'b1110011;
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
virtual function bit [2:0] get_func3();
|
||||
case (instr_name) inside
|
||||
JALR : get_func3 = 3'b000;
|
||||
BEQ : get_func3 = 3'b000;
|
||||
BNE : get_func3 = 3'b001;
|
||||
BLT : get_func3 = 3'b100;
|
||||
BGE : get_func3 = 3'b101;
|
||||
BLTU : get_func3 = 3'b110;
|
||||
BGEU : get_func3 = 3'b111;
|
||||
LB : get_func3 = 3'b000;
|
||||
LH : get_func3 = 3'b001;
|
||||
LW : get_func3 = 3'b010;
|
||||
LBU : get_func3 = 3'b100;
|
||||
LHU : get_func3 = 3'b101;
|
||||
SB : get_func3 = 3'b000;
|
||||
SH : get_func3 = 3'b001;
|
||||
SW : get_func3 = 3'b010;
|
||||
ADDI : get_func3 = 3'b000;
|
||||
NOP : get_func3 = 3'b000;
|
||||
SLTI : get_func3 = 3'b010;
|
||||
SLTIU : get_func3 = 3'b011;
|
||||
XORI : get_func3 = 3'b100;
|
||||
ORI : get_func3 = 3'b110;
|
||||
ANDI : get_func3 = 3'b111;
|
||||
SLLI : get_func3 = 3'b001;
|
||||
SRLI : get_func3 = 3'b101;
|
||||
SRAI : get_func3 = 3'b101;
|
||||
ADD : get_func3 = 3'b000;
|
||||
SUB : get_func3 = 3'b000;
|
||||
SLL : get_func3 = 3'b001;
|
||||
SLT : get_func3 = 3'b010;
|
||||
SLTU : get_func3 = 3'b011;
|
||||
XOR : get_func3 = 3'b100;
|
||||
SRL : get_func3 = 3'b101;
|
||||
SRA : get_func3 = 3'b101;
|
||||
OR : get_func3 = 3'b110;
|
||||
AND : get_func3 = 3'b111;
|
||||
FENCE : get_func3 = 3'b000;
|
||||
FENCE_I : get_func3 = 3'b001;
|
||||
ECALL : get_func3 = 3'b000;
|
||||
EBREAK : get_func3 = 3'b000;
|
||||
CSRRW : get_func3 = 3'b001;
|
||||
CSRRS : get_func3 = 3'b010;
|
||||
CSRRC : get_func3 = 3'b011;
|
||||
CSRRWI : get_func3 = 3'b101;
|
||||
CSRRSI : get_func3 = 3'b110;
|
||||
CSRRCI : get_func3 = 3'b111;
|
||||
LWU : get_func3 = 3'b110;
|
||||
LD : get_func3 = 3'b011;
|
||||
SD : get_func3 = 3'b011;
|
||||
ADDIW : get_func3 = 3'b000;
|
||||
SLLIW : get_func3 = 3'b001;
|
||||
SRLIW : get_func3 = 3'b101;
|
||||
SRAIW : get_func3 = 3'b101;
|
||||
ADDW : get_func3 = 3'b000;
|
||||
SUBW : get_func3 = 3'b000;
|
||||
SLLW : get_func3 = 3'b001;
|
||||
SRLW : get_func3 = 3'b101;
|
||||
SRAW : get_func3 = 3'b101;
|
||||
MUL : get_func3 = 3'b000;
|
||||
MULH : get_func3 = 3'b001;
|
||||
MULHSU : get_func3 = 3'b010;
|
||||
MULHU : get_func3 = 3'b011;
|
||||
DIV : get_func3 = 3'b100;
|
||||
DIVU : get_func3 = 3'b101;
|
||||
REM : get_func3 = 3'b110;
|
||||
REMU : get_func3 = 3'b111;
|
||||
MULW : get_func3 = 3'b000;
|
||||
DIVW : get_func3 = 3'b100;
|
||||
DIVUW : get_func3 = 3'b101;
|
||||
REMW : get_func3 = 3'b110;
|
||||
REMUW : get_func3 = 3'b111;
|
||||
ECALL, EBREAK, URET, SRET, MRET, DRET, WFI, SFENCE_VMA : get_func3 = 3'b000;
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
function bit [6:0] get_func7();
|
||||
case (instr_name)
|
||||
SLLI : get_func7 = 7'b0000000;
|
||||
SRLI : get_func7 = 7'b0000000;
|
||||
SRAI : get_func7 = 7'b0100000;
|
||||
ADD : get_func7 = 7'b0000000;
|
||||
SUB : get_func7 = 7'b0100000;
|
||||
SLL : get_func7 = 7'b0000000;
|
||||
SLT : get_func7 = 7'b0000000;
|
||||
SLTU : get_func7 = 7'b0000000;
|
||||
XOR : get_func7 = 7'b0000000;
|
||||
SRL : get_func7 = 7'b0000000;
|
||||
SRA : get_func7 = 7'b0100000;
|
||||
OR : get_func7 = 7'b0000000;
|
||||
AND : get_func7 = 7'b0000000;
|
||||
FENCE : get_func7 = 7'b0000000;
|
||||
FENCE_I : get_func7 = 7'b0000000;
|
||||
SLLIW : get_func7 = 7'b0000000;
|
||||
SRLIW : get_func7 = 7'b0000000;
|
||||
SRAIW : get_func7 = 7'b0100000;
|
||||
ADDW : get_func7 = 7'b0000000;
|
||||
SUBW : get_func7 = 7'b0100000;
|
||||
SLLW : get_func7 = 7'b0000000;
|
||||
SRLW : get_func7 = 7'b0000000;
|
||||
SRAW : get_func7 = 7'b0100000;
|
||||
MUL : get_func7 = 7'b0000001;
|
||||
MULH : get_func7 = 7'b0000001;
|
||||
MULHSU : get_func7 = 7'b0000001;
|
||||
MULHU : get_func7 = 7'b0000001;
|
||||
DIV : get_func7 = 7'b0000001;
|
||||
DIVU : get_func7 = 7'b0000001;
|
||||
REM : get_func7 = 7'b0000001;
|
||||
REMU : get_func7 = 7'b0000001;
|
||||
MULW : get_func7 = 7'b0000001;
|
||||
DIVW : get_func7 = 7'b0000001;
|
||||
DIVUW : get_func7 = 7'b0000001;
|
||||
REMW : get_func7 = 7'b0000001;
|
||||
REMUW : get_func7 = 7'b0000001;
|
||||
ECALL : get_func7 = 7'b0000000;
|
||||
EBREAK : get_func7 = 7'b0000000;
|
||||
URET : get_func7 = 7'b0000000;
|
||||
SRET : get_func7 = 7'b0001000;
|
||||
MRET : get_func7 = 7'b0011000;
|
||||
DRET : get_func7 = 7'b0111101;
|
||||
WFI : get_func7 = 7'b0001000;
|
||||
SFENCE_VMA: get_func7 = 7'b0001001;
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2bin(string prefix = "");
|
||||
string binary;
|
||||
case(format)
|
||||
J_FORMAT: begin
|
||||
binary = $sformatf("%8h", {imm[20], imm[10:1], imm[11], imm[19:12], rd, get_opcode()});
|
||||
end
|
||||
U_FORMAT: begin
|
||||
binary = $sformatf("%8h", {imm[31:12], rd, get_opcode()});
|
||||
end
|
||||
I_FORMAT: begin
|
||||
if(instr_name inside {FENCE, FENCE_I})
|
||||
binary = $sformatf("%8h", {17'b0, get_func3(), 5'b0, get_opcode()});
|
||||
else if(category == CSR)
|
||||
binary = $sformatf("%8h", {csr[10:0], imm[4:0], get_func3(), rd, get_opcode()});
|
||||
else if(instr_name == ECALL)
|
||||
binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()});
|
||||
else if(instr_name inside {URET, SRET, MRET})
|
||||
binary = $sformatf("%8h", {get_func7(), 5'b10, 13'b0, get_opcode()});
|
||||
else if(instr_name inside {DRET})
|
||||
binary = $sformatf("%8h", {get_func7(), 5'b10010, 13'b0, get_opcode()});
|
||||
else if(instr_name == EBREAK)
|
||||
binary = $sformatf("%8h", {get_func7(), 5'b01, 13'b0, get_opcode()});
|
||||
else if(instr_name == WFI)
|
||||
binary = $sformatf("%8h", {get_func7(), 5'b101, 13'b0, get_opcode()});
|
||||
else
|
||||
binary = $sformatf("%8h", {imm[11:0], rs1, get_func3(), rd, get_opcode()});
|
||||
end
|
||||
S_FORMAT: begin
|
||||
binary = $sformatf("%8h", {imm[11:5], rs2, rs1, get_func3(), imm[4:0], get_opcode()});
|
||||
end
|
||||
B_FORMAT: begin
|
||||
binary = $sformatf("%8h",
|
||||
{imm[12], imm[10:5], rs2, rs1, get_func3(),
|
||||
imm[4:1], imm[11], get_opcode()});
|
||||
end
|
||||
R_FORMAT: begin
|
||||
if(category == CSR)
|
||||
binary = $sformatf("%8h", {csr[10:0], rs1, get_func3(), rd, get_opcode()});
|
||||
else if(instr_name == SFENCE_VMA)
|
||||
binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()});
|
||||
else
|
||||
binary = $sformatf("%8h", {get_func7(), rs2, rs1, get_func3(), rd, get_opcode()});
|
||||
end
|
||||
endcase
|
||||
return {prefix, binary};
|
||||
endfunction
|
||||
|
||||
virtual function string get_instr_name();
|
||||
get_instr_name = instr_name.name();
|
||||
foreach(get_instr_name[i]) begin
|
||||
if (get_instr_name[i] == "_") begin
|
||||
get_instr_name[i] = ".";
|
||||
end
|
||||
end
|
||||
return get_instr_name;
|
||||
endfunction
|
||||
|
||||
// Get RVC register name for CIW, CL, CS, CB format
|
||||
function bit [2:0] get_c_gpr(riscv_reg_t gpr);
|
||||
return gpr[2:0];
|
||||
endfunction
|
||||
|
||||
// Default return imm value directly, can be overriden to use labels and symbols
|
||||
// Example: %hi(symbol), %pc_rel(label) ...
|
||||
virtual function string get_imm();
|
||||
return imm_str;
|
||||
endfunction
|
||||
|
||||
virtual function void clear_unused_label();
|
||||
if(has_label && !is_branch_target && is_local_numeric_label) begin
|
||||
has_label = 1'b0;
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void do_copy(uvm_object rhs);
|
||||
riscv_instr rhs_;
|
||||
super.copy(rhs);
|
||||
assert($cast(rhs_, rhs));
|
||||
this.group = rhs_.group;
|
||||
this.format = rhs_.format;
|
||||
this.category = rhs_.category;
|
||||
this.instr_name = rhs_.instr_name;
|
||||
this.rs2 = rhs_.rs2;
|
||||
this.rs1 = rhs_.rs1;
|
||||
this.rd = rhs_.rd;
|
||||
this.imm = rhs_.imm;
|
||||
this.imm_type = rhs_.imm_type;
|
||||
this.imm_len = rhs_.imm_len;
|
||||
this.imm_mask = rhs_.imm_mask;
|
||||
this.imm_str = rhs_.imm_str;
|
||||
this.imm_mask = rhs_.imm_mask;
|
||||
this.is_compressed = rhs_.is_compressed;
|
||||
this.has_rs2 = rhs_.has_rs2;
|
||||
this.has_rs1 = rhs_.has_rs1;
|
||||
this.has_rd = rhs_.has_rd;
|
||||
this.has_imm = rhs_.has_imm;
|
||||
endfunction : do_copy
|
||||
|
||||
virtual function void update_imm_str();
|
||||
imm_str = $sformatf("%0d", $signed(imm));
|
||||
endfunction
|
||||
|
||||
endclass
|
25
vendor/google_riscv-dv/src/isa/riscv_vector_instr.sv
vendored
Normal file
25
vendor/google_riscv-dv/src/isa/riscv_vector_instr.sv
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
class riscv_vector_instr extends riscv_instr;
|
||||
|
||||
// TODO : Add vector instruction operands here
|
||||
|
||||
`uvm_object_utils(riscv_vector_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
virtual function string get_instr_name();
|
||||
// TODO : Implement this function for vector instructions
|
||||
endfunction
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2asm(string prefix = "");
|
||||
string asm_str;
|
||||
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
|
||||
// TODO : Implement this function for vector instructions
|
||||
if(comment != "")
|
||||
asm_str = {asm_str, " #",comment};
|
||||
return asm_str.tolower();
|
||||
endfunction
|
||||
|
||||
endclass
|
7
vendor/google_riscv-dv/src/isa/rv128c_instr.sv
vendored
Normal file
7
vendor/google_riscv-dv/src/isa/rv128c_instr.sv
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
`DEFINE_C_INSTR(C_SRLI64, CB_FORMAT, SHIFT, RV128C, NZUIMM)
|
||||
`DEFINE_C_INSTR(C_SRAI64, CB_FORMAT, SHIFT, RV128C, NZUIMM)
|
||||
`DEFINE_C_INSTR(C_SLLI64, CI_FORMAT, SHIFT, RV128C, NZUIMM)
|
||||
`DEFINE_C_INSTR(C_LQ, CL_FORMAT, LOAD, RV32DC, UIMM)
|
||||
`DEFINE_C_INSTR(C_SQ, CS_FORMAT, STORE, RV32DC, UIMM)
|
||||
`DEFINE_C_INSTR(C_LQSP, CI_FORMAT, LOAD, RV32DC, UIMM)
|
||||
`DEFINE_C_INSTR(C_SQSP, CSS_FORMAT, STORE, RV32DC, UIMM)
|
11
vendor/google_riscv-dv/src/isa/rv32a_instr.sv
vendored
Normal file
11
vendor/google_riscv-dv/src/isa/rv32a_instr.sv
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
`DEFINE_AMO_INSTR(LR_W, R_FORMAT, LOAD, RV32A)
|
||||
`DEFINE_AMO_INSTR(SC_W, R_FORMAT, STORE, RV32A)
|
||||
`DEFINE_AMO_INSTR(AMOSWAP_W, R_FORMAT, AMO, RV32A)
|
||||
`DEFINE_AMO_INSTR(AMOADD_W, R_FORMAT, AMO, RV32A)
|
||||
`DEFINE_AMO_INSTR(AMOAND_W, R_FORMAT, AMO, RV32A)
|
||||
`DEFINE_AMO_INSTR(AMOOR_W, R_FORMAT, AMO, RV32A)
|
||||
`DEFINE_AMO_INSTR(AMOXOR_W, R_FORMAT, AMO, RV32A)
|
||||
`DEFINE_AMO_INSTR(AMOMIN_W, R_FORMAT, AMO, RV32A)
|
||||
`DEFINE_AMO_INSTR(AMOMAX_W, R_FORMAT, AMO, RV32A)
|
||||
`DEFINE_AMO_INSTR(AMOMINU_W, R_FORMAT, AMO, RV32A)
|
||||
`DEFINE_AMO_INSTR(AMOMAXU_W, R_FORMAT, AMO, RV32A)
|
27
vendor/google_riscv-dv/src/isa/rv32c_instr.sv
vendored
Normal file
27
vendor/google_riscv-dv/src/isa/rv32c_instr.sv
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
`DEFINE_C_INSTR(C_LW, CL_FORMAT, LOAD, RV32C, UIMM)
|
||||
`DEFINE_C_INSTR(C_SW, CS_FORMAT, STORE, RV32C, UIMM)
|
||||
`DEFINE_C_INSTR(C_LWSP, CI_FORMAT, LOAD, RV32C, UIMM)
|
||||
`DEFINE_C_INSTR(C_SWSP, CSS_FORMAT, STORE, RV32C, UIMM)
|
||||
`DEFINE_C_INSTR(C_ADDI4SPN, CIW_FORMAT, ARITHMETIC, RV32C, NZUIMM)
|
||||
`DEFINE_C_INSTR(C_ADDI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM)
|
||||
`DEFINE_C_INSTR(C_ADDI16SP, CI_FORMAT, ARITHMETIC, RV32C, NZIMM)
|
||||
`DEFINE_C_INSTR(C_LI, CI_FORMAT, ARITHMETIC, RV32C)
|
||||
`DEFINE_C_INSTR(C_LUI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM)
|
||||
`DEFINE_C_INSTR(C_SUB, CA_FORMAT, ARITHMETIC, RV32C)
|
||||
`DEFINE_C_INSTR(C_ADD, CR_FORMAT, ARITHMETIC, RV32C)
|
||||
`DEFINE_C_INSTR(C_NOP, CI_FORMAT, ARITHMETIC, RV32C)
|
||||
`DEFINE_C_INSTR(C_MV, CR_FORMAT, ARITHMETIC, RV32C)
|
||||
`DEFINE_C_INSTR(C_ANDI, CB_FORMAT, LOGICAL, RV32C)
|
||||
`DEFINE_C_INSTR(C_XOR, CA_FORMAT, LOGICAL, RV32C)
|
||||
`DEFINE_C_INSTR(C_OR, CA_FORMAT, LOGICAL, RV32C)
|
||||
`DEFINE_C_INSTR(C_AND, CA_FORMAT, LOGICAL, RV32C)
|
||||
`DEFINE_C_INSTR(C_BEQZ, CB_FORMAT, BRANCH, RV32C)
|
||||
`DEFINE_C_INSTR(C_BNEZ, CB_FORMAT, BRANCH, RV32C)
|
||||
`DEFINE_C_INSTR(C_SRLI, CB_FORMAT, SHIFT, RV32C, NZUIMM)
|
||||
`DEFINE_C_INSTR(C_SRAI, CB_FORMAT, SHIFT, RV32C, NZUIMM)
|
||||
`DEFINE_C_INSTR(C_SLLI, CI_FORMAT, SHIFT, RV32C, NZUIMM)
|
||||
`DEFINE_C_INSTR(C_J, CJ_FORMAT, JUMP, RV32C)
|
||||
`DEFINE_C_INSTR(C_JAL, CJ_FORMAT, JUMP, RV32C)
|
||||
`DEFINE_C_INSTR(C_JR, CR_FORMAT, JUMP, RV32C)
|
||||
`DEFINE_C_INSTR(C_JALR, CR_FORMAT, JUMP, RV32C)
|
||||
`DEFINE_C_INSTR(C_EBREAK, CI_FORMAT, SYSTEM, RV32C)
|
26
vendor/google_riscv-dv/src/isa/rv32d_instr.sv
vendored
Normal file
26
vendor/google_riscv-dv/src/isa/rv32d_instr.sv
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
`DEFINE_FP_INSTR(FLD, I_FORMAT, LOAD, RV32D)
|
||||
`DEFINE_FP_INSTR(FSD, S_FORMAT, STORE, RV32D)
|
||||
`DEFINE_FP_INSTR(FMADD_D, R4_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FMSUB_D, R4_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FNMSUB_D, R4_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FNMADD_D, R4_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FADD_D, R_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FSUB_D, R_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FMUL_D, R_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FDIV_D, R_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FSQRT_D, I_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FSGNJ_D, R_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FSGNJN_D, R_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FSGNJX_D, R_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FMIN_D, R_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FMAX_D, R_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FCVT_S_D, I_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FCVT_D_S, I_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FEQ_D, R_FORMAT, COMPARE, RV32D)
|
||||
`DEFINE_FP_INSTR(FLT_D, R_FORMAT, COMPARE, RV32D)
|
||||
`DEFINE_FP_INSTR(FLE_D, R_FORMAT, COMPARE, RV32D)
|
||||
`DEFINE_FP_INSTR(FCLASS_D, R_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FCVT_W_D, I_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FCVT_WU_D, I_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FCVT_D_W, I_FORMAT, ARITHMETIC, RV32D)
|
||||
`DEFINE_FP_INSTR(FCVT_D_WU, I_FORMAT, ARITHMETIC, RV32D)
|
4
vendor/google_riscv-dv/src/isa/rv32dc_instr.sv
vendored
Normal file
4
vendor/google_riscv-dv/src/isa/rv32dc_instr.sv
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
`DEFINE_FC_INSTR(C_FLD, CL_FORMAT, LOAD, RV32DC, UIMM)
|
||||
`DEFINE_FC_INSTR(C_FSD, CS_FORMAT, STORE, RV32DC, UIMM)
|
||||
`DEFINE_FC_INSTR(C_FLDSP, CI_FORMAT, LOAD, RV32DC, UIMM)
|
||||
`DEFINE_FC_INSTR(C_FSDSP, CSS_FORMAT, STORE, RV32DC, UIMM)
|
26
vendor/google_riscv-dv/src/isa/rv32f_instr.sv
vendored
Normal file
26
vendor/google_riscv-dv/src/isa/rv32f_instr.sv
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
`DEFINE_FP_INSTR(FLW, I_FORMAT, LOAD, RV32F)
|
||||
`DEFINE_FP_INSTR(FSW, S_FORMAT, STORE, RV32F)
|
||||
`DEFINE_FP_INSTR(FMADD_S, R4_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FMSUB_S, R4_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FNMSUB_S, R4_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FNMADD_S, R4_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FADD_S, R_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FSUB_S, R_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FMUL_S, R_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FDIV_S, R_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FSQRT_S, I_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FSGNJ_S, R_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FSGNJN_S, R_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FSGNJX_S, R_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FMIN_S, R_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FMAX_S, R_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FCVT_W_S, I_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FCVT_WU_S, I_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FMV_X_W, I_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FEQ_S, R_FORMAT, COMPARE, RV32F)
|
||||
`DEFINE_FP_INSTR(FLT_S, R_FORMAT, COMPARE, RV32F)
|
||||
`DEFINE_FP_INSTR(FLE_S, R_FORMAT, COMPARE, RV32F)
|
||||
`DEFINE_FP_INSTR(FCLASS_S, R_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FCVT_S_W, I_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FCVT_S_WU, I_FORMAT, ARITHMETIC, RV32F)
|
||||
`DEFINE_FP_INSTR(FMV_W_X, I_FORMAT, ARITHMETIC, RV32F)
|
4
vendor/google_riscv-dv/src/isa/rv32fc_instr.sv
vendored
Normal file
4
vendor/google_riscv-dv/src/isa/rv32fc_instr.sv
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
`DEFINE_FC_INSTR(C_FLW, CL_FORMAT, LOAD, RV32FC, UIMM)
|
||||
`DEFINE_FC_INSTR(C_FSW, CS_FORMAT, STORE, RV32FC, UIMM)
|
||||
`DEFINE_FC_INSTR(C_FLWSP, CI_FORMAT, LOAD, RV32FC, UIMM)
|
||||
`DEFINE_FC_INSTR(C_FSWSP, CSS_FORMAT, STORE, RV32FC, UIMM)
|
65
vendor/google_riscv-dv/src/isa/rv32i_instr.sv
vendored
Normal file
65
vendor/google_riscv-dv/src/isa/rv32i_instr.sv
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
// LOAD instructions
|
||||
`DEFINE_INSTR(LB, I_FORMAT, LOAD, RV32I)
|
||||
`DEFINE_INSTR(LH, I_FORMAT, LOAD, RV32I)
|
||||
`DEFINE_INSTR(LW, I_FORMAT, LOAD, RV32I)
|
||||
`DEFINE_INSTR(LBU, I_FORMAT, LOAD, RV32I)
|
||||
`DEFINE_INSTR(LHU, I_FORMAT, LOAD, RV32I)
|
||||
// STORE instructions
|
||||
`DEFINE_INSTR(SB, S_FORMAT, STORE, RV32I)
|
||||
`DEFINE_INSTR(SH, S_FORMAT, STORE, RV32I)
|
||||
`DEFINE_INSTR(SW, S_FORMAT, STORE, RV32I)
|
||||
// SHIFT intructions
|
||||
`DEFINE_INSTR(SLL, R_FORMAT, SHIFT, RV32I)
|
||||
`DEFINE_INSTR(SLLI, I_FORMAT, SHIFT, RV32I)
|
||||
`DEFINE_INSTR(SRL, R_FORMAT, SHIFT, RV32I)
|
||||
`DEFINE_INSTR(SRLI, I_FORMAT, SHIFT, RV32I)
|
||||
`DEFINE_INSTR(SRA, R_FORMAT, SHIFT, RV32I)
|
||||
`DEFINE_INSTR(SRAI, I_FORMAT, SHIFT, RV32I)
|
||||
// ARITHMETIC intructions
|
||||
`DEFINE_INSTR(ADD, R_FORMAT, ARITHMETIC, RV32I)
|
||||
`DEFINE_INSTR(ADDI, I_FORMAT, ARITHMETIC, RV32I)
|
||||
`DEFINE_INSTR(NOP, I_FORMAT, ARITHMETIC, RV32I)
|
||||
`DEFINE_INSTR(SUB, R_FORMAT, ARITHMETIC, RV32I)
|
||||
`DEFINE_INSTR(LUI, U_FORMAT, ARITHMETIC, RV32I, UIMM)
|
||||
`DEFINE_INSTR(AUIPC, U_FORMAT, ARITHMETIC, RV32I, UIMM)
|
||||
// LOGICAL instructions
|
||||
`DEFINE_INSTR(XOR, R_FORMAT, LOGICAL, RV32I)
|
||||
`DEFINE_INSTR(XORI, I_FORMAT, LOGICAL, RV32I)
|
||||
`DEFINE_INSTR(OR, R_FORMAT, LOGICAL, RV32I)
|
||||
`DEFINE_INSTR(ORI, I_FORMAT, LOGICAL, RV32I)
|
||||
`DEFINE_INSTR(AND, R_FORMAT, LOGICAL, RV32I)
|
||||
`DEFINE_INSTR(ANDI, I_FORMAT, LOGICAL, RV32I)
|
||||
// COMPARE instructions
|
||||
`DEFINE_INSTR(SLT, R_FORMAT, COMPARE, RV32I)
|
||||
`DEFINE_INSTR(SLTI, I_FORMAT, COMPARE, RV32I)
|
||||
`DEFINE_INSTR(SLTU, R_FORMAT, COMPARE, RV32I)
|
||||
`DEFINE_INSTR(SLTIU, I_FORMAT, COMPARE, RV32I)
|
||||
// BRANCH instructions
|
||||
`DEFINE_INSTR(BEQ, B_FORMAT, BRANCH, RV32I)
|
||||
`DEFINE_INSTR(BNE, B_FORMAT, BRANCH, RV32I)
|
||||
`DEFINE_INSTR(BLT, B_FORMAT, BRANCH, RV32I)
|
||||
`DEFINE_INSTR(BGE, B_FORMAT, BRANCH, RV32I)
|
||||
`DEFINE_INSTR(BLTU, B_FORMAT, BRANCH, RV32I)
|
||||
`DEFINE_INSTR(BGEU, B_FORMAT, BRANCH, RV32I)
|
||||
// JUMP instructions
|
||||
`DEFINE_INSTR(JAL, J_FORMAT, JUMP, RV32I)
|
||||
`DEFINE_INSTR(JALR, I_FORMAT, JUMP, RV32I)
|
||||
// SYNCH instructions
|
||||
`DEFINE_INSTR(FENCE, I_FORMAT, SYNCH, RV32I)
|
||||
`DEFINE_INSTR(FENCE_I, I_FORMAT, SYNCH, RV32I)
|
||||
`DEFINE_INSTR(SFENCE_VMA, R_FORMAT, SYNCH, RV32I)
|
||||
// SYSTEM instructions
|
||||
`DEFINE_INSTR(ECALL, I_FORMAT, SYSTEM, RV32I)
|
||||
`DEFINE_INSTR(EBREAK, I_FORMAT, SYSTEM, RV32I)
|
||||
`DEFINE_INSTR(URET, I_FORMAT, SYSTEM, RV32I)
|
||||
`DEFINE_INSTR(SRET, I_FORMAT, SYSTEM, RV32I)
|
||||
`DEFINE_INSTR(MRET, I_FORMAT, SYSTEM, RV32I)
|
||||
`DEFINE_INSTR(DRET, I_FORMAT, SYSTEM, RV32I)
|
||||
`DEFINE_INSTR(WFI, I_FORMAT, INTERRUPT, RV32I)
|
||||
// CSR instructions
|
||||
`DEFINE_INSTR(CSRRW, R_FORMAT, CSR, RV32I, UIMM)
|
||||
`DEFINE_INSTR(CSRRS, R_FORMAT, CSR, RV32I, UIMM)
|
||||
`DEFINE_INSTR(CSRRC, R_FORMAT, CSR, RV32I, UIMM)
|
||||
`DEFINE_INSTR(CSRRWI, I_FORMAT, CSR, RV32I, UIMM)
|
||||
`DEFINE_INSTR(CSRRSI, I_FORMAT, CSR, RV32I, UIMM)
|
||||
`DEFINE_INSTR(CSRRCI, I_FORMAT, CSR, RV32I, UIMM)
|
9
vendor/google_riscv-dv/src/isa/rv32m_instr.sv
vendored
Normal file
9
vendor/google_riscv-dv/src/isa/rv32m_instr.sv
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
//////////// RV32M instructions //////////////
|
||||
`DEFINE_INSTR(MUL, R_FORMAT, ARITHMETIC, RV32M)
|
||||
`DEFINE_INSTR(MULH, R_FORMAT, ARITHMETIC, RV32M)
|
||||
`DEFINE_INSTR(MULHSU, R_FORMAT, ARITHMETIC, RV32M)
|
||||
`DEFINE_INSTR(MULHU, R_FORMAT, ARITHMETIC, RV32M)
|
||||
`DEFINE_INSTR(DIV, R_FORMAT, ARITHMETIC, RV32M)
|
||||
`DEFINE_INSTR(DIVU, R_FORMAT, ARITHMETIC, RV32M)
|
||||
`DEFINE_INSTR(REM, R_FORMAT, ARITHMETIC, RV32M)
|
||||
`DEFINE_INSTR(REMU, R_FORMAT, ARITHMETIC, RV32M)
|
11
vendor/google_riscv-dv/src/isa/rv64a_instr.sv
vendored
Normal file
11
vendor/google_riscv-dv/src/isa/rv64a_instr.sv
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
`DEFINE_AMO_INSTR(LR_D, R_FORMAT, LOAD, RV64A)
|
||||
`DEFINE_AMO_INSTR(SC_D, R_FORMAT, STORE, RV64A)
|
||||
`DEFINE_AMO_INSTR(AMOSWAP_D, R_FORMAT, AMO, RV64A)
|
||||
`DEFINE_AMO_INSTR(AMOADD_D, R_FORMAT, AMO, RV64A)
|
||||
`DEFINE_AMO_INSTR(AMOAND_D, R_FORMAT, AMO, RV64A)
|
||||
`DEFINE_AMO_INSTR(AMOOR_D, R_FORMAT, AMO, RV64A)
|
||||
`DEFINE_AMO_INSTR(AMOXOR_D, R_FORMAT, AMO, RV64A)
|
||||
`DEFINE_AMO_INSTR(AMOMIN_D, R_FORMAT, AMO, RV64A)
|
||||
`DEFINE_AMO_INSTR(AMOMAX_D, R_FORMAT, AMO, RV64A)
|
||||
`DEFINE_AMO_INSTR(AMOMINU_D, R_FORMAT, AMO, RV64A)
|
||||
`DEFINE_AMO_INSTR(AMOMAXU_D, R_FORMAT, AMO, RV64A)
|
7
vendor/google_riscv-dv/src/isa/rv64c_instr.sv
vendored
Normal file
7
vendor/google_riscv-dv/src/isa/rv64c_instr.sv
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
`DEFINE_C_INSTR(C_ADDIW, CI_FORMAT, ARITHMETIC, RV64C)
|
||||
`DEFINE_C_INSTR(C_SUBW, CA_FORMAT, ARITHMETIC, RV64C)
|
||||
`DEFINE_C_INSTR(C_ADDW, CA_FORMAT, ARITHMETIC, RV64C)
|
||||
`DEFINE_C_INSTR(C_LD, CL_FORMAT, LOAD, RV64C, UIMM)
|
||||
`DEFINE_C_INSTR(C_SD, CS_FORMAT, STORE, RV64C, UIMM)
|
||||
`DEFINE_C_INSTR(C_LDSP, CI_FORMAT, LOAD, RV64C, UIMM)
|
||||
`DEFINE_C_INSTR(C_SDSP, CSS_FORMAT, STORE, RV64C, UIMM)
|
6
vendor/google_riscv-dv/src/isa/rv64d_instr.sv
vendored
Normal file
6
vendor/google_riscv-dv/src/isa/rv64d_instr.sv
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
`DEFINE_FP_INSTR(FMV_X_D, I_FORMAT, ARITHMETIC, RV64D)
|
||||
`DEFINE_FP_INSTR(FMV_D_X, I_FORMAT, ARITHMETIC, RV64D)
|
||||
`DEFINE_FP_INSTR(FCVT_L_D, I_FORMAT, ARITHMETIC, RV64D)
|
||||
`DEFINE_FP_INSTR(FCVT_LU_D, I_FORMAT, ARITHMETIC, RV64D)
|
||||
`DEFINE_FP_INSTR(FCVT_D_L, I_FORMAT, ARITHMETIC, RV64D)
|
||||
`DEFINE_FP_INSTR(FCVT_D_LU, I_FORMAT, ARITHMETIC, RV64D)
|
4
vendor/google_riscv-dv/src/isa/rv64f_instr.sv
vendored
Normal file
4
vendor/google_riscv-dv/src/isa/rv64f_instr.sv
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
`DEFINE_FP_INSTR(FCVT_L_S, I_FORMAT, ARITHMETIC, RV64F)
|
||||
`DEFINE_FP_INSTR(FCVT_LU_S, I_FORMAT, ARITHMETIC, RV64F)
|
||||
`DEFINE_FP_INSTR(FCVT_S_L, I_FORMAT, ARITHMETIC, RV64F)
|
||||
`DEFINE_FP_INSTR(FCVT_S_LU, I_FORMAT, ARITHMETIC, RV64F)
|
14
vendor/google_riscv-dv/src/isa/rv64i_instr.sv
vendored
Normal file
14
vendor/google_riscv-dv/src/isa/rv64i_instr.sv
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
`DEFINE_INSTR(LWU, I_FORMAT, LOAD, RV64I)
|
||||
`DEFINE_INSTR(LD, I_FORMAT, LOAD, RV64I)
|
||||
`DEFINE_INSTR(SD, S_FORMAT, STORE, RV64I)
|
||||
// SHIFT intructions
|
||||
`DEFINE_INSTR(SLLW, R_FORMAT, SHIFT, RV64I)
|
||||
`DEFINE_INSTR(SLLIW, I_FORMAT, SHIFT, RV64I)
|
||||
`DEFINE_INSTR(SRLW, R_FORMAT, SHIFT, RV64I)
|
||||
`DEFINE_INSTR(SRLIW, I_FORMAT, SHIFT, RV64I)
|
||||
`DEFINE_INSTR(SRAW, R_FORMAT, SHIFT, RV64I)
|
||||
`DEFINE_INSTR(SRAIW, I_FORMAT, SHIFT, RV64I)
|
||||
// ARITHMETIC intructions
|
||||
`DEFINE_INSTR(ADDW, R_FORMAT, ARITHMETIC, RV64I)
|
||||
`DEFINE_INSTR(ADDIW, I_FORMAT, ARITHMETIC, RV64I)
|
||||
`DEFINE_INSTR(SUBW, R_FORMAT, ARITHMETIC, RV64I)
|
5
vendor/google_riscv-dv/src/isa/rv64m_instr.sv
vendored
Normal file
5
vendor/google_riscv-dv/src/isa/rv64m_instr.sv
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
`DEFINE_INSTR(MULW, R_FORMAT, ARITHMETIC, RV64M)
|
||||
`DEFINE_INSTR(DIVW, R_FORMAT, ARITHMETIC, RV64M)
|
||||
`DEFINE_INSTR(DIVUW, R_FORMAT, ARITHMETIC, RV64M)
|
||||
`DEFINE_INSTR(REMW, R_FORMAT, ARITHMETIC, RV64M)
|
||||
`DEFINE_INSTR(REMUW, R_FORMAT, ARITHMETIC, RV64M)
|
|
@ -65,13 +65,13 @@ class riscv_amo_base_instr_stream extends riscv_mem_access_stream;
|
|||
virtual function void gen_amo_instr();
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
endclass : riscv_amo_base_instr_stream
|
||||
|
||||
// A pair of LR/SC instruction
|
||||
class riscv_lr_sc_instr_stream extends riscv_amo_base_instr_stream;
|
||||
|
||||
riscv_rand_instr lr_instr;
|
||||
riscv_rand_instr sc_instr;
|
||||
riscv_instr lr_instr;
|
||||
riscv_instr sc_instr;
|
||||
|
||||
constraint legal_c {
|
||||
num_amo == 1;
|
||||
|
@ -82,32 +82,40 @@ class riscv_lr_sc_instr_stream extends riscv_amo_base_instr_stream;
|
|||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
lr_instr = riscv_rand_instr::type_id::create("lr_instr");
|
||||
sc_instr = riscv_rand_instr::type_id::create("sc_instr");
|
||||
endfunction
|
||||
|
||||
virtual function void gen_amo_instr();
|
||||
lr_instr.cfg = cfg;
|
||||
sc_instr.cfg = cfg;
|
||||
lr_instr.disable_a_extension_c.constraint_mode(0);
|
||||
sc_instr.disable_a_extension_c.constraint_mode(0);
|
||||
lr_instr = riscv_instr::get_rand_instr(.include_instr({LR_W, LR_D}));
|
||||
sc_instr = riscv_instr::get_rand_instr(.include_instr({SC_W, SC_D}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(lr_instr,
|
||||
rs1 == rs1_reg;
|
||||
rd != rs1_reg;
|
||||
instr_name inside {LR_W, LR_D};)
|
||||
rs1 == rs1_reg;
|
||||
if (reserved_rd.size() > 0) {
|
||||
!(rd inside {reserved_rd});
|
||||
}
|
||||
if (cfg.reserved_regs.size() > 0) {
|
||||
!(rd inside {cfg.reserved_regs});
|
||||
}
|
||||
rd != rs1_reg;
|
||||
)
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(sc_instr,
|
||||
rs1 == rs1_reg;
|
||||
rd != rs1_reg;
|
||||
instr_name inside {SC_W, SC_D};)
|
||||
instr_list.push_front(lr_instr);
|
||||
instr_list.push_front(sc_instr);
|
||||
rs1 == rs1_reg;
|
||||
if (reserved_rd.size() > 0) {
|
||||
!(rd inside {reserved_rd});
|
||||
}
|
||||
if (cfg.reserved_regs.size() > 0) {
|
||||
!(rd inside {cfg.reserved_regs});
|
||||
}
|
||||
rd != rs1_reg;
|
||||
)
|
||||
instr_list.push_back(lr_instr);
|
||||
instr_list.push_back(sc_instr);
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
endclass : riscv_lr_sc_instr_stream
|
||||
|
||||
class riscv_amo_instr_stream extends riscv_amo_base_instr_stream;
|
||||
|
||||
riscv_rand_instr amo_instr[];
|
||||
riscv_instr amo_instr[];
|
||||
|
||||
constraint reasonable_c {
|
||||
solve num_amo before num_mixed_instr;
|
||||
|
@ -121,22 +129,19 @@ class riscv_amo_instr_stream extends riscv_amo_base_instr_stream;
|
|||
virtual function void gen_amo_instr();
|
||||
amo_instr = new[num_amo];
|
||||
foreach (amo_instr[i]) begin
|
||||
amo_instr[i] = riscv_rand_instr::type_id::create($sformatf("amo_instr_%0d", i));
|
||||
amo_instr[i].cfg = cfg;
|
||||
amo_instr[i].disable_a_extension_c.constraint_mode(0);
|
||||
`ifdef DSIM
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(amo_instr[i],
|
||||
rs1 == rs1_reg;
|
||||
rd != rs1_reg;
|
||||
instr_name inside {[AMOSWAP_W:AMOMAXU_D]};)
|
||||
`else
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(amo_instr[i],
|
||||
rs1 == rs1_reg;
|
||||
rd != rs1_reg;
|
||||
category == AMO;)
|
||||
`endif
|
||||
amo_instr[i] = riscv_instr::get_rand_instr(.include_category({AMO}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(amo_instr[i],
|
||||
if (reserved_rd.size() > 0) {
|
||||
!(rd inside {reserved_rd});
|
||||
}
|
||||
if (cfg.reserved_regs.size() > 0) {
|
||||
!(rd inside {cfg.reserved_regs});
|
||||
}
|
||||
rs1 == rs1_reg;
|
||||
rd != rs1_reg;
|
||||
)
|
||||
instr_list.push_front(amo_instr[i]);
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
endclass : riscv_amo_instr_stream
|
||||
|
|
231
vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
vendored
231
vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
vendored
|
@ -29,8 +29,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// User mode programs
|
||||
riscv_instr_sequence main_program;
|
||||
riscv_instr_sequence sub_program[];
|
||||
riscv_instr_sequence debug_program;
|
||||
riscv_instr_sequence debug_sub_program[];
|
||||
riscv_asm_program_gen debug_rom;
|
||||
// Kernel programs
|
||||
// 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
|
||||
|
@ -110,9 +109,9 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Privileged mode switch routine
|
||||
gen_privileged_mode_switch_routine();
|
||||
// Generate debug rom section
|
||||
gen_debug_rom();
|
||||
// Generate debug mode exception handler
|
||||
gen_debug_exception_handler();
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
gen_debug_rom();
|
||||
end
|
||||
end
|
||||
// Starting point of data section
|
||||
gen_data_page_begin();
|
||||
|
@ -340,7 +339,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
init_floating_point_gpr();
|
||||
end
|
||||
core_is_initialized();
|
||||
gen_dummy_csr_write();
|
||||
gen_dummy_csr_write(); // TODO add a way to disable xStatus read
|
||||
endfunction
|
||||
|
||||
// Setup MISA based on supported extensions
|
||||
|
@ -522,7 +521,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
string instr[$];
|
||||
string csr_handshake[$];
|
||||
string ret_instr;
|
||||
if(riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
|
||||
if(riscv_instr_pkg::supported_privileged_mode[i] != cfg.init_privileged_mode) continue;
|
||||
`uvm_info(`gfn, $sformatf("Generating privileged mode routing for %0s",
|
||||
riscv_instr_pkg::supported_privileged_mode[i].name()), UVM_LOW)
|
||||
// Enter privileged mode
|
||||
|
@ -668,8 +667,9 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
SUPERVISOR_MODE:
|
||||
gen_trap_handler_section("s", SCAUSE, STVEC, STVAL, SEPC, SSCRATCH, SSTATUS, SIE, SIP);
|
||||
USER_MODE:
|
||||
if(riscv_instr_pkg::support_umode_trap)
|
||||
if(riscv_instr_pkg::support_umode_trap) begin
|
||||
gen_trap_handler_section("u", UCAUSE, UTVEC, UTVAL, UEPC, USCRATCH, USTATUS, UIE, UIP);
|
||||
end
|
||||
endcase
|
||||
end
|
||||
// Ebreak handler
|
||||
|
@ -963,7 +963,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
privileged_reg_t status, ip, ie, scratch;
|
||||
string interrupt_handler_instr[$];
|
||||
ls_unit = (XLEN == 32) ? "w" : "d";
|
||||
if(mode < cfg.init_privileged_mode) return;
|
||||
if (mode < cfg.init_privileged_mode) return;
|
||||
if (mode == USER_MODE && !riscv_instr_pkg::support_umode_trap) return;
|
||||
case(mode)
|
||||
MACHINE_MODE: begin
|
||||
mode_prefix = "m";
|
||||
|
@ -1039,11 +1040,16 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
|
||||
// Dump performance CSRs if applicable
|
||||
virtual function void dump_perf_stats();
|
||||
string perf_stats[$];
|
||||
foreach(implemented_csr[i]) begin
|
||||
if (implemented_csr[i] inside {[MCYCLE:MHPMCOUNTER31H]}) begin
|
||||
gen_signature_handshake(.instr(instr_stream), .signature_type(WRITE_CSR), .csr(implemented_csr[i]));
|
||||
gen_signature_handshake(.instr(perf_stats),
|
||||
.signature_type(WRITE_CSR),
|
||||
.csr(implemented_csr[i]));
|
||||
end
|
||||
end
|
||||
format_section(perf_stats);
|
||||
instr_stream = {instr_stream, perf_stats};
|
||||
endfunction
|
||||
|
||||
// Write the generated program to a file
|
||||
|
@ -1215,208 +1221,15 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
endfunction
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// Generate the debug rom, and any related programs
|
||||
// TODO - refactor such that debug_rom is generated by a separate class
|
||||
// Generate the debug ROM, and any related programs
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
// Generate the program in the debug ROM
|
||||
// Processor will fetch instruction from here upon receiving debug request from debug module
|
||||
virtual function void gen_debug_rom();
|
||||
string instr[$];
|
||||
string debug_end[$];
|
||||
string dret;
|
||||
string debug_sub_program_name[$] = {};
|
||||
string str[$];
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
dret = {format_string(" ", LABEL_STR_LEN), "dret"};
|
||||
// The main debug rom
|
||||
if (!cfg.gen_debug_section) begin
|
||||
// If the debug section should not be generated, we just populate it
|
||||
// with a dret instruction.
|
||||
instr = {dret};
|
||||
gen_section("debug_rom", instr);
|
||||
end else begin
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
// As execution of ebreak in D mode causes core to
|
||||
// re-enter D mode, this directed sequence will be a loop that ensures the
|
||||
// ebreak instruction will only be executed once to prevent infinitely
|
||||
// looping back to the beginning of the debug rom.
|
||||
// Write dscratch to random GPR and branch to debug_end if greater
|
||||
// than 0, for ebreak loops.
|
||||
// Use dscratch1 to store original GPR value.
|
||||
str = {$sformatf("csrw 0x%0x, x%0d", DSCRATCH1, cfg.scratch_reg),
|
||||
$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH0),
|
||||
$sformatf("beq x%0d, x0, 1f", cfg.scratch_reg),
|
||||
$sformatf("j debug_end"),
|
||||
$sformatf("1: csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
|
||||
instr = {instr, str};
|
||||
end
|
||||
// Need to save off GPRs to avoid modifying program flow
|
||||
push_gpr_to_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
// Signal that the core entered debug rom only if the rom is actually
|
||||
// being filled with random instructions to prevent stress tests from
|
||||
// having to execute unnecessary push/pop of GPRs on the stack ever
|
||||
// time a debug request is sent
|
||||
gen_signature_handshake(instr, CORE_STATUS, IN_DEBUG_MODE);
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
// send dpc and dcsr to testbench, as this handshake will be
|
||||
// executed twice due to the ebreak loop, there should be no change
|
||||
// in their values as by the Debug Mode Spec Ch. 4.1.8
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(DCSR));
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(DPC));
|
||||
end
|
||||
if (cfg.set_dcsr_ebreak) begin
|
||||
// We want to set dcsr.ebreak(m/s/u) to 1'b1, depending on what modes
|
||||
// are available.
|
||||
// TODO(udinator) - randomize the dcsr.ebreak setup
|
||||
gen_dcsr_ebreak(instr);
|
||||
end
|
||||
if (cfg.enable_debug_single_step) begin
|
||||
// To enable debug single stepping, we must set dcsr.step to 1.
|
||||
// We will repeat the debug single stepping process a random number
|
||||
// of times, using a dscratch CSR as the counter, and decrement
|
||||
// this counter by 1 every time we enter debug mode, until this
|
||||
// counter reaches 0, at which point we set dcsr.step to 0 until
|
||||
// the next debug stimulus is asserted.
|
||||
|
||||
// Store our designated scratch_reg to dscratch1
|
||||
str = {$sformatf("csrw 0x%0x, x%0d", DSCRATCH1, cfg.scratch_reg),
|
||||
// Only un-set dcsr.step if it is 1 and the iterations counter
|
||||
// is at 0 (has finished iterating)
|
||||
$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DCSR),
|
||||
$sformatf("andi x%0d, x%0d, 4", cfg.scratch_reg, cfg.scratch_reg),
|
||||
// If dcsr.step is 0, set to 1 and set the counter
|
||||
$sformatf("beqz x%0d, 1f", cfg.scratch_reg),
|
||||
$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH0),
|
||||
// if the counter is greater than 0, decrement and continue single stepping
|
||||
$sformatf("bgtz x%0d, 2f", cfg.scratch_reg),
|
||||
$sformatf("csrc 0x%0x, 0x4", DCSR),
|
||||
$sformatf("beqz x0, 3f"),
|
||||
// Set dcsr.step and the num_iterations counter
|
||||
$sformatf("1: csrs 0x%0x, 0x4", DCSR),
|
||||
$sformatf("li x%0d, %0d", cfg.scratch_reg, cfg.single_step_iterations),
|
||||
$sformatf("csrw 0x%0x, x%0d", DSCRATCH0, cfg.scratch_reg),
|
||||
$sformatf("beqz x0, 3f"),
|
||||
// Decrement dscratch counter
|
||||
$sformatf("2: csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH0),
|
||||
$sformatf("addi x%0d, x%0d, -1", cfg.scratch_reg, cfg.scratch_reg),
|
||||
$sformatf("csrw 0x%0x, x%0d", DSCRATCH0, cfg.scratch_reg),
|
||||
// Restore scratch_reg value from dscratch1
|
||||
$sformatf("3: csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)
|
||||
};
|
||||
instr = {instr, str};
|
||||
// write dpc to testbench
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(DPC));
|
||||
// write out the counter to the testbench
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(DSCRATCH0));
|
||||
end
|
||||
// Check dcsr.cause, and update dpc by 0x4 if the cause is ebreak, as
|
||||
// ebreak will set set dpc to its own address, which will cause an
|
||||
// infinite loop.
|
||||
str = {$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DCSR),
|
||||
$sformatf("slli x%0d, x%0d, 0x17", cfg.scratch_reg, cfg.scratch_reg),
|
||||
$sformatf("srli x%0d, x%0d, 0x1d", cfg.scratch_reg, cfg.scratch_reg),
|
||||
$sformatf("li x%0d, 0x1", cfg.gpr[0]),
|
||||
$sformatf("bne x%0d, x%0d, 4f", cfg.scratch_reg, cfg.gpr[0])};
|
||||
instr = {instr, str};
|
||||
increment_csr(DPC, 4, instr);
|
||||
str = {"4: nop"};
|
||||
instr = {instr, str};
|
||||
// write DCSR to the testbench for any analysis
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(DCSR));
|
||||
// Increment dscratch0 by 1 to update the loop counter for all ebreak
|
||||
// tests
|
||||
if (cfg.enable_ebreak_in_debug_rom || cfg.set_dcsr_ebreak) begin
|
||||
// Add 1 to dscratch0
|
||||
increment_csr(DSCRATCH0, 1, instr);
|
||||
str = {$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
|
||||
instr = {instr, str};
|
||||
end
|
||||
format_section(instr);
|
||||
gen_sub_program(debug_sub_program, debug_sub_program_name,
|
||||
cfg.num_debug_sub_program, 1'b1, "debug_sub");
|
||||
debug_program = riscv_instr_sequence::type_id::create("debug_program");
|
||||
debug_program.instr_cnt = cfg.debug_program_instr_cnt;
|
||||
debug_program.is_debug_program = 1;
|
||||
debug_program.cfg = cfg;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(debug_program)
|
||||
debug_program.gen_instr(.is_main_program(1'b1), .no_branch(cfg.no_branch_jump));
|
||||
gen_callstack(debug_program, debug_sub_program, debug_sub_program_name,
|
||||
cfg.num_debug_sub_program);
|
||||
debug_program.post_process_instr();
|
||||
debug_program.generate_instr_stream(.no_label(1'b1));
|
||||
insert_sub_program(debug_sub_program, instr_stream);
|
||||
instr = {instr, debug_program.instr_string_list};
|
||||
gen_section("debug_rom", instr);
|
||||
// Set dscratch0 back to 0x0 to prepare for the next entry into debug
|
||||
// mode, and write dscratch0 and dcsr to the testbench for any
|
||||
// analysis
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
// send dpc and dcsr to testbench, as this handshake will be
|
||||
// executed twice due to the ebreak loop, there should be no change
|
||||
// in their values as by the Debug Mode Spec Ch. 4.1.8
|
||||
gen_signature_handshake(.instr(debug_end), .signature_type(WRITE_CSR), .csr(DCSR));
|
||||
gen_signature_handshake(.instr(debug_end), .signature_type(WRITE_CSR), .csr(DPC));
|
||||
str = {$sformatf("csrwi 0x%0x, 0x0", DSCRATCH0)};
|
||||
debug_end = {debug_end, str};
|
||||
end
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv,
|
||||
cfg.sp, cfg.tp, debug_end);
|
||||
// We have been using dscratch1 to store the
|
||||
// value of our given scratch register for use in ebreak loop, so we
|
||||
// need to restore its value before returning from D mode
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
str = {$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
|
||||
debug_end = {debug_end, str};
|
||||
end
|
||||
format_section(debug_end);
|
||||
debug_end = {debug_end, dret};
|
||||
gen_section("debug_end", debug_end);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Generate exception handling routine for debug ROM
|
||||
virtual function void gen_debug_exception_handler();
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
string instr[];
|
||||
instr = {"dret"};
|
||||
gen_section("debug_exception", instr);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Set dcsr.ebreak(m/s/u)
|
||||
// TODO(udinator) - randomize the setup for these fields
|
||||
virtual function void gen_dcsr_ebreak(ref string instr[$]);
|
||||
string str;
|
||||
if (MACHINE_MODE inside {riscv_instr_pkg::supported_privileged_mode}) begin
|
||||
str = $sformatf("li x%0d, 0x8000", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("csrs dcsr, x%0d", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
end
|
||||
if (SUPERVISOR_MODE inside {riscv_instr_pkg::supported_privileged_mode}) begin
|
||||
str = $sformatf("li x%0d, 0x2000", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("csrs dcsr, x%0d", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
end
|
||||
if (USER_MODE inside {riscv_instr_pkg::supported_privileged_mode}) begin
|
||||
str = $sformatf("li x%0d, 0x1000", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("csrs dcsr, x%0d", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void increment_csr(privileged_reg_t csr, int val, ref string instr[$]);
|
||||
string str;
|
||||
str = $sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, csr);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("addi x%0d, x%0d, 0x%0x", cfg.scratch_reg, cfg.scratch_reg, val);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("csrw 0x%0x, x%0d", csr, cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
`uvm_info(`gfn, "Creating debug ROM", UVM_LOW)
|
||||
debug_rom = riscv_asm_program_gen::type_id::create("debug_rom", , {"uvm_test_top", ".", `gfn});
|
||||
debug_rom.cfg = cfg;
|
||||
debug_rom.gen_program();
|
||||
instr_stream = {instr_stream, debug_rom.instr_stream};
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
247
vendor/google_riscv-dv/src/riscv_debug_rom_gen.sv
vendored
Normal file
247
vendor/google_riscv-dv/src/riscv_debug_rom_gen.sv
vendored
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// RISC-V debug ROM class
|
||||
//
|
||||
// This is the main class to generate a test debug ROM, which includes control knobs to
|
||||
// toggle various configuration fields of DCSR.
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
class riscv_debug_rom_gen extends riscv_asm_program_gen;
|
||||
|
||||
string debug_main[$];
|
||||
string debug_end[$];
|
||||
string str[$];
|
||||
string dret;
|
||||
|
||||
`uvm_object_utils(riscv_debug_rom_gen)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
dret = "dret";
|
||||
endfunction
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Main function to generate whole debug ROM
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
virtual function void gen_program();
|
||||
string sub_program_name[$] = {};
|
||||
if (!cfg.gen_debug_section) begin
|
||||
// If the debug section should not be generated, we just populate it
|
||||
// with a dret instruction.
|
||||
debug_main = {dret};
|
||||
gen_section("debug_rom", debug_main);
|
||||
end else begin
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
gen_ebreak_header();
|
||||
end
|
||||
// Need to save off GPRs to avoid modifying program flow
|
||||
push_gpr_to_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, debug_main);
|
||||
// Signal that the core entered debug rom only if the rom is actually
|
||||
// being filled with random instructions to prevent stress tests from
|
||||
// having to execute unnecessary push/pop of GPRs on the stack ever
|
||||
// time a debug request is sent
|
||||
gen_signature_handshake(debug_main, CORE_STATUS, IN_DEBUG_MODE);
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
// send dpc and dcsr to testbench, as this handshake will be
|
||||
// executed twice due to the ebreak loop, there should be no change
|
||||
// in their values as by the Debug Mode Spec Ch. 4.1.8
|
||||
gen_signature_handshake(.instr(debug_main), .signature_type(WRITE_CSR), .csr(DCSR));
|
||||
gen_signature_handshake(.instr(debug_main), .signature_type(WRITE_CSR), .csr(DPC));
|
||||
end
|
||||
if (cfg.set_dcsr_ebreak) begin
|
||||
// We want to set dcsr.ebreak(m/s/u) to 1'b1, depending on what modes
|
||||
// are available.
|
||||
// TODO(udinator) - randomize the dcsr.ebreak setup
|
||||
gen_dcsr_ebreak();
|
||||
end
|
||||
if (cfg.enable_debug_single_step) begin
|
||||
gen_single_step_logic();
|
||||
end
|
||||
gen_dpc_update();
|
||||
// write DCSR to the testbench for any analysis
|
||||
gen_signature_handshake(.instr(debug_main), .signature_type(WRITE_CSR), .csr(DCSR));
|
||||
if (cfg.enable_ebreak_in_debug_rom || cfg.set_dcsr_ebreak) begin
|
||||
gen_increment_ebreak_counter();
|
||||
end
|
||||
format_section(debug_main);
|
||||
gen_sub_program(sub_program, sub_program_name,
|
||||
cfg.num_debug_sub_program, 1'b1, "debug_sub");
|
||||
main_program = riscv_instr_sequence::type_id::create("debug_program");
|
||||
main_program.instr_cnt = cfg.debug_program_instr_cnt;
|
||||
main_program.is_debug_program = 1;
|
||||
main_program.cfg = cfg;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(main_program)
|
||||
main_program.gen_instr(.is_main_program(1'b1), .no_branch(cfg.no_branch_jump));
|
||||
gen_callstack(main_program, sub_program, sub_program_name,
|
||||
cfg.num_debug_sub_program);
|
||||
main_program.post_process_instr();
|
||||
main_program.generate_instr_stream(.no_label(1'b1));
|
||||
insert_sub_program(sub_program, debug_main);
|
||||
debug_main = {debug_main, main_program.instr_string_list};
|
||||
gen_section("debug_rom", debug_main);
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
gen_ebreak_footer();
|
||||
end
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv,
|
||||
cfg.sp, cfg.tp, debug_end);
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
gen_restore_ebreak_scratch_reg();
|
||||
end
|
||||
//format_section(debug_end);
|
||||
debug_end = {debug_end, dret};
|
||||
gen_section("debug_end", debug_end);
|
||||
end
|
||||
gen_debug_exception_handler();
|
||||
endfunction
|
||||
|
||||
// Generate exception handling routine for debug ROM
|
||||
// TODO(udinator) - remains empty for now, only a DRET
|
||||
virtual function void gen_debug_exception_handler();
|
||||
str = {"dret"};
|
||||
gen_section("debug_exception", str);
|
||||
endfunction
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Helper functions to generate smaller sections of code
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
// As execution of ebreak in D mode causes core to re-enter D mode, this directed
|
||||
// sequence will be a loop that ensures the ebreak instruction will only be executed
|
||||
// once to prevent infinitely looping back to the beginning of the debug rom.
|
||||
// Write dscratch to random GPR and branch to debug_end if greater than 0, for ebreak loops.
|
||||
// Use dscratch1 to store original GPR value.
|
||||
virtual function void gen_ebreak_header();
|
||||
str = {$sformatf("csrw 0x%0x, x%0d", DSCRATCH1, cfg.scratch_reg),
|
||||
$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH0),
|
||||
$sformatf("beq x%0d, x0, 1f", cfg.scratch_reg),
|
||||
$sformatf("j debug_end"),
|
||||
$sformatf("1: csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
|
||||
debug_main = {debug_main, str};
|
||||
endfunction
|
||||
|
||||
// Set dscratch0 back to 0x0 to prepare for the next entry into debug
|
||||
// mode, and write dscratch0 and dcsr to the testbench for any
|
||||
// analysis
|
||||
virtual function void gen_ebreak_footer();
|
||||
// send dpc and dcsr to testbench, as this handshake will be
|
||||
// executed twice due to the ebreak loop, there should be no change
|
||||
// in their values as by the Debug Mode Spec Ch. 4.1.8
|
||||
gen_signature_handshake(.instr(debug_end), .signature_type(WRITE_CSR), .csr(DCSR));
|
||||
gen_signature_handshake(.instr(debug_end), .signature_type(WRITE_CSR), .csr(DPC));
|
||||
str = {$sformatf("csrwi 0x%0x, 0x0", DSCRATCH0)};
|
||||
debug_end = {debug_end, str};
|
||||
endfunction
|
||||
|
||||
// Increment dscratch0 by 1 to update the loop counter for all ebreak tests
|
||||
virtual function void gen_increment_ebreak_counter();
|
||||
// Add 1 to dscratch0
|
||||
increment_csr(DSCRATCH0, 1, debug_main);
|
||||
str = {$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
|
||||
debug_main = {debug_main, str};
|
||||
endfunction
|
||||
|
||||
// We have been using dscratch1 to store the
|
||||
// value of our given scratch register for use in ebreak loop, so we
|
||||
// need to restore its value before returning from D mode
|
||||
virtual function void gen_restore_ebreak_scratch_reg();
|
||||
str = {$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
|
||||
debug_end = {debug_end, str};
|
||||
endfunction
|
||||
|
||||
// To enable debug single stepping, we must set dcsr.step to 1.
|
||||
// We will repeat the debug single stepping process a random number of times,
|
||||
// using a dscratch CSR as the counter, and decrement this counter by 1 every time we
|
||||
// enter debug mode, until this counter reaches 0, at which point we set
|
||||
// dcsr.step to 0 until the next debug stimulus is asserted.
|
||||
// Store our designated scratch_reg to dscratch1
|
||||
virtual function void gen_single_step_logic();
|
||||
str = {$sformatf("csrw 0x%0x, x%0d", DSCRATCH1, cfg.scratch_reg),
|
||||
// Only un-set dcsr.step if it is 1 and the iterations counter
|
||||
// is at 0 (has finished iterating)
|
||||
$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DCSR),
|
||||
$sformatf("andi x%0d, x%0d, 4", cfg.scratch_reg, cfg.scratch_reg),
|
||||
// If dcsr.step is 0, set to 1 and set the counter
|
||||
$sformatf("beqz x%0d, 1f", cfg.scratch_reg),
|
||||
$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH0),
|
||||
// if the counter is greater than 0, decrement and continue single stepping
|
||||
$sformatf("bgtz x%0d, 2f", cfg.scratch_reg),
|
||||
$sformatf("csrc 0x%0x, 0x4", DCSR),
|
||||
$sformatf("beqz x0, 3f"),
|
||||
// Set dcsr.step and the num_iterations counter
|
||||
$sformatf("1: csrs 0x%0x, 0x4", DCSR),
|
||||
$sformatf("li x%0d, %0d", cfg.scratch_reg, cfg.single_step_iterations),
|
||||
$sformatf("csrw 0x%0x, x%0d", DSCRATCH0, cfg.scratch_reg),
|
||||
$sformatf("beqz x0, 3f"),
|
||||
// Decrement dscratch counter
|
||||
$sformatf("2: csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH0),
|
||||
$sformatf("addi x%0d, x%0d, -1", cfg.scratch_reg, cfg.scratch_reg),
|
||||
$sformatf("csrw 0x%0x, x%0d", DSCRATCH0, cfg.scratch_reg),
|
||||
// Restore scratch_reg value from dscratch1
|
||||
$sformatf("3: csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)
|
||||
};
|
||||
debug_main = {debug_main, str};
|
||||
// write dpc to testbench
|
||||
gen_signature_handshake(.instr(debug_main), .signature_type(WRITE_CSR), .csr(DPC));
|
||||
// write out the counter to the testbench
|
||||
gen_signature_handshake(.instr(debug_main), .signature_type(WRITE_CSR), .csr(DSCRATCH0));
|
||||
endfunction
|
||||
|
||||
// Check dcsr.cause, and update dpc by 0x4 if the cause is ebreak, as
|
||||
// ebreak will set set dpc to its own address, which will cause an
|
||||
// infinite loop.
|
||||
virtual function void gen_dpc_update();
|
||||
str = {$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DCSR),
|
||||
$sformatf("slli x%0d, x%0d, 0x17", cfg.scratch_reg, cfg.scratch_reg),
|
||||
$sformatf("srli x%0d, x%0d, 0x1d", cfg.scratch_reg, cfg.scratch_reg),
|
||||
$sformatf("li x%0d, 0x1", cfg.gpr[0]),
|
||||
$sformatf("bne x%0d, x%0d, 4f", cfg.scratch_reg, cfg.gpr[0])};
|
||||
debug_main = {debug_main, str};
|
||||
increment_csr(DPC, 4, debug_main);
|
||||
str = {"4: nop"};
|
||||
debug_main = {debug_main, str};
|
||||
endfunction
|
||||
|
||||
// Set dcsr.ebreak(m/s/u)
|
||||
// TODO(udinator) - randomize the setup for these fields
|
||||
virtual function void gen_dcsr_ebreak();
|
||||
if (MACHINE_MODE inside {riscv_instr_pkg::supported_privileged_mode}) begin
|
||||
str = {$sformatf("li x%0d, 0x8000", cfg.scratch_reg),
|
||||
$sformatf("csrs dcsr, x%0d", cfg.scratch_reg)};
|
||||
debug_main = {debug_main, str};
|
||||
end
|
||||
if (SUPERVISOR_MODE inside {riscv_instr_pkg::supported_privileged_mode}) begin
|
||||
str = {$sformatf("li x%0d, 0x2000", cfg.scratch_reg),
|
||||
$sformatf("csrs dcsr, x%0d", cfg.scratch_reg)};
|
||||
debug_main = {debug_main, str};
|
||||
end
|
||||
if (USER_MODE inside {riscv_instr_pkg::supported_privileged_mode}) begin
|
||||
str = {$sformatf("li x%0d, 0x1000", cfg.scratch_reg),
|
||||
$sformatf("csrs dcsr, x%0d", cfg.scratch_reg)};
|
||||
debug_main = {debug_main, str};
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void increment_csr(privileged_reg_t csr, int val, ref string instr[$]);
|
||||
str = {$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, csr),
|
||||
$sformatf("addi x%0d, x%0d, 0x%0x", cfg.scratch_reg, cfg.scratch_reg, val),
|
||||
$sformatf("csrw 0x%0x, x%0d", csr, cfg.scratch_reg)};
|
||||
instr = {instr, str};
|
||||
endfunction
|
||||
|
||||
endclass
|
44
vendor/google_riscv-dv/src/riscv_defines.svh
vendored
44
vendor/google_riscv-dv/src/riscv_defines.svh
vendored
|
@ -33,3 +33,47 @@
|
|||
} \
|
||||
}
|
||||
|
||||
`define INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
|
||||
static bit valid = riscv_instr::register(instr_n); \
|
||||
`uvm_object_utils(riscv_``instr_n``_instr) \
|
||||
function new(string name = ""); \
|
||||
super.new(name); \
|
||||
this.instr_name = ``instr_n; \
|
||||
this.format = ``instr_format; \
|
||||
this.group = ``instr_group; \
|
||||
this.category = ``instr_category; \
|
||||
this.imm_type = ``imm_tp; \
|
||||
set_imm_len(); \
|
||||
set_rand_mode(); \
|
||||
endfunction \
|
||||
endclass
|
||||
|
||||
// Regular integer instruction
|
||||
`define DEFINE_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
|
||||
class riscv_``instr_n``_instr extends riscv_instr; \
|
||||
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
|
||||
|
||||
// Floating point instruction
|
||||
`define DEFINE_FP_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
|
||||
class riscv_``instr_n``_instr extends riscv_floating_point_instr; \
|
||||
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
|
||||
|
||||
// A-extension instruction
|
||||
`define DEFINE_AMO_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
|
||||
class riscv_``instr_n``_instr extends riscv_amo_instr; \
|
||||
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
|
||||
|
||||
// Compressed instruction
|
||||
`define DEFINE_C_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
|
||||
class riscv_``instr_n``_instr extends riscv_compressed_instr; \
|
||||
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
|
||||
|
||||
// Floating point compressed instruction
|
||||
`define DEFINE_FC_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
|
||||
class riscv_``instr_n``_instr extends riscv_compressed_instr; \
|
||||
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
|
||||
|
||||
// Vector instruction
|
||||
`define DEFINE_V_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
|
||||
class riscv_``instr_n``_instr extends riscv_vector_instr; \
|
||||
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
|
||||
|
|
|
@ -74,10 +74,10 @@ class riscv_mem_access_stream extends riscv_directed_instr_stream;
|
|||
|
||||
// Insert some other instructions to mix with mem_access instruction
|
||||
virtual function void add_mixed_instr(int instr_cnt);
|
||||
riscv_instr_base instr;
|
||||
riscv_instr instr;
|
||||
setup_allowed_instr(1, 1);
|
||||
for(int i = 0; i < instr_cnt; i ++) begin
|
||||
instr = riscv_instr_base::type_id::create("instr");
|
||||
instr = riscv_instr::type_id::create("instr");
|
||||
randomize_instr(instr);
|
||||
insert_instr(instr);
|
||||
end
|
||||
|
@ -92,15 +92,15 @@ endclass
|
|||
// For JAL, restore the stack before doing the jump
|
||||
class riscv_jump_instr extends riscv_directed_instr_stream;
|
||||
|
||||
riscv_instr_base jump;
|
||||
riscv_instr_base addi;
|
||||
riscv_instr jump;
|
||||
riscv_instr addi;
|
||||
riscv_pseudo_instr la;
|
||||
riscv_instr_base branch;
|
||||
riscv_instr branch;
|
||||
rand riscv_reg_t gpr;
|
||||
rand int imm;
|
||||
rand bit enable_branch;
|
||||
rand int mixed_instr_cnt;
|
||||
riscv_instr_base stack_exit_instr[];
|
||||
riscv_instr stack_exit_instr[];
|
||||
string target_program_label;
|
||||
int idx;
|
||||
bit use_jalr;
|
||||
|
@ -115,30 +115,32 @@ class riscv_jump_instr extends riscv_directed_instr_stream;
|
|||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
jump = riscv_instr_base::type_id::create("jump");
|
||||
la = riscv_pseudo_instr::type_id::create("la");
|
||||
addi = riscv_instr_base::type_id::create("addi");
|
||||
branch = riscv_instr_base::type_id::create("branch");
|
||||
endfunction
|
||||
|
||||
function void pre_randomize();
|
||||
if (use_jalr) begin
|
||||
jump = riscv_instr::get_rand_instr(.include_instr({JALR}));
|
||||
end else if (cfg.disable_compressed_instr || (cfg.ra != RA)) begin
|
||||
jump = riscv_instr::get_rand_instr(.include_instr({JAL, JALR}));
|
||||
end else begin
|
||||
jump = riscv_instr::get_rand_instr(.include_instr({JAL, JALR, C_JALR}));
|
||||
end
|
||||
addi = riscv_instr::get_rand_instr(.include_instr({ADDI}));
|
||||
branch = riscv_instr::get_rand_instr(.include_instr({BEQ, BNE, BLT, BGE, BLTU, BGEU}));
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
riscv_instr_base instr[];
|
||||
riscv_instr instr[];
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(jump,
|
||||
(use_jalr) -> (instr_name == JALR);
|
||||
instr_name dist {JAL := 2, JALR := 6, C_JALR := 2};
|
||||
if (cfg.disable_compressed_instr || (cfg.ra != RA)) {
|
||||
instr_name != C_JALR;
|
||||
if (has_rd) {
|
||||
rd == cfg.ra;
|
||||
}
|
||||
rd == cfg.ra;
|
||||
rs1 == gpr;
|
||||
)
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(addi,
|
||||
rs1 == gpr;
|
||||
instr_name == ADDI;
|
||||
rd == gpr;
|
||||
)
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(branch,
|
||||
instr_name inside {BEQ, BNE, BLT, BGE, BLTU, BGEU};)
|
||||
if (has_rs1) {
|
||||
rs1 == gpr;
|
||||
})
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(addi, rs1 == gpr; rd == gpr;)
|
||||
`DV_CHECK_RANDOMIZE_FATAL(branch)
|
||||
la.pseudo_instr_name = LA;
|
||||
la.imm_str = target_program_label;
|
||||
la.rd = gpr;
|
||||
|
@ -180,9 +182,9 @@ 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;
|
||||
riscv_instr jump[];
|
||||
riscv_instr jump_start;
|
||||
riscv_instr jump_end;
|
||||
rand int unsigned num_of_jump_instr;
|
||||
riscv_instr_name_t jal[$];
|
||||
|
||||
|
@ -213,23 +215,20 @@ class riscv_jal_instr extends riscv_rand_instr_stream;
|
|||
end
|
||||
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 = riscv_instr::get_rand_instr(.include_instr({JAL}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(jump_start, 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));
|
||||
jump[i] = riscv_instr::get_rand_instr(.include_instr({jal}));
|
||||
`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});
|
||||
if (has_rd) {
|
||||
rd dist {RA := 5, T1 := 2, [SP:T0] :/ 1, [T2:T6] :/ 2};
|
||||
!(rd inside {cfg.reserved_regs});
|
||||
}
|
||||
)
|
||||
jump[i].label = $sformatf("%0d", i);
|
||||
end
|
||||
|
@ -258,9 +257,9 @@ class riscv_push_stack_instr extends riscv_rand_instr_stream;
|
|||
int stack_len;
|
||||
int num_of_reg_to_save;
|
||||
int num_of_redudant_instr;
|
||||
riscv_instr_base push_stack_instr[];
|
||||
riscv_instr push_stack_instr[];
|
||||
riscv_reg_t saved_regs[];
|
||||
rand riscv_rand_instr branch_instr;
|
||||
riscv_instr branch_instr;
|
||||
rand bit enable_branch;
|
||||
string push_start_label;
|
||||
|
||||
|
@ -289,19 +288,22 @@ class riscv_push_stack_instr extends riscv_rand_instr_stream;
|
|||
gen_instr(1'b1);
|
||||
push_stack_instr = new[num_of_reg_to_save+1];
|
||||
foreach(push_stack_instr[i]) begin
|
||||
push_stack_instr[i] = riscv_instr_base::type_id::
|
||||
create($sformatf("push_stack_instr_%0d", i));
|
||||
push_stack_instr[i] = riscv_instr::type_id::
|
||||
create($sformatf("push_stack_instr_%0d", i));
|
||||
end
|
||||
// addi sp,sp,-imm
|
||||
push_stack_instr[0] = riscv_instr::get_rand_instr(.include_instr({ADDI}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[0],
|
||||
instr_name == ADDI; rd == cfg.sp; rs1 == cfg.sp;
|
||||
rd == cfg.sp; rs1 == cfg.sp;
|
||||
imm == (~stack_len + 1);)
|
||||
push_stack_instr[0].imm_str = $sformatf("-%0d", stack_len);
|
||||
foreach(saved_regs[i]) begin
|
||||
if(XLEN == 32) begin
|
||||
push_stack_instr[i+1] = riscv_instr::get_rand_instr(.include_instr({SW}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[i+1],
|
||||
instr_name == SW; rs2 == saved_regs[i]; rs1 == cfg.sp; imm == 4 * (i+1);)
|
||||
rs2 == saved_regs[i]; rs1 == cfg.sp; imm == 4 * (i+1);)
|
||||
end else begin
|
||||
push_stack_instr[i+1] = riscv_instr::get_rand_instr(.include_instr({SD}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(push_stack_instr[i+1],
|
||||
instr_name == SD; rs2 == saved_regs[i]; rs1 == cfg.sp; imm == 8 * (i+1);)
|
||||
end
|
||||
|
@ -313,15 +315,8 @@ class riscv_push_stack_instr extends riscv_rand_instr_stream;
|
|||
enable_branch = 0;
|
||||
end
|
||||
if(enable_branch) begin
|
||||
// Cover jal -> branch scenario, the branch is added before push stack operation
|
||||
branch_instr = riscv_rand_instr::type_id::create("branch_instr");
|
||||
branch_instr.cfg = cfg;
|
||||
`ifdef DSIM
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(branch_instr,
|
||||
instr_name inside {[BEQ:BGEU], C_BEQZ, C_BNEZ};)
|
||||
`else
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(branch_instr, category == BRANCH;)
|
||||
`endif
|
||||
branch_instr = riscv_instr::get_rand_instr(.include_category({BRANCH}));
|
||||
`DV_CHECK_RANDOMIZE_FATAL(branch_instr)
|
||||
branch_instr.imm_str = push_start_label;
|
||||
branch_instr.branch_assigned = 1'b1;
|
||||
push_stack_instr[0].label = push_start_label;
|
||||
|
@ -341,11 +336,11 @@ endclass
|
|||
// Pop stack instruction stream
|
||||
class riscv_pop_stack_instr extends riscv_rand_instr_stream;
|
||||
|
||||
int stack_len;
|
||||
int num_of_reg_to_save;
|
||||
int num_of_redudant_instr;
|
||||
riscv_instr_base pop_stack_instr[];
|
||||
riscv_reg_t saved_regs[];
|
||||
int stack_len;
|
||||
int num_of_reg_to_save;
|
||||
int num_of_redudant_instr;
|
||||
riscv_instr pop_stack_instr[];
|
||||
riscv_reg_t saved_regs[];
|
||||
|
||||
`uvm_object_utils(riscv_pop_stack_instr)
|
||||
|
||||
|
@ -371,22 +366,25 @@ class riscv_pop_stack_instr extends riscv_rand_instr_stream;
|
|||
gen_instr(1'b1);
|
||||
pop_stack_instr = new[num_of_reg_to_save+1];
|
||||
foreach(pop_stack_instr[i]) begin
|
||||
pop_stack_instr[i] = riscv_instr_base::type_id::
|
||||
create($sformatf("pop_stack_instr_%0d", i));
|
||||
pop_stack_instr[i] = riscv_instr::type_id::
|
||||
create($sformatf("pop_stack_instr_%0d", i));
|
||||
end
|
||||
foreach(saved_regs[i]) begin
|
||||
if(XLEN == 32) begin
|
||||
pop_stack_instr[i] = riscv_instr::get_rand_instr(.include_instr({LW}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[i],
|
||||
instr_name == LW; rd == saved_regs[i]; rs1 == cfg.sp; imm == 4 * (i+1);)
|
||||
rd == saved_regs[i]; rs1 == cfg.sp; imm == 4 * (i+1);)
|
||||
end else begin
|
||||
pop_stack_instr[i] = riscv_instr::get_rand_instr(.include_instr({LD}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[i],
|
||||
instr_name == LD; rd == saved_regs[i]; rs1 == cfg.sp; imm == 8 * (i+1);)
|
||||
rd == saved_regs[i]; rs1 == cfg.sp; imm == 8 * (i+1);)
|
||||
end
|
||||
pop_stack_instr[i].process_load_store = 0;
|
||||
end
|
||||
// addi sp,sp,imm
|
||||
pop_stack_instr[num_of_reg_to_save] = riscv_instr::get_rand_instr(.include_instr({ADDI}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[num_of_reg_to_save],
|
||||
instr_name == ADDI; rd == cfg.sp; rs1 == cfg.sp; imm == stack_len;)
|
||||
rd == cfg.sp; rs1 == cfg.sp; imm == stack_len;)
|
||||
pop_stack_instr[num_of_reg_to_save].imm_str = $sformatf("%0d", stack_len);
|
||||
mix_instr_stream(pop_stack_instr);
|
||||
foreach(instr_list[i]) begin
|
||||
|
@ -396,136 +394,3 @@ class riscv_pop_stack_instr extends riscv_rand_instr_stream;
|
|||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Cover the long fprward and backward jump
|
||||
class riscv_long_branch_instr extends riscv_rand_instr_stream;
|
||||
|
||||
int branch_instr_stream_len = 100;
|
||||
int branch_instr_offset = 999;
|
||||
riscv_rand_instr_stream forward_branch_instr_stream;
|
||||
riscv_rand_instr_stream backward_branch_instr_stream;
|
||||
riscv_instr_base jump_instr;
|
||||
|
||||
`uvm_object_utils(riscv_long_branch_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
forward_branch_instr_stream = riscv_rand_instr_stream::type_id::
|
||||
create("forward_branch_instr_stream");
|
||||
backward_branch_instr_stream = riscv_rand_instr_stream::type_id::
|
||||
create("backward_branch_instr_stream");
|
||||
jump_instr = riscv_instr_base::type_id::create("jump_instr");
|
||||
endfunction
|
||||
|
||||
function void init(int instr_len);
|
||||
branch_instr_stream_len = instr_len;
|
||||
initialize_instr_list(branch_instr_offset-branch_instr_stream_len);
|
||||
forward_branch_instr_stream.cfg = cfg;
|
||||
backward_branch_instr_stream.cfg = cfg;
|
||||
forward_branch_instr_stream.initialize_instr_list(branch_instr_stream_len);
|
||||
backward_branch_instr_stream.initialize_instr_list(branch_instr_stream_len);
|
||||
endfunction
|
||||
|
||||
virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1,
|
||||
bit is_debug_program = 1'b0);
|
||||
int branch_offset;
|
||||
super.gen_instr(1'b1);
|
||||
forward_branch_instr_stream.gen_instr();
|
||||
backward_branch_instr_stream.gen_instr();
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(jump_instr, instr_name == JAL;)
|
||||
jump_instr.imm_str = "test_done";
|
||||
instr_list = {forward_branch_instr_stream.instr_list, instr_list,
|
||||
jump_instr, backward_branch_instr_stream.instr_list};
|
||||
foreach(instr_list[i]) begin
|
||||
instr_list[i].atomic = 1'b1;
|
||||
if(!instr_list[i].is_branch_target) begin
|
||||
instr_list[i].has_label = 1'b0;
|
||||
end
|
||||
if(instr_list[i].category == BRANCH) begin
|
||||
if(i < branch_instr_stream_len)
|
||||
branch_offset = branch_instr_offset;
|
||||
else
|
||||
branch_offset = -branch_instr_offset;
|
||||
instr_list[i].imm_str = $sformatf("target_%0d", i);
|
||||
instr_list[i].branch_assigned = 1'b1;
|
||||
// Avoid dead loop
|
||||
if(((instr_list[i+branch_offset].category == BRANCH) ||
|
||||
instr_list[i+branch_offset].is_branch_target) && (branch_offset < 0))
|
||||
branch_offset = branch_offset + 1;
|
||||
`uvm_info(get_full_name(), $sformatf("Branch [%0d] %0s -> [%0d] %0s", i,
|
||||
instr_list[i].convert2asm(), i+branch_offset,
|
||||
instr_list[i+branch_offset].convert2asm()), UVM_LOW)
|
||||
if(i < -branch_offset)
|
||||
`uvm_fatal(get_name(), $sformatf("Unexpected branch instr at %0d", i))
|
||||
instr_list[i+branch_offset].label = $sformatf("target_%0d", i);
|
||||
instr_list[i+branch_offset].has_label = 1'b1;
|
||||
instr_list[i+branch_offset].is_branch_target = 1;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
class riscv_sw_interrupt_instr extends riscv_directed_instr_stream;
|
||||
|
||||
rand bit usip;
|
||||
rand bit ssip;
|
||||
rand bit msip;
|
||||
rand privileged_reg_t ip_reg;
|
||||
rand riscv_pseudo_instr li_instr;
|
||||
rand riscv_instr_base csr_instr;
|
||||
riscv_privil_reg ip;
|
||||
rand riscv_reg_t rs1_reg;
|
||||
|
||||
constraint ip_reg_c {
|
||||
if(cfg.init_privileged_mode == MACHINE_MODE) {
|
||||
ip_reg == MIP;
|
||||
} else {
|
||||
ip_reg == SIP;
|
||||
}
|
||||
(ip_reg == MIP) -> (usip || ssip || msip);
|
||||
(ip_reg == SIP) -> (usip || ssip);
|
||||
}
|
||||
|
||||
constraint instr_c {
|
||||
!(rs1_reg inside {cfg.reserved_regs});
|
||||
rs1_reg != ZERO;
|
||||
li_instr.pseudo_instr_name == LI;
|
||||
li_instr.rd == rs1_reg;
|
||||
csr_instr.instr_name == CSRRW;
|
||||
csr_instr.rs1 == rs1_reg;
|
||||
// TODO: Support non-zero rd for SIP, MIP
|
||||
// csr_instr.rd inside {cfg.avail_regs};
|
||||
csr_instr.rd == ZERO;
|
||||
csr_instr.csr == ip_reg;
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_sw_interrupt_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
li_instr = riscv_pseudo_instr::type_id::create("li_instr");
|
||||
csr_instr = riscv_instr_base::type_id::create("csr_instr");
|
||||
ip = riscv_privil_reg::type_id::create("ip");
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
// TODO: Support UIP
|
||||
if(cfg.init_privileged_mode == USER_MODE) return;
|
||||
ip.init_reg(ip_reg);
|
||||
if(ip_reg == SIP) begin
|
||||
ip.set_field("USIP", usip);
|
||||
ip.set_field("SSIP", ssip);
|
||||
end else begin
|
||||
ip.set_field("USIP", usip);
|
||||
ip.set_field("SSIP", ssip);
|
||||
ip.set_field("MSIP", msip);
|
||||
end
|
||||
li_instr.imm_str = $sformatf("0x%0x", ip.get_val());
|
||||
csr_instr.comment = ip_reg.name();
|
||||
instr_list = {li_instr, csr_instr};
|
||||
super.post_randomize();
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
|
|
|
@ -281,6 +281,9 @@ class riscv_illegal_instr extends uvm_object;
|
|||
if (!compressed) {
|
||||
if (exception == kIllegalFunc7) {
|
||||
!(func7 inside {7'b0, 7'b0100000, 7'b1});
|
||||
if (opcode == 7'b001001) { // SLLI, SRLI, SRAI
|
||||
!(func7[6:1] inside {6'b0, 6'b010000});
|
||||
}
|
||||
} else {
|
||||
func7 inside {7'b0, 7'b0100000, 7'b1};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class riscv_instr_cov_item extends riscv_instr_base;
|
||||
class riscv_instr_cov_item extends `INSTR;
|
||||
|
||||
typedef enum bit[1:0] {
|
||||
POSITIVE, NEGATIVE
|
||||
|
@ -23,6 +23,9 @@ class riscv_instr_cov_item extends riscv_instr_base;
|
|||
rand bit [XLEN-1:0] rs1_value;
|
||||
rand bit [XLEN-1:0] rs2_value;
|
||||
rand bit [XLEN-1:0] rd_value;
|
||||
rand bit [XLEN-1:0] fs1_value;
|
||||
rand bit [XLEN-1:0] fs2_value;
|
||||
rand bit [XLEN-1:0] fd_value;
|
||||
bit [31:0] binary;
|
||||
bit [XLEN-1:0] pc;
|
||||
bit [XLEN-1:0] mem_addr;
|
||||
|
@ -46,6 +49,8 @@ class riscv_instr_cov_item extends riscv_instr_base;
|
|||
logical_similarity_e logical_similarity;
|
||||
string trace;
|
||||
|
||||
`VECTOR_INCLUDE("riscv_instr_cov_item_inc_declares.sv")
|
||||
|
||||
`uvm_object_utils(riscv_instr_cov_item)
|
||||
`uvm_object_new
|
||||
|
||||
|
|
|
@ -14,6 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
`ifndef COMPLIANCE_MODE
|
||||
`define DV(TEXT) TEXT
|
||||
`else
|
||||
`define DV(TEXT)
|
||||
`endif
|
||||
|
||||
`define SAMPLE(cg, val) \
|
||||
if (cg != null) cg.sample(val);
|
||||
|
||||
`define INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
covergroup ``INSTR_NAME``_cg with function sample(riscv_instr_cov_item instr);
|
||||
|
@ -26,7 +34,7 @@
|
|||
cp_rs1_sign : coverpoint instr.rs1_sign; \
|
||||
cp_rs2_sign : coverpoint instr.rs2_sign; \
|
||||
cp_rd_sign : coverpoint instr.rd_sign; \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard; \
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
|
||||
|
||||
`define CMP_INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
`INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
|
@ -34,7 +42,7 @@
|
|||
cp_rd : coverpoint instr.rd; \
|
||||
cp_rs1_sign : coverpoint instr.rs1_sign; \
|
||||
cp_result : coverpoint instr.rd_value[0]; \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard; \
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
|
||||
|
||||
`define SB_INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
`INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
|
@ -45,35 +53,35 @@
|
|||
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_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
`DV(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 { \
|
||||
ignore_bins zero = {ZERO}; \
|
||||
`DV(ignore_bins zero = {ZERO};) \
|
||||
} \
|
||||
cp_rs2 : coverpoint instr.rs2; \
|
||||
cp_imm_sign : coverpoint instr.imm_sign; \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
|
||||
} \
|
||||
cp_lsu_hazard : coverpoint instr.lsu_hazard { \
|
||||
}) \
|
||||
`DV(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 { \
|
||||
ignore_bins zero = {ZERO}; \
|
||||
`DV(ignore_bins zero = {ZERO};) \
|
||||
} \
|
||||
cp_rd : coverpoint instr.rd; \
|
||||
cp_imm_sign : coverpoint instr.imm_sign; \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard; \
|
||||
cp_lsu_hazard : coverpoint instr.lsu_hazard { \
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
|
||||
`DV(cp_lsu_hazard : coverpoint instr.lsu_hazard { \
|
||||
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
|
||||
}
|
||||
}) \
|
||||
|
||||
`define I_INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
`INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
|
@ -82,14 +90,13 @@
|
|||
cp_rs1_sign : coverpoint instr.rs1_sign; \
|
||||
cp_rd_sign : coverpoint instr.rd_sign; \
|
||||
cp_imm_sign : coverpoint instr.imm_sign; \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard;
|
||||
`DV(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_gpr_hazard : coverpoint instr.gpr_hazard;
|
||||
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
|
||||
|
||||
`define J_INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
`INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
|
@ -97,35 +104,34 @@
|
|||
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_rd : coverpoint instr.rd; \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard;
|
||||
`DV(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_hazard : coverpoint instr.gpr_hazard;
|
||||
`DV(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_hazard : coverpoint instr.gpr_hazard { \
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
bins valid_hazard[] = {NO_HAZARD, WAR_HAZARD, WAW_HAZARD}; \
|
||||
}
|
||||
})
|
||||
|
||||
`define CSS_INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
`INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
cp_rs2 : coverpoint instr.rs2; \
|
||||
cp_imm_sign : coverpoint instr.imm_sign; \
|
||||
cp_rs2_sign : coverpoint instr.rs2_sign; \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
|
||||
}
|
||||
})
|
||||
|
||||
`define CIW_INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
`INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
|
@ -133,9 +139,9 @@
|
|||
cp_rd : coverpoint instr.rd { \
|
||||
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
|
||||
} \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
`DV(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) \
|
||||
|
@ -145,10 +151,10 @@
|
|||
cp_rd : coverpoint instr.rd { \
|
||||
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
|
||||
} \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard; \
|
||||
cp_lsu_hazard : coverpoint instr.lsu_hazard { \
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
|
||||
`DV(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) \
|
||||
|
@ -164,12 +170,12 @@
|
|||
cp_rs2 : coverpoint instr.rs2 { \
|
||||
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
|
||||
} \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
|
||||
} \
|
||||
cp_lsu_hazard : coverpoint instr.lsu_hazard { \
|
||||
}) \
|
||||
`DV(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) \
|
||||
|
@ -185,7 +191,7 @@
|
|||
cp_rs2 : coverpoint instr.rs2 { \
|
||||
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
|
||||
} \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard;
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
|
||||
|
||||
|
||||
`define CB_INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
|
@ -193,9 +199,9 @@
|
|||
cp_rs1 : coverpoint instr.rs1 { \
|
||||
bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \
|
||||
} \
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard { \
|
||||
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD}; \
|
||||
}
|
||||
})
|
||||
|
||||
`define CJ_INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
`INSTR_CG_BEGIN(INSTR_NAME) \
|
||||
|
@ -203,6 +209,12 @@
|
|||
|
||||
`define CG_END endgroup
|
||||
|
||||
`define CG_SELECTOR_BEGIN(CG_ISA) \
|
||||
if ((CG_ISA inside {supported_isa}) && (!select_isa || (cov_isa == CG_ISA))) begin
|
||||
|
||||
`define CG_SELECTOR_END \
|
||||
end
|
||||
|
||||
class riscv_instr_cover_group;
|
||||
|
||||
riscv_instr_gen_config cfg;
|
||||
|
@ -212,6 +224,25 @@ class riscv_instr_cover_group;
|
|||
int unsigned instr_cnt;
|
||||
int unsigned branch_instr_cnt;
|
||||
bit [4:0] branch_hit_history; // The last 5 branch result
|
||||
exception_cause_t ignored_exceptions[];
|
||||
|
||||
// Mode of the coverage model
|
||||
|
||||
// In complicance mode, all the micro-architecture related covergroups are removed. Only the ones
|
||||
// related to RISC-V specification compliance is sampled.
|
||||
bit compliance_mode;
|
||||
|
||||
// By default the coverage model run with instruction trace from ISS simulation. When simulating
|
||||
// with ISS, certain covergroups like debug/interrupt could not be hit as these are not simulated
|
||||
// with ISS. You can turn off this mode by adding +iss_mode=0 if you use the instruction trace
|
||||
// from RTL simulation.
|
||||
bit iss_mode = 1'b1;
|
||||
|
||||
// Select an ISA extension to cover
|
||||
bit select_isa;
|
||||
riscv_instr_group_t cov_isa;
|
||||
|
||||
`VECTOR_INCLUDE("riscv_instr_cover_group_inc_cpu_declare.sv")
|
||||
|
||||
///////////// RV32I instruction functional coverage //////////////
|
||||
|
||||
|
@ -252,7 +283,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_hazard : coverpoint instr.gpr_hazard;
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
|
||||
`CG_END
|
||||
|
||||
`INSTR_CG_BEGIN(slli)
|
||||
|
@ -260,7 +291,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_hazard : coverpoint instr.gpr_hazard;
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
|
||||
`CG_END
|
||||
|
||||
`INSTR_CG_BEGIN(srli)
|
||||
|
@ -268,7 +299,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_hazard : coverpoint instr.gpr_hazard;
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
|
||||
`CG_END
|
||||
|
||||
// Logical instructions
|
||||
|
@ -422,7 +453,6 @@ class riscv_instr_cover_group;
|
|||
endgroup
|
||||
|
||||
// RV32M
|
||||
|
||||
`R_INSTR_CG_BEGIN(mul)
|
||||
cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign;
|
||||
`CG_END
|
||||
|
@ -546,7 +576,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_hazard : coverpoint instr.gpr_hazard;
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
|
||||
`CG_END
|
||||
|
||||
`INSTR_CG_BEGIN(slliw)
|
||||
|
@ -554,7 +584,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_hazard : coverpoint instr.gpr_hazard;
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
|
||||
`CG_END
|
||||
|
||||
`INSTR_CG_BEGIN(srliw)
|
||||
|
@ -562,7 +592,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_hazard : coverpoint instr.gpr_hazard;
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
|
||||
`CG_END
|
||||
|
||||
`R_INSTR_CG_BEGIN(addw)
|
||||
|
@ -599,9 +629,9 @@ class riscv_instr_cover_group;
|
|||
|
||||
`INSTR_CG_BEGIN(c_addi16sp)
|
||||
cp_imm_sign : coverpoint instr.imm_sign;
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard {
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard {
|
||||
bins valid_hazard[] = {NO_HAZARD, WAR_HAZARD, WAW_HAZARD};
|
||||
}
|
||||
})
|
||||
`CG_END
|
||||
|
||||
`CI_INSTR_CG_BEGIN(c_li)
|
||||
|
@ -609,7 +639,7 @@ class riscv_instr_cover_group;
|
|||
|
||||
`INSTR_CG_BEGIN(c_lui)
|
||||
cp_rd : coverpoint instr.rd {
|
||||
ignore_bins bin = {ZERO, SP};
|
||||
`DV(ignore_bins bin = {ZERO, SP};)
|
||||
}
|
||||
`CG_END
|
||||
|
||||
|
@ -651,9 +681,9 @@ class riscv_instr_cover_group;
|
|||
|
||||
`INSTR_CG_BEGIN(c_slli)
|
||||
cp_rd : coverpoint instr.rd;
|
||||
cp_gpr_hazard : coverpoint instr.gpr_hazard {
|
||||
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard {
|
||||
bins valid_hazard[] = {NO_HAZARD, RAW_HAZARD};
|
||||
}
|
||||
})
|
||||
`CG_END
|
||||
|
||||
`CJ_INSTR_CG_BEGIN(c_j)
|
||||
|
@ -664,13 +694,13 @@ class riscv_instr_cover_group;
|
|||
|
||||
`INSTR_CG_BEGIN(c_jr)
|
||||
cp_rs1 : coverpoint instr.rs1 {
|
||||
ignore_bins zero = {ZERO};
|
||||
`DV(ignore_bins zero = {ZERO};)
|
||||
}
|
||||
`CG_END
|
||||
|
||||
`INSTR_CG_BEGIN(c_jalr)
|
||||
cp_rs1 : coverpoint instr.rs1 {
|
||||
ignore_bins zero = {ZERO};
|
||||
`DV(ignore_bins zero = {ZERO};)
|
||||
}
|
||||
cp_rd_align : coverpoint instr.rd_value[1];
|
||||
`CG_END
|
||||
|
@ -783,7 +813,8 @@ class riscv_instr_cover_group;
|
|||
// Privileged CSR covergroup
|
||||
covergroup mcause_exception_cg with function sample(exception_cause_t exception);
|
||||
cp_exception: coverpoint exception {
|
||||
bins exception[] = cp_exception with (item inside {implemented_exception});
|
||||
bins exception[] = cp_exception with ((item inside {implemented_exception}) &&
|
||||
!(item inside {ignored_exceptions}));
|
||||
}
|
||||
endgroup
|
||||
|
||||
|
@ -805,65 +836,113 @@ class riscv_instr_cover_group;
|
|||
cp_mpp : coverpoint val[12:11];
|
||||
endgroup
|
||||
|
||||
`VECTOR_INCLUDE("riscv_instr_cover_group_inc_cg_add.sv")
|
||||
|
||||
function new(riscv_instr_gen_config cfg);
|
||||
string opts;
|
||||
this.cfg = cfg;
|
||||
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();
|
||||
// RV32I instruction functional coverage instantiation
|
||||
add_cg = new();
|
||||
sub_cg = new();
|
||||
addi_cg = new();
|
||||
lui_cg = new();
|
||||
auipc_cg = new();
|
||||
sll_cg = new();
|
||||
srl_cg = new();
|
||||
sra_cg = new();
|
||||
slli_cg = new();
|
||||
srli_cg = new();
|
||||
srai_cg = new();
|
||||
and_cg = new();
|
||||
or_cg = new();
|
||||
xor_cg = new();
|
||||
andi_cg = new();
|
||||
ori_cg = new();
|
||||
xori_cg = new();
|
||||
slt_cg = new();
|
||||
sltu_cg = new();
|
||||
slti_cg = new();
|
||||
sltiu_cg = new();
|
||||
jal_cg = new();
|
||||
jalr_cg = new();
|
||||
beq_cg = new();
|
||||
bne_cg = new();
|
||||
blt_cg = new();
|
||||
bge_cg = new();
|
||||
bgeu_cg = new();
|
||||
bltu_cg = new();
|
||||
lb_cg = new();
|
||||
lh_cg = new();
|
||||
lw_cg = new();
|
||||
lbu_cg = new();
|
||||
lhu_cg = new();
|
||||
sb_cg = new();
|
||||
sh_cg = new();
|
||||
sw_cg = new();
|
||||
csrrw_cg = new();
|
||||
csrrs_cg = new();
|
||||
csrrc_cg = new();
|
||||
csrrwi_cg = new();
|
||||
csrrsi_cg = new();
|
||||
csrrci_cg = new();
|
||||
// instr_trans_cg = new();
|
||||
branch_hit_history_cg = new();
|
||||
rv32i_misc_cg = new();
|
||||
if (RV32C inside {supported_isa}) begin
|
||||
illegal_compressed_instr_cg = new();
|
||||
compressed_opcode_cg = new();
|
||||
hint_cg = new();
|
||||
`ifdef COMPLIANCE_MODE
|
||||
compliance_mode = 1;
|
||||
`endif
|
||||
// process coverage options
|
||||
void'($value$plusargs("iss_mode=%0d", iss_mode));
|
||||
|
||||
if ($value$plusargs("cov_isa=%0s", opts)) begin
|
||||
if (!uvm_enum_wrapper#(riscv_instr_group_t)::from_name(opts, cov_isa)) begin
|
||||
`uvm_fatal("riscv_instr_covergroup",
|
||||
$sformatf("Cannot find enum for specifed cov_isa=%0s", opts))
|
||||
end
|
||||
select_isa = 1'b1;
|
||||
end
|
||||
opcode_cg = new();
|
||||
if (RV32M inside {supported_isa}) begin
|
||||
// TODO if we want to selectively enable/disable coverage based on categories...
|
||||
// e.g. +cov_category=OPV_CONFIG
|
||||
if ($test$plusargs("cov_category=")) begin
|
||||
string cov_category_str;
|
||||
void'($value$plusargs("cov_category=%0s", cov_category_str));
|
||||
$display("coverage option: +cov_category=%0s", cov_category_str);
|
||||
// used to further subset coverage (used by vectors)
|
||||
end
|
||||
|
||||
if ($test$plusargs("stop_on_first_error")) begin
|
||||
$display("coverage option: +stop_on_first_error");
|
||||
end
|
||||
|
||||
`VECTOR_INCLUDE("riscv_instr_cover_group_inc_cg_instantiation.sv")
|
||||
|
||||
// RV32I instruction functional coverage instantiation
|
||||
`CG_SELECTOR_BEGIN(RV32I)
|
||||
add_cg = new();
|
||||
sub_cg = new();
|
||||
addi_cg = new();
|
||||
lui_cg = new();
|
||||
auipc_cg = new();
|
||||
sll_cg = new();
|
||||
srl_cg = new();
|
||||
sra_cg = new();
|
||||
slli_cg = new();
|
||||
srli_cg = new();
|
||||
srai_cg = new();
|
||||
and_cg = new();
|
||||
or_cg = new();
|
||||
xor_cg = new();
|
||||
andi_cg = new();
|
||||
ori_cg = new();
|
||||
xori_cg = new();
|
||||
slt_cg = new();
|
||||
sltu_cg = new();
|
||||
slti_cg = new();
|
||||
sltiu_cg = new();
|
||||
jal_cg = new();
|
||||
jalr_cg = new();
|
||||
beq_cg = new();
|
||||
bne_cg = new();
|
||||
blt_cg = new();
|
||||
bge_cg = new();
|
||||
bgeu_cg = new();
|
||||
bltu_cg = new();
|
||||
lb_cg = new();
|
||||
lh_cg = new();
|
||||
lw_cg = new();
|
||||
lbu_cg = new();
|
||||
lhu_cg = new();
|
||||
sb_cg = new();
|
||||
sh_cg = new();
|
||||
sw_cg = new();
|
||||
`CG_SELECTOR_END
|
||||
|
||||
// TODO sort when there is a RV32ZICSR isa enum
|
||||
if (RV32I inside {supported_isa}) begin
|
||||
if (!compliance_mode) begin
|
||||
csrrw_cg = new();
|
||||
csrrs_cg = new();
|
||||
csrrc_cg = new();
|
||||
csrrwi_cg = new();
|
||||
csrrsi_cg = new();
|
||||
csrrci_cg = new();
|
||||
end
|
||||
end
|
||||
|
||||
if (!compliance_mode) begin
|
||||
// instr_trans_cg = new();
|
||||
branch_hit_history_cg = new();
|
||||
rv32i_misc_cg = new();
|
||||
opcode_cg = new();
|
||||
end
|
||||
|
||||
if (RV32C inside {supported_isa} || RV64C inside {supported_isa}) begin
|
||||
if (!compliance_mode) begin
|
||||
compressed_opcode_cg = new();
|
||||
hint_cg = new();
|
||||
if (!cfg.disable_compressed_instr) begin
|
||||
illegal_compressed_instr_cg = new();
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
`CG_SELECTOR_BEGIN(RV32M)
|
||||
mul_cg = new();
|
||||
mulh_cg = new();
|
||||
mulhsu_cg = new();
|
||||
|
@ -872,15 +951,17 @@ class riscv_instr_cover_group;
|
|||
divu_cg = new();
|
||||
rem_cg = new();
|
||||
remu_cg = new();
|
||||
end
|
||||
if (RV64M inside {supported_isa}) begin
|
||||
`CG_SELECTOR_END
|
||||
|
||||
`CG_SELECTOR_BEGIN(RV64M)
|
||||
mulw_cg = new();
|
||||
divw_cg = new();
|
||||
divuw_cg = new();
|
||||
remw_cg = new();
|
||||
remuw_cg = new();
|
||||
end
|
||||
if (RV64I inside {supported_isa}) begin
|
||||
`CG_SELECTOR_END
|
||||
|
||||
`CG_SELECTOR_BEGIN(RV64I)
|
||||
lwu_cg = new();
|
||||
ld_cg = new();
|
||||
sd_cg = new();
|
||||
|
@ -896,8 +977,9 @@ class riscv_instr_cover_group;
|
|||
addw_cg = new();
|
||||
addiw_cg = new();
|
||||
subw_cg = new();
|
||||
end
|
||||
if (RV32C inside {supported_isa}) begin
|
||||
`CG_SELECTOR_END
|
||||
|
||||
`CG_SELECTOR_BEGIN(RV32C)
|
||||
c_lw_cg = new();
|
||||
c_sw_cg = new();
|
||||
c_lwsp_cg = new();
|
||||
|
@ -925,8 +1007,9 @@ class riscv_instr_cover_group;
|
|||
end
|
||||
c_jr_cg = new();
|
||||
c_jalr_cg = new();
|
||||
end
|
||||
if (RV64C inside {supported_isa}) begin
|
||||
`CG_SELECTOR_END
|
||||
|
||||
`CG_SELECTOR_BEGIN(RV64C)
|
||||
c_ld_cg = new();
|
||||
c_sd_cg = new();
|
||||
c_ldsp_cg = new();
|
||||
|
@ -934,14 +1017,27 @@ class riscv_instr_cover_group;
|
|||
c_addiw_cg = new();
|
||||
c_subw_cg = new();
|
||||
c_addw_cg = new();
|
||||
`CG_SELECTOR_END
|
||||
|
||||
// Ignore the exception which cannot be covered when running with ISS
|
||||
if (iss_mode) begin
|
||||
ignored_exceptions = {INSTRUCTION_ACCESS_FAULT, LOAD_ACCESS_FAULT};
|
||||
if (support_unaligned_load_store) begin
|
||||
ignored_exceptions = {ignored_exceptions, LOAD_ADDRESS_MISALIGNED};
|
||||
end
|
||||
end
|
||||
privileged_csr_cg = new();
|
||||
mcause_exception_cg = new();
|
||||
mcause_interrupt_cg = new();
|
||||
if (RV32C inside {supported_isa}) begin
|
||||
mepc_alignment_cg = new();
|
||||
|
||||
if (!compliance_mode) begin
|
||||
privileged_csr_cg = new();
|
||||
mcause_exception_cg = new();
|
||||
if (!iss_mode) begin
|
||||
mcause_interrupt_cg = new();
|
||||
end
|
||||
if (!cfg.disable_compressed_instr) begin
|
||||
mepc_alignment_cg = new();
|
||||
end
|
||||
mstatus_m_cg = new();
|
||||
end
|
||||
mstatus_m_cg = new();
|
||||
endfunction
|
||||
|
||||
function void sample(riscv_instr_cov_item instr);
|
||||
|
@ -950,134 +1046,143 @@ class riscv_instr_cover_group;
|
|||
instr.check_hazard_condition(pre_instr);
|
||||
end
|
||||
if ((instr.binary[1:0] != 2'b11) && (RV32C inside {supported_isa})) begin
|
||||
hint_cg.sample(instr);
|
||||
compressed_opcode_cg.sample(instr.binary[15:0]);
|
||||
if (!compliance_mode) begin
|
||||
hint_cg.sample(instr);
|
||||
compressed_opcode_cg.sample(instr.binary[15:0]);
|
||||
end
|
||||
end
|
||||
if (instr.binary[1:0] == 2'b11) begin
|
||||
opcode_cg.sample(instr.binary[6:2]);
|
||||
if (!compliance_mode) begin
|
||||
opcode_cg.sample(instr.binary[6:2]);
|
||||
end
|
||||
end
|
||||
case (instr.instr_name)
|
||||
ADD : add_cg.sample(instr);
|
||||
SUB : sub_cg.sample(instr);
|
||||
ADDI : addi_cg.sample(instr);
|
||||
LUI : lui_cg.sample(instr);
|
||||
AUIPC : auipc_cg.sample(instr);
|
||||
SLL : sll_cg.sample(instr);
|
||||
SRL : srl_cg.sample(instr);
|
||||
SRA : sra_cg.sample(instr);
|
||||
ADD : `SAMPLE(add_cg, instr)
|
||||
SUB : `SAMPLE(sub_cg, instr)
|
||||
ADDI : `SAMPLE(addi_cg, instr)
|
||||
LUI : `SAMPLE(lui_cg, instr)
|
||||
AUIPC : `SAMPLE(auipc_cg, instr)
|
||||
SLL : `SAMPLE(sll_cg, instr)
|
||||
SRL : `SAMPLE(srl_cg, instr)
|
||||
SRA : `SAMPLE(sra_cg, instr)
|
||||
SLLI : begin
|
||||
slli_cg.sample(instr);
|
||||
`SAMPLE(slli_cg, instr)
|
||||
if (RV64I inside {supported_isa}) begin
|
||||
slli64_cg.sample(instr);
|
||||
`SAMPLE(slli64_cg, instr)
|
||||
end
|
||||
end
|
||||
SRLI : begin
|
||||
srli_cg.sample(instr);
|
||||
`SAMPLE(srli_cg, instr)
|
||||
if (RV64I inside {supported_isa}) begin
|
||||
srli64_cg.sample(instr);
|
||||
`SAMPLE(srli64_cg, instr)
|
||||
end
|
||||
end
|
||||
SRAI : begin
|
||||
srai_cg.sample(instr);
|
||||
`SAMPLE(srai_cg, instr)
|
||||
if (RV64I inside {supported_isa}) begin
|
||||
srai64_cg.sample(instr);
|
||||
`SAMPLE(srai64_cg, instr)
|
||||
end
|
||||
end
|
||||
AND : and_cg.sample(instr);
|
||||
OR : or_cg.sample(instr);
|
||||
XOR : xor_cg.sample(instr);
|
||||
ANDI : andi_cg.sample(instr);
|
||||
ORI : ori_cg.sample(instr);
|
||||
XORI : xori_cg.sample(instr);
|
||||
SLT : slt_cg.sample(instr);
|
||||
SLTU : sltu_cg.sample(instr);
|
||||
SLTI : slti_cg.sample(instr);
|
||||
SLTIU : sltiu_cg.sample(instr);
|
||||
JAL : jal_cg.sample(instr);
|
||||
JALR : jalr_cg.sample(instr);
|
||||
BEQ : beq_cg.sample(instr);
|
||||
BNE : bne_cg.sample(instr);
|
||||
BLT : blt_cg.sample(instr);
|
||||
BGE : bge_cg.sample(instr);
|
||||
BLTU : bltu_cg.sample(instr);
|
||||
BGEU : bgeu_cg.sample(instr);
|
||||
LW : lw_cg.sample(instr);
|
||||
LH : lh_cg.sample(instr);
|
||||
LB : lb_cg.sample(instr);
|
||||
LBU : lbu_cg.sample(instr);
|
||||
LHU : lhu_cg.sample(instr);
|
||||
SW : sw_cg.sample(instr);
|
||||
SH : sh_cg.sample(instr);
|
||||
SB : sb_cg.sample(instr);
|
||||
CSRRW : csrrw_cg.sample(instr);
|
||||
CSRRS : csrrs_cg.sample(instr);
|
||||
CSRRC : csrrc_cg.sample(instr);
|
||||
CSRRWI : csrrwi_cg.sample(instr);
|
||||
CSRRSI : csrrsi_cg.sample(instr);
|
||||
CSRRCI : csrrci_cg.sample(instr);
|
||||
MUL : mul_cg.sample(instr);
|
||||
MULH : mulh_cg.sample(instr);
|
||||
MULHSU : mulhsu_cg.sample(instr);
|
||||
MULHU : mulhu_cg.sample(instr);
|
||||
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);
|
||||
REMW : remw_cg.sample(instr);
|
||||
REMUW : remuw_cg.sample(instr);
|
||||
LWU : lwu_cg.sample(instr);
|
||||
LD : ld_cg.sample(instr);
|
||||
SD : sd_cg.sample(instr);
|
||||
SLLW : sllw_cg.sample(instr);
|
||||
SLLIW : slliw_cg.sample(instr);
|
||||
SRLW : srlw_cg.sample(instr);
|
||||
SRLIW : srliw_cg.sample(instr);
|
||||
SRAW : sraw_cg.sample(instr);
|
||||
SRAIW : sraiw_cg.sample(instr);
|
||||
ADDW : addw_cg.sample(instr);
|
||||
ADDIW : addiw_cg.sample(instr);
|
||||
SUBW : subw_cg.sample(instr);
|
||||
C_LW : c_lw_cg.sample(instr);
|
||||
C_SW : c_sw_cg.sample(instr);
|
||||
C_LWSP : c_lwsp_cg.sample(instr);
|
||||
C_SWSP : c_swsp_cg.sample(instr);
|
||||
C_ADDI4SPN : c_addi4spn_cg.sample(instr);
|
||||
C_ADDI : c_addi_cg.sample(instr);
|
||||
C_ADDI16SP : c_addi16sp_cg.sample(instr);
|
||||
C_LI : c_li_cg.sample(instr);
|
||||
C_LUI : c_lui_cg.sample(instr);
|
||||
C_SUB : c_sub_cg.sample(instr);
|
||||
C_ADD : c_add_cg.sample(instr);
|
||||
C_MV : c_mv_cg.sample(instr);
|
||||
C_ANDI : c_andi_cg.sample(instr);
|
||||
C_XOR : c_xor_cg.sample(instr);
|
||||
C_OR : c_or_cg.sample(instr);
|
||||
C_AND : c_and_cg.sample(instr);
|
||||
C_BEQZ : c_beqz_cg.sample(instr);
|
||||
C_BNEZ : c_bnez_cg.sample(instr);
|
||||
C_SRLI : c_srli_cg.sample(instr);
|
||||
C_SRAI : c_srai_cg.sample(instr);
|
||||
C_SLLI : c_slli_cg.sample(instr);
|
||||
C_J : c_j_cg.sample(instr);
|
||||
C_JAL : c_jal_cg.sample(instr);
|
||||
C_JR : c_jr_cg.sample(instr);
|
||||
C_JALR : c_jalr_cg.sample(instr);
|
||||
C_LD : c_ld_cg.sample(instr);
|
||||
C_SD : c_sd_cg.sample(instr);
|
||||
C_LDSP : c_ldsp_cg.sample(instr);
|
||||
C_SDSP : c_sdsp_cg.sample(instr);
|
||||
C_SUBW : c_subw_cg.sample(instr);
|
||||
C_ADDW : c_addw_cg.sample(instr);
|
||||
C_ADDIW : c_addiw_cg.sample(instr);
|
||||
AND : `SAMPLE(and_cg, instr)
|
||||
OR : `SAMPLE(or_cg, instr)
|
||||
XOR : `SAMPLE(xor_cg, instr)
|
||||
ANDI : `SAMPLE(andi_cg, instr)
|
||||
ORI : `SAMPLE(ori_cg, instr)
|
||||
XORI : `SAMPLE(xori_cg, instr)
|
||||
SLT : `SAMPLE(slt_cg, instr)
|
||||
SLTU : `SAMPLE(sltu_cg, instr)
|
||||
SLTI : `SAMPLE(slti_cg, instr)
|
||||
SLTIU : `SAMPLE(sltiu_cg, instr)
|
||||
JAL : `SAMPLE(jal_cg, instr)
|
||||
JALR : `SAMPLE(jalr_cg, instr)
|
||||
BEQ : `SAMPLE(beq_cg, instr)
|
||||
BNE : `SAMPLE(bne_cg, instr)
|
||||
BLT : `SAMPLE(blt_cg, instr)
|
||||
BGE : `SAMPLE(bge_cg, instr)
|
||||
BLTU : `SAMPLE(bltu_cg, instr)
|
||||
BGEU : `SAMPLE(bgeu_cg, instr)
|
||||
LW : `SAMPLE(lw_cg, instr)
|
||||
LH : `SAMPLE(lh_cg, instr)
|
||||
LB : `SAMPLE(lb_cg, instr)
|
||||
LBU : `SAMPLE(lbu_cg, instr)
|
||||
LHU : `SAMPLE(lhu_cg, instr)
|
||||
SW : `SAMPLE(sw_cg, instr)
|
||||
SH : `SAMPLE(sh_cg, instr)
|
||||
SB : `SAMPLE(sb_cg, instr)
|
||||
CSRRW : `SAMPLE(csrrw_cg, instr)
|
||||
CSRRS : `SAMPLE(csrrs_cg, instr)
|
||||
CSRRC : `SAMPLE(csrrc_cg, instr)
|
||||
CSRRWI : `SAMPLE(csrrwi_cg, instr)
|
||||
CSRRSI : `SAMPLE(csrrsi_cg, instr)
|
||||
CSRRCI : `SAMPLE(csrrci_cg, instr)
|
||||
MUL : `SAMPLE(mul_cg, instr)
|
||||
MULH : `SAMPLE(mulh_cg, instr)
|
||||
MULHSU : `SAMPLE(mulhsu_cg, instr)
|
||||
MULHU : `SAMPLE(mulhu_cg, instr)
|
||||
DIV : `SAMPLE(div_cg, instr)
|
||||
DIVU : `SAMPLE(divu_cg, instr)
|
||||
REM : `SAMPLE(rem_cg, instr)
|
||||
REMU : `SAMPLE(remu_cg, instr)
|
||||
MULW : `SAMPLE(mulw_cg, instr)
|
||||
DIVW : `SAMPLE(divw_cg, instr)
|
||||
DIVUW : `SAMPLE(divuw_cg, instr)
|
||||
REMW : `SAMPLE(remw_cg, instr)
|
||||
REMUW : `SAMPLE(remuw_cg, instr)
|
||||
LWU : `SAMPLE(lwu_cg, instr)
|
||||
LD : `SAMPLE(ld_cg, instr)
|
||||
SD : `SAMPLE(sd_cg, instr)
|
||||
SLLW : `SAMPLE(sllw_cg, instr)
|
||||
SLLIW : `SAMPLE(slliw_cg, instr)
|
||||
SRLW : `SAMPLE(srlw_cg, instr)
|
||||
SRLIW : `SAMPLE(srliw_cg, instr)
|
||||
SRAW : `SAMPLE(sraw_cg, instr)
|
||||
SRAIW : `SAMPLE(sraiw_cg, instr)
|
||||
ADDW : `SAMPLE(addw_cg, instr)
|
||||
ADDIW : `SAMPLE(addiw_cg, instr)
|
||||
SUBW : `SAMPLE(subw_cg, instr)
|
||||
C_LW : `SAMPLE(c_lw_cg, instr)
|
||||
C_SW : `SAMPLE(c_sw_cg, instr)
|
||||
C_LWSP : `SAMPLE(c_lwsp_cg, instr)
|
||||
C_SWSP : `SAMPLE(c_swsp_cg, instr)
|
||||
C_ADDI4SPN : `SAMPLE(c_addi4spn_cg, instr)
|
||||
C_ADDI : `SAMPLE(c_addi_cg, instr)
|
||||
C_ADDI16SP : `SAMPLE(c_addi16sp_cg, instr)
|
||||
C_LI : `SAMPLE(c_li_cg, instr)
|
||||
C_LUI : `SAMPLE(c_lui_cg, instr)
|
||||
C_SUB : `SAMPLE(c_sub_cg, instr)
|
||||
C_ADD : `SAMPLE(c_add_cg, instr)
|
||||
C_MV : `SAMPLE(c_mv_cg, instr)
|
||||
C_ANDI : `SAMPLE(c_andi_cg, instr)
|
||||
C_XOR : `SAMPLE(c_xor_cg, instr)
|
||||
C_OR : `SAMPLE(c_or_cg, instr)
|
||||
C_AND : `SAMPLE(c_and_cg, instr)
|
||||
C_BEQZ : `SAMPLE(c_beqz_cg, instr)
|
||||
C_BNEZ : `SAMPLE(c_bnez_cg, instr)
|
||||
C_SRLI : `SAMPLE(c_srli_cg, instr)
|
||||
C_SRAI : `SAMPLE(c_srai_cg, instr)
|
||||
C_SLLI : `SAMPLE(c_slli_cg, instr)
|
||||
C_J : `SAMPLE(c_j_cg, instr)
|
||||
C_JAL : `SAMPLE(c_jal_cg, instr)
|
||||
C_JR : `SAMPLE(c_jr_cg, instr)
|
||||
C_JALR : `SAMPLE(c_jalr_cg, instr)
|
||||
C_LD : `SAMPLE(c_ld_cg, instr)
|
||||
C_SD : `SAMPLE(c_sd_cg, instr)
|
||||
C_LDSP : `SAMPLE(c_ldsp_cg, instr)
|
||||
C_SDSP : `SAMPLE(c_sdsp_cg, instr)
|
||||
C_SUBW : `SAMPLE(c_subw_cg, instr)
|
||||
C_ADDW : `SAMPLE(c_addw_cg, instr)
|
||||
C_ADDIW : `SAMPLE(c_addiw_cg, instr)
|
||||
`VECTOR_INCLUDE("riscv_instr_cover_group_inc_cg_sample.sv")
|
||||
default: begin
|
||||
if (RV32C inside {supported_isa}) begin
|
||||
illegal_compressed_instr_cg.sample(instr.binary);
|
||||
if (!compliance_mode) begin
|
||||
illegal_compressed_instr_cg.sample(instr.binary);
|
||||
end
|
||||
end
|
||||
if (instr.group == RV32I) begin
|
||||
rv32i_misc_cg.sample(instr);
|
||||
if (!compliance_mode) begin
|
||||
rv32i_misc_cg.sample(instr);
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
@ -1085,39 +1190,54 @@ class riscv_instr_cover_group;
|
|||
branch_hit_history = (branch_hit_history << 1) | instr.branch_hit;
|
||||
branch_instr_cnt += 1;
|
||||
if (branch_instr_cnt >= $bits(branch_hit_history)) begin
|
||||
branch_hit_history_cg.sample();
|
||||
if (!compliance_mode) begin
|
||||
branch_hit_history_cg.sample();
|
||||
end
|
||||
end
|
||||
end
|
||||
if (instr.category == CSR) begin
|
||||
privileged_csr_cg.sample(instr.csr);
|
||||
if (!compliance_mode) begin
|
||||
privileged_csr_cg.sample(instr.csr);
|
||||
end
|
||||
case (instr.csr)
|
||||
MCAUSE: begin
|
||||
if (instr.rd_value[XLEN-1]) begin
|
||||
interrupt_cause_t interrupt;
|
||||
if ($cast(interrupt, instr.rd_value[3:0])) begin
|
||||
mcause_interrupt_cg.sample(interrupt);
|
||||
if (!compliance_mode && !iss_mode) begin
|
||||
mcause_interrupt_cg.sample(interrupt);
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
exception_cause_t exception;
|
||||
if ($cast(exception, instr.rd_value[3:0])) begin
|
||||
mcause_exception_cg.sample(exception);
|
||||
if (!compliance_mode) begin
|
||||
mcause_exception_cg.sample(exception);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
MEPC: begin
|
||||
if (RV32C inside {supported_isa}) begin
|
||||
mepc_alignment_cg.sample(instr.rd_value);
|
||||
if (!compliance_mode) begin
|
||||
mepc_alignment_cg.sample(instr.rd_value);
|
||||
end
|
||||
end
|
||||
end
|
||||
MSTATUS: begin
|
||||
mstatus_m_cg.sample(instr.rd_value);
|
||||
if (!compliance_mode) begin
|
||||
mstatus_m_cg.sample(instr.rd_value);
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
if (instr_cnt > 1) begin
|
||||
// instr_trans_cg.sample();
|
||||
if (!compliance_mode) begin
|
||||
//instr_trans_cg.sample();
|
||||
end
|
||||
end
|
||||
pre_instr.copy_base_instr(instr);
|
||||
`VECTOR_INCLUDE("riscv_instr_cover_group_inc_sample.sv")
|
||||
pre_instr.copy(instr);
|
||||
pre_instr.mem_addr = instr.mem_addr;
|
||||
endfunction
|
||||
|
||||
|
@ -1144,15 +1264,20 @@ class riscv_instr_cover_group;
|
|||
riscv_instr_name_t instr_name;
|
||||
instr_name = instr_name.first;
|
||||
do begin
|
||||
riscv_instr_base instr;
|
||||
`INSTR instr;
|
||||
if (!(instr_name inside {unsupported_instr}) && (instr_name != INVALID_INSTR)) begin
|
||||
instr = riscv_instr_base::type_id::create("instr");
|
||||
if (!instr.randomize() with {instr_name == local::instr_name;}) begin
|
||||
`uvm_fatal("riscv_instr_cover_group",
|
||||
$sformatf("Instruction %0s randomization failure", instr_name.name()))
|
||||
end
|
||||
`ifdef DEPRECATED
|
||||
instr = riscv_instr_base::type_id::create("instr");
|
||||
if (!instr.randomize() with {instr_name == local::instr_name;}) begin
|
||||
`uvm_fatal("riscv_instr_cover_group",
|
||||
$sformatf("Instruction %0s randomization failure", instr_name.name()))
|
||||
end
|
||||
`else
|
||||
instr = riscv_instr::create_instr(instr_name);
|
||||
`endif
|
||||
if ((instr.group inside {supported_isa}) &&
|
||||
(instr.group inside {RV32I, RV32M, RV64M, RV64I, RV32C, RV64C})) begin
|
||||
(instr.group inside {RV32I, RV32M, RV64M, RV64I, RV32C, RV64C,
|
||||
RV32V, RV64V, RV64B, RV32B})) begin
|
||||
if (((instr_name inside {URET}) && !support_umode_trap) ||
|
||||
((instr_name inside {SRET, SFENCE_VMA}) &&
|
||||
!(SUPERVISOR_MODE inside {supported_privileged_mode})) ||
|
||||
|
@ -1174,6 +1299,13 @@ class riscv_instr_cover_group;
|
|||
instr_cnt = 0;
|
||||
branch_instr_cnt = 0;
|
||||
branch_hit_history = '0;
|
||||
`VECTOR_INCLUDE("riscv_instr_cover_group_inc_cpu_reset.sv")
|
||||
endfunction
|
||||
|
||||
function void fatal(string str);
|
||||
if ($test$plusargs("stop_on_first_error")) begin
|
||||
`uvm_fatal("riscv_instr_cover_group", $sformatf("FATAL Error: %0s", str))
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
137
vendor/google_riscv-dv/src/riscv_instr_gen_config.sv
vendored
137
vendor/google_riscv-dv/src/riscv_instr_gen_config.sv
vendored
|
@ -116,14 +116,6 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// Number of instructions for each kernel program
|
||||
int kernel_program_instr_cnt = 400;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Instruction list based on the config, generate by build_instruction_template
|
||||
//-----------------------------------------------------------------------------
|
||||
riscv_instr_base instr_template[riscv_instr_name_t];
|
||||
riscv_instr_name_t basic_instr[$];
|
||||
riscv_instr_name_t instr_group[riscv_instr_group_t][$];
|
||||
riscv_instr_name_t instr_category[riscv_instr_category_t][$];
|
||||
|
||||
// Queue of all the main implemented CSRs that the boot privilege mode cannot access
|
||||
// e.g. these CSRs are in higher privilege modes - access should raise an exception
|
||||
privileged_reg_t invalid_priv_mode_csrs[$];
|
||||
|
@ -390,8 +382,54 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
}
|
||||
|
||||
`uvm_object_utils_begin(riscv_instr_gen_config)
|
||||
`uvm_field_int(main_program_instr_cnt, UVM_DEFAULT)
|
||||
`uvm_field_int(main_program_instr_cnt, UVM_DEFAULT)
|
||||
`uvm_field_sarray_int(sub_program_instr_cnt, UVM_DEFAULT)
|
||||
`uvm_field_int(debug_program_instr_cnt, UVM_DEFAULT)
|
||||
`uvm_field_enum(data_pattern_t, data_page_pattern, UVM_DEFAULT)
|
||||
`uvm_field_enum(privileged_mode_t, init_privileged_mode, UVM_DEFAULT)
|
||||
`uvm_field_array_enum(riscv_reg_t, reserved_regs, UVM_DEFAULT)
|
||||
`uvm_field_enum(riscv_reg_t, ra, UVM_DEFAULT)
|
||||
`uvm_field_enum(riscv_reg_t, sp, UVM_DEFAULT)
|
||||
`uvm_field_enum(riscv_reg_t, tp, UVM_DEFAULT)
|
||||
`uvm_field_int(no_data_page, UVM_DEFAULT)
|
||||
`uvm_field_int(no_branch_jump, UVM_DEFAULT)
|
||||
`uvm_field_int(no_load_store, UVM_DEFAULT)
|
||||
`uvm_field_int(no_csr_instr, UVM_DEFAULT)
|
||||
`uvm_field_int(no_ebreak, UVM_DEFAULT)
|
||||
`uvm_field_int(no_dret, UVM_DEFAULT)
|
||||
`uvm_field_int(no_fence, UVM_DEFAULT)
|
||||
`uvm_field_int(no_wfi, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_unaligned_load_store, UVM_DEFAULT)
|
||||
`uvm_field_int(illegal_instr_ratio, UVM_DEFAULT)
|
||||
`uvm_field_int(hint_instr_ratio, UVM_DEFAULT)
|
||||
`uvm_field_string(boot_mode_opts, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_page_table_exception, UVM_DEFAULT)
|
||||
`uvm_field_int(no_directed_instr, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_interrupt, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_timer_irq, UVM_DEFAULT)
|
||||
`uvm_field_int(bare_program_mode, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_illegal_csr_instruction, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_access_invalid_csr_level, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_dummy_csr_write, UVM_DEFAULT)
|
||||
`uvm_field_int(randomize_csr, UVM_DEFAULT)
|
||||
`uvm_field_int(allow_sfence_exception, UVM_DEFAULT)
|
||||
`uvm_field_int(no_delegation, UVM_DEFAULT)
|
||||
`uvm_field_int(force_m_delegation, UVM_DEFAULT)
|
||||
`uvm_field_int(force_s_delegation, UVM_DEFAULT)
|
||||
`uvm_field_int(support_supervisor_mode, UVM_DEFAULT)
|
||||
`uvm_field_int(disable_compressed_instr, UVM_DEFAULT)
|
||||
`uvm_field_int(signature_addr, UVM_DEFAULT)
|
||||
`uvm_field_int(require_signature_addr, UVM_DEFAULT)
|
||||
`uvm_field_int(gen_debug_section, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_ebreak_in_debug_rom, UVM_DEFAULT)
|
||||
`uvm_field_int(set_dcsr_ebreak, UVM_DEFAULT)
|
||||
`uvm_field_int(num_debug_sub_program, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_debug_single_step, UVM_DEFAULT)
|
||||
`uvm_field_int(single_step_iterations, UVM_DEFAULT)
|
||||
`uvm_field_int(set_mstatus_tw, UVM_DEFAULT)
|
||||
`uvm_field_int(max_branch_step, UVM_DEFAULT)
|
||||
`uvm_field_int(max_directed_instr_stream_seq, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_floating_point, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
function new (string name = "");
|
||||
|
@ -539,6 +577,10 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
min_stack_len_per_program = 2 * (XLEN/8);
|
||||
// Check if the setting is legal
|
||||
check_setting();
|
||||
// WFI is not supported in umode
|
||||
if (init_privileged_mode == USER_MODE) begin
|
||||
no_wfi = 1'b1;
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void check_setting();
|
||||
|
@ -569,7 +611,8 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// TODO(udi) - include performance/pmp/trigger CSRs?
|
||||
virtual function void get_invalid_priv_lvl_csr();
|
||||
string invalid_lvl[$];
|
||||
string csr;
|
||||
string csr_name;
|
||||
privileged_reg_t csr;
|
||||
// Debug CSRs are inaccessible from all but Debug Mode, and we cannot boot into Debug Mode
|
||||
invalid_lvl.push_back("D");
|
||||
case (init_privileged_mode)
|
||||
|
@ -587,8 +630,9 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
end
|
||||
endcase
|
||||
foreach (implemented_csr[i]) begin
|
||||
csr = implemented_csr[i].name();
|
||||
if (csr[0] inside {invalid_lvl}) begin
|
||||
privileged_reg_t csr = implemented_csr[i];
|
||||
csr_name = csr.name();
|
||||
if (csr_name[0] inside {invalid_lvl}) begin
|
||||
invalid_priv_mode_csrs.push_back(implemented_csr[i]);
|
||||
end
|
||||
end
|
||||
|
@ -618,73 +662,4 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// Build instruction template
|
||||
virtual function void build_instruction_template(bit skip_instr_exclusion = 0);
|
||||
riscv_instr_name_t instr_name;
|
||||
riscv_instr_name_t excluded_instr[$];
|
||||
excluded_instr = {INVALID_INSTR};
|
||||
if (!skip_instr_exclusion) begin
|
||||
get_excluded_instr(excluded_instr);
|
||||
end
|
||||
instr_name = instr_name.first;
|
||||
do begin
|
||||
riscv_instr_base instr;
|
||||
if (!(instr_name inside {unsupported_instr, excluded_instr})) begin
|
||||
instr = riscv_instr_base::type_id::create("instr");
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(instr, instr_name == local::instr_name;)
|
||||
if ((instr.group inside {supported_isa}) &&
|
||||
!(disable_compressed_instr && instr.is_compressed) &&
|
||||
!(!enable_floating_point && (instr.group inside {RV32F, RV64F, RV32D, RV64D}))) begin
|
||||
`uvm_info(`gfn, $sformatf("Adding [%s] %s to the list",
|
||||
instr.group.name(), instr.instr_name.name()), UVM_HIGH)
|
||||
instr_group[instr.group].push_back(instr_name);
|
||||
instr_category[instr.category].push_back(instr_name);
|
||||
instr_template[instr_name] = instr;
|
||||
end
|
||||
end
|
||||
instr_name = instr_name.next;
|
||||
end
|
||||
while (instr_name != instr_name.first);
|
||||
endfunction
|
||||
|
||||
virtual function void build_instruction_list();
|
||||
basic_instr = {instr_category[SHIFT], instr_category[ARITHMETIC],
|
||||
instr_category[LOGICAL], instr_category[COMPARE]};
|
||||
basic_instr = {basic_instr, EBREAK};
|
||||
foreach(riscv_instr_pkg::supported_isa[i]) begin
|
||||
if (riscv_instr_pkg::supported_isa[i] inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) begin
|
||||
basic_instr = {basic_instr, C_EBREAK};
|
||||
break;
|
||||
end
|
||||
end
|
||||
if (no_dret == 0) begin
|
||||
basic_instr = {basic_instr, DRET};
|
||||
end
|
||||
if (no_fence == 0) begin
|
||||
basic_instr = {basic_instr, instr_category[SYNCH]};
|
||||
end
|
||||
// TODO: Support CSR instruction in other mode
|
||||
if ((no_csr_instr == 0) && (init_privileged_mode == MACHINE_MODE)) begin
|
||||
`uvm_info(`gfn, $sformatf("Adding CSR instr, mode: %0s", init_privileged_mode.name()), UVM_LOW)
|
||||
basic_instr = {basic_instr, instr_category[CSR]};
|
||||
end
|
||||
if (no_wfi == 0) begin
|
||||
basic_instr = {basic_instr, WFI};
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void get_excluded_instr(ref riscv_instr_name_t excluded[$]);
|
||||
// Below instrutions will modify stack pointer, not allowed in normal instruction stream.
|
||||
// It can be used in stack operation instruction stream.
|
||||
excluded = {excluded, C_SWSP, C_SDSP, C_ADDI16SP};
|
||||
if (!enable_sfence) begin
|
||||
excluded = {excluded, SFENCE_VMA};
|
||||
end
|
||||
if (no_fence) begin
|
||||
excluded = {excluded, FENCE, FENCE_I, SFENCE_VMA};
|
||||
end
|
||||
// TODO: Support C_ADDI4SPN
|
||||
excluded = {excluded, C_ADDI4SPN};
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
88
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
88
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
|
@ -86,7 +86,11 @@ package riscv_instr_pkg;
|
|||
RV32C,
|
||||
RV64C,
|
||||
RV128I,
|
||||
RV128C
|
||||
RV128C,
|
||||
RV32V,
|
||||
RV32B,
|
||||
RV64V,
|
||||
RV64B
|
||||
} riscv_instr_group_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -318,6 +322,7 @@ package riscv_instr_pkg;
|
|||
SRET,
|
||||
WFI,
|
||||
SFENCE_VMA,
|
||||
`VECTOR_INCLUDE("riscv_instr_pkg_inc_riscv_instr_name_t.sv")
|
||||
// You can add other instructions here
|
||||
INVALID_INSTR
|
||||
} riscv_instr_name_t;
|
||||
|
@ -331,12 +336,14 @@ package riscv_instr_pkg;
|
|||
S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6
|
||||
} riscv_reg_t;
|
||||
|
||||
`VECTOR_INCLUDE("riscv_instr_pkg_inc_enum.sv")
|
||||
|
||||
typedef enum bit [4:0] {
|
||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,
|
||||
F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
|
||||
} riscv_fpr_t;
|
||||
|
||||
typedef enum bit [3:0] {
|
||||
typedef enum bit [5:0] {
|
||||
J_FORMAT = 0,
|
||||
U_FORMAT,
|
||||
I_FORMAT,
|
||||
|
@ -352,10 +359,11 @@ package riscv_instr_pkg;
|
|||
CL_FORMAT,
|
||||
CS_FORMAT,
|
||||
CSS_FORMAT,
|
||||
CIW_FORMAT
|
||||
`VECTOR_INCLUDE("riscv_instr_pkg_inc_riscv_instr_format_t.sv")
|
||||
CIW_FORMAT // (last one)
|
||||
} riscv_instr_format_t;
|
||||
|
||||
typedef enum bit [3:0] {
|
||||
typedef enum bit [5:0] {
|
||||
LOAD = 0,
|
||||
STORE,
|
||||
SHIFT,
|
||||
|
@ -371,7 +379,8 @@ package riscv_instr_pkg;
|
|||
CHANGELEVEL,
|
||||
TRAP,
|
||||
INTERRUPT,
|
||||
AMO
|
||||
`VECTOR_INCLUDE("riscv_instr_pkg_inc_riscv_instr_category_t.sv")
|
||||
AMO // (last one)
|
||||
} riscv_instr_category_t;
|
||||
|
||||
typedef bit [11:0] riscv_csr_t;
|
||||
|
@ -602,7 +611,8 @@ package riscv_instr_pkg;
|
|||
DCSR = 'h7B0, // Debug control and status register
|
||||
DPC = 'h7B1, // Debug PC
|
||||
DSCRATCH0 = 'h7B2, // Debug scratch register
|
||||
DSCRATCH1 = 'h7B3 // Debug scratch register
|
||||
`VECTOR_INCLUDE("riscv_instr_pkg_inc_privileged_reg_t.sv")
|
||||
DSCRATCH1 = 'h7B3 // Debug scratch register (last one)
|
||||
} privileged_reg_t;
|
||||
|
||||
typedef enum bit [5:0] {
|
||||
|
@ -715,6 +725,21 @@ package riscv_instr_pkg;
|
|||
|
||||
`include "riscv_core_setting.sv"
|
||||
|
||||
// TODO hardware target definition so should move to riscv_core_setting.sv
|
||||
`ifdef ENABLE_VECTORS
|
||||
parameter bit has_vector_engine = 'b1;
|
||||
parameter int VLEN = `VLEN;
|
||||
parameter int ELEN = `ELEN;
|
||||
parameter int SLEN = `SLEN;
|
||||
`else
|
||||
parameter bit has_vector_engine = 'b0;
|
||||
parameter int VLEN = 512;
|
||||
parameter int ELEN = 64;
|
||||
parameter int SLEN = 64;
|
||||
`endif
|
||||
|
||||
`VECTOR_INCLUDE("riscv_instr_pkg_inc_variables.sv")
|
||||
|
||||
typedef bit [15:0] program_id_t;
|
||||
|
||||
// xSTATUS bit mask
|
||||
|
@ -844,8 +869,42 @@ package riscv_instr_pkg;
|
|||
|
||||
riscv_reg_t compressed_gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5};
|
||||
|
||||
`include "riscv_instr_base.sv"
|
||||
`include "riscv_instr_gen_config.sv"
|
||||
riscv_instr_category_t all_categories[] = {
|
||||
LOAD, STORE, SHIFT, ARITHMETIC, LOGICAL, COMPARE, BRANCH, JUMP,
|
||||
SYNCH, SYSTEM, COUNTER, CSR, CHANGELEVEL, TRAP, INTERRUPT, AMO
|
||||
};
|
||||
|
||||
`ifdef DEPRECATED
|
||||
`define INSTR riscv_instr_base
|
||||
`include "deprecated/riscv_instr_base.sv"
|
||||
`include "deprecated/riscv_instr_gen_config.sv"
|
||||
`else
|
||||
`define INSTR riscv_instr
|
||||
typedef class riscv_instr;
|
||||
`include "riscv_instr_gen_config.sv"
|
||||
`include "isa/riscv_instr.sv"
|
||||
`include "isa/riscv_amo_instr.sv"
|
||||
`include "isa/riscv_floating_point_instr.sv"
|
||||
`include "isa/riscv_vector_instr.sv"
|
||||
`include "isa/riscv_compressed_instr.sv"
|
||||
`include "isa/rv32a_instr.sv"
|
||||
`include "isa/rv32c_instr.sv"
|
||||
`include "isa/rv32dc_instr.sv"
|
||||
`include "isa/rv32d_instr.sv"
|
||||
`include "isa/rv32fc_instr.sv"
|
||||
`include "isa/rv32f_instr.sv"
|
||||
`include "isa/rv32i_instr.sv"
|
||||
`include "isa/rv32m_instr.sv"
|
||||
`include "isa/rv64a_instr.sv"
|
||||
`include "isa/rv64c_instr.sv"
|
||||
`include "isa/rv64d_instr.sv"
|
||||
`include "isa/rv64f_instr.sv"
|
||||
`include "isa/rv64i_instr.sv"
|
||||
`include "isa/rv64m_instr.sv"
|
||||
`include "isa/rv128c_instr.sv"
|
||||
`endif
|
||||
|
||||
`include "riscv_pseudo_instr.sv"
|
||||
`include "riscv_illegal_instr.sv"
|
||||
`include "riscv_reg.sv"
|
||||
`include "riscv_privil_reg.sv"
|
||||
|
@ -856,14 +915,25 @@ package riscv_instr_pkg;
|
|||
`include "riscv_privileged_common_seq.sv"
|
||||
`include "riscv_callstack_gen.sv"
|
||||
`include "riscv_data_page_gen.sv"
|
||||
`include "riscv_rand_instr.sv"
|
||||
|
||||
`ifdef DEPRECATED
|
||||
`include "deprecated/riscv_rand_instr.sv"
|
||||
`include "deprecated/riscv_instr_stream.sv"
|
||||
`include "deprecated/riscv_loop_instr.sv"
|
||||
`include "deprecated/riscv_directed_instr_lib.sv"
|
||||
`include "deprecated/riscv_load_store_instr_lib.sv"
|
||||
`include "deprecated/riscv_amo_instr_lib.sv"
|
||||
`else
|
||||
`include "riscv_instr_stream.sv"
|
||||
`include "riscv_loop_instr.sv"
|
||||
`include "riscv_directed_instr_lib.sv"
|
||||
`include "riscv_load_store_instr_lib.sv"
|
||||
`include "riscv_amo_instr_lib.sv"
|
||||
`endif
|
||||
|
||||
`include "riscv_instr_sequence.sv"
|
||||
`include "riscv_asm_program_gen.sv"
|
||||
`include "riscv_debug_rom_gen.sv"
|
||||
`include "riscv_instr_cov_item.sv"
|
||||
`include "riscv_instr_cover_group.sv"
|
||||
`include "user_extension.svh"
|
||||
|
|
159
vendor/google_riscv-dv/src/riscv_instr_stream.sv
vendored
159
vendor/google_riscv-dv/src/riscv_instr_stream.sv
vendored
|
@ -20,7 +20,7 @@
|
|||
// instruction, mix two instruction streams etc.
|
||||
class riscv_instr_stream extends uvm_object;
|
||||
|
||||
riscv_instr_base instr_list[$];
|
||||
`INSTR instr_list[$];
|
||||
int unsigned instr_cnt;
|
||||
string label = "";
|
||||
// User can specify a small group of available registers to generate various hazard condition
|
||||
|
@ -40,16 +40,16 @@ class riscv_instr_stream extends uvm_object;
|
|||
endfunction
|
||||
|
||||
virtual function void create_instr_instance();
|
||||
riscv_instr_base instr;
|
||||
`INSTR instr;
|
||||
for(int i = 0; i < instr_cnt; i++) begin
|
||||
instr = riscv_instr_base::type_id::create($sformatf("instr_%0d", i));
|
||||
instr = `INSTR::type_id::create($sformatf("instr_%0d", i));
|
||||
instr_list.push_back(instr);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Insert an instruction to the existing instruction stream at the given index
|
||||
// When index is -1, the instruction is injected at a random location
|
||||
function void insert_instr(riscv_instr_base instr, int idx = -1);
|
||||
function void insert_instr(`INSTR instr, int idx = -1);
|
||||
int current_instr_cnt = instr_list.size();
|
||||
if(idx == -1) begin
|
||||
idx = $urandom_range(0, current_instr_cnt-1);
|
||||
|
@ -70,7 +70,7 @@ class riscv_instr_stream extends uvm_object;
|
|||
// Insert an instruction to the existing instruction stream at the given index
|
||||
// When index is -1, the instruction is injected at a random location
|
||||
// When replace is 1, the original instruction at the inserted position will be replaced
|
||||
function void insert_instr_stream(riscv_instr_base new_instr[], int idx = -1, bit replace = 1'b0);
|
||||
function void insert_instr_stream(`INSTR new_instr[], int idx = -1, bit replace = 1'b0);
|
||||
int current_instr_cnt = instr_list.size();
|
||||
int new_instr_cnt = new_instr.size();
|
||||
if(current_instr_cnt == 0) begin
|
||||
|
@ -119,7 +119,7 @@ class riscv_instr_stream extends uvm_object;
|
|||
// Mix the input instruction stream with the original instruction, the instruction order is
|
||||
// preserved. When 'contained' is set, the original instruction stream will be inside the
|
||||
// new instruction stream with the first and last instruction from the input instruction stream.
|
||||
function void mix_instr_stream(riscv_instr_base new_instr[], bit contained = 1'b0);
|
||||
function void mix_instr_stream(`INSTR new_instr[], bit contained = 1'b0);
|
||||
int current_instr_cnt = instr_list.size();
|
||||
int insert_instr_position[];
|
||||
int new_instr_cnt = new_instr.size();
|
||||
|
@ -167,25 +167,25 @@ class riscv_rand_instr_stream extends riscv_instr_stream;
|
|||
`uvm_object_new
|
||||
|
||||
virtual function void create_instr_instance();
|
||||
riscv_instr_base instr;
|
||||
for(int i = 0; i < instr_cnt; i++) begin
|
||||
instr = riscv_instr_base::type_id::create($sformatf("instr_%0d", i));
|
||||
instr_list.push_back(instr);
|
||||
`INSTR instr;
|
||||
for (int i = 0; i < instr_cnt; i++) begin
|
||||
instr_list.push_back(null);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void setup_allowed_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1);
|
||||
allowed_instr = cfg.basic_instr;
|
||||
allowed_instr = riscv_instr::basic_instr;
|
||||
if (no_branch == 0) begin
|
||||
allowed_instr = {allowed_instr, cfg.instr_category[BRANCH]};
|
||||
allowed_instr = {allowed_instr, riscv_instr::instr_category[BRANCH]};
|
||||
end
|
||||
if (no_load_store == 0) begin
|
||||
allowed_instr = {allowed_instr, cfg.instr_category[LOAD], cfg.instr_category[STORE]};
|
||||
allowed_instr = {allowed_instr, riscv_instr::instr_category[LOAD],
|
||||
riscv_instr::instr_category[STORE]};
|
||||
end
|
||||
setup_instruction_dist(no_branch, no_load_store);
|
||||
endfunction
|
||||
|
||||
function setup_instruction_dist(bit no_branch = 1'b0, bit no_load_store = 1'b1);
|
||||
function void setup_instruction_dist(bit no_branch = 1'b0, bit no_load_store = 1'b1);
|
||||
if (cfg.dist_control_mode) begin
|
||||
category_dist = cfg.category_dist;
|
||||
if (no_branch) begin
|
||||
|
@ -213,94 +213,51 @@ class riscv_rand_instr_stream extends riscv_instr_stream;
|
|||
end
|
||||
endfunction
|
||||
|
||||
function void randomize_instr(riscv_instr_base instr,
|
||||
bit is_in_debug = 1'b0,
|
||||
bit skip_rs1 = 1'b0,
|
||||
bit skip_rs2 = 1'b0,
|
||||
bit skip_rd = 1'b0,
|
||||
bit skip_imm = 1'b0,
|
||||
bit skip_csr = 1'b0,
|
||||
bit disable_dist = 1'b0);
|
||||
riscv_instr_name_t instr_name;
|
||||
if ((cfg.dist_control_mode == 1) && !disable_dist) begin
|
||||
riscv_instr_category_t category;
|
||||
int unsigned idx;
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(category,
|
||||
category dist {LOAD := category_dist[LOAD],
|
||||
STORE := category_dist[STORE],
|
||||
SHIFT := category_dist[SHIFT],
|
||||
ARITHMETIC := category_dist[ARITHMETIC],
|
||||
LOGICAL := category_dist[LOGICAL],
|
||||
COMPARE := category_dist[COMPARE],
|
||||
BRANCH := category_dist[BRANCH],
|
||||
SYNCH := category_dist[SYNCH],
|
||||
CSR := category_dist[CSR]};)
|
||||
idx = $urandom_range(0, cfg.instr_category[category].size() - 1);
|
||||
instr_name = cfg.instr_category[category][idx];
|
||||
// if set_dcsr_ebreak is set, we do not want to generate any ebreak
|
||||
// instructions inside the debug_rom
|
||||
end else if ((cfg.no_ebreak && !is_in_debug) ||
|
||||
(!cfg.enable_ebreak_in_debug_rom && is_in_debug)) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name,
|
||||
instr_name inside {allowed_instr};
|
||||
!(instr_name inside {EBREAK, C_EBREAK});)
|
||||
end else begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name,
|
||||
instr_name inside {allowed_instr};)
|
||||
end
|
||||
instr.copy_base_instr(cfg.instr_template[instr_name]);
|
||||
`uvm_info(`gfn, $sformatf("%s: rs1:%0d, rs2:%0d, rd:%0d, imm:%0d",
|
||||
instr.instr_name.name(),
|
||||
instr.has_rs1,
|
||||
instr.has_rs2,
|
||||
instr.has_rd,
|
||||
instr.has_imm), UVM_FULL)
|
||||
if (instr.has_imm && !skip_imm) begin
|
||||
instr.gen_rand_imm();
|
||||
end
|
||||
if (instr.has_rs1 && !skip_rs1) begin
|
||||
if (instr.is_compressed) begin
|
||||
// Compressed instruction could use the same register for rs1 and rd
|
||||
instr.rs1 = instr.gen_rand_gpr(
|
||||
.included_reg(avail_regs),
|
||||
.excluded_reg({reserved_rd, cfg.reserved_regs}));
|
||||
end else begin
|
||||
instr.rs1 = instr.gen_rand_gpr(.included_reg(avail_regs));
|
||||
end
|
||||
end
|
||||
if (instr.has_rs2 && !skip_rs2) begin
|
||||
instr.rs2 = instr.gen_rand_gpr(.included_reg(avail_regs));
|
||||
end
|
||||
if (instr.has_rd && !skip_rd) begin
|
||||
if (instr_name == C_LUI) begin
|
||||
instr.rd = instr.gen_rand_gpr(
|
||||
.included_reg(avail_regs),
|
||||
.excluded_reg({reserved_rd, cfg.reserved_regs, SP}));
|
||||
end else begin
|
||||
instr.rd = instr.gen_rand_gpr(
|
||||
.included_reg(avail_regs),
|
||||
.excluded_reg({reserved_rd, cfg.reserved_regs}));
|
||||
end
|
||||
end
|
||||
if ((instr.category == CSR) && !skip_csr) begin
|
||||
instr.gen_rand_csr(.privileged_mode(cfg.init_privileged_mode),
|
||||
.enable_floating_point(cfg.enable_floating_point),
|
||||
.illegal_csr_instr(cfg.enable_illegal_csr_instruction),
|
||||
.legal_invalid_csr_instr(cfg.enable_access_invalid_csr_level),
|
||||
.invalid_csrs(cfg.invalid_priv_mode_csrs));
|
||||
end
|
||||
if (instr.has_fs1) begin
|
||||
instr.fs1 = instr.gen_rand_fpr();
|
||||
end
|
||||
if (instr.has_fs2) begin
|
||||
instr.fs2 = instr.gen_rand_fpr();
|
||||
end
|
||||
if (instr.has_fs3) begin
|
||||
instr.fs3 = instr.gen_rand_fpr();
|
||||
end
|
||||
if (instr.has_fd) begin
|
||||
instr.fd = instr.gen_rand_fpr();
|
||||
function void randomize_instr(output riscv_instr instr,
|
||||
input bit is_in_debug = 1'b0,
|
||||
input bit disable_dist = 1'b0);
|
||||
riscv_instr_name_t exclude_instr[];
|
||||
if ((SP inside {reserved_rd, cfg.reserved_regs}) ||
|
||||
((avail_regs.size() > 0) && !(SP inside {avail_regs}))) begin
|
||||
exclude_instr = {C_ADDI4SPN, C_ADDI16SP, C_LWSP, C_LDSP};
|
||||
end
|
||||
instr = riscv_instr::get_rand_instr(.include_instr(allowed_instr),
|
||||
.exclude_instr(exclude_instr));
|
||||
randomize_gpr(instr);
|
||||
endfunction
|
||||
|
||||
function void randomize_gpr(ref riscv_instr instr);
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(instr,
|
||||
if (avail_regs.size() > 0) {
|
||||
if (has_rs1) {
|
||||
rs1 inside {avail_regs};
|
||||
}
|
||||
if (has_rs2) {
|
||||
rs2 inside {avail_regs};
|
||||
}
|
||||
if (has_rd) {
|
||||
rd inside {avail_regs};
|
||||
}
|
||||
}
|
||||
if (reserved_rd.size() > 0) {
|
||||
if (has_rd) {
|
||||
!(rd inside {reserved_rd});
|
||||
}
|
||||
if (format == CB_FORMAT) {
|
||||
!(rs1 inside {reserved_rd});
|
||||
}
|
||||
}
|
||||
if (cfg.reserved_regs.size() > 0) {
|
||||
if (has_rd) {
|
||||
!(rd inside {cfg.reserved_regs});
|
||||
}
|
||||
if (format == CB_FORMAT) {
|
||||
!(rs1 inside {cfg.reserved_regs});
|
||||
}
|
||||
}
|
||||
// TODO: Add constraint for CSR, floating point register
|
||||
)
|
||||
endfunction
|
||||
|
||||
|
||||
endclass
|
||||
|
|
|
@ -30,14 +30,23 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
|||
rand int base;
|
||||
int offset[];
|
||||
int addr[];
|
||||
riscv_instr_base load_store_instr[$];
|
||||
riscv_instr load_store_instr[$];
|
||||
rand int unsigned data_page_id;
|
||||
rand riscv_reg_t rs1_reg;
|
||||
rand locality_e locality;
|
||||
rand int max_load_store_offset;
|
||||
rand bit use_sp_as_rs1;
|
||||
|
||||
`uvm_object_utils(riscv_load_store_base_instr_stream)
|
||||
|
||||
constraint sp_c {
|
||||
solve use_sp_as_rs1 before rs1_reg;
|
||||
use_sp_as_rs1 dist {1 := 1, 0 := 2};
|
||||
if (use_sp_as_rs1) {
|
||||
rs1_reg == SP;
|
||||
}
|
||||
}
|
||||
|
||||
constraint rs1_c {
|
||||
!(rs1_reg inside {cfg.reserved_regs, reserved_rd, ZERO});
|
||||
}
|
||||
|
@ -64,7 +73,6 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
|||
addr = new[num_load_store];
|
||||
for (int i=0; i<num_load_store; i++) begin
|
||||
if (!std::randomize(offset_, addr_) with {
|
||||
// Locality
|
||||
if (locality == NARROW) {
|
||||
soft offset_ inside {[-16:16]};
|
||||
} else if (locality == HIGH) {
|
||||
|
@ -84,6 +92,14 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
|||
end
|
||||
endfunction
|
||||
|
||||
function void pre_randomize();
|
||||
super.pre_randomize();
|
||||
if (SP inside {cfg.reserved_regs, reserved_rd}) begin
|
||||
use_sp_as_rs1 = 0;
|
||||
use_sp_as_rs1.rand_mode(0);
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
randomize_offset();
|
||||
// rs1 cannot be modified by other instructions
|
||||
|
@ -99,7 +115,7 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
|||
// Generate each load/store instruction
|
||||
virtual function void gen_load_store_instr();
|
||||
bit enable_compressed_load_store;
|
||||
riscv_instr_base instr;
|
||||
riscv_instr instr;
|
||||
if(avail_regs.size() > 0) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(avail_regs,
|
||||
unique{avail_regs};
|
||||
|
@ -109,11 +125,10 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
|||
},
|
||||
"Cannot randomize avail_regs")
|
||||
end
|
||||
if ((rs1_reg inside {[S0 : A5]}) && !cfg.disable_compressed_instr) begin
|
||||
if ((rs1_reg inside {[S0 : A5], SP}) && !cfg.disable_compressed_instr) begin
|
||||
enable_compressed_load_store = 1;
|
||||
end
|
||||
foreach(addr[i]) begin
|
||||
instr = riscv_instr_base::type_id::create("instr");
|
||||
// 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};
|
||||
|
@ -129,9 +144,14 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
|||
if((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0) &&
|
||||
(RV32C inside {riscv_instr_pkg::supported_isa}) &&
|
||||
enable_compressed_load_store) begin
|
||||
allowed_instr = {C_LW, C_SW, allowed_instr};
|
||||
if (cfg.enable_floating_point && (RV32FC inside {supported_isa})) begin
|
||||
allowed_instr = {C_FLW, C_FSW, allowed_instr};
|
||||
if (rs1_reg == SP) begin
|
||||
`uvm_info(`gfn, "Add LWSP/SWSP to allowed instr", UVM_LOW)
|
||||
allowed_instr = {C_LWSP, C_SWSP};
|
||||
end else begin
|
||||
allowed_instr = {C_LW, C_SW, allowed_instr};
|
||||
if (cfg.enable_floating_point && (RV32FC inside {supported_isa})) begin
|
||||
allowed_instr = {C_FLW, C_FSW, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -143,31 +163,47 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
|||
if((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0) &&
|
||||
(RV64C inside {riscv_instr_pkg::supported_isa} &&
|
||||
enable_compressed_load_store)) begin
|
||||
allowed_instr = {C_LD, C_SD, allowed_instr};
|
||||
if (cfg.enable_floating_point && (RV32DC inside {supported_isa})) begin
|
||||
allowed_instr = {C_FLD, C_FSD, allowed_instr};
|
||||
if (rs1_reg == SP) begin
|
||||
allowed_instr = {C_LDSP, C_SDSP};
|
||||
end else begin
|
||||
allowed_instr = {C_LD, C_SD, allowed_instr};
|
||||
if (cfg.enable_floating_point && (RV32DC inside {supported_isa})) begin
|
||||
allowed_instr = {C_FLD, C_FSD, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
end else begin // unaligned load/store
|
||||
allowed_instr = {LW, SW, LH, LHU, SH, allowed_instr};
|
||||
// Compressed load/store still needs to be aligned
|
||||
if ((offset[i] inside {[0:127]}) && (offset[i] % 4 == 0) &&
|
||||
(RV32C inside {riscv_instr_pkg::supported_isa}) &&
|
||||
enable_compressed_load_store) begin
|
||||
allowed_instr = {C_LW, C_SW, allowed_instr};
|
||||
if (rs1_reg == SP) begin
|
||||
allowed_instr = {C_LWSP, C_SWSP};
|
||||
end else begin
|
||||
allowed_instr = {C_LW, C_SW, allowed_instr};
|
||||
end
|
||||
end
|
||||
if (XLEN >= 64) begin
|
||||
allowed_instr = {LWU, LD, SD, allowed_instr};
|
||||
if ((offset[i] inside {[0:255]}) && (offset[i] % 8 == 0) &&
|
||||
(RV64C inside {riscv_instr_pkg::supported_isa}) &&
|
||||
enable_compressed_load_store) begin
|
||||
allowed_instr = {C_LD, C_SD, allowed_instr};
|
||||
if (rs1_reg == SP) begin
|
||||
allowed_instr = {C_LWSP, C_SWSP};
|
||||
end else begin
|
||||
allowed_instr = {C_LD, C_SD, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
randomize_instr(instr, .skip_rs1(1'b1), .skip_imm(1'b1), .disable_dist(1'b1));
|
||||
instr = riscv_instr::get_load_store_instr(allowed_instr);
|
||||
instr.has_rs1 = 0;
|
||||
instr.has_imm = 0;
|
||||
randomize_gpr(instr);
|
||||
instr.rs1 = rs1_reg;
|
||||
instr.set_imm(offset[i]);
|
||||
instr.imm_str = $sformatf("%0d", $signed(offset[i]));
|
||||
instr.process_load_store = 0;
|
||||
instr_list.push_back(instr);
|
||||
load_store_instr.push_back(instr);
|
||||
|
@ -318,6 +354,7 @@ class riscv_multi_page_load_store_instr_stream extends riscv_mem_access_stream;
|
|||
load_store_instr_stream[i].min_instr_cnt = 5;
|
||||
load_store_instr_stream[i].max_instr_cnt = 10;
|
||||
load_store_instr_stream[i].cfg = cfg;
|
||||
load_store_instr_stream[i].sp_c.constraint_mode(0);
|
||||
// Make sure each load/store sequence doesn't override the rs1 of other sequences.
|
||||
foreach(rs1_reg[j]) begin
|
||||
if(i != j) begin
|
||||
|
@ -396,10 +433,10 @@ class riscv_load_store_rand_addr_instr_stream extends riscv_load_store_base_inst
|
|||
endfunction `uvm_object_new
|
||||
|
||||
virtual function void add_rs1_init_la_instr(riscv_reg_t gpr, int id, int base = 0);
|
||||
riscv_instr_base instr[$];
|
||||
riscv_instr instr[$];
|
||||
riscv_pseudo_instr li_instr;
|
||||
riscv_instr_base store_instr;
|
||||
riscv_instr_base add_instr;
|
||||
riscv_instr store_instr;
|
||||
riscv_instr add_instr;
|
||||
int min_offset[$];
|
||||
int max_offset[$];
|
||||
min_offset = offset.min();
|
||||
|
@ -413,9 +450,8 @@ class riscv_load_store_rand_addr_instr_stream extends riscv_load_store_base_inst
|
|||
)
|
||||
li_instr.imm_str = $sformatf("0x%0x", addr_offset);
|
||||
// Add offset to the base address
|
||||
add_instr = riscv_instr_base::type_id::create("add_instr");
|
||||
add_instr = riscv_instr::get_rand_instr(.include_instr({ADD}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(add_instr,
|
||||
instr_name == ADD;
|
||||
rs1 == gpr;
|
||||
rs2 == li_instr.rd;
|
||||
rd == gpr;
|
||||
|
@ -423,7 +459,7 @@ class riscv_load_store_rand_addr_instr_stream extends riscv_load_store_base_inst
|
|||
instr.push_back(li_instr);
|
||||
instr.push_back(add_instr);
|
||||
// Create SW instruction template
|
||||
store_instr = riscv_instr_base::type_id::create("store_instr");
|
||||
store_instr = riscv_instr::get_rand_instr(.include_instr({SB}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(store_instr,
|
||||
instr_name == SB;
|
||||
rs1 == gpr;
|
||||
|
@ -431,9 +467,9 @@ class riscv_load_store_rand_addr_instr_stream extends riscv_load_store_base_inst
|
|||
// Initialize the location which used by load instruction later
|
||||
foreach (load_store_instr[i]) begin
|
||||
if (load_store_instr[i].category == LOAD) begin
|
||||
riscv_instr_base store;
|
||||
store = riscv_instr_base::type_id::create("store");
|
||||
store.copy_base_instr(store_instr);
|
||||
riscv_instr store;
|
||||
store = riscv_instr::type_id::create("store");
|
||||
store.copy(store_instr);
|
||||
store.rs2 = riscv_reg_t'(i % 32);
|
||||
store.imm_str = load_store_instr[i].imm_str;
|
||||
case (load_store_instr[i].instr_name) inside
|
||||
|
|
38
vendor/google_riscv-dv/src/riscv_loop_instr.sv
vendored
38
vendor/google_riscv-dv/src/riscv_loop_instr.sv
vendored
|
@ -27,12 +27,12 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
|
|||
rand bit [2:0] num_of_nested_loop;
|
||||
rand int num_of_instr_in_loop;
|
||||
rand riscv_instr_name_t branch_type[];
|
||||
riscv_instr_base loop_init_instr[];
|
||||
riscv_instr_base loop_update_instr[];
|
||||
riscv_instr_base loop_branch_instr[];
|
||||
riscv_rand_instr loop_branch_target_instr[];
|
||||
riscv_instr loop_init_instr[];
|
||||
riscv_instr loop_update_instr[];
|
||||
riscv_instr loop_branch_instr[];
|
||||
riscv_instr loop_branch_target_instr[];
|
||||
// Aggregated loop instruction stream
|
||||
riscv_instr_base loop_instr[];
|
||||
riscv_instr loop_instr[];
|
||||
|
||||
constraint legal_loop_regs_c {
|
||||
solve num_of_nested_loop before loop_cnt_reg;
|
||||
|
@ -124,9 +124,8 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
|
|||
loop_branch_target_instr = new[num_of_nested_loop];
|
||||
for(int i = 0; i < num_of_nested_loop; i++) begin
|
||||
// Instruction to init the loop counter
|
||||
loop_init_instr[2*i] = riscv_instr_base::type_id::create("loop_init_instr");
|
||||
loop_init_instr[2*i] = riscv_instr::get_rand_instr(.include_instr({ADDI}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_init_instr[2*i],
|
||||
instr_name == ADDI;
|
||||
rd == loop_cnt_reg[i];
|
||||
rs1 == ZERO;
|
||||
imm == loop_init_val[i];,
|
||||
|
@ -134,9 +133,8 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
|
|||
loop_init_instr[2*i].comment = $sformatf("init loop %0d counter", i);
|
||||
|
||||
// Instruction to init loop limit
|
||||
loop_init_instr[2*i+1] = riscv_instr_base::type_id::create("loop_init_instr");
|
||||
loop_init_instr[2*i+1] = riscv_instr::get_rand_instr(.include_instr({ADDI}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_init_instr[2*i+1],
|
||||
instr_name == ADDI;
|
||||
rd == loop_limit_reg[i];
|
||||
rs1 == ZERO;
|
||||
imm == loop_limit_val[i];,
|
||||
|
@ -144,28 +142,30 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
|
|||
loop_init_instr[2*i+1].comment = $sformatf("init loop %0d limit", i);
|
||||
|
||||
// Branch target instruction, can be anything
|
||||
loop_branch_target_instr[i] = riscv_rand_instr::type_id::create("loop_branch_target_instr");
|
||||
loop_branch_target_instr[i].cfg = cfg;
|
||||
loop_branch_target_instr[i].reserved_rd = reserved_rd;
|
||||
loop_branch_target_instr[i] = riscv_instr::get_rand_instr(
|
||||
.include_category({ARITHMETIC, LOGICAL, COMPARE}),
|
||||
.exclude_instr({C_ADDI16SP}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_branch_target_instr[i],
|
||||
!(category inside {LOAD, STORE, BRANCH, JUMP});,
|
||||
"Cannot randomize branch target instruction")
|
||||
if (format == CB_FORMAT) {
|
||||
!(rs1 inside {reserved_rd, cfg.reserved_regs});
|
||||
}
|
||||
if (has_rd) {
|
||||
!(rd inside {reserved_rd, cfg.reserved_regs});
|
||||
}, "Cannot randomize branch target instruction")
|
||||
loop_branch_target_instr[i].label = $sformatf("%0s_%0d_t", label, i);
|
||||
|
||||
// Instruction to update loop counter
|
||||
loop_update_instr[i] = riscv_instr_base::type_id::create("loop_update_instr");
|
||||
loop_update_instr[i] = riscv_instr::get_rand_instr(.include_instr({ADDI}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_update_instr[i],
|
||||
instr_name == ADDI;
|
||||
rd == loop_cnt_reg[i];
|
||||
rs1== loop_cnt_reg[i];
|
||||
rs1 == loop_cnt_reg[i];
|
||||
imm == loop_step_val[i];,
|
||||
"Cannot randomize loop update instruction")
|
||||
loop_update_instr[i].comment = $sformatf("update loop %0d counter", i);
|
||||
|
||||
// Backward branch instruction
|
||||
loop_branch_instr[i] = riscv_instr_base::type_id::create("loop_branch_instr");
|
||||
loop_branch_instr[i] = riscv_instr::get_rand_instr(.include_instr({branch_type[i]}));
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_branch_instr[i],
|
||||
instr_name == branch_type[i];
|
||||
rs1 == loop_cnt_reg[i];
|
||||
if (!(branch_type[i] inside {C_BEQZ, C_BNEZ})) {
|
||||
rs2 == loop_limit_reg[i];
|
||||
|
|
32
vendor/google_riscv-dv/src/riscv_pseudo_instr.sv
vendored
Normal file
32
vendor/google_riscv-dv/src/riscv_pseudo_instr.sv
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Psuedo instructions are used to simplify assembly program writing
|
||||
class riscv_pseudo_instr extends `INSTR;
|
||||
|
||||
rand riscv_pseudo_instr_name_t pseudo_instr_name;
|
||||
|
||||
`add_pseudo_instr(LI, I_FORMAT, LOAD, RV32I)
|
||||
`add_pseudo_instr(LA, I_FORMAT, LOAD, RV32I)
|
||||
|
||||
`uvm_object_utils(riscv_pseudo_instr)
|
||||
|
||||
function new(string name = "");
|
||||
super.new(name);
|
||||
process_load_store = 0;
|
||||
this.format = I_FORMAT;
|
||||
endfunction
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2asm(string prefix = "");
|
||||
string asm_str;
|
||||
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
|
||||
// instr rd,imm
|
||||
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm());
|
||||
if(comment != "")
|
||||
asm_str = {asm_str, " #",comment};
|
||||
return asm_str.tolower();
|
||||
endfunction
|
||||
|
||||
virtual function string get_instr_name();
|
||||
return pseudo_instr_name.name();
|
||||
endfunction
|
||||
|
||||
endclass
|
18
vendor/google_riscv-dv/target/exp/riscvOVPsim.ic
vendored
Normal file
18
vendor/google_riscv-dv/target/exp/riscvOVPsim.ic
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
# riscOVPsim configuration file converted from YAML
|
||||
--variant RV64GC
|
||||
--override riscvOVPsim/cpu/misa_MXL=2
|
||||
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/unaligned=T
|
||||
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/user_version=2.3
|
||||
--override riscvOVPsim/cpu/priv_version=1.11
|
||||
--override riscvOVPsim/cpu/mvendorid=0
|
||||
--override riscvOVPsim/cpu/marchid=0
|
||||
--override riscvOVPsim/cpu/mimpid=0
|
||||
--override riscvOVPsim/cpu/mhartid=0
|
||||
--override riscvOVPsim/cpu/cycle_undefined=F
|
||||
--override riscvOVPsim/cpu/instret_undefined=F
|
||||
--override riscvOVPsim/cpu/time_undefined=T
|
||||
--override riscvOVPsim/cpu/reset_address=0x80000000
|
||||
--override riscvOVPsim/cpu/simulateexceptions=T
|
149
vendor/google_riscv-dv/target/exp/riscv_core_setting.sv
vendored
Normal file
149
vendor/google_riscv-dv/target/exp/riscv_core_setting.sv
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
`define EXPERIMENTAL
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 = 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, RV32C, RV64C, RV32A, RV64A,
|
||||
RV32F, RV64F, RV32D, RV64D};
|
||||
|
||||
// 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 = 1;
|
||||
|
||||
// Support unaligned load/store
|
||||
bit support_unaligned_load_store = 1'b1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Implemented previlieged CSR list
|
||||
`ifdef DSIM
|
||||
privileged_reg_t implemented_csr[] = {
|
||||
`else
|
||||
parameter privileged_reg_t implemented_csr[] = {
|
||||
`endif
|
||||
// User mode CSR
|
||||
USTATUS, // User status
|
||||
UIE, // User interrupt-enable register
|
||||
UTVEC, // User trap-handler base address
|
||||
USCRATCH, // Scratch register for user trap handlers
|
||||
UEPC, // User exception program counter
|
||||
UCAUSE, // User trap cause
|
||||
UTVAL, // User bad address or instruction
|
||||
UIP, // User interrupt pending
|
||||
// Supervisor mode CSR
|
||||
SSTATUS, // Supervisor status
|
||||
SEDELEG, // Supervisor exception delegation register
|
||||
SIDELEG, // Supervisor interrupt delegation register
|
||||
SIE, // Supervisor interrupt-enable register
|
||||
STVEC, // Supervisor trap-handler base address
|
||||
SCOUNTEREN, // Supervisor counter enable
|
||||
SSCRATCH, // Scratch register for supervisor trap handlers
|
||||
SEPC, // Supervisor exception program counter
|
||||
SCAUSE, // Supervisor trap cause
|
||||
STVAL, // Supervisor bad address or instruction
|
||||
SIP, // Supervisor interrupt pending
|
||||
SATP, // Supervisor address translation and protection
|
||||
// Machine mode mode CSR
|
||||
MVENDORID, // Vendor ID
|
||||
MARCHID, // Architecture ID
|
||||
MIMPID, // Implementation ID
|
||||
MHARTID, // Hardware thread ID
|
||||
MSTATUS, // Machine status
|
||||
MISA, // ISA and extensions
|
||||
MEDELEG, // Machine exception delegation register
|
||||
MIDELEG, // Machine interrupt delegation register
|
||||
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
|
||||
// Floating point CSR
|
||||
FCSR // Floating point control and status
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Supported interrupt/exception setting, used for functional coverage
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
`ifdef DSIM
|
||||
interrupt_cause_t implemented_interrupt[] = {
|
||||
`else
|
||||
parameter interrupt_cause_t implemented_interrupt[] = {
|
||||
`endif
|
||||
U_SOFTWARE_INTR,
|
||||
S_SOFTWARE_INTR,
|
||||
M_SOFTWARE_INTR,
|
||||
U_TIMER_INTR,
|
||||
S_TIMER_INTR,
|
||||
M_TIMER_INTR,
|
||||
U_EXTERNAL_INTR,
|
||||
S_EXTERNAL_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,
|
||||
STORE_AMO_ADDRESS_MISALIGNED,
|
||||
STORE_AMO_ACCESS_FAULT,
|
||||
ECALL_UMODE,
|
||||
ECALL_SMODE,
|
||||
ECALL_MMODE,
|
||||
INSTRUCTION_PAGE_FAULT,
|
||||
LOAD_PAGE_FAULT,
|
||||
STORE_AMO_PAGE_FAULT
|
||||
};
|
42
vendor/google_riscv-dv/target/exp/testlist.yaml
vendored
Normal file
42
vendor/google_riscv-dv/target/exp/testlist.yaml
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
# 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
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
- import: <riscv_dv_root>/target/rv64gc/testlist.yaml
|
||||
|
||||
- test: riscv_instr_test
|
||||
description: >
|
||||
New experimental instruction class test
|
||||
iterations: 0
|
||||
gen_test: riscv_instr_test
|
||||
gen_opts: >
|
||||
+instr_cnt=10000
|
||||
+num_of_sub_program=5
|
||||
+boot_mode=m
|
|
@ -48,6 +48,9 @@ bit support_umode_trap = 0;
|
|||
// Support sfence.vma instruction
|
||||
bit support_sfence = 0;
|
||||
|
||||
// Support unaligned load/store
|
||||
bit support_unaligned_load_store = 1'b1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -48,6 +48,9 @@ bit support_umode_trap = 0;
|
|||
// Support sfence.vma instruction
|
||||
bit support_sfence = 0;
|
||||
|
||||
// Support unaligned load/store
|
||||
bit support_unaligned_load_store = 1'b1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -48,6 +48,9 @@ bit support_umode_trap = 0;
|
|||
// Support sfence.vma instruction
|
||||
bit support_sfence = 0;
|
||||
|
||||
// Support unaligned load/store
|
||||
bit support_unaligned_load_store = 1'b1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -32,7 +32,6 @@ riscv_instr_name_t unsupported_instr[];
|
|||
// ISA supported by the processor
|
||||
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C, RV32A, RV64A,
|
||||
RV32F, RV64F, RV32D, RV64D};
|
||||
|
||||
// Interrupt mode support
|
||||
mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};
|
||||
|
||||
|
@ -49,6 +48,9 @@ bit support_umode_trap = 0;
|
|||
// Support sfence.vma instruction
|
||||
bit support_sfence = 1;
|
||||
|
||||
// Support unaligned load/store
|
||||
bit support_unaligned_load_store = 1'b1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -60,7 +60,6 @@
|
|||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+require_signature_addr=1
|
||||
+instr_cnt=6000
|
||||
+num_of_sub_program=0
|
||||
+enable_access_invalid_csr_level=1
|
||||
|
@ -122,8 +121,15 @@
|
|||
Enable floating point instructions
|
||||
gen_opts: >
|
||||
+enable_floating_point=1
|
||||
+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_multi_page_load_store_instr_stream,4
|
||||
+directed_instr_3=riscv_mem_region_stress_test,4
|
||||
+directed_instr_4=riscv_jal_instr,4
|
||||
iterations: 1
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_test: riscv_instr_base_test
|
||||
rtl_test: core_base_test
|
||||
|
||||
- test: riscv_floating_point_mmu_stress_test
|
||||
|
|
|
@ -48,6 +48,9 @@ bit support_umode_trap = 0;
|
|||
// Support sfence.vma instruction
|
||||
bit support_sfence = 0;
|
||||
|
||||
// Support unaligned load/store
|
||||
bit support_unaligned_load_store = 1'b1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -24,6 +24,8 @@ class riscv_instr_base_test extends uvm_test;
|
|||
riscv_asm_program_gen asm_gen;
|
||||
string instr_seq;
|
||||
int start_idx;
|
||||
uvm_coreservice_t coreservice;
|
||||
uvm_factory factory;
|
||||
|
||||
`uvm_component_utils(riscv_instr_base_test)
|
||||
|
||||
|
@ -35,6 +37,8 @@ class riscv_instr_base_test extends uvm_test;
|
|||
|
||||
virtual function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
coreservice = uvm_coreservice_t::get();
|
||||
factory = coreservice.get_factory();
|
||||
`uvm_info(`gfn, "Create configuration instance", UVM_LOW)
|
||||
cfg = riscv_instr_gen_config::type_id::create("cfg");
|
||||
`uvm_info(`gfn, "Create configuration instance...done", UVM_LOW)
|
||||
|
@ -43,10 +47,13 @@ class riscv_instr_base_test extends uvm_test;
|
|||
asm_file_name = {asm_file_name, ".", cfg.asm_test_suffix};
|
||||
// Override the default riscv instruction sequence
|
||||
if($value$plusargs("instr_seq=%0s", instr_seq)) begin
|
||||
uvm_coreservice_t coreservice = uvm_coreservice_t::get();
|
||||
uvm_factory factory = coreservice.get_factory();
|
||||
factory.set_type_override_by_name("riscv_instr_sequence", instr_seq);
|
||||
end
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
factory.set_inst_override_by_name("riscv_asm_program_gen",
|
||||
"riscv_debug_rom_gen",
|
||||
{`gfn, ".asm_gen.debug_rom"});
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void report_phase(uvm_phase phase);
|
||||
|
@ -73,12 +80,18 @@ class riscv_instr_base_test extends uvm_test;
|
|||
|
||||
task run_phase(uvm_phase phase);
|
||||
int fd;
|
||||
cfg.build_instruction_template();
|
||||
`ifdef DEPRECATED
|
||||
cfg.build_instruction_template();
|
||||
`endif
|
||||
for(int i = 0; i < cfg.num_of_tests; i++) begin
|
||||
string test_name;
|
||||
randomize_cfg();
|
||||
cfg.build_instruction_list();
|
||||
asm_gen = riscv_asm_program_gen::type_id::create("asm_gen");
|
||||
`ifdef DEPRECATED
|
||||
cfg.build_instruction_list();
|
||||
`else
|
||||
riscv_instr::create_instr_list(cfg);
|
||||
`endif
|
||||
asm_gen = riscv_asm_program_gen::type_id::create("asm_gen", , `gfn);
|
||||
asm_gen.cfg = cfg;
|
||||
asm_gen.get_directed_instr_stream();
|
||||
test_name = $sformatf("%0s_%0d.S", asm_file_name, i+start_idx);
|
||||
|
|
|
@ -4,6 +4,7 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
typedef uvm_enum_wrapper#(riscv_instr_name_t) instr_enum;
|
||||
typedef uvm_enum_wrapper#(riscv_reg_t) gpr_enum;
|
||||
typedef uvm_enum_wrapper#(privileged_reg_t) preg_enum;
|
||||
`VECTOR_INCLUDE("riscv_instr_cov_test_inc_typedef.sv")
|
||||
|
||||
riscv_instr_gen_config cfg;
|
||||
riscv_instr_cover_group instr_cg;
|
||||
|
@ -38,11 +39,17 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
cfg = riscv_instr_gen_config::type_id::create("cfg");
|
||||
// disable_compressed_instr is not relevant to coverage test
|
||||
cfg.disable_compressed_instr = 0;
|
||||
cfg.build_instruction_template(.skip_instr_exclusion(1));
|
||||
`ifdef DEPRECATED
|
||||
cfg.build_instruction_template(.skip_instr_exclusion(1));
|
||||
`else
|
||||
riscv_instr::create_instr_list(cfg);
|
||||
`endif
|
||||
instr = riscv_instr_cov_item::type_id::create("instr");
|
||||
instr.rand_mode(0);
|
||||
`ifdef DEPRECATED
|
||||
instr.no_hint_illegal_instr_c.constraint_mode(0);
|
||||
instr.imm_val_c.constraint_mode(0);
|
||||
`endif
|
||||
instr_cg = new(cfg);
|
||||
`uvm_info(`gfn, $sformatf("%0d CSV trace files to be processed", trace_csv.size()), UVM_LOW)
|
||||
foreach (trace_csv[i]) begin
|
||||
|
@ -81,16 +88,11 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
// TODO: Enable functional coverage for AMO test
|
||||
continue;
|
||||
end
|
||||
`uvm_info(`gfn, $sformatf("Processing line[%0d] : %0s",
|
||||
entry_cnt, trace["str"]), UVM_FULL)
|
||||
if (!sample()) begin
|
||||
if (expect_illegal_instr) begin
|
||||
`uvm_info(`gfn, $sformatf("Found illegal instr: %0s [%0s]",
|
||||
trace["instr"], line), UVM_HIGH)
|
||||
end else begin
|
||||
unexpected_illegal_instr_cnt += 1;
|
||||
`uvm_error(`gfn, $sformatf("Found illegal instr: %0s [%0s]",
|
||||
trace["instr"], line))
|
||||
`uvm_info(`gfn, $sformatf("Found illegal instr: %0s [%0s]",
|
||||
trace["instr"], line), UVM_HIGH)
|
||||
if (!expect_illegal_instr) begin
|
||||
unexpected_illegal_instr_cnt++;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -108,39 +110,55 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
if ((skipped_cnt > 0) || (unexpected_illegal_instr_cnt > 0)) begin
|
||||
`uvm_error(`gfn, $sformatf("%0d instructions skipped, %0d illegal instruction",
|
||||
skipped_cnt, unexpected_illegal_instr_cnt))
|
||||
|
||||
end else begin
|
||||
`uvm_info(`gfn, "TEST PASSED", UVM_NONE);
|
||||
end
|
||||
endtask
|
||||
|
||||
virtual function void post_process_trace();
|
||||
endfunction
|
||||
|
||||
function void fatal (string str);
|
||||
`uvm_info(`gfn, str, UVM_NONE);
|
||||
if ($test$plusargs("stop_on_first_error")) begin
|
||||
`uvm_fatal(`gfn, "Errors: *. Warnings: * (written by riscv_instr_cov.sv)")
|
||||
end
|
||||
endfunction
|
||||
|
||||
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
|
||||
`ifdef DEPRECATED
|
||||
if (cfg.instr_template.exists(instr_name)) begin
|
||||
instr.copy_base_instr(cfg.instr_template[instr_name]);
|
||||
`else
|
||||
if (riscv_instr::instr_template.exists(instr_name)) begin
|
||||
instr.copy(riscv_instr::instr_template[instr_name]);
|
||||
`endif
|
||||
assign_trace_info_to_instr(instr);
|
||||
instr.pre_sample();
|
||||
instr_cg.sample(instr);
|
||||
return 1'b1;
|
||||
end
|
||||
end
|
||||
`uvm_info(`gfn, $sformatf("Cannot find opcode: %0s",
|
||||
process_instr_name(trace["instr"])), UVM_LOW)
|
||||
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);
|
||||
`SAMPLE(instr_cg.compressed_opcode_cg, val[15:0])
|
||||
`SAMPLE(instr_cg.illegal_compressed_instr_cg, 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]);
|
||||
`uvm_info("DBG", $sformatf("Sample opcode: %0x [%0s]", val[6:2], trace["instr"]), UVM_LOW)
|
||||
`SAMPLE(instr_cg.opcode_cg, val[6:2])
|
||||
end
|
||||
return 1'b0;
|
||||
endfunction
|
||||
|
||||
virtual function void assign_trace_info_to_instr(riscv_instr_cov_item instr);
|
||||
riscv_reg_t gpr;
|
||||
`VECTOR_INCLUDE("riscv_instr_cov_test_inc_assign_trace_info_to_instr_declares.sv")
|
||||
privileged_reg_t preg;
|
||||
get_val(trace["addr"], instr.pc);
|
||||
get_val(trace["binary"], instr.binary);
|
||||
|
@ -154,7 +172,7 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
instr.rs2 = gpr;
|
||||
get_val(trace["rs2_val"], instr.rs2_value);
|
||||
end else begin
|
||||
`uvm_error(`gfn, $sformatf("Unrecoganized rs2: [%0s] (%0s)",
|
||||
`uvm_error(`gfn, $sformatf("Unrecognized rs2: [%0s] (%0s)",
|
||||
trace["rs2"], trace["csv_entry"]))
|
||||
end
|
||||
end
|
||||
|
@ -163,7 +181,7 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
instr.rd = gpr;
|
||||
get_val(trace["rd_val"], instr.rd_value);
|
||||
end else begin
|
||||
`uvm_error(`gfn, $sformatf("Unrecoganized rd: [%0s] (%0s)",
|
||||
`uvm_error(`gfn, $sformatf("Unrecognized rd: [%0s] (%0s)",
|
||||
trace["rd"], trace["csv_entry"]))
|
||||
end
|
||||
end
|
||||
|
@ -176,7 +194,7 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
instr.rs1 = gpr;
|
||||
get_val(trace["rs1_val"], instr.rs1_value);
|
||||
end else begin
|
||||
`uvm_error(`gfn, $sformatf("Unrecoganized rs1: [%0s] (%0s)",
|
||||
`uvm_error(`gfn, $sformatf("Unrecognized rs1: [%0s] (%0s)",
|
||||
trace["rs1"], trace["csv_entry"]))
|
||||
end
|
||||
end
|
||||
|
@ -204,6 +222,9 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
instr.mem_addr = instr.rs1_value + {padding, instr.imm};
|
||||
end
|
||||
end
|
||||
|
||||
`VECTOR_INCLUDE("riscv_instr_cov_test_inc_assign_trace_info_to_instr.sv")
|
||||
|
||||
endfunction
|
||||
|
||||
function bit get_gpr(input string str, output riscv_reg_t gpr);
|
||||
|
@ -215,6 +236,8 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
end
|
||||
endfunction
|
||||
|
||||
`VECTOR_INCLUDE("riscv_instr_cov_test_inc_assign_trace_info_to_instr_functions.sv")
|
||||
|
||||
function void get_val(input string str, output bit [XLEN-1:0] val);
|
||||
val = str.atohex();
|
||||
endfunction
|
||||
|
|
58
vendor/google_riscv-dv/test/riscv_instr_test.sv
vendored
Normal file
58
vendor/google_riscv-dv/test/riscv_instr_test.sv
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Sanity test for riscv_instr_test class
|
||||
class riscv_instr_test extends riscv_instr_base_test;
|
||||
|
||||
`uvm_component_utils(riscv_instr_test)
|
||||
`uvm_component_new
|
||||
|
||||
task run_phase(uvm_phase phase);
|
||||
int fd;
|
||||
riscv_instr instr;
|
||||
riscv_instr_name_t instr_name;
|
||||
string test_name = $sformatf("%0s_0.S", asm_file_name);
|
||||
fd = $fopen(test_name,"w");
|
||||
`uvm_info(`gfn, "Creating instruction list", UVM_LOW)
|
||||
riscv_instr::create_instr_list(cfg);
|
||||
`uvm_info(`gfn, "Randomizing instruction list now...", UVM_LOW)
|
||||
repeat (10000) begin
|
||||
instr = riscv_instr::get_rand_instr();
|
||||
`DV_CHECK_RANDOMIZE_FATAL(instr);
|
||||
$fwrite(fd, {instr.convert2asm(),"\n"});
|
||||
end
|
||||
repeat (10000) begin
|
||||
instr = riscv_instr::get_rand_instr(.include_category({LOAD, STORE}));
|
||||
`DV_CHECK_RANDOMIZE_FATAL(instr);
|
||||
$fwrite(fd, {instr.convert2asm(),"\n"});
|
||||
end
|
||||
repeat (10000) begin
|
||||
instr = riscv_instr::get_rand_instr(.exclude_category({LOAD, STORE , BRANCH}),
|
||||
.include_group({RV32I, RV32M}));
|
||||
`DV_CHECK_RANDOMIZE_FATAL(instr);
|
||||
$fwrite(fd, {instr.convert2asm(),"\n"});
|
||||
end
|
||||
$fclose(fd);
|
||||
`uvm_info(get_full_name(), $sformatf("%0s is generated", test_name), UVM_LOW)
|
||||
endtask
|
||||
|
||||
virtual function void randomize_cfg();
|
||||
`DV_CHECK_RANDOMIZE_FATAL(cfg);
|
||||
`uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
|
||||
cfg.sprint()), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
endclass
|
|
@ -23,5 +23,8 @@ package riscv_instr_test_pkg;
|
|||
`include "riscv_instr_test_lib.sv"
|
||||
`include "riscv_instr_cov_debug_test.sv"
|
||||
`include "riscv_instr_cov_test.sv"
|
||||
`ifdef EXPERIMENTAL
|
||||
`include "riscv_instr_test.sv"
|
||||
`endif
|
||||
|
||||
endpackage
|
||||
|
|
|
@ -59,7 +59,6 @@
|
|||
+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
|
||||
+directed_instr_7=riscv_load_store_rand_addr_instr_stream,4
|
||||
rtl_test: core_base_test
|
||||
|
||||
- test: riscv_jump_stress_test
|
||||
|
@ -91,7 +90,7 @@
|
|||
gen_test: riscv_instr_base_test
|
||||
gen_opts: >
|
||||
+instr_cnt=10000
|
||||
+num_of_sub_program=20
|
||||
+num_of_sub_program=10
|
||||
+directed_instr_0=riscv_load_store_rand_instr_stream,8
|
||||
rtl_test: core_base_test
|
||||
|
||||
|
@ -151,10 +150,8 @@
|
|||
gen_opts: >
|
||||
+instr_cnt=6000
|
||||
+no_ebreak=0
|
||||
+require_signature_addr=1
|
||||
rtl_test: core_base_test
|
||||
sim_opts: >
|
||||
+require_signature_addr=1
|
||||
+enable_debug_seq=1
|
||||
compare_opts: >
|
||||
+compare_final_value_only=1
|
||||
|
@ -166,11 +163,9 @@
|
|||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+enable_interrupt=1
|
||||
+require_signature_addr=1
|
||||
rtl_test: core_base_test
|
||||
sim_opts: >
|
||||
+enable_irq_seq=1
|
||||
+require_signature_addr=1
|
||||
compare_opts: >
|
||||
+compare_final_value_only=1
|
||||
|
||||
|
|
16
vendor/google_riscv-dv/yaml/simulator.yaml
vendored
16
vendor/google_riscv-dv/yaml/simulator.yaml
vendored
|
@ -68,6 +68,7 @@
|
|||
cov_opts: >
|
||||
-do "coverage save -onexit <out>/cov.ucdb;"
|
||||
|
||||
# TODO: Remove +DEPRECATED for dsim
|
||||
- tool: dsim
|
||||
env_var: DSIM,DSIM_LIB_PATH
|
||||
compile:
|
||||
|
@ -76,6 +77,7 @@
|
|||
- "<DSIM> -sv -work <out>/dsim
|
||||
-genimage image
|
||||
+incdir+$UVM_HOME/src
|
||||
+define+DEPRECATED
|
||||
$UVM_HOME/src/uvm_pkg.sv
|
||||
+define+DSIM
|
||||
+incdir+<setting>
|
||||
|
@ -86,3 +88,17 @@
|
|||
cmd: >
|
||||
<DSIM> <sim_opts> -sv_seed <seed> -pli_lib <DSIM_LIB_PATH>/libuvm_dpi.so +acc+rwb -image image -work <out>/dsim
|
||||
|
||||
- tool: qrun
|
||||
compile:
|
||||
cmd:
|
||||
- "qrun -f <cwd>/qrun_option.f
|
||||
+incdir+<setting>
|
||||
+incdir+<user_extension>
|
||||
-f <cwd>/files.f <cmp_opts>
|
||||
-l <out>/qrun_compile_optimize.log
|
||||
-outdir <out>/qrun.out"
|
||||
sim:
|
||||
cmd: >
|
||||
qrun -64 -simulate -snapshot design_opt -c <cov_opts> <sim_opts> -sv_seed <seed> -outdir <out>/qrun.out
|
||||
cov_opts: >
|
||||
-coverage -ucdb <out>/cov.ucdb
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue