mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-23 05:27:30 -04:00
Update google_riscv-dv to google/riscv-dv@4b333ba (#462)
Update code from upstream repository https://github.com/google/riscv- dv to revision 4b333ba1ef285ec4508c606efa64610136154a5e * cg instantion based on supported_isa (google/riscv-dv#303) (udinator) * Fix coverage collection issue, change default target to rv32imc (google/riscv-dv#302) (taoliug) * Integrate whisper(swerv-ISS) (google/riscv-dv#301) (taoliug) * Fix cov.py, set UVM_VERBOSITY to UVM_HIGH for verbose mode (google/riscv-dv#299) (taoliug) * Fix jalr handling issue for ovpsim (google/riscv-dv#298) (taoliug) * Add noclean option, change default output directory of coverage collection (google/riscv-dv#297) (taoliug) * Enable using core trace logs for coverage collection (google/riscv- dv#291) (udinator) * Fix isa/mabi setup issue for RV64GC target (google/riscv-dv#296) (taoliug) * fixed line widths (x2) and check error returns for any questa simalator (google/riscv-dv#293) (simond-imperas) * Unknown instruction fix (google/riscv-dv#290) (simond-imperas) * Fix ovpsim log process issue (google/riscv-dv#289) (udinator) * adding riscvOVPsim vector instruction trace to csv processing - start (3rd Attempt) (google/riscv-dv#288) (simond-imperas) Signed-off-by: Udi <udij@google.com>
This commit is contained in:
parent
1cc4831480
commit
6ce8b6ecf2
14 changed files with 579 additions and 183 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: 44bec7695fd2399166e181fa84b66a608b5f745f
|
||||
rev: 4b333ba1ef285ec4508c606efa64610136154a5e
|
||||
}
|
||||
}
|
||||
|
|
2
vendor/google_riscv-dv/.gitignore
vendored
2
vendor/google_riscv-dv/.gitignore
vendored
|
@ -1,6 +1,6 @@
|
|||
*.ini
|
||||
*.bin
|
||||
out_*/
|
||||
*out_*/
|
||||
work/
|
||||
*.pyc
|
||||
/.cproject
|
||||
|
|
20
vendor/google_riscv-dv/README.md
vendored
20
vendor/google_riscv-dv/README.md
vendored
|
@ -65,12 +65,18 @@ one of below to run ISS simulation.
|
|||
- [riscv-ovpsim](https://github.com/riscv/riscv-ovpsim) setup
|
||||
- Download the riscv-ovpsim binary
|
||||
- Set environment variable OVPSIM_PATH to the directory of the ovpsim binary
|
||||
- [whisper(swerv-ISS)](https://github.com/westerndigitalcorporation/swerv-ISS) setup
|
||||
- Follow the instruction to install the ISS, and set WHISPER_ISS to the
|
||||
whisper binary
|
||||
- [sail-riscv](https://github.com/rems-project/sail-riscv) setup
|
||||
- Follow the [steps](https://github.com/rems-project/sail-riscv/blob/master/README.md) to install sail-riscv
|
||||
- Set environment variable SAIL_RISCV to the sail-riscv binary
|
||||
|
||||
```bash
|
||||
export SPIKE_PATH=$RISCV_TOOLCHAIN/bin
|
||||
export SAIL_RISCV="xx/xxx/riscv_ocaml_sim_RV64"
|
||||
export OVPSIM_PATH=/xx/xxx/riscv-ovpsim/bin/Linux64
|
||||
export WHISPER_ISS="xx/xxx/swerv-ISS/build-Linux/whisper"
|
||||
```
|
||||
|
||||
## Running the generator
|
||||
|
@ -144,6 +150,9 @@ python3 run.py --test riscv_arithmetic_basic_test --iss spike
|
|||
# Run ISS with riscv-ovpsim
|
||||
python3 run.py --test riscv_rand_instr_test --iss ovpsim
|
||||
|
||||
# Run ISS with whisper (swerv-ISS)
|
||||
python3 run.py --test riscv_rand_instr_test --iss whisper
|
||||
|
||||
# Run ISS with sail-riscv
|
||||
python3 run.py --test riscv_rand_instr_test --iss sail
|
||||
```
|
||||
|
@ -163,6 +172,7 @@ real RISC-V processor.
|
|||
|
||||
```bash
|
||||
python3 run.py --test=riscv_rand_instr_test --iss=spike,ovpsim
|
||||
python3 run.py --test=riscv_rand_instr_test --iss=ovpsim,whisper
|
||||
python3 run.py --test=riscv_rand_instr_test --iss=spike,sail
|
||||
```
|
||||
|
||||
|
@ -459,11 +469,11 @@ For more information, detailed documentation of this mechanism can be found in
|
|||
## Functional coverage (work in progress)
|
||||
|
||||
This flow extracts functional coverage information from the
|
||||
instruction trace generated by ISS. It's indepdent of the instruction generation
|
||||
instruction trace generated by ISS. It's independent of the instruction generation
|
||||
flow and does not require a tracer implementation in the RTL. You can use this
|
||||
flow as long as your program can be run with the ISS supported in this flow. The
|
||||
flow as long as your program can be run with an ISS supported in this flow. The
|
||||
flow parses the instruction trace log and converts it to a CSV trace format. After
|
||||
that, a SV test will be run to process the CSV trace files and sample functional
|
||||
that, a SV test is run to process the CSV trace files and sample functional
|
||||
coverage from there.
|
||||
|
||||
The functional covergroup is defined in [riscv_instr_cover_group.sv](https://github.com/google/riscv-dv/blob/master/src/riscv_instr_cover_group.sv). It includes below major categories:
|
||||
|
@ -476,13 +486,13 @@ The functional covergroup is defined in [riscv_instr_cover_group.sv](https://git
|
|||
- Hint instruction
|
||||
- Illegal instruction
|
||||
- All compressed and non-compressed opcode
|
||||
- Access to all implemened privieleged CSR
|
||||
- Access to all implemened privileged CSR
|
||||
- Exception and interrupt
|
||||
|
||||
The functional covergroup is still under active development. Please feel free to
|
||||
add anything you are interested or file a bug for any feature request.
|
||||
|
||||
Before start, please check the you have modified [riscv_core_setting.sv](https://github.com/google/riscv-dv/blob/master/setting/riscv_core_setting.sv) to reflect your processor capabilities. The covergroup is selectively instantiated based on this setting so that you don't need to deal with excluding unrelated coverpoints later. You also need to get the Spike ISS setup before running this flow.
|
||||
Before start, please check the you have modified [riscv_core_setting.sv](https://github.com/google/riscv-dv/blob/master/setting/riscv_core_setting.sv) to reflect your processor capabilities. The covergroup is selectively instantiated based on this setting so that you don't need to deal with excluding unrelated coverpoints later. You also need to get the Spike ISS or riscvOVPsim ISS (riscv-ovpsim) setup before running this flow.
|
||||
|
||||
|
||||
```bash
|
||||
|
|
114
vendor/google_riscv-dv/cov.py
vendored
114
vendor/google_riscv-dv/cov.py
vendored
|
@ -31,31 +31,44 @@ from scripts.sail_log_to_trace_csv import *
|
|||
|
||||
LOGGER = logging.getLogger()
|
||||
|
||||
def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, \
|
||||
opts, timeout, simulator, simulator_yaml, custom_target, target):
|
||||
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):
|
||||
"""Collect functional coverage from the instruction trace
|
||||
|
||||
Args:
|
||||
log_dir : ISS log directory
|
||||
out : Output directory
|
||||
iss : Instruction set simulator
|
||||
test_list : Testlist of the coverage test
|
||||
batch_size : Number of trace CSV to process per test
|
||||
lsf_cmd : LSF command used to run the instruction generator
|
||||
steps : csv:log to CSV, cov:sample coverage
|
||||
opts : Additional options to the instruction generator
|
||||
timeout : Timeout limit in seconds
|
||||
simulator : RTL simulator used to run
|
||||
simulator_yaml : RTL simulator configuration file in YAML format
|
||||
custom_target : Path for the custom target dir
|
||||
target : Predefined target
|
||||
log_dir : Trace log directory
|
||||
out : Output directory
|
||||
core : RISC-V core to be used for analysis
|
||||
iss : Instruction set simulator
|
||||
testlist : Testlist of the coverage test
|
||||
batch_size : Number of trace CSV to process per test
|
||||
lsf_cmd : LSF command used to run the instruction generator
|
||||
steps : csv:log to CSV, cov:sample coverage
|
||||
opts : Additional options to the instruction generator
|
||||
timeout : Timeout limit in seconds
|
||||
simulator : RTL simulator used to run
|
||||
simulator_yaml : RTL simulator configuration file in YAML format
|
||||
custom_target : Path for the custom target dir
|
||||
isa : RISC-V ISA variant
|
||||
target : Predefined target
|
||||
stop_on_first_error : will end run on first error detected
|
||||
"""
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
log_list = []
|
||||
csv_list = []
|
||||
trace_log = ("%s/%s_trace_log" % (out, iss))
|
||||
logging.info("Processing trace log under %s" % log_dir)
|
||||
run_cmd("find %s -name \"*.log\" | sort > %s" % (log_dir, trace_log))
|
||||
if core:
|
||||
"""
|
||||
If functional coverage is being collected from an RTL core implementation,
|
||||
the flow assumes that the core's trace logs have already been converted to
|
||||
CSV files by the post_compare step of the flow.
|
||||
"""
|
||||
trace_log = ("%s/%s_trace_log" % (out, core))
|
||||
run_cmd("find %s -name \"*.csv\" | sort > %s" % (log_dir, trace_log))
|
||||
else:
|
||||
trace_log = ("%s/%s_trace_log" % (out, iss))
|
||||
run_cmd("find %s -name \"*.log\" | sort > %s" % (log_dir, trace_log))
|
||||
with open(trace_log) as f:
|
||||
for line in f:
|
||||
line = line.rstrip()
|
||||
|
@ -66,14 +79,18 @@ def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, \
|
|||
for i in range(len(log_list)):
|
||||
log = log_list[i]
|
||||
csv = csv_list[i]
|
||||
logging.info("Process %0s log[%0d/%0d] : %s" % (iss, i+1, len(log_list), log))
|
||||
if iss == "spike":
|
||||
process_spike_sim_log(log, csv, 1)
|
||||
elif iss == "ovpsim":
|
||||
process_ovpsim_sim_log(log, csv, 1)
|
||||
# If a core target is defined, prioritize over ISS
|
||||
if core:
|
||||
logging.info("Process %0s log[%0d/%0d] : %s" % (core, i+1, len(log_list), log))
|
||||
else:
|
||||
logging.error("Full trace for %s is not supported yet" % iss)
|
||||
sys.exit(1)
|
||||
logging.info("Process %0s log[%0d/%0d] : %s" % (iss, i+1, len(log_list), log))
|
||||
if iss == "spike":
|
||||
process_spike_sim_log(log, csv, 1)
|
||||
elif iss == "ovpsim":
|
||||
process_ovpsim_sim_log(log, csv, 1, stop_on_first_error)
|
||||
else:
|
||||
logging.error("Full trace for %s is not supported yet" % iss)
|
||||
sys.exit(1)
|
||||
if steps == "all" or re.match("cov", steps):
|
||||
build_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s "
|
||||
" --co -o %s --cov -tl %s %s " %
|
||||
|
@ -91,7 +108,8 @@ def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, \
|
|||
if custom_target:
|
||||
base_sim_cmd += (" --custom_target %s" % custom_target)
|
||||
logging.info("Building the coverage collection framework")
|
||||
run_cmd(build_cmd)
|
||||
output = run_cmd(build_cmd)
|
||||
check_simulator_return(output, simulator, stop_on_first_error)
|
||||
file_idx = 0
|
||||
trace_idx = 0
|
||||
trace_csv_opts = ""
|
||||
|
@ -115,6 +133,7 @@ def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, \
|
|||
if lsf_cmd == "":
|
||||
logging.info("Processing batch %0d/%0d" % (file_idx+1, batch_cnt))
|
||||
run_cmd(sim_cmd)
|
||||
check_simulator_return(output, simulator, stop_on_first_error)
|
||||
else:
|
||||
sim_cmd += (" --lsf_cmd \"%s\"" % lsf_cmd)
|
||||
sim_cmd_list.append(sim_cmd)
|
||||
|
@ -125,7 +144,7 @@ def collect_cov(log_dir, out, iss, testlist, batch_size, lsf_cmd, steps, \
|
|||
|
||||
|
||||
def run_cov_debug_test(out, instr_cnt, testlist, batch_size, opts, lsf_cmd,\
|
||||
timeout, simulator, simulator_yaml, custom_target, target):
|
||||
timeout, simulator, simulator_yaml, custom_target, isa, target):
|
||||
"""Collect functional coverage from the instruction trace
|
||||
|
||||
Args:
|
||||
|
@ -139,6 +158,7 @@ def run_cov_debug_test(out, instr_cnt, testlist, batch_size, opts, lsf_cmd,\
|
|||
simulator : RTL simulator used to run
|
||||
simulator_yaml : RTL simulator configuration file in YAML format
|
||||
custom_target : Path for the custom target dir
|
||||
isa : RISC-V ISA variant
|
||||
target : Predefined target
|
||||
"""
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
|
@ -153,10 +173,10 @@ def run_cov_debug_test(out, instr_cnt, testlist, batch_size, opts, lsf_cmd,\
|
|||
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 %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, opts))
|
||||
(cwd, simulator, simulator_yaml, out, testlist, isa, opts))
|
||||
if target:
|
||||
base_sim_cmd += (" --target %s" % target)
|
||||
if custom_target:
|
||||
|
@ -200,7 +220,7 @@ def setup_parser():
|
|||
parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
|
||||
help="Verbose logging")
|
||||
parser.add_argument("--dir", type=str,
|
||||
help="Directory of ISS log")
|
||||
help="Directory of trace log files")
|
||||
parser.add_argument("-bz", "--batch_size", dest="batch_size", type=int, default=0,
|
||||
help="Number of CSV to process per run")
|
||||
parser.add_argument("-d", "--debug_mode", dest="debug_mode", action="store_true",
|
||||
|
@ -211,6 +231,10 @@ def setup_parser():
|
|||
help="Number of CSV to process per run")
|
||||
parser.add_argument("-s", "--steps", type=str, default="all",
|
||||
help="Run steps: csv,cov", dest="steps")
|
||||
parser.add_argument("--core", type=str, default="",
|
||||
help="Name of target core")
|
||||
parser.add_argument("--isa", type=str, default="",
|
||||
help="RISC-V ISA variant")
|
||||
parser.add_argument("--iss", type=str, default="spike",
|
||||
help="RISC-V instruction set simulator: spike,ovpsim,sail")
|
||||
parser.add_argument("-tl", "--testlist", type=str, default="",
|
||||
|
@ -224,15 +248,21 @@ def setup_parser():
|
|||
help="Run the generator with pre-defined targets: \
|
||||
rv32imc, rv32i, rv64imc, rv64gc")
|
||||
parser.add_argument("-si", "--simulator", type=str, default="vcs",
|
||||
help="Simulator used to run the generator, default VCS", dest="simulator")
|
||||
help="Simulator used to run the generator, \
|
||||
default VCS", dest="simulator")
|
||||
parser.add_argument("--simulator_yaml", type=str, default="",
|
||||
help="RTL simulator setting YAML")
|
||||
parser.add_argument("-ct", "--custom_target", type=str, default="",
|
||||
help="Directory name of the custom target")
|
||||
parser.add_argument("-cs", "--core_setting_dir", type=str, default="",
|
||||
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("--noclean", action="store_true",
|
||||
help="Do not clean the output of the previous runs")
|
||||
return parser
|
||||
|
||||
def main():
|
||||
|
@ -255,6 +285,10 @@ def main():
|
|||
if args.debug_mode:
|
||||
args.target = "rv64gc"
|
||||
|
||||
# Disable ISS coverage if a core is passed in
|
||||
if args.core:
|
||||
args.iss = ""
|
||||
|
||||
# Keep the core_setting_dir option to be backward compatible, suggest to use
|
||||
# --custom_target
|
||||
if args.core_setting_dir:
|
||||
|
@ -265,25 +299,31 @@ def main():
|
|||
|
||||
if not args.custom_target:
|
||||
args.core_setting_dir = cwd + "/target/"+ args.target
|
||||
else:
|
||||
args.testlist = args.custom_target + "/testlist.yaml"
|
||||
|
||||
args.testlist = cwd + "/yaml/cov_testlist.yaml" ## needed if need to force
|
||||
|
||||
# Create output directory
|
||||
if args.o is None:
|
||||
output_dir = "out_" + str(date.today())
|
||||
output_dir = "cov_out_" + str(date.today())
|
||||
else:
|
||||
output_dir = args.o
|
||||
|
||||
if args.noclean is False:
|
||||
os.system("rm -rf %s" % output_dir)
|
||||
|
||||
subprocess.run(["mkdir", "-p", output_dir])
|
||||
|
||||
if args.debug_mode:
|
||||
run_cov_debug_test(output_dir, args.instr_cnt, args.testlist,
|
||||
args.batch_size, args.opts, args.lsf_cmd, args.timeout,
|
||||
args.simulator, args.simulator_yaml, args.custom_target, args.target)
|
||||
args.simulator, args.simulator_yaml, args.custom_target,
|
||||
args.isa, args.target)
|
||||
else:
|
||||
collect_cov(args.dir, output_dir, args.iss, args.testlist, args.batch_size,
|
||||
args.lsf_cmd, args.steps, args.opts, args.timeout,
|
||||
args.simulator, args.simulator_yaml, args.custom_target, args.target)
|
||||
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)
|
||||
logging.info("Coverage results are saved to %s" % output_dir)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
50
vendor/google_riscv-dv/run.py
vendored
50
vendor/google_riscv-dv/run.py
vendored
|
@ -27,6 +27,7 @@ from datetime import date
|
|||
from scripts.lib import *
|
||||
from scripts.spike_log_to_trace_csv import *
|
||||
from scripts.ovpsim_log_to_trace_csv import *
|
||||
from scripts.whisper_log_trace_csv import *
|
||||
from scripts.sail_log_to_trace_csv import *
|
||||
from scripts.instr_trace_compare import *
|
||||
|
||||
|
@ -95,6 +96,16 @@ def parse_iss_yaml(iss, iss_yaml, isa, setting_dir):
|
|||
cmd = re.sub("\<path_var\>", get_env_var(entry['path_var']), cmd)
|
||||
if iss == "ovpsim":
|
||||
cmd = re.sub("\<cfg_path\>", setting_dir, cmd)
|
||||
elif iss == "whisper":
|
||||
m = re.search(r"rv(?P<xlen>[0-9]+?)(?P<variant>[a-z]+?)$", isa)
|
||||
if m:
|
||||
# TODO: Support u/s mode
|
||||
cmd = re.sub("\<xlen\>", m.group('xlen'), cmd)
|
||||
variant = re.sub('g', 'imafd', m.group('variant'))
|
||||
cmd = re.sub("\<variant\>", variant, cmd)
|
||||
else:
|
||||
logging.error("Illegal ISA %0s" % isa)
|
||||
cmd = re.sub("\<xlen\>", setting_dir, cmd)
|
||||
else:
|
||||
cmd = re.sub("\<variant\>", isa, cmd)
|
||||
return cmd
|
||||
|
@ -121,7 +132,7 @@ def get_iss_cmd(base_cmd, elf, log):
|
|||
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):
|
||||
log_suffix, batch_size, seed_yaml, stop_on_first_error, verbose=False):
|
||||
"""Run the instruction generator
|
||||
|
||||
Args:
|
||||
|
@ -145,6 +156,7 @@ 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
|
||||
"""
|
||||
# Mutually exclusive options between compile_only and sim_only
|
||||
if compile_only and sim_only:
|
||||
|
@ -170,7 +182,9 @@ def gen(test_list, csr_file, end_signature_addr, isa, simulator,
|
|||
cmd = re.sub("<cmp_opts>", cmp_opts, cmd)
|
||||
|
||||
logging.debug("Compile command: %s" % cmd)
|
||||
logging.debug(run_cmd(cmd))
|
||||
output = run_cmd(cmd)
|
||||
logging.debug(output)
|
||||
check_simulator_return(output, simulator, stop_on_first_error)
|
||||
# Run the instruction generator
|
||||
if not compile_only:
|
||||
cmd_list = []
|
||||
|
@ -201,7 +215,8 @@ def gen(test_list, csr_file, end_signature_addr, isa, simulator,
|
|||
if lsf_cmd:
|
||||
cmd_list.append(cmd)
|
||||
else:
|
||||
run_cmd(cmd, timeout_s)
|
||||
output = run_cmd(cmd, timeout_s)
|
||||
check_simulator_return(output, simulator, stop_on_first_error)
|
||||
else:
|
||||
if batch_size > 0:
|
||||
batch_cnt = int((iterations + batch_size - 1) / batch_size);
|
||||
|
@ -224,6 +239,8 @@ def gen(test_list, csr_file, end_signature_addr, isa, simulator,
|
|||
(" +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:
|
||||
|
@ -235,7 +252,8 @@ def gen(test_list, csr_file, end_signature_addr, isa, simulator,
|
|||
else:
|
||||
logging.info("Running %s, batch %0d/%0d, test_cnt:%0d" %
|
||||
(test['test'], i+1, batch_cnt, test_cnt))
|
||||
run_cmd(cmd, timeout_s)
|
||||
output = run_cmd(cmd, timeout_s)
|
||||
check_simulator_return(output, simulator, stop_on_first_error)
|
||||
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)
|
||||
|
@ -362,7 +380,7 @@ 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):
|
||||
def iss_cmp(test_list, iss, output_dir, isa, stop_on_first_error):
|
||||
"""Compare ISS simulation reult
|
||||
|
||||
Args:
|
||||
|
@ -370,6 +388,7 @@ def iss_cmp(test_list, iss, output_dir, isa):
|
|||
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(",")
|
||||
if len(iss_list) != 2:
|
||||
|
@ -390,9 +409,11 @@ def iss_cmp(test_list, iss, output_dir, isa):
|
|||
if iss == "spike":
|
||||
process_spike_sim_log(log, csv)
|
||||
elif iss == "ovpsim":
|
||||
process_ovpsim_sim_log(log, csv)
|
||||
process_ovpsim_sim_log(log, csv, 1, 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)
|
||||
|
@ -413,7 +434,7 @@ def setup_parser():
|
|||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument("--target", type=str, default="rv64imc",
|
||||
parser.add_argument("--target", type=str, default="rv32imc",
|
||||
help="Run the generator with pre-defined targets: \
|
||||
rv32imc, rv32i, rv64imc, rv64gc")
|
||||
parser.add_argument("-o", "--output", type=str,
|
||||
|
@ -481,10 +502,13 @@ def setup_parser():
|
|||
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")
|
||||
parser.add_argument("--stop_on_first_error", dest="stop_on_first_error", action="store_true",
|
||||
help="Stop on detecting first error")
|
||||
parser.set_defaults(co=False)
|
||||
parser.set_defaults(so=False)
|
||||
parser.set_defaults(verbose=False)
|
||||
parser.set_defaults(cov=False)
|
||||
parser.set_defaults(stop_on_first_error=False)
|
||||
return parser
|
||||
|
||||
|
||||
|
@ -526,14 +550,18 @@ def main():
|
|||
elif args.target == "rv64imc":
|
||||
args.mabi = "lp64"
|
||||
args.isa = "rv64imc"
|
||||
elif args.target == "rv64gc":
|
||||
args.mabi = "lp64"
|
||||
args.isa = "rv64gc"
|
||||
elif args.target == "ml":
|
||||
args.mabi = "lp64"
|
||||
args.isa = "rv64imc"
|
||||
else:
|
||||
print ("Unsupported pre-defined target: %0s" % args.target)
|
||||
else:
|
||||
if (not args.mabi) or (not args.isa):
|
||||
sys.exit("mabi and isa must be specified for custom target %0s" % args.custom_target)
|
||||
if re.match(".*gcc_compile.*", args.steps) or re.match(".*iss_sim.*", args.steps):
|
||||
if (not args.mabi) or (not args.isa):
|
||||
sys.exit("mabi and isa must be specified for custom target %0s" % args.custom_target)
|
||||
if not args.testlist:
|
||||
args.testlist = args.custom_target + "/testlist.yaml"
|
||||
|
||||
|
@ -565,7 +593,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.seed_yaml, args.stop_on_first_error, args.verbose)
|
||||
|
||||
if not args.co:
|
||||
# Compile the assembly program to ELF, convert to plain binary
|
||||
|
@ -579,7 +607,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)
|
||||
iss_cmp(matched_list, args.iss, output_dir, args.isa, args.stop_on_first_error)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
0
vendor/google_riscv-dv/scripts/__init__.py
vendored
0
vendor/google_riscv-dv/scripts/__init__.py
vendored
18
vendor/google_riscv-dv/scripts/lib.py
vendored
18
vendor/google_riscv-dv/scripts/lib.py
vendored
|
@ -172,3 +172,21 @@ def process_regression_list(testlist, test, iterations, matched_list):
|
|||
logging.info("Found matched tests: %s, iterations:%0d" %
|
||||
(entry['test'], entry['iterations']))
|
||||
matched_list.append(entry)
|
||||
|
||||
def check_simulator_return(output, simulator, stop_on_first_error):
|
||||
"""
|
||||
tests simulator output for errors and terminates run if found
|
||||
ONLY works when verbose is on (as output not returned otherwise)
|
||||
TODO add other simulators
|
||||
"""
|
||||
|
||||
if not stop_on_first_error: return
|
||||
|
||||
if "questa" in simulator:
|
||||
for line in output.splitlines():
|
||||
if "Errors: " in line:
|
||||
if not "Errors: 0" in line:
|
||||
logging.fatal (
|
||||
"check_simulator_return (%s): TERMINATING as got errors: [%s]" %
|
||||
(simulator, line))
|
||||
sys.exit(-1)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"""
|
||||
Copyright 2019 Google LLC
|
||||
Copyright 2019 Imperas Software Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@ 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.
|
||||
|
||||
Convert ovpsim sim log to standard riscv instruction trace format
|
||||
Convert ovpsim sim log to standard riscv-dv .csv instruction trace format
|
||||
"""
|
||||
import re
|
||||
import os
|
||||
|
@ -21,29 +22,62 @@ import argparse
|
|||
import logging
|
||||
|
||||
import sys
|
||||
import pprint as pp
|
||||
from lib import *
|
||||
|
||||
from riscv_trace_csv import *
|
||||
|
||||
def convert_mode(pri, line):
|
||||
if "Machine" in pri: return str(3)
|
||||
logging.info("convert_mode = UNKNOWN PRIV MODE [%s]: %s" % (pri, line))
|
||||
try:
|
||||
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)
|
||||
|
||||
stop_on_first_error = 0
|
||||
|
||||
def fatal (s):
|
||||
""" ensure we end if a problem """
|
||||
logging.fatal("ERROR: "+s)
|
||||
sys.exit(-1)
|
||||
|
||||
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)
|
||||
|
||||
REGS = ["zero","ra","sp","gp","tp","t0","t1","t2","s0","s1",
|
||||
"a0","a1","a2","a3","a4","a5","a6","a7",
|
||||
"s2","s3","s4","s5","s6","s7","s8","s9","s10","s11",
|
||||
"t3","t4","t5","t6"]
|
||||
|
||||
def process_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(operands[1])
|
||||
else:
|
||||
fatal("process_jal(%s) wrong num operands (%d)" %
|
||||
(trace.instr, len(operands)))
|
||||
|
||||
def process_jalr(trace, operands, gpr):
|
||||
""" process jalr """
|
||||
## jalr x3
|
||||
## jalr 9(x3)
|
||||
## jalr x2,x3
|
||||
## jalr x2,4(x3)
|
||||
if len(operands) == 1:
|
||||
trace.rd = 'zero'
|
||||
trace.rd_val = '0'
|
||||
m = ADDR_RE.search(operands[0])
|
||||
trace.rd = 'ra'
|
||||
trace.rd_val = gpr['ra']
|
||||
if m: # jalr 9(x3)
|
||||
trace.rs1 = m.group('rs1')
|
||||
trace.rs1_val = gpr[trace.rs1]
|
||||
|
@ -66,9 +100,11 @@ def process_jalr(trace, operands, gpr):
|
|||
trace.imm = get_imm_hex_val('0')
|
||||
|
||||
def process_if_compressed(prev_trace):
|
||||
""" convert naming for compressed instructions """
|
||||
if len(prev_trace.binary) == 4: # compressed are always 4 hex digits
|
||||
prev_trace.instr = "c."+prev_trace.instr
|
||||
# logging.debug("process_if_compressed(%s, %s)" % (prev_trace.instr, prev_trace.binary))
|
||||
# logging.debug("process_if_compressed(%s, %s)" %
|
||||
# (prev_trace.instr, prev_trace.binary))
|
||||
|
||||
pseudos={
|
||||
'mv' :'addi',
|
||||
|
@ -96,7 +132,9 @@ pseudos={
|
|||
'j' :'jal',
|
||||
'jr' :'jal',
|
||||
}
|
||||
def check_conversion(entry, stop_on_first_error):
|
||||
|
||||
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]:
|
||||
|
@ -108,152 +146,271 @@ def check_conversion(entry, stop_on_first_error):
|
|||
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))
|
||||
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))
|
||||
logging.error("converted %10s -> %s <<-- not correct at all" %
|
||||
(instr_str_0, instr))
|
||||
if stop_on_first_error:
|
||||
sys.exit(-1)
|
||||
|
||||
def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 0, stop_on_first_error = 1):
|
||||
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))
|
||||
|
||||
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))
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
def process_ovpsim_sim_log(ovpsim_log, csv, full_trace = 1, stop = 0,
|
||||
dont_truncate_after_first_ecall = 0,
|
||||
verbose2 = False):
|
||||
"""Process OVPsim simulation log.
|
||||
|
||||
Extract instruction and affected register information from ovpsim simulation
|
||||
log and save to a list.
|
||||
"""
|
||||
logging.info("Processing ovpsim log [%d]: %s" % (full_trace, ovpsim_log))
|
||||
instr_cnt = 0
|
||||
trace_instr = ""
|
||||
trace_bin = ""
|
||||
trace_addr = ""
|
||||
|
||||
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))
|
||||
|
||||
# Remove the header part of ovpsim log
|
||||
cmd = ("sed -i '/Info 1:/,$!d' %s" % ovpsim_log)
|
||||
os.system(cmd)
|
||||
# Remove all instructions after ecall (end of program excecution)
|
||||
cmd = ("sed -i '/ecall/q' %s" % ovpsim_log)
|
||||
# Remove all instructions after end of trace data (end of program excecution)
|
||||
if dont_truncate_after_first_ecall:
|
||||
cmd = ("sed -i '/^Info --/q' %s" % ovpsim_log)
|
||||
logging.info("Dont truncate logfile after first ecall: %s", ovpsim_log)
|
||||
else:
|
||||
cmd = ("sed -i '/ecall/q' %s" % ovpsim_log)
|
||||
os.system(cmd)
|
||||
|
||||
# storage and initial values of gpr and csr
|
||||
|
||||
gpr = {}
|
||||
|
||||
for g in REGS:
|
||||
csr = {}
|
||||
|
||||
for g in REGS: # base base isa gprs
|
||||
gpr[g] = 0
|
||||
for i in range(32): # add in v0-v31 gprs
|
||||
|
||||
gpr["v"+str(i)] = 0
|
||||
|
||||
csr["vl"] = 0
|
||||
csr["vtype"] = 0
|
||||
|
||||
instr_cnt = 0
|
||||
with open(ovpsim_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
prev_trace = 0
|
||||
logit = 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>.*?)$", line)
|
||||
"(?P<mode>[A-Za-z]*?)\s+(?P<bin>[a-f0-9]*?)\s+(?P<instr_str>.*?)$",
|
||||
line)
|
||||
if m:
|
||||
if prev_trace: # if not yet written as it had no data following it
|
||||
check_conversion(prev_trace, stop_on_first_error)
|
||||
# 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
|
||||
trace_bin = m.group("bin")
|
||||
trace_instr_str = m.group("instr")
|
||||
trace_addr = m.group("addr")
|
||||
trace_section = m.group("section")
|
||||
trace_mode = convert_mode(m.group("mode"), line)
|
||||
trace_instr = trace_instr_str.split(" ")[0]
|
||||
instr_cnt += 1
|
||||
prev_trace = RiscvInstructionTraceEntry()
|
||||
prev_trace.instr_str = trace_instr_str
|
||||
prev_trace.binary = trace_bin
|
||||
prev_trace.addr = trace_addr
|
||||
prev_trace.privileged_mode = trace_mode
|
||||
prev_trace.instr = trace_instr
|
||||
prev_trace.instr_str = m.group("instr_str")
|
||||
prev_trace.instr = prev_trace.instr_str.split(" ")[0]
|
||||
prev_trace.binary = m.group("bin")
|
||||
prev_trace.addr = m.group("addr")
|
||||
prev_trace.section = m.group("section")
|
||||
prev_trace.privileged_mode = convert_mode(m.group("mode"), line)
|
||||
prev_trace.updated_csr = []
|
||||
prev_trace.updated_gpr = []
|
||||
|
||||
if 0:
|
||||
print ("line ::"+line)
|
||||
print ("bin ::"+trace_bin)
|
||||
print ("instr::"+trace_instr_str)
|
||||
print ("ins ::"+trace_instr)
|
||||
print ("addr ::"+trace_addr)
|
||||
print ("sect ::"+trace_section)
|
||||
print ("mode ::"+trace_mode)
|
||||
sys.exit(-1)
|
||||
#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
|
||||
|
||||
show_line_instr(line, prev_trace)
|
||||
|
||||
if full_trace:
|
||||
i = re.search (r"(?P<instr>[a-z]*?)\s", trace_instr_str)
|
||||
if i:
|
||||
trace_instr = i.group("instr")
|
||||
prev_trace.instr = trace_instr
|
||||
# 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
|
||||
process_if_compressed(prev_trace)
|
||||
o = re.search (r"(?P<instr>[a-z]*?)\s(?P<operand>.*)", trace_instr_str)
|
||||
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']):
|
||||
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:
|
||||
assign_operand(prev_trace, operands, gpr)
|
||||
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)
|
||||
assign_operand(prev_trace, operands, gpr,
|
||||
stop_on_first_error)
|
||||
else:
|
||||
# print("no operand for [%s] in [%s]" % (trace_instr, trace_instr_str))
|
||||
# logging.debug("no operand for [%s] in [%s]" % (trace_instr,
|
||||
# trace_instr_str))
|
||||
pass
|
||||
else:
|
||||
trace_instr = ""
|
||||
else:
|
||||
if 0:
|
||||
print ("not ins line... [%s]" % (line))
|
||||
# Extract register value information
|
||||
n = re.search(r" (?P<rd>[a-z]{1,3}[0-9]{0,2}?) (?P<pre>[a-f0-9]+?)" \
|
||||
# its a csr, gpr new value or report
|
||||
if 0: 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 n:
|
||||
# Write the extracted instruction to a csvcol buffer file
|
||||
# print("%0s %0s = %0s" % (trace_instr_str, m.group("rd"), m.group("val")))
|
||||
if n.group("rd") != "frm":
|
||||
rv_instr_trace = RiscvInstructionTraceEntry()
|
||||
rv_instr_trace.rd = n.group("rd")
|
||||
rv_instr_trace.rd_val = n.group("val")
|
||||
rv_instr_trace.rs1 = prev_trace.rs1
|
||||
rv_instr_trace.rs1_val = prev_trace.rs1_val
|
||||
rv_instr_trace.rs2 = prev_trace.rs2
|
||||
rv_instr_trace.rs2_val = prev_trace.rs2_val
|
||||
rv_instr_trace.instr_str = trace_instr_str
|
||||
rv_instr_trace.instr = prev_trace.instr
|
||||
rv_instr_trace.binary = trace_bin
|
||||
rv_instr_trace.addr = trace_addr
|
||||
rv_instr_trace.privileged_mode = trace_mode
|
||||
gpr[rv_instr_trace.rd] = rv_instr_trace.rd_val
|
||||
check_conversion(rv_instr_trace, stop_on_first_error)
|
||||
trace_csv.write_trace_entry(rv_instr_trace)
|
||||
prev_trace = 0 # we wrote out as it had data, so no need to write it next time round
|
||||
if 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
|
||||
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 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")
|
||||
else:
|
||||
# backwards compatible
|
||||
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, trace_bin, trace_addr))
|
||||
print (rv_instr_trace.__dict__)
|
||||
sys.exit(-1)
|
||||
trace_instr_str, prev_trace.binary, prev_trace.addr))
|
||||
print (rv_instr_trace.__dict__)
|
||||
sys.exit(-1)
|
||||
else:
|
||||
if 0:
|
||||
print ("write previous entry: [%s] %s " % (str(instr_cnt), line))
|
||||
sys.exit(-1)
|
||||
logging.info("Processed instruction count : %d" % instr_cnt)
|
||||
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)
|
||||
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")
|
||||
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
parser.add_argument("-f", "--full_trace", dest="full_trace", action="store_true",
|
||||
parser.add_argument("--full_trace", dest="full_trace",
|
||||
action="store_true",
|
||||
help="Generate the full trace")
|
||||
parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
|
||||
parser.add_argument("--verbose", dest="verbose", action="store_true",
|
||||
help="Verbose logging")
|
||||
parser.add_argument("--verbose2", dest="verbose2", action="store_true",
|
||||
help="Verbose logging detail 2")
|
||||
parser.add_argument("--stop_on_first_error", dest="stop_on_first_error",
|
||||
action="store_true",
|
||||
help="Stop on first error")
|
||||
parser.add_argument("--dont_truncate_after_first_ecall",
|
||||
dest="dont_truncate_after_first_ecall",
|
||||
action="store_true",
|
||||
help="Dont truncate on first ecall")
|
||||
parser.set_defaults(full_trace=False)
|
||||
parser.set_defaults(verbose=False)
|
||||
parser.set_defaults(verbose2=False)
|
||||
parser.set_defaults(stop_on_first_error=False)
|
||||
parser.set_defaults(dont_truncate_after_first_ecall=False)
|
||||
args = parser.parse_args()
|
||||
setup_logging(args.verbose)
|
||||
logging.debug("Logging Debug set")
|
||||
# Process ovpsim log
|
||||
process_ovpsim_sim_log(args.log, args.csv, args.full_trace)
|
||||
process_ovpsim_sim_log(args.log, args.csv, args.full_trace,
|
||||
args.stop_on_first_error, args.dont_truncate_after_first_ecall,
|
||||
args.verbose2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
103
vendor/google_riscv-dv/scripts/riscv_trace_csv.py
vendored
103
vendor/google_riscv-dv/scripts/riscv_trace_csv.py
vendored
|
@ -19,6 +19,7 @@ Class for RISC-V instruction trace CSV
|
|||
import csv
|
||||
import re
|
||||
import logging
|
||||
import sys
|
||||
|
||||
class RiscvInstructionTraceEntry(object):
|
||||
"""RISC-V instruction trace entry"""
|
||||
|
@ -37,6 +38,20 @@ class RiscvInstructionTraceEntry(object):
|
|||
self.instr = ""
|
||||
self.privileged_mode = ""
|
||||
self.csr = ""
|
||||
self.vd = ""
|
||||
self.vd_val = ""
|
||||
self.vs1 = ""
|
||||
self.vs1_val = ""
|
||||
self.vs2 = ""
|
||||
self.vs2_val = ""
|
||||
self.vs3 = ""
|
||||
self.vs3_val = ""
|
||||
self.vtype_e = ""
|
||||
self.vtype_m = ""
|
||||
self.vtype_d = ""
|
||||
self.vm = ""
|
||||
self.updated_csr = ""
|
||||
self.updated_gpr = ""
|
||||
|
||||
def get_trace_string(self):
|
||||
"""Return a short string of the trace entry"""
|
||||
|
@ -56,8 +71,11 @@ class RiscvInstructionTraceCsv(object):
|
|||
|
||||
def start_new_trace(self):
|
||||
"""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"]
|
||||
fields = [
|
||||
"instr", "rd", "rd_val", "rs1", "rs1_val", "rs2", "rs2_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"]
|
||||
self.csv_writer = csv.DictWriter(self.csv_fd, fieldnames=fields)
|
||||
self.csv_writer.writeheader()
|
||||
|
||||
|
@ -78,18 +96,34 @@ 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})
|
||||
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,
|
||||
})
|
||||
|
||||
|
||||
def gpr_to_abi(gpr):
|
||||
|
@ -185,7 +219,7 @@ def get_imm_hex_val(imm):
|
|||
|
||||
ADDR_RE = re.compile(r"(?P<imm>[\-0-9]+?)\((?P<rs1>.*)\)")
|
||||
|
||||
def assign_operand(trace, operands, gpr):
|
||||
def assign_operand(trace, operands, gpr, stop_on_first_error = 0):
|
||||
"""Assign the operand value of the instruction trace"""
|
||||
if trace.instr in ['lb', 'lh', 'lw', 'lbu', 'lhu', 'ld', 'lq', 'lwu', 'ldu',
|
||||
'c.lw', 'c.ld', 'c.lq', 'c.lwsp', 'c.ldsp', 'c.lqsp']:
|
||||
|
@ -213,11 +247,12 @@ def assign_operand(trace, operands, gpr):
|
|||
trace.rs1_val = gpr[trace.rs1]
|
||||
else:
|
||||
logging.info("Unexpected store address %0s", operands[1])
|
||||
elif trace.instr in ['mul', 'mulh', 'mulhsu', 'mulhu', 'div', 'divu', 'rem', 'remu',
|
||||
'mulw', 'muld', 'divw', 'divuw', 'divd', 'remw', 'remd', 'remuw',
|
||||
'remud', 'sll', 'srl', 'sra', 'add', 'sub', 'xor', 'or', 'and',
|
||||
'slt', 'sltu', 'sllw', 'slld', 'srlw', 'srld', 'sraw', 'srad',
|
||||
'addw', 'addd', 'subw', 'subd']:
|
||||
elif trace.instr in [
|
||||
'mul', 'mulh', 'mulhsu', 'mulhu', 'div', 'divu', 'rem', 'remu',
|
||||
'mulw', 'muld', 'divw', 'divuw', 'divd', 'remw', 'remd', 'remuw',
|
||||
'remud', 'sll', 'srl', 'sra', 'add', 'sub', 'xor', 'or', 'and',
|
||||
'slt', 'sltu', 'sllw', 'slld', 'srlw', 'srld', 'sraw', 'srad',
|
||||
'addw', 'addd', 'subw', 'subd']:
|
||||
# R type instruction
|
||||
trace.rd = operands[0]
|
||||
trace.rd_val = gpr[trace.rd]
|
||||
|
@ -225,7 +260,8 @@ def assign_operand(trace, operands, gpr):
|
|||
trace.rs1_val = gpr[trace.rs1]
|
||||
trace.rs2 = operands[2]
|
||||
trace.rs2_val = gpr[trace.rs2]
|
||||
elif trace.instr in ['c.add', 'c.addw', 'c.mv', 'c.sub', 'c.and', 'c.or', 'c.xor', 'c.subw']:
|
||||
elif trace.instr in [
|
||||
'c.add', 'c.addw', 'c.mv', 'c.sub', 'c.and', 'c.or', 'c.xor', 'c.subw']:
|
||||
# CR type
|
||||
trace.rd = operands[0]
|
||||
trace.rd_val = gpr[trace.rd]
|
||||
|
@ -245,9 +281,10 @@ def assign_operand(trace, operands, gpr):
|
|||
trace.rs1_val = gpr[trace.rs1]
|
||||
trace.rs2 = 'zero'
|
||||
trace.rs2_val = '0'
|
||||
elif trace.instr in ['slli', 'srli', 'srai', 'addi', 'xori', 'ori', 'andi', 'slti',
|
||||
'sltiu', 'slliw', 'sllid', 'srliw', 'srlid', 'sraiw', 'sraid',
|
||||
'addiw', 'addid']:
|
||||
elif trace.instr in [
|
||||
'slli', 'srli', 'srai', 'addi', 'xori', 'ori', 'andi', 'slti',
|
||||
'sltiu', 'slliw', 'sllid', 'srliw', 'srlid', 'sraiw', 'sraid',
|
||||
'addiw', 'addid']:
|
||||
# I type instruction
|
||||
trace.rd = operands[0]
|
||||
trace.rd_val = gpr[trace.rd]
|
||||
|
@ -291,8 +328,9 @@ def assign_operand(trace, operands, gpr):
|
|||
trace.rd_val = gpr[trace.rd]
|
||||
trace.csr = operands[1]
|
||||
trace.imm = get_imm_hex_val(operands[2])
|
||||
elif trace.instr in ['scall', 'sbreak', 'fence', 'fence.i', 'ecall', 'ebreak', 'wfi',
|
||||
'sfence.vma', 'c.ebreak', 'nop', 'c.nop']:
|
||||
elif trace.instr in [
|
||||
'scall', 'sbreak', 'fence', 'fence.i', 'ecall', 'ebreak', 'wfi',
|
||||
'sfence.vma', 'c.ebreak', 'nop', 'c.nop']:
|
||||
trace.rd = 'zero'
|
||||
trace.rs1 = 'zero'
|
||||
trace.rs2 = 'zero'
|
||||
|
@ -318,8 +356,13 @@ def assign_operand(trace, operands, gpr):
|
|||
trace.rs1 = operands[1]
|
||||
trace.rs1_val = gpr[trace.rs1]
|
||||
trace.imm = get_imm_hex_val(operands[2])
|
||||
elif trace.instr in ['c.j', 'c.jal']:
|
||||
elif trace.instr in ['c.j']:
|
||||
trace.imm = get_imm_hex_val(operands[0])
|
||||
elif trace.instr in ['c.jal']:
|
||||
if len(operands) == 1:
|
||||
trace.imm = get_imm_hex_val(operands[0])
|
||||
else:
|
||||
trace.imm = get_imm_hex_val(operands[1])
|
||||
# Pseudo instruction convertion below
|
||||
elif trace.instr in ['mv']:
|
||||
trace.instr = 'addi'
|
||||
|
@ -449,5 +492,7 @@ def assign_operand(trace, operands, gpr):
|
|||
pass
|
||||
else:
|
||||
# TODO: Support other instructions
|
||||
logging.info("Unsupported instr : %s" % trace.instr)
|
||||
|
||||
logging.debug("Unsupported instr : %s (%s)" %
|
||||
(trace.instr, trace.instr_str))
|
||||
if stop_on_first_error:
|
||||
sys.exit(-1)
|
||||
|
|
93
vendor/google_riscv-dv/scripts/whisper_log_trace_csv.py
vendored
Normal file
93
vendor/google_riscv-dv/scripts/whisper_log_trace_csv.py
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
"""
|
||||
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.
|
||||
|
||||
Convert whisper sim log to standard riscv instruction trace format
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import logging
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
from riscv_trace_csv import *
|
||||
from lib import *
|
||||
|
||||
INSTR_RE = re.compile(r"#(?P<n>[0-9]+?)\s+(?P<mode>[0-9]+?)\s+(?P<pc>[0-9a-f]+?)\s+" \
|
||||
"(?P<bin>[0-9a-f]+?)\s+(?P<type>[a-z]+?)\s+" \
|
||||
"(?P<reg>[0-9a-f]+?)\s+(?P<val>[0-9a-f]+?)\s+(?P<instr>.*?)$")
|
||||
|
||||
LOGGER = logging.getLogger()
|
||||
|
||||
def process_whisper_sim_log(whisper_log, csv, full_trace = 0):
|
||||
"""Process SPIKE simulation log.
|
||||
|
||||
Extract instruction and affected register information from whisper simulation
|
||||
log and save to a list.
|
||||
"""
|
||||
logging.info("Processing whisper log : %s" % whisper_log)
|
||||
instr_cnt = 0
|
||||
whisper_instr = ""
|
||||
gpr = {}
|
||||
gpr["zero"] = 0
|
||||
|
||||
with open(whisper_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
for line in f:
|
||||
# Extract instruction infromation
|
||||
m = INSTR_RE.search(line)
|
||||
if m:
|
||||
logging.debug("-> mode: %s, pc:%s, bin:%s, instr:%s" %
|
||||
(m.group('mode'), m.group('pc'), m.group('bin'), m.group('instr')))
|
||||
if re.search('ecall', m.group('instr')):
|
||||
break
|
||||
if m.group('type') == 'r':
|
||||
whisper_instr = m.group("instr").replace("\. + ", "")
|
||||
whisper_instr = whisper_instr.replace("\. - ", "-")
|
||||
rv_instr_trace = RiscvInstructionTraceEntry()
|
||||
rv_instr_trace.instr_str = whisper_instr
|
||||
rv_instr_trace.binary = m.group("bin")
|
||||
reg = "x" + str(int(m.group("reg"), 16))
|
||||
rv_instr_trace.rd = gpr_to_abi(reg)
|
||||
rv_instr_trace.rd_val = m.group("val")
|
||||
trace_csv.write_trace_entry(rv_instr_trace)
|
||||
instr_cnt += 1
|
||||
logging.info("Processed instruction count : %d" % instr_cnt)
|
||||
logging.info("CSV saved to : %s" % csv)
|
||||
|
||||
|
||||
def main():
|
||||
instr_trace = []
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input whisper simulation log")
|
||||
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
parser.add_argument("-f", "--full_trace", dest="full_trace", action="store_true",
|
||||
help="Generate the full trace")
|
||||
parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
|
||||
help="Verbose logging")
|
||||
parser.set_defaults(full_trace=False)
|
||||
parser.set_defaults(verbose=False)
|
||||
args = parser.parse_args()
|
||||
setup_logging(args.verbose)
|
||||
# Process whisper log
|
||||
process_whisper_sim_log(args.log, args.csv, args.full_trace)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -340,7 +340,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(); // comment out if not want to read incorrect values from csr
|
||||
endfunction
|
||||
|
||||
// Setup MISA based on supported extensions
|
||||
|
|
|
@ -857,14 +857,12 @@ class riscv_instr_cover_group;
|
|||
// instr_trans_cg = new();
|
||||
branch_hit_history_cg = new();
|
||||
rv32i_misc_cg = new();
|
||||
if (!cfg.disable_compressed_instr) begin
|
||||
illegal_compressed_instr_cg = new();
|
||||
end
|
||||
opcode_cg = new();
|
||||
if (RV32C inside {supported_isa}) begin
|
||||
illegal_compressed_instr_cg = new();
|
||||
compressed_opcode_cg = new();
|
||||
hint_cg = new();
|
||||
end
|
||||
opcode_cg = new();
|
||||
if (RV32M inside {supported_isa}) begin
|
||||
mul_cg = new();
|
||||
mulh_cg = new();
|
||||
|
@ -940,7 +938,7 @@ class riscv_instr_cover_group;
|
|||
privileged_csr_cg = new();
|
||||
mcause_exception_cg = new();
|
||||
mcause_interrupt_cg = new();
|
||||
if (!cfg.disable_compressed_instr) begin
|
||||
if (RV32C inside {supported_isa}) begin
|
||||
mepc_alignment_cg = new();
|
||||
end
|
||||
mstatus_m_cg = new();
|
||||
|
@ -1075,7 +1073,7 @@ class riscv_instr_cover_group;
|
|||
C_ADDW : c_addw_cg.sample(instr);
|
||||
C_ADDIW : c_addiw_cg.sample(instr);
|
||||
default: begin
|
||||
if (!cfg.disable_compressed_instr) begin
|
||||
if (RV32C inside {supported_isa}) begin
|
||||
illegal_compressed_instr_cg.sample(instr.binary);
|
||||
end
|
||||
if (instr.group == RV32I) begin
|
||||
|
@ -1107,7 +1105,7 @@ class riscv_instr_cover_group;
|
|||
end
|
||||
end
|
||||
MEPC: begin
|
||||
if (!cfg.disable_compressed_instr) begin
|
||||
if (RV32C inside {supported_isa}) begin
|
||||
mepc_alignment_cg.sample(instr.rd_value);
|
||||
end
|
||||
end
|
||||
|
|
|
@ -36,6 +36,8 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
i++;
|
||||
end
|
||||
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));
|
||||
instr = riscv_instr_cov_item::type_id::create("instr");
|
||||
instr.rand_mode(0);
|
||||
|
|
5
vendor/google_riscv-dv/yaml/iss.yaml
vendored
5
vendor/google_riscv-dv/yaml/iss.yaml
vendored
|
@ -32,3 +32,8 @@
|
|||
path_var: SAIL_RISCV
|
||||
cmd: >
|
||||
<path_var> <elf>
|
||||
|
||||
- iss: whisper
|
||||
path_var: WHISPER_ISS
|
||||
cmd: >
|
||||
<path_var> <elf> --log --xlen <xlen> --isa <variant>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue