diff --git a/vendor/google_riscv-dv.lock.hjson b/vendor/google_riscv-dv.lock.hjson index e89e5698..78d8f179 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: 80d429475138b4b94d863030246a06980c89889d + rev: 44505927a70a6234b996d15f2e51bd1e2632b68e } } diff --git a/vendor/google_riscv-dv/cov.py b/vendor/google_riscv-dv/cov.py new file mode 100644 index 00000000..c7eccc70 --- /dev/null +++ b/vendor/google_riscv-dv/cov.py @@ -0,0 +1,160 @@ +""" +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. + +Regression script for RISC-V random instruction generator +""" + +import argparse +import os +import subprocess +import re +import sys +import logging + +from datetime import date +from scripts.lib import * +from scripts.spike_log_to_trace_csv import * +from scripts.ovpsim_log_to_trace_csv import * +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): + """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 + """ + 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)) + with open(trace_log) as f: + for line in f: + line = line.rstrip() + log_list.append(line) + csv = line[0:-4] + ".csv" + csv_list.append(csv) + if steps == "all" or re.match("csv", 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) + 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 = ("%s python3 run.py --co -o %s --cov -tl %s %s" % + (lsf_cmd, out, testlist, opts)) + base_sim_cmd = ("%s python3 run.py --so -o %s --cov -tl %s %s " + "-tn riscv_instr_cov_test --steps gen --sim_opts \"\"" % + (lsf_cmd, out, testlist, opts)) + run_cmd(build_cmd) + file_idx = 0 + trace_idx = 0 + trace_csv_opts = "" + batch_cnt = 1 + sim_cmd_list = [] + logging.info("Collecting functional coverage from %0d trace CSV" % len(csv_list)) + if batch_size > 0: + batch_cnt = (len(csv_list)+batch_size-1)/batch_size; + logging.info("Batch size: %0d, Batch cnt:%0d" % (batch_size, batch_cnt)) + for i in range(len(csv_list)): + if batch_size > 0: + file_idx = i / batch_size; + trace_idx = i % batch_size; + else: + file_idx = 0 + trace_idx = i + trace_csv_opts += (" +trace_csv_%0d=%s" % (trace_idx, csv_list[i])) + if ((i == len(csv_list)-1) or ((batch_size > 0) and (trace_idx == batch_size-1))): + sim_cmd = base_sim_cmd.replace("", trace_csv_opts) + sim_cmd += (" --log_suffix _%d" % file_idx) + if lsf_cmd == "": + logging.info("Processing batch %0d/%0d" % (file_idx+1, batch_cnt)) + run_cmd(sim_cmd) + else: + sim_cmd_list.append(sim_cmd) + trace_csv_opts = "" + if lsf_cmd != "": + run_parallel_cmd(sim_cmd_list, timeout) + logging.info("Collecting functional coverage from %0d trace CSV...done" % len(csv_list)) + + +def setup_parser(): + """Create a command line parser. + + Returns: The created parser. + """ + # Parse input arguments + parser = argparse.ArgumentParser() + parser.add_argument("-o", "--output", type=str, + help="Output directory name", dest="o") + parser.add_argument("-v", "--verbose", dest="verbose", action="store_true", + help="Verbose logging") + parser.add_argument("--dir", type=str, + help="Directory of ISS log") + parser.add_argument("-bz", "--batch_size", dest="batch_size", type=int, default=0, + help="Number of CSV to process per run") + parser.add_argument("-to", "--timeout", dest="timeout", type=int, default=1000, + 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("--iss", type=str, default="spike", + help="RISC-V instruction set simulator: spike,ovpsim,sail") + parser.add_argument("-tl", "--testlist", type=str, default="", + help="Regression testlist", dest="testlist") + parser.add_argument("--opts", type=str, default="", + help="Additional options for the instruction generator") + parser.add_argument("--lsf_cmd", type=str, default="", + help="LSF command. Run in local sequentially if lsf \ + command is not specified") + parser.set_defaults(verbose=False) + return parser + +def main(): + """This is the main entry point.""" + parser = setup_parser() + args = parser.parse_args() + cwd = os.path.dirname(os.path.realpath(__file__)) + setup_logging(args.verbose) + + if not args.testlist: + args.testlist = cwd + "/yaml/cov_testlist.yaml" + + # Create output directory + if args.o is None: + output_dir = "out_" + str(date.today()) + else: + output_dir = args.o + + subprocess.run(["mkdir", "-p", output_dir]) + + collect_cov(args.dir, output_dir, args.iss, args.testlist, args.batch_size, + args.lsf_cmd, args.steps, args.opts, args.timeout) + +if __name__ == "__main__": + main() diff --git a/vendor/google_riscv-dv/run.py b/vendor/google_riscv-dv/run.py index c59c7f5d..b01eadcd 100644 --- a/vendor/google_riscv-dv/run.py +++ b/vendor/google_riscv-dv/run.py @@ -32,12 +32,13 @@ from scripts.instr_trace_compare import * LOGGER = logging.getLogger() -def get_generator_cmd(simulator, simulator_yaml): +def get_generator_cmd(simulator, simulator_yaml, cov): """ Setup the compile and simulation command for the generator Args: simulator : RTL simulator used to run instruction generator simulator_yaml : RTL simulator configuration file in YAML format + cov : Enable functional coverage Returns: compile_cmd : RTL simulator command to compile the instruction generator @@ -49,8 +50,18 @@ def get_generator_cmd(simulator, simulator_yaml): for entry in yaml_data: if entry['tool'] == simulator: logging.info("Found matching simulator: %s" % entry['tool']) - compile_cmd = entry['compile_cmd'] - sim_cmd = entry['sim_cmd'] + compile_spec = entry['compile'] + compile_cmd = compile_spec['cmd'] + for i in range(len(compile_cmd)): + if ('cov_opts' in compile_spec) and cov: + compile_cmd[i] = re.sub('', compile_spec['cov_opts'].rstrip(), compile_cmd[i]) + else: + compile_cmd[i] = re.sub('', '', compile_cmd[i]) + sim_cmd = entry['sim']['cmd'] + if ('cov_opts' in entry['sim']) and cov: + sim_cmd = re.sub('', entry['sim']['cov_opts'].rstrip(), sim_cmd) + else: + sim_cmd = re.sub('', '', sim_cmd) if 'env_var' in entry: for env_var in entry['env_var'].split(','): for i in range(len(compile_cmd)): @@ -107,7 +118,8 @@ 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): + cwd, cmp_opts, sim_opts, timeout_s, core_setting_dir, ext_dir, cov, + log_suffix, batch_size): """Run the instruction generator Args: @@ -127,6 +139,9 @@ def gen(test_list, csr_file, end_signature_addr, isa, simulator, timeout_s : Timeout limit in seconds core_setting_dir : Path for riscv_core_setting.sv ext_dir : User extension directory + cov : Enable functional coverage + log_suffix : Simulation log file name suffix + batch_size : Number of tests to generate per run """ # Mutually exclusive options between compile_only and sim_only if compile_only and sim_only: @@ -134,8 +149,8 @@ def gen(test_list, csr_file, end_signature_addr, isa, simulator, # Setup the compile and simulation command for the generator compile_cmd = [] sim_cmd = "" - compile_cmd, sim_cmd = get_generator_cmd(simulator, simulator_yaml); - if len(test_list) == 0: + compile_cmd, sim_cmd = get_generator_cmd(simulator, simulator_yaml, cov); + if ((compile_only == 0) and (len(test_list) == 0)): return # Compile the instruction generator if not sim_only: @@ -165,6 +180,7 @@ def gen(test_list, csr_file, end_signature_addr, isa, simulator, logging.info("Running RISC-V instruction generator") for test in test_list: iterations = test['iterations'] + logging.info("Generating %d %s" % (iterations, test['test'])) if iterations > 0: """ If we are running a CSR test, need to call a separate python script @@ -177,23 +193,39 @@ def gen(test_list, csr_file, end_signature_addr, isa, simulator, (" --iterations %i" % iterations) + \ (" --out %s/asm_tests" % output_dir) + \ (" --end_signature_addr %s" % end_signature_addr) + if lsf_cmd: + cmd_list.append(cmd) + else: + run_cmd(cmd, timeout_s) else: - rand_seed = get_seed(seed) - cmd = lsf_cmd + " " + sim_cmd.rstrip() + \ - (" +UVM_TESTNAME=%s " % test['gen_test']) + \ - (" +num_of_tests=%i " % iterations) + \ - (" +asm_file_name=%s/asm_tests/%s " % (output_dir, test['test'])) + \ - (" -l %s/sim_%s.log " % (output_dir, test['test'])) - cmd = re.sub("", str(rand_seed), cmd) - if "gen_opts" in test: - cmd += test['gen_opts'] - if not re.search("c", isa): - cmd += "+disable_comparessed_instr=1"; - logging.info("Generating %d %s" % (iterations, test['test'])) - if lsf_cmd: - cmd_list.append(cmd) - else: - run_cmd(cmd, timeout_s) + if batch_size > 0: + batch_cnt = int((iterations + batch_size - 1) / batch_size); + else: + batch_cnt = 1 + logging.info("Running %s with %0d batches" % (test['test'], batch_cnt)) + for i in range(0, batch_cnt): + rand_seed = get_seed(seed) + if i < batch_cnt - 1: + test_cnt = batch_size + else: + test_cnt = iterations - i * batch_size; + cmd = lsf_cmd + " " + sim_cmd.rstrip() + \ + (" +UVM_TESTNAME=%s " % test['gen_test']) + \ + (" +num_of_tests=%i " % test_cnt) + \ + (" +start_idx=%d " % (i*batch_size)) + \ + (" +asm_file_name=%s/asm_tests/%s " % (output_dir, test['test'])) + \ + (" -l %s/sim_%s_%d%s.log " % (output_dir, test['test'], i, log_suffix)) + cmd = re.sub("", str(rand_seed), cmd) + if "gen_opts" in test: + cmd += test['gen_opts'] + if not re.search("c", isa): + cmd += "+disable_comparessed_instr=1"; + if lsf_cmd: + cmd_list.append(cmd) + else: + logging.info("Running %s, batch %0d/%0d, test_cnt:%0d" % + (test['test'], i+1, batch_cnt, test_cnt)) + run_cmd(cmd, timeout_s) if lsf_cmd: run_parallel_cmd(cmd_list, timeout_s) @@ -209,6 +241,8 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts): """ for test in test_list: for i in range(0, test['iterations']): + if 'no_gcc' in test and test['no_gcc'] == 1: + continue prefix = ("%s/asm_tests/%s_%d" % (output_dir, test['test'], i)) asm = prefix + ".S" elf = prefix + ".o" @@ -304,7 +338,7 @@ def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s): elf = prefix + ".o" log = ("%s/%s.%d.log" % (log_dir, test['test'], i)) cmd = get_iss_cmd(base_cmd, elf, log) - logging.info("Running ISS simulation: %s" % elf) + logging.info("Running %s sim: %s" % (iss, elf)) run_cmd(cmd, timeout_s) logging.debug(cmd) @@ -378,6 +412,8 @@ def setup_parser(): help="Verbose logging") parser.add_argument("--co", dest="co", action="store_true", help="Compile the generator only") + parser.add_argument("--cov", dest="cov", action="store_true", + help="Enable functional coverage") parser.add_argument("--so", dest="so", action="store_true", help="Simulate the generator only") parser.add_argument("--cmp_opts", type=str, default="", @@ -413,9 +449,15 @@ def setup_parser(): help="Path for the user extension directory") parser.add_argument("--asm_test", type=str, default="", help="Directed assembly test") + parser.add_argument("--log_suffix", type=str, default="", + help="Simulation log name suffix") + 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.set_defaults(co=False) parser.set_defaults(so=False) parser.set_defaults(verbose=False) + parser.set_defaults(cov=False) return parser @@ -454,17 +496,19 @@ def main(): # Process regression test list matched_list = [] - process_regression_list(args.testlist, args.test, args.iterations, matched_list) - if len(matched_list) == 0: - sys.exit("Cannot find %s in %s" % (args.test, args.testlist)) + + if not args.co: + process_regression_list(args.testlist, args.test, args.iterations, matched_list) + if len(matched_list) == 0: + sys.exit("Cannot find %s in %s" % (args.test, args.testlist)) # Run instruction generator if args.steps == "all" or re.match("gen", args.steps): gen(matched_list, args.csr_yaml, args.end_signature_addr, args.isa, args.simulator, args.simulator_yaml, output_dir, args.so, 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.sim_opts, args.gen_timeout, args.core_setting_dir, + args.user_extension_dir, args.cov, args.log_suffix, args.batch_size) if not args.co: # Compile the assembly program to ELF, convert to plain binary diff --git a/vendor/google_riscv-dv/scripts/riscv_trace_csv.py b/vendor/google_riscv-dv/scripts/riscv_trace_csv.py index 4dfd104b..79daa54e 100644 --- a/vendor/google_riscv-dv/scripts/riscv_trace_csv.py +++ b/vendor/google_riscv-dv/scripts/riscv_trace_csv.py @@ -34,6 +34,7 @@ class RiscvInstructiontTraceEntry(object): self.instr_str = "" self.instr = "" self.privileged_mode = "" + self.csr = "" def get_trace_string(self): """Return a short string of the trace entry""" @@ -54,7 +55,7 @@ class RiscvInstructiontTraceCsv(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", "mode"] + "imm", "str", "addr", "binary", "csr", "mode"] self.csv_writer = csv.DictWriter(self.csv_fd, fieldnames=fields) self.csv_writer.writeheader() @@ -85,8 +86,8 @@ class RiscvInstructiontTraceCsv(object): 'addr' : entry.addr, 'instr' : entry.instr, 'imm' : entry.imm, - 'binary' : entry.binary, - 'addr' : entry.addr}) + 'csr' : entry.csr, + 'binary' : entry.binary}) def gpr_to_abi(gpr): diff --git a/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py b/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py index bb7cf23e..06362aea 100644 --- a/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py +++ b/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py @@ -25,8 +25,21 @@ import logging sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) from riscv_trace_csv import * +from lib import * -def process_spike_sim_log(spike_log, csv): +RD_RE = re.compile(r"(?P\d) 0x(?P[a-f0-9]+?) " \ + "\((?P.*?)\) x\s*(?P\d*?) 0x(?P[a-f0-9]+)") +CORE_RE = re.compile(r"core.*0x(?P[a-f0-9]+?) \(0x(?P.*?)\) (?P.*?)$") +INSTR_RE = re.compile(r"(?P[a-z\.0-9]+?)(\s+?)(?P.*)") +GPR_RE = re.compile(r"^[a-z][0-9a-z]$") +ILLE_RE = re.compile(r"trap_illegal_instruction") +ADDR_RE = re.compile(r"(?P[\-0-9]+?)\((?P.*)\)") +PC_RE = re.compile(r"pc+") +HEX_RE = re.compile(r"^0x") + +LOGGER = logging.getLogger() + +def process_spike_sim_log(spike_log, csv, full_trace = 1): """Process SPIKE simulation log. Extract instruction and affected register information from spike simulation @@ -36,16 +49,8 @@ def process_spike_sim_log(spike_log, csv): instr_cnt = 0 spike_instr = "" - RD_RE = re.compile(r"(?P\d) 0x(?P[a-f0-9]+?) " \ - "\((?P.*?)\) x\s*(?P\d*?) 0x(?P[a-f0-9]+)") - CORE_RE = re.compile(r"core.*0x(?P[a-f0-9]+?) \(0x(?P.*?)\) (?P.*?)$") - INSTR_RE = re.compile(r"(?P[a-z\.]+?)(\s+?)(?P.*)") - GPR_RE = re.compile(r"^[a-z][0-9a-z]$") - CSR_RE = re.compile(r"csr") - ILLE_RE = re.compile(r"trap_illegal_instruction") - # Remove all the init spike boot instructions - cmd = ("sed -i '/core.*0x0000000000001010/,$!d' %s" % spike_log) + cmd = ("sed -i '/3 0x0000000000001010/,$!d' %s" % spike_log) os.system(cmd) # Remove all instructions after ecall (end of program excecution) cmd = ("sed -i '/ecall/q' %s" % spike_log) @@ -61,7 +66,8 @@ def process_spike_sim_log(spike_log, csv): # Extract instruction infromation m = CORE_RE.search(line) if m: - spike_instr = m.group("instr") + spike_instr = m.group("instr").replace("pc + ", "") + spike_instr = spike_instr.replace("pc - ", "-") rv_instr_trace = RiscvInstructiontTraceEntry() rv_instr_trace.instr_str = spike_instr rv_instr_trace.addr = m.group("addr") @@ -81,46 +87,308 @@ def process_spike_sim_log(spike_log, csv): rv_instr_trace.rd_val = m.group("val") rv_instr_trace.privileged_mode = m.group("pri") gpr[rv_instr_trace.rd] = rv_instr_trace.rd_val - s = INSTR_RE.search(spike_instr) - if s: - rv_instr_trace.instr = s.group("instr") - operand_str = s.group("operand").replace(" ", "") - if operand_str != "" : + else: + # If full trace is not enabled, skip the entry that doesn't have + # architectural state update. + if not full_trace: + continue + if full_trace: + s = INSTR_RE.search(spike_instr) + if s: + rv_instr_trace.instr = s.group("instr") + operand_str = s.group("operand").replace(" ", "") operands = operand_str.split(",") - if CSR_RE.search(s.group("instr")): - # CSR instruction - operand = operands[-1] - if GPR_RE.search(operand) or operand == "zero": - rv_instr_trace.rs1 = operand - rv_instr_trace.rs1_val = gpr[operand] - else: - rv_instr_trace.imm = operand - else: - # Non CSR instruction - for i in range(1, len(operands)): - operand = operands[i] - if GPR_RE.search(operand) or operand == "zero": - if i == 1: - rv_instr_trace.rs1 = operand - rv_instr_trace.rs1_val = gpr[operand] - else: - rv_instr_trace.rs2 = operands[i] - rv_instr_trace.rs2_val = gpr[operand] - else: - rv_instr_trace.imm = operand - trace_csv.write_trace_entry(rv_instr_trace) + assign_operand(rv_instr_trace, operands, gpr) + else: + rv_instr_trace.instr = spike_instr + else: + rv_instr_trace.instr = spike_instr + trace_csv.write_trace_entry(rv_instr_trace) logging.info("Processed instruction count : %d" % instr_cnt) + logging.info("CSV saved to : %s" % csv) +def sint_to_hex(val): + """Signed integer to hex conversion""" + return str(hex((val + (1 << 32)) % (1 << 32))) + + +def get_imm_hex_val(imm): + """Get the hex representation of the imm value""" + if imm[0] == '-': + is_negative = 1 + imm = imm[1:] + else: + is_negative = 0 + imm_val = int(imm, 0) + if is_negative: + imm_val = -imm_val + hexstr = sint_to_hex(imm_val) + return hexstr[2:] + + +def assign_operand(trace, operands, gpr): + #logging.debug("-> [%0s] %0s" % (trace.instr, trace.instr_str)) + if trace.instr in ['lb', 'lh', 'lw', 'lbu', 'lhu', 'ld', 'lq', 'lwu', 'ldu', + 'c.lw', 'c.ld', 'c.lq', 'c.lwsp', 'c.ldsp', 'c.lqsp']: + # TODO: Support regular load/store format + m = ADDR_RE.search(operands[1]) + # Load instruction + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + if m: + trace.imm = get_imm_hex_val(m.group('imm')) + trace.rs1 = m.group('rs1') + trace.rs1_val = gpr[trace.rs1] + else: + logging.info("Unexpected load address %0s", operands[1]) + elif trace.instr in ['sb', 'sh', 'sw', 'sd', 'sq', 'c.sw', 'c.sd', 'c.sq', + 'c.swsp', 'c.sdsp', 'c.sqsp']: + # Store instruction + m = ADDR_RE.search(operands[1]) + # Load instruction + trace.rs2 = operands[0] + trace.rs2_val = gpr[trace.rs2] + if m: + trace.imm = get_imm_hex_val(m.group('imm')) + trace.rs1 = m.group('rs1') + trace.rs1_val = gpr[trace.rs1] + else: + logging.info("Unexpected store address %0s", operands[1]) + elif trace.instr in ['mul', 'mulh', 'mulhsu', 'mulhu', 'div', 'divu', 'rem', 'remu', + 'mulw', 'muld', 'divw', 'divuw', 'divd', 'remw', 'remd', 'remuw', + 'remud', 'sll', 'srl', 'sra', 'add', 'sub', 'xor', 'or', 'and', + 'slt', 'sltu', 'sllw', 'slld', 'srlw', 'srld', 'sraw', 'srad', + 'addw', 'addd', 'subw', 'subd']: + # R type instruction + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = operands[1] + trace.rs1_val = gpr[trace.rs1] + trace.rs2 = operands[2] + trace.rs2_val = gpr[trace.rs2] + elif trace.instr in ['c.add', 'c.addw', 'c.mv', 'c.sub', 'c.jr', 'c.and', 'c.or', + 'c.xor', 'c.subw']: + # CR type + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = operands[0] + trace.rs1_val = gpr[trace.rs1] + trace.rs2 = operands[1] + trace.rs2_val = gpr[trace.rs2] + elif trace.instr in ['slli', 'srli', 'srai', 'addi', 'xori', 'ori', 'andi', 'slti', + 'sltiu', 'slliw', 'sllid', 'srliw', 'srlid', 'sraiw', 'sraid', + 'addiw', 'addid']: + # I type instruction + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = operands[1] + trace.rs1_val = gpr[trace.rs1] + trace.imm = get_imm_hex_val(operands[2]) + elif trace.instr in ['c.addi', 'c.addiw', 'c.addi16sp', 'c.addi4spn', 'c.li', 'c.lui', + 'c.slli', 'c.srai', 'c.srli', 'c.andi']: + # CI/CIW type + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.imm = get_imm_hex_val(operands[-1]) + elif trace.instr in ['beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu']: + # SB type instruction + trace.rs1 = operands[0] + trace.rs1_val = gpr[trace.rs1] + trace.rs2 = operands[1] + trace.rs2_val = gpr[trace.rs2] + trace.imm = get_imm_hex_val(operands[2]) + elif trace.instr in ['c.beqz', 'c.bnez']: + # CB type instruction + trace.rs1 = operands[0] + trace.rs1_val = gpr[trace.rs1] + trace.imm = get_imm_hex_val(operands[1]) + elif trace.instr in ['csrrw', 'csrrs', 'csrrc']: + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.csr = operands[1] + trace.rs1 = operands[2] + trace.rs1_val = gpr[trace.rs1] + elif trace.instr in ['csrrwi', 'csrrsi', 'csrrci']: + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.csr = operands[1] + trace.imm = get_imm_hex_val(operands[2]) + elif trace.instr in ['scall', 'sbreak', 'fence', 'fence.i', 'ecall', 'ebreak', 'wfi', + 'sfence.vma', 'c.ebreak', 'nop', 'c.nop']: + trace.rd = 'zero' + trace.rs1 = 'zero' + trace.rs2 = 'zero' + trace.rd_val = '0' + trace.rs1_val = '0' + trace.rs2_val = '0' + trace.imm = get_imm_hex_val('0') + elif trace.instr in ['lui', 'auipc']: + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.imm = get_imm_hex_val(operands[1]) + elif trace.instr in ['jal']: + if len(operands) == 1: + trace.imm = get_imm_hex_val(operands[0]) + else: + trace.imm = get_imm_hex_val(operands[1]) + elif trace.instr in ['jalr']: + if len(operands) == 1: + trace.rs1 = operands[0] + trace.rs1_val = gpr[trace.rs1] + trace.imm = get_imm_hex_val('0') + else: + trace.rs1 = operands[1] + trace.rs1_val = gpr[trace.rs1] + trace.imm = get_imm_hex_val(operands[2]) + elif trace.instr in ['c.j', 'c.jal']: + trace.imm = get_imm_hex_val(operands[0]) + # Pseudo instruction convertion below + elif trace.instr in ['mv']: + trace.instr = 'addi' + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = operands[1] + trace.rs1_val = gpr[trace.rs1] + trace.imm = get_imm_hex_val('0') + elif trace.instr in ['not']: + trace.instr = 'xori' + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = operands[1] + trace.rs1_val = gpr[trace.rs1] + trace.imm = get_imm_hex_val('-1') + elif trace.instr in ['neg']: + trace.instr = 'sub' + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = 'zero' + trace.rs1_val = '0' + trace.rs1 = operands[1] + trace.rs1_val = gpr[trace.rs1] + elif trace.instr in ['negw']: + trace.instr = 'subw' + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = 'zero' + trace.rs1_val = '0' + trace.rs2 = operands[1] + trace.rs2_val = gpr[trace.rs2] + elif trace.instr in ['sext.w']: + trace.instr = 'addiw' + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = operands[1] + trace.rs1_val = gpr[trace.rs1] + trace.imm = get_imm_hex_val('0') + elif trace.instr in ['seqz']: + trace.instr = 'sltiu' + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = operands[1] + trace.rs1_val = gpr[trace.rs1] + trace.imm = get_imm_hex_val('1') + elif trace.instr in ['snez']: + trace.instr = 'sltu' + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = 'zero' + trace.rs1_val = '0' + trace.rs2 = operands[1] + trace.rs2_val = gpr[trace.rs2] + elif trace.instr in ['sltz']: + trace.instr = 'slt' + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = operands[1] + trace.rs1_val = gpr[trace.rs1] + trace.rs2 = 'zero' + trace.rs2_val = '0' + elif trace.instr in ['sgtz']: + trace.instr = 'slt' + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.rs1 = 'zero' + trace.rs1_val = '0' + trace.rs2 = operands[1] + trace.rs2_val = gpr[trace.rs2] + elif trace.instr in ['beqz', 'bnez', 'bgez', 'bltz']: + trace.instr = trace.instr[0:3] + trace.rs1 = operands[0] + trace.rs1_val = gpr[trace.rs1] + trace.rs2 = 'zero' + trace.rs2_val = '0' + trace.imm = get_imm_hex_val(operands[1]) + elif trace.instr in ['blez']: + trace.instr = 'bge' + trace.rs1 = 'zero' + trace.rs1_val = '0' + trace.rs2 = operands[0] + trace.rs2_val = gpr[trace.rs2] + trace.imm = get_imm_hex_val(operands[1]) + elif trace.instr in ['bgtz']: + trace.instr = 'blt' + trace.rs1 = 'zero' + trace.rs1_val = '0' + trace.rs2 = operands[0] + trace.rs2_val = gpr[trace.rs2] + trace.imm = get_imm_hex_val(operands[1]) + elif trace.instr in ['csrr']: + trace.instr = 'csrrw' + trace.rd = operands[0] + trace.rd_val = gpr[trace.rd] + trace.csr = operands[1] + trace.rs1 = 'zero' + trace.rs1_val = '0' + elif trace.instr in ['csrw', 'csrs', 'csrc']: + trace.instr = 'csrr' + trace.instr[-1] + trace.csr = operands[0] + trace.rs1 = operands[1] + trace.rs1_val = gpr[trace.rs1] + trace.rd = 'zero' + trace.rd_val = '0' + elif trace.instr in ['csrwi', 'csrsi', 'csrci']: + trace.instr = 'csrr' + trace.instr[-2:] + trace.rd = 'zero' + trace.rd_val = '0' + trace.csr = operands[0] + trace.imm = get_imm_hex_val(operands[1]) + elif trace.instr in ['j']: + trace.instr = 'jal' + trace.rd = 'zero' + trace.rd_val = '0' + trace.imm = get_imm_hex_val(operands[0]) + elif trace.instr in ['jr']: + trace.instr = 'jal' + trace.rd = 'zero' + trace.rd_val = '0' + trace.rs1 = operands[0] + trace.rs1_val = gpr[trace.rs1] + elif trace.instr in ['li']: + trace.instr = 'li' + elif trace.instr[0:2] in ['lr', 'am', 'sc']: + # TODO: Support A-extension + pass + else: + # TODO: Support other instructions + logging.info("Unsupported instr : %s" % trace.instr) + def main(): instr_trace = [] # Parse input arguments parser = argparse.ArgumentParser() parser.add_argument("--log", type=str, help="Input spike 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 spike log - process_spike_sim_log(args.log, args.csv) + process_spike_sim_log(args.log, args.csv, args.full_trace) if __name__ == "__main__": diff --git a/vendor/google_riscv-dv/setting/riscv_core_setting.sv b/vendor/google_riscv-dv/setting/riscv_core_setting.sv index 6a4c20f0..c481c5f2 100644 --- a/vendor/google_riscv-dv/setting/riscv_core_setting.sv +++ b/vendor/google_riscv-dv/setting/riscv_core_setting.sv @@ -53,7 +53,7 @@ bit support_sfence = 1; // ---------------------------------------------------------------------------- // Implemented previlieged CSR list -privileged_reg_t implemented_csr[$] = { +parameter privileged_reg_t implemented_csr[] = { // User mode CSR USTATUS, // User status UIE, // User interrupt-enable register 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 b6ba06a6..b72821c5 100644 --- a/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv +++ b/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv @@ -993,6 +993,11 @@ class riscv_asm_program_gen extends uvm_object; // Dump performance CSRs if applicable virtual function void dump_perf_stats(); + foreach(implemented_csr[i]) begin + if (implemented_csr[i] inside {[MCYCLE:MHPMCOUNTER31H]}) begin + gen_signature_handshake(.instr(instr_stream), .signature_type(WRITE_CSR), .csr(implemented_csr[i])); + end + end endfunction // Write the generated program to a file @@ -1083,6 +1088,7 @@ class riscv_asm_program_gen extends uvm_object; virtual function void add_directed_instr_stream(string name, int unsigned ratio); directed_instr_stream_ratio[name] = ratio; + `uvm_info(`gfn, $sformatf("Adding directed instruction stream:%0s ratio:%0d/1000", name, ratio), UVM_LOW) endfunction virtual function void get_directed_instr_stream(); diff --git a/vendor/google_riscv-dv/src/riscv_illegal_instr.sv b/vendor/google_riscv-dv/src/riscv_illegal_instr.sv index 128dab47..7107908e 100644 --- a/vendor/google_riscv-dv/src/riscv_illegal_instr.sv +++ b/vendor/google_riscv-dv/src/riscv_illegal_instr.sv @@ -60,6 +60,8 @@ class riscv_illegal_instr extends uvm_object; solve opcode before instr_bin; solve func3 before instr_bin; solve func7 before instr_bin; + solve c_msb before instr_bin; + solve c_op before instr_bin; if (compressed) { instr_bin[1:0] == c_op; instr_bin[15:13] == c_msb; @@ -111,7 +113,9 @@ class riscv_illegal_instr extends uvm_object; if (exception == kHintInstr) { ((c_msb == 3'b000) && (c_op == 2'b01) && ({instr_bin[12], instr_bin[6:2]} == 6'b0)) || ((c_msb == 3'b010) && (c_op == 2'b01) && (instr_bin[11:7] == 5'b0)) || - ((c_msb == 3'b011) && (c_op == 2'b01) && (instr_bin[11:7] == 5'b0)) || + // C.LUI + ((c_msb == 3'b011) && (c_op == 2'b01) && (instr_bin[11:7] == 5'b0) && + ({instr_bin[12], instr_bin[6:2]} != 6'b0)) || ((c_msb == 3'b100) && (c_op == 2'b10) && (instr_bin[12:7] == 6'b0) && (instr_bin[6:2] != 0)); } diff --git a/vendor/google_riscv-dv/src/riscv_instr_base.sv b/vendor/google_riscv-dv/src/riscv_instr_base.sv index 4c0cf6aa..58f1046d 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_base.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_base.sv @@ -92,6 +92,7 @@ class riscv_instr_base extends uvm_object; imm_len == 8; } } + imm_len <= 20; } constraint imm_val_c { @@ -113,7 +114,7 @@ class riscv_instr_base extends uvm_object; if (instr_name == C_JR) { rs1 != ZERO; } - if (instr_name == C_MV) { + if (instr_name inside {C_ADD, C_MV}) { rs2 != ZERO; } } @@ -128,21 +129,9 @@ class riscv_instr_base extends uvm_object; } } - constraint fence_c { - if (instr_name == FENCE) { - rs1 == ZERO; - rd == ZERO; - imm == 0; - } - if (instr_name == FENCEI) { - rs1 == ZERO; - rd == ZERO; - imm == 0; - } - } - // Cannot shift more than the width of the bus constraint shift_imm_val_c { + solve category before imm; if(category == SHIFT) { if(group == RV64I) { // The new instruction in RV64I only handles 32 bits value @@ -182,9 +171,6 @@ class riscv_instr_base extends uvm_object; rs2 inside {[S0:A5]}; rd inside {[S0:A5]}; } - if(format inside {CI_FORMAT, CR_FORMAT}) { - rs1 == rd; - } // C_ADDI16SP is only valid when rd == SP if(instr_name == C_ADDI16SP) { rd == SP; @@ -240,7 +226,7 @@ class riscv_instr_base extends uvm_object; `add_instr(JALR, I_FORMAT, JUMP, RV32I) // SYNCH instructions `add_instr(FENCE, I_FORMAT, SYNCH, RV32I) - `add_instr(FENCEI, I_FORMAT, SYNCH, RV32I) + `add_instr(FENCE_I, I_FORMAT, SYNCH, RV32I) // SYSTEM instructions `add_instr(ECALL, I_FORMAT, SYSTEM, RV32I) `add_instr(EBREAK, I_FORMAT, SYSTEM, RV32I) @@ -334,7 +320,7 @@ class riscv_instr_base extends uvm_object; `add_instr(C_LI, CI_FORMAT, ARITHMETIC, RV32C) `add_instr(C_LUI, CI_FORMAT, ARITHMETIC, RV32C, NZUIMM) `add_instr(C_SUB, CS_FORMAT, ARITHMETIC, RV32C) - `add_instr(C_ADD, CS_FORMAT, ARITHMETIC, RV32C) + `add_instr(C_ADD, CR_FORMAT, ARITHMETIC, RV32C) `add_instr(C_NOP, CI_FORMAT, ARITHMETIC, RV32C) `add_instr(C_MV, CR_FORMAT, ARITHMETIC, RV32C) `add_instr(C_ANDI, CB_FORMAT, LOGICAL, RV32C) @@ -424,15 +410,21 @@ class riscv_instr_base extends uvm_object; update_imm_str(); end end - if (format inside {R_FORMAT, S_FORMAT, B_FORMAT, CSS_FORMAT, CS_FORMAT}) begin + if (format inside {R_FORMAT, S_FORMAT, B_FORMAT, CSS_FORMAT, CS_FORMAT, CR_FORMAT}) begin has_rs2 = 1'b1; end - if (!(format inside {J_FORMAT, U_FORMAT, CJ_FORMAT, CSS_FORMAT})) begin + if (!(format inside {J_FORMAT, U_FORMAT, CJ_FORMAT, CSS_FORMAT, CR_FORMAT, CI_FORMAT})) begin has_rs1 = 1'b1; end if (!(format inside {CJ_FORMAT, CB_FORMAT, CS_FORMAT, CSS_FORMAT, B_FORMAT, S_FORMAT})) begin has_rd = 1'b1; end + if (category == CSR) begin + has_rs2 = 1'b0; + if (instr_name inside {CSRRWI, CSRRSI, CSRRCI}) begin + has_rs1 = 1'b0; + end + end endfunction function void mask_imm(); @@ -544,11 +536,13 @@ class riscv_instr_base extends uvm_object; I_FORMAT: // instr rd,rs1,imm if(instr_name == NOP) asm_str = "nop"; + else if(instr_name == C_NOP) + asm_str = "c.nop"; else if(instr_name == WFI) asm_str = "wfi"; else if(instr_name == FENCE) asm_str = $sformatf("fence"); // TODO: Support all fence combinations - else if(instr_name == FENCEI) + else if(instr_name == FENCE_I) asm_str = "fence.i"; else if(category == LOAD) // Use psuedo instruction format asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name()); @@ -624,7 +618,7 @@ class riscv_instr_base extends uvm_object; MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU : get_opcode = 7'b0110011; ADDIW, SLLIW, SRLIW, SRAIW : get_opcode = 7'b0011011; MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU : get_opcode = 7'b0110011; - FENCE, FENCEI : get_opcode = 7'b0001111; + FENCE, FENCE_I : get_opcode = 7'b0001111; ECALL, EBREAK, CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI : get_opcode = 7'b1110011; ADDW, SUBW, SLLW, SRLW, SRAW, MULW, DIVW, DIVUW, REMW, REMUW : get_opcode = 7'b0111011; ECALL, EBREAK, URET, SRET, MRET, DRET, WFI, SFENCE_VMA : get_opcode = 7'b1110011; @@ -686,7 +680,7 @@ class riscv_instr_base extends uvm_object; OR : get_func3 = 3'b110; AND : get_func3 = 3'b111; FENCE : get_func3 = 3'b000; - FENCEI : get_func3 = 3'b001; + FENCE_I : get_func3 = 3'b001; ECALL : get_func3 = 3'b000; EBREAK : get_func3 = 3'b000; CSRRW : get_func3 = 3'b001; @@ -790,7 +784,7 @@ class riscv_instr_base extends uvm_object; OR : get_func7 = 7'b0000000; AND : get_func7 = 7'b0000000; FENCE : get_func7 = 7'b0000000; - FENCEI : get_func7 = 7'b0000000; + FENCE_I : get_func7 = 7'b0000000; ECALL : get_func7 = 7'b0000000; EBREAK : get_func7 = 7'b0000000; SLLIW : get_func7 = 7'b0000000; @@ -838,7 +832,7 @@ class riscv_instr_base extends uvm_object; binary = $sformatf("%8h", {imm[31:12], rd, get_opcode()}); end I_FORMAT: begin - if(instr_name inside {FENCE, FENCEI}) + if(instr_name inside {FENCE, FENCE_I}) binary = $sformatf("%8h", {17'b0, get_func3(), 5'b0, get_opcode()}); else if(category == CSR) binary = $sformatf("%8h", {csr[10:0], imm[4:0], get_func3(), rd, get_opcode()}); diff --git a/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv b/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv new file mode 100644 index 00000000..0eb3a053 --- /dev/null +++ b/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv @@ -0,0 +1,191 @@ +class riscv_instr_cov_item extends riscv_instr_base; + + typedef enum bit[1:0] { + POSITIVE, NEGATIVE + } operand_sign_e; + + typedef enum bit[1:0] { + EQUAL, LARGER, SMALLER + } compare_result_e; + + typedef enum bit [1:0] { + IDENTICAL, OPPOSITE, SIMILAR, DIFFERENT + } logical_similarity_e; + + typedef enum bit[2:0] { + NORMAL_VAL, MIN_VAL, MAX_VAL, ZERO_VAL + } special_val_e; + + rand bit [XLEN-1:0] rs1_value; + rand bit [XLEN-1:0] rs2_value; + rand bit [XLEN-1:0] rd_value; + bit [XLEN-1:0] pc; + bit [XLEN-1:0] mem_addr; + + bit unaligned_pc; + bit unaligned_mem_access; + bit compressed; + bit branch_hit; + operand_sign_e rs1_sign; + operand_sign_e rs2_sign; + operand_sign_e imm_sign; + operand_sign_e rd_sign; + special_val_e rs1_special_val; + special_val_e rs2_special_val; + special_val_e rd_special_val; + special_val_e imm_special_val; + compare_result_e compare_result; + logical_similarity_e logical_similarity; + string trace; + + `uvm_object_utils(riscv_instr_cov_item) + `uvm_object_new + + virtual function void pre_sample(); + unaligned_pc = (pc[1:0] != 2'b00); + rs1_sign = get_operand_sign(rs1_value); + rs2_sign = get_operand_sign(rs2_value); + rd_sign = get_operand_sign(rd_value); + imm_sign = get_imm_sign(imm); + rs1_special_val = get_operand_special_val(rs1_value); + rd_special_val = get_operand_special_val(rd_value); + rs2_special_val = get_operand_special_val(rs2_value); + if ((format != R_FORMAT) && (format != CR_FORMAT)) begin + imm_special_val = get_imm_special_val(imm); + end + if (category inside {COMPARE, BRANCH}) begin + compare_result = get_compare_result(); + end + if (category inside {LOAD, STORE}) begin + unaligned_mem_access = is_unaligned_mem_access(); + if (unaligned_mem_access) begin + `uvm_info(`gfn, $sformatf("Unaligned: %0s, mem_addr:%0x", instr_name.name(), mem_addr), UVM_LOW) + end + end + if (category == LOGICAL) begin + logical_similarity = get_logical_similarity(); + end + if (category == BRANCH) begin + branch_hit = is_branch_hit(); + end + endfunction + + function operand_sign_e get_operand_sign(bit [XLEN-1:0] value); + if (value[XLEN-1]) begin + return NEGATIVE; + end else begin + return POSITIVE; + end + endfunction + + function bit is_unaligned_mem_access(); + if ((instr_name inside {LWU, LD, SD, C_LD, C_SD}) && (mem_addr % 8 != 0)) begin + return 1'b1; + end else if ((instr_name inside {LW, SW, C_LW, C_SW}) && (mem_addr % 4 != 0)) begin + return 1'b1; + end else if ((instr_name inside {LH, LHU, SH}) && (mem_addr % 2 != 0)) begin + return 1'b1; + end begin + return 1'b0; + end + endfunction + + function operand_sign_e get_imm_sign(bit [31:0] value); + if (value[31]) begin + return NEGATIVE; + end else begin + return POSITIVE; + end + endfunction + + function special_val_e get_operand_special_val(bit [XLEN-1:0] value); + if (value == 0) begin + return ZERO_VAL; + end else if (value == '1 << (XLEN-1)) begin + return MIN_VAL; + end else if (value == '1 >> 1) begin + return MAX_VAL; + end else begin + return NORMAL_VAL; + end + endfunction + + function special_val_e get_imm_special_val(bit [31:0] value); + void'(randomize(imm_len)); + if (value == 0) begin + return ZERO_VAL; + end else if (format == U_FORMAT) begin + // unsigend immediate value + bit [31:0] max_val; + max_val = (1 << imm_len)-1; + if (value == '0) begin + return MIN_VAL; + end + if (value == max_val) begin + return MAX_VAL; + end + end else begin + // signed immediate value + int signed max_val, min_val; + max_val = 2 ** (imm_len-1) - 1; + min_val = -2 ** (imm_len-1); + if (min_val == $signed(value)) begin + return MIN_VAL; + end + if (max_val == $signed(value)) begin + return MAX_VAL; + end + end + return NORMAL_VAL; + endfunction + + function compare_result_e get_compare_result(); + bit [XLEN-1:0] val1, val2; + val1 = rs1_value; + val2 = (format == I_FORMAT) ? imm : rs2_value; + if (val1 == val2) begin + return EQUAL; + end else if (val1 < val2) begin + return SMALLER; + end else begin + return LARGER; + end + endfunction + + function bit is_branch_hit(); + case(instr_name) + BEQ : is_branch_hit = (rs1_value == rs2_value); + C_BEQZ : is_branch_hit = (rs1_value == 0); + BNE : is_branch_hit = (rs1_value == rs2_value); + C_BNEZ : is_branch_hit = (rs1_value != 0); + BLT : is_branch_hit = ($signed(rs1_value) < $signed(rs2_value)); + BGE : is_branch_hit = ($signed(rs1_value) > $signed(rs2_value)); + BLTU : is_branch_hit = (rs1_value < rs2_value); + BGEU : is_branch_hit = (rs1_value > rs2_value); + BGEU : is_branch_hit = (rs1_value > rs2_value); + default: `uvm_error(get_name(), $sformatf("Unexpected instr %0s", instr_name.name())) + endcase + return is_branch_hit; + endfunction + + function logical_similarity_e get_logical_similarity(); + bit [XLEN-1:0] val1, val2; + int bit_difference; + val1 = rs1_value; + val2 = (format == I_FORMAT) ? imm : rs2_value; + bit_difference = $countones(val1 ^ val2); + if (val1 == val2) + return IDENTICAL; + else if (bit_difference == 32) + return OPPOSITE; + else if (bit_difference < 5) + return SIMILAR; + else + return DIFFERENT; + endfunction + + virtual function void sample_cov(); + pre_sample(); + endfunction + +endclass diff --git a/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv b/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv new file mode 100644 index 00000000..d14589ef --- /dev/null +++ b/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv @@ -0,0 +1,847 @@ +`define INSTR_CG_BEGIN(INSTR_NAME) \ + covergroup ``INSTR_NAME``_cg with function sample(riscv_instr_cov_item instr); + +`define R_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs1 : coverpoint instr.rs1; \ + cp_rs2 : coverpoint instr.rs2; \ + cp_rd : coverpoint instr.rd; \ + cp_rs1_sign : coverpoint instr.rs1_sign; \ + cp_rs2_sign : coverpoint instr.rs2_sign; \ + cp_rd_sign : coverpoint instr.rd_sign; + +`define CMP_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs1 : coverpoint instr.rs1; \ + cp_rd : coverpoint instr.rd; \ + cp_rs1_sign : coverpoint instr.rs1_sign; \ + cp_result : coverpoint instr.rd_value[0]; + +`define SB_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs1 : coverpoint instr.rs1; \ + cp_rs2 : coverpoint instr.rs2; \ + cp_rs1_sign : coverpoint instr.rs1_sign; \ + cp_rs2_sign : coverpoint instr.rs2_sign; \ + cp_imm_sign : coverpoint instr.imm_sign; \ + cp_branch_hit : coverpoint instr.branch_hit; \ + cp_sign_cross : cross cp_rs1_sign, cp_rs2_sign, cp_imm_sign; + +`define STORE_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs1 : coverpoint instr.rs1; \ + cp_rs2 : coverpoint instr.rs2; \ + cp_imm_sign : coverpoint instr.imm_sign; \ + +`define LOAD_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs1 : coverpoint instr.rs1; \ + cp_rd : coverpoint instr.rd; \ + cp_imm_sign : coverpoint instr.imm_sign; \ + +`define I_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs1 : coverpoint instr.rs1; \ + cp_rd : coverpoint instr.rd; \ + cp_rs1_sign : coverpoint instr.rs1_sign; \ + cp_rd_sign : coverpoint instr.rd_sign; \ + cp_imm_sign : coverpoint instr.imm_sign; + +`define U_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rd : coverpoint instr.rd; \ + cp_rd_sign : coverpoint instr.rd_sign; \ + cp_imm_sign : coverpoint instr.imm_sign; + +`define CSR_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_csr : coverpoint instr.csr { \ + bins csr[] = cp_csr with (is_implemented_csr(item)); \ + } \ + cp_rs1 : coverpoint instr.rs1; \ + cp_rd : coverpoint instr.rd; + +`define CR_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs2 : coverpoint instr.rs2; \ + cp_rd : coverpoint instr.rd; \ + cp_rs2_sign : coverpoint instr.rs2_sign; + +`define CI_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rd : coverpoint instr.rd; \ + cp_imm_sign : coverpoint instr.imm_sign; + +`define CSS_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs2 : coverpoint instr.rs2; \ + cp_imm_sign : coverpoint instr.imm_sign; \ + cp_rs2_sign : coverpoint instr.rs2_sign; + +`define CIW_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_imm_sign : coverpoint instr.imm_sign; \ + cp_rd : coverpoint instr.rd { \ + bins gpr[] = cp_rd with (is_compressed_gpr(riscv_reg_t'(item))); \ + } + +`define CL_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_imm_sign : coverpoint instr.imm_sign; \ + cp_rs1 : coverpoint instr.rs1 { \ + bins gpr[] = cp_rs1 with (is_compressed_gpr(riscv_reg_t'(item))); \ + } \ + cp_rd : coverpoint instr.rd { \ + bins gpr[] = cp_rd with (is_compressed_gpr(riscv_reg_t'(item))); \ + } + +`define CS_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_imm_sign : coverpoint instr.imm_sign; \ + cp_rs1 : coverpoint instr.rs1 { \ + bins gpr[] = cp_rs1 with (is_compressed_gpr(riscv_reg_t'(item))); \ + } \ + cp_rs2 : coverpoint instr.rs2 { \ + bins gpr[] = cp_rs2 with (is_compressed_gpr(riscv_reg_t'(item))); \ + } + +`define CB_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_imm_sign : coverpoint instr.imm_sign; \ + cp_rs1 : coverpoint instr.rs1 { \ + bins gpr[] = cp_rs1 with (is_compressed_gpr(riscv_reg_t'(item))); \ + } + +`define CJ_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_imm_sign : coverpoint instr.imm_sign; + +`define CG_END endgroup + +class riscv_instr_cover_group#(privileged_reg_t implemented_pcsr[] = + riscv_instr_pkg::implemented_csr); + + riscv_instr_gen_config cfg; + riscv_instr_name_t instr_name; + riscv_instr_name_t pre_instr_name; + riscv_instr_name_t instr_list[$]; + int unsigned instr_cnt; + int unsigned branch_instr_cnt; + bit [4:0] branch_hit_history; // The last 5 branch result + privileged_reg_t privil_csr[$]; + + ///////////// RV32I instruction functional coverage ////////////// + + // Arithmetic instructions + `R_INSTR_CG_BEGIN(add) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign, cp_rd_sign; + `CG_END + + `R_INSTR_CG_BEGIN(sub) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign, cp_rd_sign; + `CG_END + + `I_INSTR_CG_BEGIN(addi) + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign, cp_rd_sign; + `CG_END + + `U_INSTR_CG_BEGIN(lui) + cp_sign_cross: cross cp_imm_sign, cp_rd_sign; + `CG_END + + `U_INSTR_CG_BEGIN(auipc) + cp_sign_cross: cross cp_imm_sign, cp_rd_sign; + `CG_END + + // Shift instructions + `R_INSTR_CG_BEGIN(sra) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(sll) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(srl) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `I_INSTR_CG_BEGIN(srai) + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign; + `CG_END + + `I_INSTR_CG_BEGIN(slli) + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign; + `CG_END + + `I_INSTR_CG_BEGIN(srli) + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign; + `CG_END + + // Logical instructions + `R_INSTR_CG_BEGIN(xor) + cp_logical : coverpoint instr.logical_similarity; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(or) + cp_logical : coverpoint instr.logical_similarity; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(and) + cp_logical : coverpoint instr.logical_similarity; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `I_INSTR_CG_BEGIN(xori) + cp_logical : coverpoint instr.logical_similarity; + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign; + `CG_END + + `I_INSTR_CG_BEGIN(ori) + cp_logical : coverpoint instr.logical_similarity; + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign; + `CG_END + + `I_INSTR_CG_BEGIN(andi) + cp_logical : coverpoint instr.logical_similarity; + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign; + `CG_END + + // Compare instructions + `CMP_INSTR_CG_BEGIN(slt) + cp_rs2 : coverpoint instr.rs2; + cp_rs2_sign : coverpoint instr.rs2_sign; + cp_sign_cross : cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `CMP_INSTR_CG_BEGIN(sltu) + cp_rs2 : coverpoint instr.rs2; + cp_rs2_sign : coverpoint instr.rs2_sign; + cp_sign_cross : cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `CMP_INSTR_CG_BEGIN(slti) + cp_imm_sign : coverpoint instr.imm_sign; + cp_sign_cross : cross cp_rs1_sign, cp_imm_sign; + `CG_END + + `CMP_INSTR_CG_BEGIN(sltiu) + cp_imm_sign : coverpoint instr.imm_sign; + cp_sign_cross : cross cp_rs1_sign, cp_imm_sign; + `CG_END + + // Branch instruction + `SB_INSTR_CG_BEGIN(beq) + `CG_END + + `SB_INSTR_CG_BEGIN(bne) + `CG_END + + `SB_INSTR_CG_BEGIN(blt) + `CG_END + + `SB_INSTR_CG_BEGIN(bge) + `CG_END + + `SB_INSTR_CG_BEGIN(bltu) + `CG_END + + `SB_INSTR_CG_BEGIN(bgeu) + `CG_END + + // Load instructions + `LOAD_INSTR_CG_BEGIN(lb) + `CG_END + + `LOAD_INSTR_CG_BEGIN(lh) + cp_align: coverpoint instr.unaligned_mem_access; + `CG_END + + `LOAD_INSTR_CG_BEGIN(lw) + cp_align: coverpoint instr.unaligned_mem_access; + `CG_END + + `LOAD_INSTR_CG_BEGIN(lbu) + `CG_END + + `LOAD_INSTR_CG_BEGIN(lhu) + cp_align: coverpoint instr.unaligned_mem_access; + `CG_END + + // Store instruction + `STORE_INSTR_CG_BEGIN(sb) + `CG_END + + `STORE_INSTR_CG_BEGIN(sh) + cp_misalign: coverpoint instr.unaligned_mem_access; + `CG_END + + `STORE_INSTR_CG_BEGIN(sw) + cp_misalign: coverpoint instr.unaligned_mem_access; + `CG_END + + // CSR instructions + `CSR_INSTR_CG_BEGIN(csrrw) + cp_rs2 : coverpoint instr.rs1; + `CG_END + + `CSR_INSTR_CG_BEGIN(csrrs) + cp_rs2 : coverpoint instr.rs1; + `CG_END + + `CSR_INSTR_CG_BEGIN(csrrc) + cp_rs2 : coverpoint instr.rs1; + `CG_END + + `CSR_INSTR_CG_BEGIN(csrrwi) + cp_imm_sign : coverpoint instr.imm_sign; + `CG_END + + `CSR_INSTR_CG_BEGIN(csrrsi) + cp_imm_sign : coverpoint instr.imm_sign; + `CG_END + + `CSR_INSTR_CG_BEGIN(csrrci) + cp_imm_sign : coverpoint instr.imm_sign; + `CG_END + + // RV32M + + `R_INSTR_CG_BEGIN(mul) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(mulh) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(mulhsu) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(mulhu) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(div) + cp_rs2_val : coverpoint instr.rs2_special_val; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(divu) + cp_rs2_val : coverpoint instr.rs2_special_val; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(rem) + cp_rs2_val : coverpoint instr.rs2_special_val; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(remu) + cp_rs2_val : coverpoint instr.rs2_special_val; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + // RV64M + + `R_INSTR_CG_BEGIN(mulw) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(divw) + cp_rs2_val : coverpoint instr.rs2_special_val; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(divuw) + cp_rs2_val : coverpoint instr.rs2_special_val; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(remw) + cp_rs2_val : coverpoint instr.rs2_special_val; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(remuw) + cp_rs2_val : coverpoint instr.rs2_special_val; + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + // RV64I + `LOAD_INSTR_CG_BEGIN(lwu) + cp_align: coverpoint instr.unaligned_mem_access; + `CG_END + + `LOAD_INSTR_CG_BEGIN(ld) + cp_align: coverpoint instr.unaligned_mem_access; + `CG_END + + `STORE_INSTR_CG_BEGIN(sd) + cp_misalign: coverpoint instr.unaligned_mem_access; + `CG_END + + `R_INSTR_CG_BEGIN(sraw) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(sllw) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `R_INSTR_CG_BEGIN(srlw) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign; + `CG_END + + `I_INSTR_CG_BEGIN(sraiw) + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign; + `CG_END + + `I_INSTR_CG_BEGIN(slliw) + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign; + `CG_END + + `I_INSTR_CG_BEGIN(srliw) + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign; + `CG_END + + `R_INSTR_CG_BEGIN(addw) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign, cp_rd_sign; + `CG_END + + `R_INSTR_CG_BEGIN(subw) + cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign, cp_rd_sign; + `CG_END + + `I_INSTR_CG_BEGIN(addiw) + cp_sign_cross: cross cp_rs1_sign, cp_imm_sign, cp_rd_sign; + `CG_END + + // RV32C + + `CL_INSTR_CG_BEGIN(c_lw) + `CG_END + + `CL_INSTR_CG_BEGIN(c_lwsp) + `CG_END + + `CS_INSTR_CG_BEGIN(c_sw) + `CG_END + + `CS_INSTR_CG_BEGIN(c_swsp) + `CG_END + + `CIW_INSTR_CG_BEGIN(c_addi4spn) + `CG_END + + `CI_INSTR_CG_BEGIN(c_addi) + `CG_END + + `CI_INSTR_CG_BEGIN(c_addi16sp) + `CG_END + + `CI_INSTR_CG_BEGIN(c_li) + `CG_END + + `CI_INSTR_CG_BEGIN(c_lui) + `CG_END + + `CS_INSTR_CG_BEGIN(c_sub) + `CG_END + + `CR_INSTR_CG_BEGIN(c_add) + `CG_END + + `CR_INSTR_CG_BEGIN(c_mv) + `CG_END + + `CB_INSTR_CG_BEGIN(c_andi) + `CG_END + + `CS_INSTR_CG_BEGIN(c_xor) + `CG_END + + `CS_INSTR_CG_BEGIN(c_or) + `CG_END + + `CS_INSTR_CG_BEGIN(c_and) + `CG_END + + `CB_INSTR_CG_BEGIN(c_beqz) + `CG_END + + `CB_INSTR_CG_BEGIN(c_bnez) + `CG_END + + `CB_INSTR_CG_BEGIN(c_srli) + `CG_END + + `CB_INSTR_CG_BEGIN(c_srai) + `CG_END + + `CI_INSTR_CG_BEGIN(c_slli) + `CG_END + + `CJ_INSTR_CG_BEGIN(c_j) + `CG_END + + `CJ_INSTR_CG_BEGIN(c_jal) + `CG_END + + `CR_INSTR_CG_BEGIN(c_jr) + `CG_END + + `CR_INSTR_CG_BEGIN(c_jalr) + `CG_END + + // RV64C + + `CL_INSTR_CG_BEGIN(c_ld) + `CG_END + + `CL_INSTR_CG_BEGIN(c_ldsp) + `CG_END + + `CS_INSTR_CG_BEGIN(c_sd) + `CG_END + + `CS_INSTR_CG_BEGIN(c_sdsp) + `CG_END + + `CI_INSTR_CG_BEGIN(c_addiw) + `CG_END + + `CS_INSTR_CG_BEGIN(c_subw) + `CG_END + + `CR_INSTR_CG_BEGIN(c_addw) + `CG_END + + // Branch hit history + covergroup branch_hit_history_cg; + coverpoint branch_hit_history; + endgroup + + // Instruction transition for all supported instructions + /* TODO: Refine the transition functional coverage, not all combinations are interesting + covergroup instr_trans_cg with function sample(); + cp_instr: coverpoint instr_name { + bins instr[] = cp_instr with (is_supported_instr(riscv_instr_name_t'(item))); + } + cp_pre_instr: coverpoint pre_instr_name { + // This is a helper coverpoint for cross coverpoint below, it should not be counted when + // calculate the coverage score + type_option.weight = 0; + bins instr[] = cp_pre_instr with (is_supported_instr(riscv_instr_name_t'(item))); + } + cp_trans: cross cp_pre_instr, cp_instr { + // Cover all instruction transitions, except for below system instructions + ignore_bins ignore = binsof(cp_instr) intersect {ECALL, URET, SRET, SRET, DRET} || + binsof(cp_pre_instr) intersect {ECALL, URET, SRET, SRET, DRET}; + } + endgroup + */ + + // TODO: Add covergroup for various hazard conditions + + function new(riscv_instr_gen_config cfg); + this.cfg = cfg; + build_instr_list(); + // RV32I instruction functional coverage instantiation + add_cg = new(); + sub_cg = new(); + addi_cg = new(); + lui_cg = new(); + auipc_cg = new(); + sll_cg = new(); + srl_cg = new(); + sra_cg = new(); + slli_cg = new(); + srli_cg = new(); + srai_cg = new(); + and_cg = new(); + or_cg = new(); + xor_cg = new(); + andi_cg = new(); + ori_cg = new(); + xori_cg = new(); + slt_cg = new(); + sltu_cg = new(); + slti_cg = new(); + sltiu_cg = new(); + beq_cg = new(); + bne_cg = new(); + blt_cg = new(); + bge_cg = new(); + bgeu_cg = new(); + bltu_cg = new(); + lb_cg = new(); + lh_cg = new(); + lw_cg = new(); + lbu_cg = new(); + lhu_cg = new(); + sb_cg = new(); + sh_cg = new(); + sw_cg = new(); + csrrw_cg = new(); + csrrs_cg = new(); + csrrc_cg = new(); + csrrwi_cg = new(); + csrrsi_cg = new(); + csrrci_cg = new(); + // instr_trans_cg = new(); + branch_hit_history_cg = new(); + if (RV32M inside {supported_isa}) begin + mul_cg = new(); + mulh_cg = new(); + mulhsu_cg = new(); + mulhu_cg = new(); + div_cg = new(); + divu_cg = new(); + rem_cg = new(); + end + if (RV64M inside {supported_isa}) begin + mulw_cg = new(); + divw_cg = new(); + divuw_cg = new(); + remw_cg = new(); + remuw_cg = new(); + end + if (RV64I inside {supported_isa}) begin + lwu_cg = new(); + ld_cg = new(); + sd_cg = new(); + sllw_cg = new(); + slliw_cg = new(); + srlw_cg = new(); + srliw_cg = new(); + sraw_cg = new(); + sraiw_cg = new(); + addw_cg = new(); + addiw_cg = new(); + subw_cg = new(); + end + if (RV32C inside {supported_isa}) begin + c_lw_cg = new(); + c_sw_cg = new(); + c_lwsp_cg = new(); + c_swsp_cg = new(); + c_addi4spn_cg = new(); + c_addi_cg = new(); + c_addi16sp_cg = new(); + c_li_cg = new(); + c_lui_cg = new(); + c_sub_cg = new(); + c_add_cg = new(); + c_mv_cg = new(); + c_andi_cg = new(); + c_xor_cg = new(); + c_or_cg = new(); + c_and_cg = new(); + c_beqz_cg = new(); + c_bnez_cg = new(); + c_srli_cg = new(); + c_srai_cg = new(); + c_slli_cg = new(); + c_j_cg = new(); + c_jal_cg = new(); + c_jr_cg = new(); + c_jalr_cg = new(); + end + if (RV64C inside {supported_isa}) begin + c_ld_cg = new(); + c_sd_cg = new(); + c_ldsp_cg = new(); + c_sdsp_cg = new(); + c_addiw_cg = new(); + c_subw_cg = new(); + c_addw_cg = new(); + end + endfunction + + function void sample(riscv_instr_cov_item instr); + pre_instr_name = instr_name; + instr_name = instr.instr_name; + instr_cnt += 1; + case (instr.instr_name) + ADD : add_cg.sample(instr); + SUB : sub_cg.sample(instr); + ADDI : addi_cg.sample(instr); + LUI : lui_cg.sample(instr); + AUIPC : auipc_cg.sample(instr); + SLL : sll_cg.sample(instr); + SRL : srl_cg.sample(instr); + SRA : sra_cg.sample(instr); + SLLI : slli_cg.sample(instr); + SRLI : srli_cg.sample(instr); + SRAI : srai_cg.sample(instr); + AND : and_cg.sample(instr); + OR : or_cg.sample(instr); + XOR : xor_cg.sample(instr); + ANDI : andi_cg.sample(instr); + ORI : ori_cg.sample(instr); + XORI : xori_cg.sample(instr); + SLT : slt_cg.sample(instr); + SLTU : sltu_cg.sample(instr); + SLTI : slti_cg.sample(instr); + SLTIU : sltiu_cg.sample(instr); + BEQ : beq_cg.sample(instr); + BNE : bne_cg.sample(instr); + BLT : blt_cg.sample(instr); + BGE : bge_cg.sample(instr); + BLTU : bltu_cg.sample(instr); + BGEU : bgeu_cg.sample(instr); + LW : lw_cg.sample(instr); + LH : lh_cg.sample(instr); + LB : lb_cg.sample(instr); + LBU : lbu_cg.sample(instr); + LHU : lhu_cg.sample(instr); + SW : sw_cg.sample(instr); + SH : sh_cg.sample(instr); + SB : sb_cg.sample(instr); + CSRRW : csrrw_cg.sample(instr); + CSRRS : csrrs_cg.sample(instr); + CSRRC : csrrc_cg.sample(instr); + CSRRWI : csrrwi_cg.sample(instr); + CSRRSI : csrrsi_cg.sample(instr); + CSRRCI : csrrci_cg.sample(instr); + MUL : mul_cg.sample(instr); + MULH : mulh_cg.sample(instr); + MULHSU : mulhsu_cg.sample(instr); + MULHU : mulhu_cg.sample(instr); + DIV : div_cg.sample(instr); + DIVU : divu_cg.sample(instr); + REM : rem_cg.sample(instr); + MULW : mulw_cg.sample(instr); + DIVW : divw_cg.sample(instr); + DIVUW : divuw_cg.sample(instr); + REMW : remw_cg.sample(instr); + REMUW : remuw_cg.sample(instr); + LWU : lwu_cg.sample(instr); + LD : ld_cg.sample(instr); + SD : sd_cg.sample(instr); + SLLW : sllw_cg.sample(instr); + SLLIW : slliw_cg.sample(instr); + SRLW : srlw_cg.sample(instr); + SRLIW : srliw_cg.sample(instr); + SRAW : sraw_cg.sample(instr); + SRAIW : sraiw_cg.sample(instr); + ADDW : addw_cg.sample(instr); + ADDIW : addiw_cg.sample(instr); + SUBW : subw_cg.sample(instr); + C_LW : c_lw_cg.sample(instr); + C_SW : c_sw_cg.sample(instr); + C_LWSP : c_lwsp_cg.sample(instr); + C_SWSP : c_swsp_cg.sample(instr); + C_ADDI4SPN : c_addi4spn_cg.sample(instr); + C_ADDI : c_addi_cg.sample(instr); + C_ADDI16SP : c_addi16sp_cg.sample(instr); + C_LI : c_li_cg.sample(instr); + C_LUI : c_lui_cg.sample(instr); + C_SUB : c_sub_cg.sample(instr); + C_ADD : c_add_cg.sample(instr); + C_MV : c_mv_cg.sample(instr); + C_ANDI : c_andi_cg.sample(instr); + C_XOR : c_xor_cg.sample(instr); + C_OR : c_or_cg.sample(instr); + C_AND : c_and_cg.sample(instr); + C_BEQZ : c_beqz_cg.sample(instr); + C_BNEZ : c_bnez_cg.sample(instr); + C_SRLI : c_srli_cg.sample(instr); + C_SRAI : c_srai_cg.sample(instr); + C_SLLI : c_slli_cg.sample(instr); + C_J : c_j_cg.sample(instr); + C_JAL : c_jal_cg.sample(instr); + C_JR : c_jr_cg.sample(instr); + C_JALR : c_jalr_cg.sample(instr); + C_LD : c_ld_cg.sample(instr); + C_SD : c_sd_cg.sample(instr); + C_LDSP : c_ldsp_cg.sample(instr); + C_SDSP : c_sdsp_cg.sample(instr); + C_SUBW : c_subw_cg.sample(instr); + C_ADDW : c_addw_cg.sample(instr); + C_ADDIW : c_addiw_cg.sample(instr); + endcase + if (instr.category == BRANCH) begin + branch_hit_history = (branch_hit_history << 1) | instr.branch_hit; + branch_instr_cnt += 1; + if (branch_instr_cnt >= $bits(branch_hit_history)) begin + branch_hit_history_cg.sample(); + end + end + if (instr_cnt > 1) begin + // instr_trans_cg.sample(); + end + endfunction + + // Check if the privileged CSR is implemented + virtual function bit is_implemented_csr(bit [11:0] pcsr); + if (pcsr inside {implemented_pcsr}) begin + return 1'b1; + end else begin + return 1'b0; + end + endfunction + + // Check if the instruction is supported + virtual function bit is_supported_instr(riscv_instr_name_t name); + if (name inside {instr_list}) begin + return 1'b1; + end else begin + return 1'b0; + end + endfunction + + // Check if the instruction is supported + virtual function bit is_compressed_gpr(riscv_reg_t gpr); + if (gpr inside {[S0:A5]}) begin + return 1'b1; + end else begin + return 1'b0; + end + endfunction + + // Build the supported instruction list based on the core setting + virtual function void build_instr_list(); + riscv_instr_name_t instr_name; + instr_name = instr_name.first; + foreach (riscv_instr_pkg::implemented_csr[i]) begin + privil_csr.push_back(riscv_instr_pkg::implemented_csr[i]); + end + do begin + riscv_instr_base instr; + if (!(instr_name inside {unsupported_instr}) && (instr_name != INVALID_INSTR)) begin + instr = riscv_instr_base::type_id::create("instr"); + if (!instr.randomize() with {instr_name == local::instr_name;}) begin + `uvm_fatal("riscv_instr_cover_group", + $sformatf("Instruction %0s randomization failure", instr_name.name())) + end + if ((instr.group inside {supported_isa}) && + (instr.group inside {RV32I, RV32M, RV64M, RV64I, RV32C, RV64C})) begin + if (((instr_name inside {URET}) && !support_umode_trap) || + ((instr_name inside {SRET, SFENCE_VMA}) && + !(SUPERVISOR_MODE inside {supported_privileged_mode})) || + ((instr_name inside {DRET}) && !support_debug_mode)) begin + instr_name = instr_name.next; + continue; + end + `uvm_info("riscv_instr_cover_group", $sformatf("Adding [%s] %s to the list", + instr.group.name(), instr.instr_name.name()), UVM_HIGH) + instr_list.push_back(instr_name); + end + end + instr_name = instr_name.next; + end + while (instr_name != instr_name.first); + endfunction + + function void reset(); + instr_cnt = 0; + branch_instr_cnt = 0; + branch_hit_history = '0; + endfunction + +endclass diff --git a/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv b/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv index 9dba46f9..a6825176 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv @@ -505,10 +505,13 @@ class riscv_instr_gen_config extends uvm_object; endfunction // Build instruction template - virtual function void build_instruction_template(); + virtual function void build_instruction_template(bit skip_instr_exclusion = 0); riscv_instr_name_t instr_name; riscv_instr_name_t excluded_instr[$]; - get_excluded_instr(excluded_instr); + excluded_instr = {INVALID_INSTR}; + if (!skip_instr_exclusion) begin + get_excluded_instr(excluded_instr); + end instr_name = instr_name.first; do begin riscv_instr_base instr; @@ -518,9 +521,6 @@ class riscv_instr_gen_config extends uvm_object; if (instr.group inside {supported_isa}) begin `uvm_info(`gfn, $sformatf("Adding [%s] %s to the list", instr.group.name(), instr.instr_name.name()), UVM_HIGH) - if (instr.category inside {SHIFT, ARITHMETIC, LOGICAL, COMPARE}) begin - basic_instr.push_back(instr_name); - end instr_group[instr.group].push_back(instr_name); instr_category[instr.category].push_back(instr_name); instr_template[instr_name] = instr; @@ -529,6 +529,11 @@ class riscv_instr_gen_config extends uvm_object; instr_name = instr_name.next; end while (instr_name != instr_name.first); + endfunction + + virtual function void build_instruction_list(); + basic_instr = {instr_category[SHIFT], instr_category[ARITHMETIC], + instr_category[LOGICAL], instr_category[COMPARE]}; if (no_ebreak == 0) begin basic_instr = {basic_instr, EBREAK}; foreach(riscv_instr_pkg::supported_isa[i]) begin @@ -546,6 +551,7 @@ class riscv_instr_gen_config extends uvm_object; end // TODO: Support CSR instruction in other mode if ((no_csr_instr == 0) && (init_privileged_mode == MACHINE_MODE)) begin + `uvm_info(`gfn, $sformatf("Adding CSR instr, mode: %0s", init_privileged_mode.name()), UVM_LOW) basic_instr = {basic_instr, instr_category[CSR]}; end if (no_wfi == 0) begin @@ -554,7 +560,6 @@ class riscv_instr_gen_config extends uvm_object; endfunction virtual function void get_excluded_instr(ref riscv_instr_name_t excluded[$]); - excluded = {excluded, INVALID_INSTR}; // Below instrutions will modify stack pointer, not allowed in normal instruction stream. // It can be used in stack operation instruction stream. excluded = {excluded, C_SWSP, C_SDSP, C_ADDI16SP}; @@ -562,7 +567,7 @@ class riscv_instr_gen_config extends uvm_object; excluded = {excluded, SFENCE_VMA}; end if (no_fence) begin - excluded = {excluded, FENCE, FENCEI, SFENCE_VMA}; + excluded = {excluded, FENCE, FENCE_I, SFENCE_VMA}; end // TODO: Support C_ADDI4SPN excluded = {excluded, C_ADDI4SPN}; diff --git a/vendor/google_riscv-dv/src/riscv_instr_pkg.sv b/vendor/google_riscv-dv/src/riscv_instr_pkg.sv index 2562f914..f67edc81 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_pkg.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_pkg.sv @@ -19,6 +19,7 @@ package riscv_instr_pkg; `include "dv_defines.svh" `include "riscv_defines.svh" + `include "uvm_macros.svh" import uvm_pkg::*; import riscv_signature_pkg::*; @@ -121,7 +122,7 @@ package riscv_instr_pkg; AND, NOP, FENCE, - FENCEI, + FENCE_I, ECALL, EBREAK, CSRRW, @@ -445,7 +446,7 @@ package riscv_instr_pkg; SIP = 'h144, // Supervisor interrupt pending SATP = 'h180, // Supervisor address translation and protection // Machine mode register - MVENDORID = 'hF11, // Vendor ID + MVENDORID = 'hF11, // Vendor ID MARCHID = 'hF12, // Architecture ID MIMPID = 'hF13, // Implementation ID MHARTID = 'hF14, // Hardware thread ID @@ -543,6 +544,7 @@ package riscv_instr_pkg; MHPMCOUNTER29H = 'hB9D, // Upper 32 bits of HPMCOUNTER29, RV32I only MHPMCOUNTER30H = 'hB9E, // Upper 32 bits of HPMCOUNTER30, RV32I only MHPMCOUNTER31H = 'hB9F, // Upper 32 bits of HPMCOUNTER31, RV32I only + MCOUNTINHIBIT = 'h320, // Machine counter-inhibit register MHPMEVENT3 = 'h323, // Machine performance-monitoring event selector MHPMEVENT4 = 'h324, // Machine performance-monitoring event selector MHPMEVENT5 = 'h325, // Machine performance-monitoring event selector @@ -692,10 +694,10 @@ package riscv_instr_pkg; parameter bit [XLEN - 1 : 0] SUM_BIT_MASK = 'h1 << 18; parameter bit [XLEN - 1 : 0] MPP_BIT_MASK = 'h3 << 11; - parameter IMM25_WIDTH = 25; - parameter IMM12_WIDTH = 12; - parameter INSTR_WIDTH = 32; - parameter DATA_WIDTH = 32; + parameter IMM25_WIDTH = 25; + parameter IMM12_WIDTH = 12; + parameter INSTR_WIDTH = 32; + parameter DATA_WIDTH = 32; // Parameters for output assembly program formatting parameter MAX_INSTR_STR_LEN = 11; @@ -830,6 +832,8 @@ package riscv_instr_pkg; `include "riscv_amo_instr_lib.sv" `include "riscv_instr_sequence.sv" `include "riscv_asm_program_gen.sv" + `include "riscv_instr_cov_item.sv" + `include "riscv_instr_cover_group.sv" `include "user_extension.svh" endpackage diff --git a/vendor/google_riscv-dv/src/riscv_rand_instr.sv b/vendor/google_riscv-dv/src/riscv_rand_instr.sv index eee6f03f..ce65c37d 100644 --- a/vendor/google_riscv-dv/src/riscv_rand_instr.sv +++ b/vendor/google_riscv-dv/src/riscv_rand_instr.sv @@ -62,7 +62,7 @@ class riscv_rand_instr extends riscv_instr_base; instr_name != SFENCE_VMA; } if(cfg.no_fence) { - !(instr_name inside {FENCE, FENCEI, SFENCE_VMA}); + !(instr_name inside {FENCE, FENCE_I, SFENCE_VMA}); } // TODO: Support C_ADDI4SPN instr_name != C_ADDI4SPN; diff --git a/vendor/google_riscv-dv/test/riscv_instr_base_test.sv b/vendor/google_riscv-dv/test/riscv_instr_base_test.sv index 40ca998c..09694376 100644 --- a/vendor/google_riscv-dv/test/riscv_instr_base_test.sv +++ b/vendor/google_riscv-dv/test/riscv_instr_base_test.sv @@ -15,8 +15,6 @@ */ -`include "uvm_macros.svh" - // Base test class riscv_instr_base_test extends uvm_test; @@ -25,12 +23,14 @@ class riscv_instr_base_test extends uvm_test; string asm_file_name = "riscv_asm_test"; riscv_asm_program_gen asm_gen; string instr_seq; + int start_idx; `uvm_component_utils(riscv_instr_base_test) function new(string name="", uvm_component parent=null); super.new(name, parent); void'($value$plusargs("asm_file_name=%0s", asm_file_name)); + void'($value$plusargs("start_idx=%0d", start_idx)); endfunction virtual function void build_phase(uvm_phase phase); @@ -68,40 +68,20 @@ class riscv_instr_base_test extends uvm_test; super.report_phase(phase); endfunction - function void get_directed_instr_stream_opts(); - string cmd_opts_prefix; - string opts; - string opt[$]; - int i = 0; - while(1) begin - cmd_opts_prefix = $sformatf("directed_instr_%0d", i); - if($value$plusargs({cmd_opts_prefix, "=%0s"}, opts)) begin - uvm_split_string(opts, ",", opt); - `DV_CHECK_FATAL(opt.size() == 2) - asm_gen.add_directed_instr_stream(opt[0], opt[1].atoi()); - end else begin - break; - end - `uvm_info(`gfn, $sformatf("Got directed instr[%0d] %0s, ratio = %0s/1000", - i, opt[0], opt[1]), UVM_LOW) - i++; - end - - endfunction - virtual function void apply_directed_instr(); endfunction task run_phase(uvm_phase phase); int fd; + cfg.build_instruction_template(); for(int i = 0; i < cfg.num_of_tests; i++) begin string test_name; randomize_cfg(); - cfg.build_instruction_template(); + cfg.build_instruction_list(); asm_gen = riscv_asm_program_gen::type_id::create("asm_gen"); - get_directed_instr_stream_opts(); asm_gen.cfg = cfg; - test_name = $sformatf("%0s_%0d.S", asm_file_name, i); + asm_gen.get_directed_instr_stream(); + test_name = $sformatf("%0s_%0d.S", asm_file_name, i+start_idx); apply_directed_instr(); `uvm_info(`gfn, "All directed instruction is applied", UVM_LOW) asm_gen.gen_program(); diff --git a/vendor/google_riscv-dv/test/riscv_instr_cov_debug_test.sv b/vendor/google_riscv-dv/test/riscv_instr_cov_debug_test.sv new file mode 100644 index 00000000..edd2cc2c --- /dev/null +++ b/vendor/google_riscv-dv/test/riscv_instr_cov_debug_test.sv @@ -0,0 +1,29 @@ +// This test is only used to debug covergroup implementation + +class riscv_instr_cov_debug_test extends uvm_test; + + riscv_instr_gen_config cfg; + riscv_instr_cover_group instr_cg; + riscv_instr_cov_item instr; + int unsigned num_of_iterations = 10000; + + `uvm_component_utils(riscv_instr_cov_debug_test) + `uvm_component_new + + task run_phase(uvm_phase phase); + bit [XLEN-1:0] rand_val; + void'($value$plusargs("num_of_iterations=%0d", num_of_iterations)); + cfg = riscv_instr_gen_config::type_id::create("cfg"); + instr = riscv_instr_cov_item::type_id::create("instr"); + instr_cg = new(cfg); + repeat(20000) begin + void'(instr.randomize() with {group == RV32I; + csr inside {implemented_csr};}); + `uvm_info(`gfn, instr.convert2asm(), UVM_LOW) + instr.pre_sample(); + instr_cg.sample(instr); + end + `uvm_info("", "TEST PASSED", UVM_NONE); + endtask + +endclass diff --git a/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv b/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv new file mode 100644 index 00000000..5436c5ce --- /dev/null +++ b/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv @@ -0,0 +1,230 @@ +// This test read all trace CSV, and collect functional coverage from the instruction trace +class riscv_instr_cov_test extends uvm_test; + + typedef uvm_enum_wrapper#(riscv_instr_name_t) instr_enum; + typedef uvm_enum_wrapper#(riscv_reg_t) gpr_enum; + typedef uvm_enum_wrapper#(privileged_reg_t) preg_enum; + + riscv_instr_gen_config cfg; + riscv_instr_cover_group instr_cg; + riscv_instr_cov_item instr; + string trace_csv[$]; + string trace[string]; + int unsigned entry_cnt; + int unsigned total_entry_cnt; + int unsigned skipped_cnt; + int unsigned illegal_instr_cnt; + + `uvm_component_utils(riscv_instr_cov_test) + `uvm_component_new + + task run_phase(uvm_phase phase); + int i; + string args; + string csv; + string line; + string header[$]; + string entry[$]; + int fd; + while(1) begin + args = {$sformatf("trace_csv_%0d", i), "=%s"}; + if ($value$plusargs(args, csv)) begin + trace_csv.push_back(csv); + end else begin + break; + end + i++; + end + cfg = riscv_instr_gen_config::type_id::create("cfg"); + cfg.build_instruction_template(.skip_instr_exclusion(1)); + instr = riscv_instr_cov_item::type_id::create("instr"); + instr.rand_mode(0); + instr.no_hint_illegal_instr_c.constraint_mode(0); + instr.imm_val_c.constraint_mode(0); + instr_cg = new(cfg); + `uvm_info(`gfn, $sformatf("%0d CSV trace files to be processed", trace_csv.size()), UVM_LOW) + foreach (trace_csv[i]) begin + entry_cnt = 0; + instr_cg.reset(); + `uvm_info(`gfn, $sformatf("Processing CSV trace[%0d]: %s", i, trace_csv[i]), UVM_LOW) + fd = $fopen(trace_csv[i], "r"); + if (fd) begin + // Get the header line + if ($fgets(line, fd)) begin + split_string(line, ",", header); + `uvm_info(`gfn, $sformatf("Header: %0s", line), UVM_HIGH); + end else begin + `uvm_info(`gfn, $sformatf("Skipping empty trace file: %0s", trace_csv[i]), UVM_LOW) + continue; + end + while ($fgets(line, fd)) begin + split_string(line, ",", entry); + if (entry.size() != header.size()) begin + `uvm_info(`gfn, $sformatf("Skipping malformed entry[%0d] : %0s", entry_cnt, line), UVM_LOW) + skipped_cnt += 1; + end else begin + trace["csv_entry"] = line; + foreach (header[j]) begin + trace[header[j]] = entry[j]; + end + post_process_trace(); + if (trace["instr"] inside {"li", "ret", "la"}) continue; + if (uvm_is_match("amo*",trace["instr"]) || + uvm_is_match("lr*" ,trace["instr"]) || + uvm_is_match("sc*" ,trace["instr"])) begin + // TODO: Enable functional coverage for AMO test + continue; + end + if (!sample()) begin + `uvm_info(`gfn, $sformatf("Skipping illegal instr name: %0s [%0s]", + trace["instr"], line), UVM_LOW) + end + end + entry_cnt += 1; + end + end else begin + `uvm_error(`gfn, $sformatf("%0s cannot be openned", trace_csv[i])) + end + `uvm_info(`gfn, $sformatf("[%s] : %0d instructions processed", + trace_csv[i], entry_cnt), UVM_LOW) + total_entry_cnt += entry_cnt; + end + `uvm_info(`gfn, $sformatf("Finished processing %0d trace CSV, %0d instructions", + trace_csv.size(), total_entry_cnt), UVM_LOW) + if ((skipped_cnt > 0) || (illegal_instr_cnt > 0)) begin + `uvm_error(`gfn, $sformatf("%0d instructions skipped, %0d illegal instruction", + skipped_cnt, illegal_instr_cnt)) + + end else begin + `uvm_info(`gfn, "TEST PASSED", UVM_NONE); + end + endtask + + virtual function void post_process_trace(); + endfunction + + function bit sample(); + riscv_instr_name_t instr_name; + if (instr_enum::from_name(process_instr_name(trace["instr"]), instr_name)) begin + if (cfg.instr_template.exists(instr_name)) begin + instr.copy_base_instr(cfg.instr_template[instr_name]); + assign_trace_info_to_instr(instr); + instr.pre_sample(); + instr_cg.sample(instr); + return 1'b1; + end + end + illegal_instr_cnt++; + return 1'b0; + endfunction + + virtual function void assign_trace_info_to_instr(riscv_instr_cov_item instr); + riscv_reg_t gpr; + privileged_reg_t preg; + get_val(trace["addr"], instr.pc); + instr.trace = trace["instr_str"]; + if (instr.instr_name inside {ECALL, EBREAK, FENCE, FENCE_I, NOP, + C_NOP, WFI, MRET, C_EBREAK}) begin + return; + end + if (instr.has_rs2) begin + if (get_gpr(trace["rs2"], gpr)) begin + instr.rs2 = gpr; + get_val(trace["rs2_val"], instr.rs2_value); + end else begin + `uvm_error(`gfn, $sformatf("Unrecoganized rs2: [%0s] (%0s)", + trace["rs2"], trace["csv_entry"])) + end + end + if (instr.has_rd) begin + if (get_gpr(trace["rd"], gpr)) begin + instr.rd = gpr; + get_val(trace["rd_val"], instr.rd_value); + end else begin + `uvm_error(`gfn, $sformatf("Unrecoganized rd: [%0s] (%0s)", + trace["rd"], trace["csv_entry"])) + end + end + if (instr.has_rs1) begin + if (instr.format inside {CI_FORMAT, CR_FORMAT, CB_FORMAT}) begin + instr.rs1 = instr.rd; + end else begin + if (get_gpr(trace["rs1"], gpr)) begin + instr.rs1 = gpr; + get_val(trace["rs1_val"], instr.rs1_value); + end else begin + `uvm_error(`gfn, $sformatf("Unrecoganized rs1: [%0s] (%0s)", + trace["rs1"], trace["csv_entry"])) + end + end + end + if (instr.has_imm) begin + get_val(trace["imm"], instr.imm); + end + if (instr.category == CSR) begin + if (preg_enum::from_name(trace["csr"].toupper(), preg)) begin + instr.csr = preg; + end else begin + get_val(trace["csr"], instr.csr); + end + end + if (instr.category inside {LOAD, STORE}) begin + if (XLEN == 32) begin + instr.mem_addr = instr.rs1_value + instr.imm; + end else begin + bit [XLEN-32-1:0] padding; + if (instr.imm[31]) begin + padding = '1; + end else begin + padding = '0; + end + instr.mem_addr = instr.rs1_value + {padding, instr.imm}; + end + end + endfunction + + function bit get_gpr(input string str, output riscv_reg_t gpr); + str = str.toupper(); + if (gpr_enum::from_name(str, gpr)) begin + return 1'b1; + end else begin + return 1'b0; + end + endfunction + + function void get_val(input string str, output bit [XLEN-1:0] val); + val = str.atohex(); + endfunction + + function string process_instr_name(string instr_name); + instr_name = instr_name.toupper(); + foreach (instr_name[i]) begin + if (instr_name[i] == ".") begin + instr_name[i] = "_"; + end + end + return instr_name; + endfunction + + function void split_string(string str, byte step, ref string result[$]); + string tmp_str; + int i; + bit in_quote; + result = {}; + while (i < str.len()) begin + if (str[i] == "\"") begin + in_quote = ~in_quote; + end else if ((str[i] == step) && !in_quote) begin + result.push_back(tmp_str); + tmp_str = ""; + end else begin + tmp_str = {tmp_str, str[i]}; + end + if (i == str.len()-1) begin + result.push_back(tmp_str); + end + i++; + end + endfunction + +endclass diff --git a/vendor/google_riscv-dv/test/riscv_instr_gen_tb_top.sv b/vendor/google_riscv-dv/test/riscv_instr_gen_tb_top.sv index b889d01a..8d54d05f 100644 --- a/vendor/google_riscv-dv/test/riscv_instr_gen_tb_top.sv +++ b/vendor/google_riscv-dv/test/riscv_instr_gen_tb_top.sv @@ -16,8 +16,6 @@ module riscv_instr_gen_tb_top; - `include "uvm_macros.svh" - import uvm_pkg::*; import riscv_instr_test_pkg::*; diff --git a/vendor/google_riscv-dv/test/riscv_instr_test_pkg.sv b/vendor/google_riscv-dv/test/riscv_instr_test_pkg.sv index 0506f0a0..5e93bd0a 100644 --- a/vendor/google_riscv-dv/test/riscv_instr_test_pkg.sv +++ b/vendor/google_riscv-dv/test/riscv_instr_test_pkg.sv @@ -21,5 +21,7 @@ package riscv_instr_test_pkg; `include "riscv_instr_base_test.sv" `include "riscv_instr_test_lib.sv" + `include "riscv_instr_cov_debug_test.sv" + `include "riscv_instr_cov_test.sv" endpackage diff --git a/vendor/google_riscv-dv/yaml/cov_testlist.yaml b/vendor/google_riscv-dv/yaml/cov_testlist.yaml new file mode 100644 index 00000000..b1ade51d --- /dev/null +++ b/vendor/google_riscv-dv/yaml/cov_testlist.yaml @@ -0,0 +1,18 @@ +- test: riscv_instr_cov_debug_test + description: > + Functional coverage debug test, this is not a functional test to the core. + iterations: 1 + gen_test: riscv_instr_cov_debug_test + no_iss: 1 + no_gcc: 1 + no_post_compare: 1 + +- test: riscv_instr_cov_test + description: > + Parse the instruction information from the CSV trace log, sample functional + coverage from the instruction trace. + iterations: 1 + gen_test: riscv_instr_cov_test + no_iss: 1 + no_gcc: 1 + no_post_compare: 1 diff --git a/vendor/google_riscv-dv/yaml/simulator.yaml b/vendor/google_riscv-dv/yaml/simulator.yaml index ac3cb8bc..b47cb81c 100644 --- a/vendor/google_riscv-dv/yaml/simulator.yaml +++ b/vendor/google_riscv-dv/yaml/simulator.yaml @@ -13,62 +13,74 @@ # limitations under the License. - tool: vcs - compile_cmd: - - "vcs -file /vcs.compile.option.f - +incdir+ - +incdir+ - -f /files.f -full64 - -l /compile.log - -Mdir=/vcs_simv.csrc - -o /vcs_simv " - sim_cmd: > - /vcs_simv +vcs+lic+wait +ntb_random_seed= + compile: + cmd: + - "vcs -file /vcs.compile.option.f + +incdir+ + +incdir+ + -f /files.f -full64 + -l /compile.log + -Mdir=/vcs_simv.csrc + -o /vcs_simv " + cov_opts: > + -cm_dir /test.vdb + sim: + cmd: > + /vcs_simv +vcs+lic+wait +ntb_random_seed= + cov_opts: > + -cm_dir /test.vdb -cm_log /dev/null -cm_name test_ - tool: ius - compile_cmd: - - "irun -64bit -access +rwc -f /files.f - +incdir+ - +incdir+ - -q -sv -uvm -vlog_ext +.vh -I. - -uvmhome CDNS-1.2 - -elaborate - -l /compile.log " - sim_cmd: > - irun -R -svseed + compile: + cmd: + - "irun -64bit -access +rwc -f /files.f + +incdir+ + +incdir+ + -q -sv -uvm -vlog_ext +.vh -I. + -uvmhome CDNS-1.2 + -elaborate + -l /compile.log " + sim: + cmd: > + irun -R -svseed - tool: questa - compile_cmd: - - "vmap mtiUvm $QUESTA_HOME/questasim/uvm-1.2" - - "vlog -64 - +incdir+ - +incdir+ - -access=rwc - -f /files.f - -sv - -mfcu -cuname design_cuname - +define+UVM_REGEX_NO_DPI - -writetoplevels /top.list - -l /compile.log " - - "vopt -64 -debug - +designfile -f /top.list - -l /optimize.log - -o design_opt" - sim_cmd: > - vsim -64 -c -do /questa_sim.tcl design_opt -sv_seed + compile: + cmd: + - "vmap mtiUvm $QUESTA_HOME/questasim/uvm-1.2" + - "vlog -64 + +incdir+ + +incdir+ + -access=rwc + -f /files.f + -sv + -mfcu -cuname design_cuname + +define+UVM_REGEX_NO_DPI + -writetoplevels /top.list + -l /compile.log " + - "vopt -64 -debug + +designfile -f /top.list + -l /optimize.log + -o design_opt" + sim: + cmd: > + vsim -64 -c -do /questa_sim.tcl design_opt -sv_seed - tool: dsim env_var: DSIM,DSIM_LIB_PATH - compile_cmd: - - "mkdir -p /dsim" - - " -sv -work /dsim - -genimage image - +incdir+$UVM_HOME/src - $UVM_HOME/src/uvm_pkg.sv - +define+DSIM - +incdir+ - +incdir+ - -f /files.f - -l /dsim/compile.log " - sim_cmd: > - -sv_seed -pli_lib /libuvm_dpi.so +acc+rwb -image image -work /dsim + compile: + cmd: + - "mkdir -p /dsim" + - " -sv -work /dsim + -genimage image + +incdir+$UVM_HOME/src + $UVM_HOME/src/uvm_pkg.sv + +define+DSIM + +incdir+ + +incdir+ + -f /files.f + -l /dsim/compile.log " + sim: + cmd: > + -sv_seed -pli_lib /libuvm_dpi.so +acc+rwb -image image -work /dsim