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:
udinator 2019-09-23 18:08:16 -07:00 committed by taoliug
parent ec02461b4a
commit 1e8381bfa1
21 changed files with 1985 additions and 192 deletions

View file

@ -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
View 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()

View file

@ -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

View file

@ -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):

View file

@ -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__":

View file

@ -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

View file

@ -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();

View file

@ -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));
}

View file

@ -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()});

View 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

View 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

View file

@ -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};

View file

@ -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

View file

@ -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;

View file

@ -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();

View 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

View 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

View file

@ -16,8 +16,6 @@
module riscv_instr_gen_tb_top;
`include "uvm_macros.svh"
import uvm_pkg::*;
import riscv_instr_test_pkg::*;

View file

@ -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

View 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

View file

@ -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