mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-23 13:27:10 -04:00
Update google_riscv-dv to google/riscv-dv@4450592 (#347)
Update code from upstream repository https://github.com/google/riscv- dv to revision 44505927a70a6234b996d15f2e51bd1e2632b68e * Dump performance counters to testbench at EOT (Udi) * Fix a constraint issue (google/riscv-dv#174) (taoliug) * Allow split a long test to small batches (google/riscv-dv#173) (taoliug) * Fix ius compile problem (google/riscv-dv#172) (taoliug) * Add basic functional coverage for RV64IMC (google/riscv-dv#171) (taoliug) * Initial prototype of functional coverage (google/riscv-dv#169) (taoliug)
This commit is contained in:
parent
ec02461b4a
commit
1e8381bfa1
21 changed files with 1985 additions and 192 deletions
2
vendor/google_riscv-dv.lock.hjson
vendored
2
vendor/google_riscv-dv.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/google/riscv-dv
|
||||
rev: 80d429475138b4b94d863030246a06980c89889d
|
||||
rev: 44505927a70a6234b996d15f2e51bd1e2632b68e
|
||||
}
|
||||
}
|
||||
|
|
160
vendor/google_riscv-dv/cov.py
vendored
Normal file
160
vendor/google_riscv-dv/cov.py
vendored
Normal file
|
@ -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 \"<trace_csv_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>", 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()
|
100
vendor/google_riscv-dv/run.py
vendored
100
vendor/google_riscv-dv/run.py
vendored
|
@ -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('<cov_opts>', compile_spec['cov_opts'].rstrip(), compile_cmd[i])
|
||||
else:
|
||||
compile_cmd[i] = re.sub('<cov_opts>', '', compile_cmd[i])
|
||||
sim_cmd = entry['sim']['cmd']
|
||||
if ('cov_opts' in entry['sim']) and cov:
|
||||
sim_cmd = re.sub('<cov_opts>', entry['sim']['cov_opts'].rstrip(), sim_cmd)
|
||||
else:
|
||||
sim_cmd = re.sub('<cov_opts>', '', 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("<seed>", 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("<seed>", 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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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<pri>\d) 0x(?P<addr>[a-f0-9]+?) " \
|
||||
"\((?P<bin>.*?)\) x\s*(?P<reg>\d*?) 0x(?P<val>[a-f0-9]+)")
|
||||
CORE_RE = re.compile(r"core.*0x(?P<addr>[a-f0-9]+?) \(0x(?P<bin>.*?)\) (?P<instr>.*?)$")
|
||||
INSTR_RE = re.compile(r"(?P<instr>[a-z\.0-9]+?)(\s+?)(?P<operand>.*)")
|
||||
GPR_RE = re.compile(r"^[a-z][0-9a-z]$")
|
||||
ILLE_RE = re.compile(r"trap_illegal_instruction")
|
||||
ADDR_RE = re.compile(r"(?P<imm>[\-0-9]+?)\((?P<rs1>.*)\)")
|
||||
PC_RE = re.compile(r"pc+")
|
||||
HEX_RE = re.compile(r"^0x")
|
||||
|
||||
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<pri>\d) 0x(?P<addr>[a-f0-9]+?) " \
|
||||
"\((?P<bin>.*?)\) x\s*(?P<reg>\d*?) 0x(?P<val>[a-f0-9]+)")
|
||||
CORE_RE = re.compile(r"core.*0x(?P<addr>[a-f0-9]+?) \(0x(?P<bin>.*?)\) (?P<instr>.*?)$")
|
||||
INSTR_RE = re.compile(r"(?P<instr>[a-z\.]+?)(\s+?)(?P<operand>.*)")
|
||||
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__":
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
46
vendor/google_riscv-dv/src/riscv_instr_base.sv
vendored
46
vendor/google_riscv-dv/src/riscv_instr_base.sv
vendored
|
@ -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()});
|
||||
|
|
191
vendor/google_riscv-dv/src/riscv_instr_cov_item.sv
vendored
Normal file
191
vendor/google_riscv-dv/src/riscv_instr_cov_item.sv
vendored
Normal file
|
@ -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
|
847
vendor/google_riscv-dv/src/riscv_instr_cover_group.sv
vendored
Normal file
847
vendor/google_riscv-dv/src/riscv_instr_cover_group.sv
vendored
Normal file
|
@ -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
|
|
@ -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};
|
||||
|
|
16
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
16
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
29
vendor/google_riscv-dv/test/riscv_instr_cov_debug_test.sv
vendored
Normal file
29
vendor/google_riscv-dv/test/riscv_instr_cov_debug_test.sv
vendored
Normal file
|
@ -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
|
230
vendor/google_riscv-dv/test/riscv_instr_cov_test.sv
vendored
Normal file
230
vendor/google_riscv-dv/test/riscv_instr_cov_test.sv
vendored
Normal file
|
@ -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
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
module riscv_instr_gen_tb_top;
|
||||
|
||||
`include "uvm_macros.svh"
|
||||
|
||||
import uvm_pkg::*;
|
||||
import riscv_instr_test_pkg::*;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
18
vendor/google_riscv-dv/yaml/cov_testlist.yaml
vendored
Normal file
18
vendor/google_riscv-dv/yaml/cov_testlist.yaml
vendored
Normal file
|
@ -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
|
114
vendor/google_riscv-dv/yaml/simulator.yaml
vendored
114
vendor/google_riscv-dv/yaml/simulator.yaml
vendored
|
@ -13,62 +13,74 @@
|
|||
# limitations under the License.
|
||||
|
||||
- tool: vcs
|
||||
compile_cmd:
|
||||
- "vcs -file <cwd>/vcs.compile.option.f
|
||||
+incdir+<setting>
|
||||
+incdir+<user_extension>
|
||||
-f <cwd>/files.f -full64
|
||||
-l <out>/compile.log
|
||||
-Mdir=<out>/vcs_simv.csrc
|
||||
-o <out>/vcs_simv <cmp_opts>"
|
||||
sim_cmd: >
|
||||
<out>/vcs_simv +vcs+lic+wait <sim_opts> +ntb_random_seed=<seed>
|
||||
compile:
|
||||
cmd:
|
||||
- "vcs -file <cwd>/vcs.compile.option.f
|
||||
+incdir+<setting>
|
||||
+incdir+<user_extension>
|
||||
-f <cwd>/files.f -full64
|
||||
-l <out>/compile.log
|
||||
-Mdir=<out>/vcs_simv.csrc
|
||||
-o <out>/vcs_simv <cmp_opts> <cov_opts> "
|
||||
cov_opts: >
|
||||
-cm_dir <out>/test.vdb
|
||||
sim:
|
||||
cmd: >
|
||||
<out>/vcs_simv +vcs+lic+wait <sim_opts> +ntb_random_seed=<seed> <cov_opts>
|
||||
cov_opts: >
|
||||
-cm_dir <out>/test.vdb -cm_log /dev/null -cm_name test_<seed>
|
||||
|
||||
- tool: ius
|
||||
compile_cmd:
|
||||
- "irun -64bit -access +rwc -f <cwd>/files.f
|
||||
+incdir+<setting>
|
||||
+incdir+<user_extension>
|
||||
-q -sv -uvm -vlog_ext +.vh -I.
|
||||
-uvmhome CDNS-1.2
|
||||
-elaborate
|
||||
-l <out>/compile.log <cmp_opts>"
|
||||
sim_cmd: >
|
||||
irun -R <sim_opts> -svseed <seed>
|
||||
compile:
|
||||
cmd:
|
||||
- "irun -64bit -access +rwc -f <cwd>/files.f
|
||||
+incdir+<setting>
|
||||
+incdir+<user_extension>
|
||||
-q -sv -uvm -vlog_ext +.vh -I.
|
||||
-uvmhome CDNS-1.2
|
||||
-elaborate
|
||||
-l <out>/compile.log <cmp_opts>"
|
||||
sim:
|
||||
cmd: >
|
||||
irun -R <sim_opts> -svseed <seed>
|
||||
|
||||
- tool: questa
|
||||
compile_cmd:
|
||||
- "vmap mtiUvm $QUESTA_HOME/questasim/uvm-1.2"
|
||||
- "vlog -64
|
||||
+incdir+<setting>
|
||||
+incdir+<user_extension>
|
||||
-access=rwc
|
||||
-f <cwd>/files.f
|
||||
-sv
|
||||
-mfcu -cuname design_cuname
|
||||
+define+UVM_REGEX_NO_DPI
|
||||
-writetoplevels <out>/top.list
|
||||
-l <out>/compile.log <cmp_opts>"
|
||||
- "vopt -64 -debug
|
||||
+designfile -f <out>/top.list
|
||||
-l <out>/optimize.log <cmp_opts>
|
||||
-o design_opt"
|
||||
sim_cmd: >
|
||||
vsim -64 -c -do <cwd>/questa_sim.tcl design_opt <sim_opts> -sv_seed <seed>
|
||||
compile:
|
||||
cmd:
|
||||
- "vmap mtiUvm $QUESTA_HOME/questasim/uvm-1.2"
|
||||
- "vlog -64
|
||||
+incdir+<setting>
|
||||
+incdir+<user_extension>
|
||||
-access=rwc
|
||||
-f <cwd>/files.f
|
||||
-sv
|
||||
-mfcu -cuname design_cuname
|
||||
+define+UVM_REGEX_NO_DPI
|
||||
-writetoplevels <out>/top.list
|
||||
-l <out>/compile.log <cmp_opts>"
|
||||
- "vopt -64 -debug
|
||||
+designfile -f <out>/top.list
|
||||
-l <out>/optimize.log <cmp_opts>
|
||||
-o design_opt"
|
||||
sim:
|
||||
cmd: >
|
||||
vsim -64 -c -do <cwd>/questa_sim.tcl design_opt <sim_opts> -sv_seed <seed>
|
||||
|
||||
- tool: dsim
|
||||
env_var: DSIM,DSIM_LIB_PATH
|
||||
compile_cmd:
|
||||
- "mkdir -p <out>/dsim"
|
||||
- "<DSIM> -sv -work <out>/dsim
|
||||
-genimage image
|
||||
+incdir+$UVM_HOME/src
|
||||
$UVM_HOME/src/uvm_pkg.sv
|
||||
+define+DSIM
|
||||
+incdir+<setting>
|
||||
+incdir+<user_extension>
|
||||
-f <cwd>/files.f
|
||||
-l <out>/dsim/compile.log <cmp_opts>"
|
||||
sim_cmd: >
|
||||
<DSIM> <sim_opts> -sv_seed <seed> -pli_lib <DSIM_LIB_PATH>/libuvm_dpi.so +acc+rwb -image image -work <out>/dsim
|
||||
compile:
|
||||
cmd:
|
||||
- "mkdir -p <out>/dsim"
|
||||
- "<DSIM> -sv -work <out>/dsim
|
||||
-genimage image
|
||||
+incdir+$UVM_HOME/src
|
||||
$UVM_HOME/src/uvm_pkg.sv
|
||||
+define+DSIM
|
||||
+incdir+<setting>
|
||||
+incdir+<user_extension>
|
||||
-f <cwd>/files.f
|
||||
-l <out>/dsim/compile.log <cmp_opts>"
|
||||
sim:
|
||||
cmd: >
|
||||
<DSIM> <sim_opts> -sv_seed <seed> -pli_lib <DSIM_LIB_PATH>/libuvm_dpi.so +acc+rwb -image image -work <out>/dsim
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue