diff --git a/vendor/google_riscv-dv.lock.hjson b/vendor/google_riscv-dv.lock.hjson index 6bccab75..9896f942 100644 --- a/vendor/google_riscv-dv.lock.hjson +++ b/vendor/google_riscv-dv.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/google/riscv-dv - rev: 44bec7695fd2399166e181fa84b66a608b5f745f + rev: 4b333ba1ef285ec4508c606efa64610136154a5e } } diff --git a/vendor/google_riscv-dv/.gitignore b/vendor/google_riscv-dv/.gitignore index 59773a1e..6e29a600 100644 --- a/vendor/google_riscv-dv/.gitignore +++ b/vendor/google_riscv-dv/.gitignore @@ -1,6 +1,6 @@ *.ini *.bin -out_*/ +*out_*/ work/ *.pyc /.cproject diff --git a/vendor/google_riscv-dv/README.md b/vendor/google_riscv-dv/README.md index 2f03c789..0a165195 100644 --- a/vendor/google_riscv-dv/README.md +++ b/vendor/google_riscv-dv/README.md @@ -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 diff --git a/vendor/google_riscv-dv/cov.py b/vendor/google_riscv-dv/cov.py index b1f06d6c..16d9dd0c 100644 --- a/vendor/google_riscv-dv/cov.py +++ b/vendor/google_riscv-dv/cov.py @@ -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=\"" % - (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() diff --git a/vendor/google_riscv-dv/run.py b/vendor/google_riscv-dv/run.py index 2902c0ab..138b7be6 100644 --- a/vendor/google_riscv-dv/run.py +++ b/vendor/google_riscv-dv/run.py @@ -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("\", get_env_var(entry['path_var']), cmd) if iss == "ovpsim": cmd = re.sub("\", setting_dir, cmd) + elif iss == "whisper": + m = re.search(r"rv(?P[0-9]+?)(?P[a-z]+?)$", isa) + if m: + # TODO: Support u/s mode + cmd = re.sub("\", m.group('xlen'), cmd) + variant = re.sub('g', 'imafd', m.group('variant')) + cmd = re.sub("\", variant, cmd) + else: + logging.error("Illegal ISA %0s" % isa) + cmd = re.sub("\", setting_dir, cmd) else: cmd = re.sub("\", 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, 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("", 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() diff --git a/vendor/google_riscv-dv/scripts/__init__.py b/vendor/google_riscv-dv/scripts/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/google_riscv-dv/scripts/lib.py b/vendor/google_riscv-dv/scripts/lib.py index 695fb0ad..56852fd3 100644 --- a/vendor/google_riscv-dv/scripts/lib.py +++ b/vendor/google_riscv-dv/scripts/lib.py @@ -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) diff --git a/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py b/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py index e3129ab0..ca9fd053 100644 --- a/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py +++ b/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py @@ -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.*?)(?P
\(.*\): ?)" \ - "(?P[A-Za-z]*?)\s+(?P[a-f0-9]*?)\s+(?P.*?)$", line) + "(?P[A-Za-z]*?)\s+(?P[a-f0-9]*?)\s+(?P.*?)$", + 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[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[a-z]*?)\s(?P.*)", trace_instr_str) + o = re.search (r"(?P[a-z]*?)\s(?P.*)", + 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[a-z]{1,3}[0-9]{0,2}?) (?P
[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[a-z]*[0-9]{0,2}?) (?P
[a-f0-9]+?)" \
                        " -> (?P[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[a-z]{1,3}[0-9]{0,2}?) (?P
[a-f0-9]+?)" \
+                       " -> (?P[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(" (%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__":
diff --git a/vendor/google_riscv-dv/scripts/riscv_trace_csv.py b/vendor/google_riscv-dv/scripts/riscv_trace_csv.py
index b3a06d7d..a909265a 100644
--- a/vendor/google_riscv-dv/scripts/riscv_trace_csv.py
+++ b/vendor/google_riscv-dv/scripts/riscv_trace_csv.py
@@ -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[\-0-9]+?)\((?P.*)\)")
 
-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)
diff --git a/vendor/google_riscv-dv/scripts/whisper_log_trace_csv.py b/vendor/google_riscv-dv/scripts/whisper_log_trace_csv.py
new file mode 100644
index 00000000..ae366e43
--- /dev/null
+++ b/vendor/google_riscv-dv/scripts/whisper_log_trace_csv.py
@@ -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[0-9]+?)\s+(?P[0-9]+?)\s+(?P[0-9a-f]+?)\s+" \
+                       "(?P[0-9a-f]+?)\s+(?P[a-z]+?)\s+" \
+                       "(?P[0-9a-f]+?)\s+(?P[0-9a-f]+?)\s+(?P.*?)$")
+
+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()
diff --git a/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv b/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
index bb1791f1..fdbdfcf8 100644
--- a/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
+++ b/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
@@ -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
diff --git a/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv b/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv
index 1d0f17d4..dbc0c407 100644
--- a/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv
+++ b/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv
@@ -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
diff --git a/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv b/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv
index 16d46173..01eb2638 100644
--- a/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv
+++ b/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv
@@ -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);
diff --git a/vendor/google_riscv-dv/yaml/iss.yaml b/vendor/google_riscv-dv/yaml/iss.yaml
index 5677ef01..ddd08641 100644
--- a/vendor/google_riscv-dv/yaml/iss.yaml
+++ b/vendor/google_riscv-dv/yaml/iss.yaml
@@ -32,3 +32,8 @@
   path_var: SAIL_RISCV
   cmd: >
      
+
+- iss: whisper
+  path_var: WHISPER_ISS
+  cmd: >
+      --log --xlen  --isa