Update google_riscv-dv to google/riscv-dv@e6a63ff

Update code from upstream repository https://github.com/google/riscv-
dv to revision e6a63ff19ddf162a89379f9e03f76345c3558ecc

* Restructure coverage (google/riscv-dv#569) (weicaiyang)
* Add --seed_start argument and tidy up seed handling (google/riscv-
  dv#570) (Rupert Swarbrick)
*  Move `sext.b/h` bitmanip instructions to ZB_TMP (google/riscv-
  dv#573) (weicaiyang)
* PR to minor fix for running riscv_asm_program_gen.py (google/riscv-
  dv#571) (Hai Hoang Dang)
* Quickly fix broken link (google/riscv-dv#568) (weicaiyang)

Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
This commit is contained in:
Rupert Swarbrick 2020-05-18 09:53:31 +01:00 committed by Rupert Swarbrick
parent a325430904
commit f767214d88
16 changed files with 805 additions and 717 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 162ea7312d21ac0b8ae73669fb68bf284b68f851
rev: e6a63ff19ddf162a89379f9e03f76345c3558ecc
}
}

View file

@ -2,8 +2,8 @@
This directory contains the proof-of-concept work of python based RISC-V random
instruction generator. The class structure can be directly mapped to the
existing SV/UVM verison. The constraint part is implemented basd on
[https://labix.org/python-constraint](python-constraint).
existing SV/UVM verison. The constraint part is implemented based on
[python-constraint](https://labix.org/python-constraint).
The work here is just experimental. We plan to take a fresh look of the
framework and build a scalable python based generator in the near future.

View file

@ -13,6 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License.
"""
import subprocess
import random
from bitstring import BitArray, BitStream
import utils
@ -209,6 +210,7 @@ class riscv_asm_program_gen:
self.instr_stream.append(str)
def print_instr_stream(self):
subprocess.run(["mkdir", "-p", "out"])
f = open("./out/test.S", "w+")
for s in self.instr_stream:
if isinstance(s, list):

View file

@ -329,7 +329,7 @@ class riscv_instr_base:
return True
def only_arithmetic_and_logical_c(category):
if category == "ARITHMETIC" or category == "LOGICAL" or
if category == "ARITHMETIC" or category == "LOGICAL" or \
category == "BRANCH" or category == "LOAD" or category == "STORE":
return True

View file

@ -18,6 +18,7 @@ Regression script for RISC-V random instruction generator
import argparse
import os
import random
import re
import sys
import logging
@ -33,6 +34,39 @@ from types import SimpleNamespace
LOGGER = logging.getLogger()
class SeedGen:
'''An object that will generate a pseudo-random seed for test iterations'''
def __init__(self, start_seed, fixed_seed, seed_yaml):
# These checks are performed with proper error messages at argument parsing
# time, but it can't hurt to do a belt-and-braces check here too.
assert fixed_seed is None or start_seed is None
self.fixed_seed = fixed_seed
self.start_seed = start_seed
self.rerun_seed = {} if seed_yaml is None else read_yaml(seed_yaml)
def get(self, test_id, test_iter):
'''Get the seed to use for the given test and iteration'''
if test_id in self.rerun_seed:
# Note that test_id includes the iteration index (well, the batch index,
# at any rate), so this makes sense even if test_iter > 0.
return self.rerun_seed[test_id]
if self.fixed_seed is not None:
# Checked at argument parsing time
assert test_iter == 0
return self.fixed_seed
if self.start_seed is not None:
return self.start_seed + test_iter
# If the user didn't specify seeds in some way, we generate a random seed
# every time
return random.getrandbits(31)
def get_generator_cmd(simulator, simulator_yaml, cov, exp, debug_cmd):
""" Setup the compile and simulation command for the generator
@ -186,7 +220,7 @@ def run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
run_cmd(cmd, timeout_s, debug_cmd = debug_cmd)
def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_gen, csr_file,
isa, end_signature_addr, lsf_cmd, timeout_s, log_suffix,
batch_size, output_dir, verbose, check_return_code, debug_cmd):
"""Run the instruction generator
@ -196,8 +230,7 @@ def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
test_list : List of assembly programs to be compiled
cwd : Filesystem path to RISCV-DV repo
sim_opts : Simulation options for the generator
seed_yaml : Seed specification from a prior regression
seed : Seed to the instruction generator
seed_gen : A SeedGen seed generator
csr_file : YAML file containing description of all CSRs
isa : Processor supported ISA subset
end_signature_addr : Address that tests will write pass/fail signature to at end of test
@ -213,9 +246,7 @@ def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
sim_cmd = re.sub("<out>", os.path.abspath(output_dir), sim_cmd)
sim_cmd = re.sub("<cwd>", cwd, sim_cmd)
sim_cmd = re.sub("<sim_opts>", sim_opts, sim_cmd)
rerun_seed = {}
if seed_yaml:
rerun_seed = read_yaml(seed_yaml)
logging.info("Running RISC-V instruction generator")
sim_seed = {}
for test in test_list:
@ -233,10 +264,7 @@ def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
logging.info("Running %s with %0d batches" % (test['test'], batch_cnt))
for i in range(0, batch_cnt):
test_id = '%0s_%0d' % (test['test'], i)
if test_id in rerun_seed:
rand_seed = rerun_seed[test_id]
else:
rand_seed = get_seed(seed)
rand_seed = seed_gen.get(test_id, i * batch_cnt)
if i < batch_cnt - 1:
test_cnt = batch_size
else:
@ -270,18 +298,15 @@ def do_simulate(sim_cmd, test_list, cwd, sim_opts, seed_yaml, seed, csr_file,
debug_cmd = debug_cmd)
def gen(test_list, cfg, output_dir, cwd):
def gen(test_list, argv, output_dir, cwd):
"""Run the instruction generator
Args:
test_list : List of assembly programs to be compiled
cfg : Loaded configuration dictionary.
argv : Configuration arguments
output_dir : Output directory of the ELF files
cwd : Filesystem path to RISCV-DV repo
"""
# Convert key dictionary to argv variable
argv= SimpleNamespace(**cfg)
check_return_code = True
if argv.simulator == "ius":
# Incisive return non-zero return code even test passes
@ -304,7 +329,8 @@ def gen(test_list, cfg, output_dir, cwd):
argv.cmp_opts, output_dir, argv.debug, argv.lsf_cmd)
# Run the instruction generator
if not argv.co:
do_simulate(sim_cmd, test_list, cwd, argv.sim_opts, argv.seed_yaml, argv.seed, argv.csr_yaml,
seed_gen = SeedGen(argv.start_seed, argv.seed, argv.seed_yaml)
do_simulate(sim_cmd, test_list, cwd, argv.sim_opts, seed_gen, argv.csr_yaml,
argv.isa, argv.end_signature_addr, argv.lsf_cmd, argv.gen_timeout, argv.log_suffix,
argv.batch_size, output_dir, argv.verbose, check_return_code, argv.debug)
@ -644,7 +670,20 @@ def save_regr_report(report):
logging.info("ISS regression report is saved to %s" % report)
def setup_parser():
def read_seed(arg):
'''Read --seed or --seed_start'''
try:
seed = int(arg)
if seed < 0:
raise ValueError('bad seed')
return seed
except ValueError:
raise argparse.ArgumentTypeError('Bad seed ({}): '
'must be a non-negative integer.'
.format(arg))
def parse_args(cwd):
"""Create a command line parser.
Returns: The created parser.
@ -661,8 +700,6 @@ def setup_parser():
help="Regression testlist", dest="testlist")
parser.add_argument("-tn", "--test", type=str, default="all",
help="Test name, 'all' means all tests in the list", dest="test")
parser.add_argument("--seed", type=int, default=-1,
help="Randomization seed, default -1 means random seed")
parser.add_argument("-i", "--iterations", type=int, default=0,
help="Override the iteration count in the test list", dest="iterations")
parser.add_argument("-si", "--simulator", type=str, default="vcs",
@ -706,9 +743,6 @@ def setup_parser():
help="RTL simulator setting YAML")
parser.add_argument("--csr_yaml", type=str, default="",
help="CSR description file")
parser.add_argument("--seed_yaml", type=str, default="",
help="Rerun the generator with the seed specification \
from a prior regression")
parser.add_argument("-ct", "--custom_target", type=str, default="",
help="Directory name of the custom target")
parser.add_argument("-cs", "--core_setting_dir", type=str, default="",
@ -735,7 +769,47 @@ def setup_parser():
help="Run verilog style check")
parser.add_argument("-d", "--debug", type=str, default="",
help="Generate debug command log file")
return parser
rsg = parser.add_argument_group('Random seeds',
'To control random seeds, use at most one '
'of the --start_seed, --seed or --seed_yaml '
'arguments. Since the latter two only give '
'a single seed for each test, they imply '
'--iterations=1.')
rsg.add_argument("--start_seed", type=read_seed,
help=("Randomization seed to use for first iteration of "
"each test. Subsequent iterations use seeds "
"counting up from there. Cannot be used with "
"--seed or --seed_yaml."))
rsg.add_argument("--seed", type=read_seed,
help=("Randomization seed to use for each test. "
"Implies --iterations=1. Cannot be used with "
"--start_seed or --seed_yaml."))
rsg.add_argument("--seed_yaml", type=str,
help=("Rerun the generator with the seed specification "
"from a prior regression. Implies --iterations=1. "
"Cannot be used with --start_seed or --seed."))
args = parser.parse_args()
if args.seed is not None and args.start_seed is not None:
logging.error('--start_seed and --seed are mutually exclusive.')
sys.exit(RET_FAIL)
if args.seed is not None:
if args.iterations == 0:
args.iterations = 1
elif args.iterations > 1:
logging.error('--seed is incompatible with setting --iterations '
'greater than 1.')
sys.exit(RET_FAIL)
# We've parsed all the arguments from the command line; default values
# can be set in the config file. Read that here.
load_config(args, cwd)
return args
def load_config(args, cwd):
@ -804,21 +878,17 @@ def load_config(args, cwd):
sys.exit("mabi and isa must be specified for custom target %0s" % args.custom_target)
if not args.testlist:
args.testlist = args.custom_target + "/testlist.yaml"
# Create loaded configuration dictionary.
cfg = vars(args)
return cfg
def main():
"""This is the main entry point."""
try:
parser = setup_parser()
args = parser.parse_args()
cwd = os.path.dirname(os.path.realpath(__file__))
os.environ["RISCV_DV_ROOT"] = cwd
args = parse_args(cwd)
setup_logging(args.verbose)
# Load configuration from the command line and the configuration file.
cfg = load_config(args, cwd)
# Create output directory
output_dir = create_output(args.o, args.noclean)
@ -941,7 +1011,7 @@ def main():
sys.exit(RET_FAIL)
# Run remaining tests using the instruction generator
gen(matched_list, cfg, output_dir, cwd)
gen(matched_list, args, output_dir, cwd)
if not args.co:
# Compile the assembly program to ELF, convert to plain binary

View file

@ -85,20 +85,6 @@ def get_env_var(var, debug_cmd = None):
return val
def get_seed(seed):
"""Get the seed to run the generator
Args:
seed : input seed
Returns:
seed to run instruction generator
"""
if seed >= 0:
return seed
return random.getrandbits(31)
def run_cmd(cmd, timeout_s = 999, exit_on_error = 1, check_return_code = True, debug_cmd = None):
"""Run a command and return output

View file

@ -475,9 +475,7 @@ class riscv_b_instr extends riscv_instr;
}) ||
(ZBE inside {cfg.enable_bitmanip_groups} && instr_name inside {
BEXT, BEXTW,
BDEP, BDEPW,
// TODO, spec 0.92 doesn't categorize these 2 instr in any group, put in ZBE for now
SEXT_B, SEXT_H
BDEP, BDEPW
}) ||
(ZBF inside {cfg.enable_bitmanip_groups} && instr_name inside {BFP, BFPW}) ||
(ZBC inside {cfg.enable_bitmanip_groups} && instr_name inside {
@ -492,7 +490,11 @@ class riscv_b_instr extends riscv_instr;
}) ||
(ZBT inside {cfg.enable_bitmanip_groups} && instr_name inside {
CMOV, CMIX,
FSL, FSLW, FSR, FSRW, FSRI, FSRIW}));
FSL, FSLW, FSR, FSRW, FSRI, FSRIW}) ||
// TODO, spec 0.92 doesn't categorize these 2 instr, put them in ZB_TMP #572
(ZB_TMP inside {cfg.enable_bitmanip_groups} && instr_name inside {
SEXT_B, SEXT_H})
);
endfunction
endclass

View file

@ -649,4 +649,6 @@ class riscv_instr extends uvm_object;
imm_str = $sformatf("%0d", $signed(imm));
endfunction
`include "isa/riscv_instr_cov.svh"
endclass

View file

@ -0,0 +1,510 @@
typedef uvm_enum_wrapper#(riscv_reg_t) gpr_enum;
typedef uvm_enum_wrapper#(riscv_fpr_t) fpr_enum;
typedef uvm_enum_wrapper#(privileged_reg_t) preg_enum;
typedef enum bit[1:0] {
POSITIVE, NEGATIVE
} operand_sign_e;
typedef enum bit[1:0] {
DIV_NORMAL, DIV_BY_ZERO, DIV_OVERFLOW
} div_result_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;
static bit [XLEN-1:0] gpr_state[string];
rand bit [XLEN-1:0] rs1_value;
rand bit [XLEN-1:0] rs2_value;
rand bit [XLEN-1:0] rs3_value;
rand bit [XLEN-1:0] rd_value;
rand bit [XLEN-1:0] fs1_value;
rand bit [XLEN-1:0] fs2_value;
rand bit [XLEN-1:0] fs3_value;
rand bit [XLEN-1:0] fd_value;
bit [31:0] binary;
bit [XLEN-1:0] pc;
bit [XLEN-1:0] mem_addr;
bit unaligned_pc;
bit unaligned_mem_access;
bit compressed;
bit branch_hit;
div_result_e div_result;
operand_sign_e rs1_sign;
operand_sign_e rs2_sign;
operand_sign_e rs3_sign;
operand_sign_e fs1_sign;
operand_sign_e fs2_sign;
operand_sign_e fs3_sign;
operand_sign_e imm_sign;
operand_sign_e rd_sign;
operand_sign_e fd_sign;
hazard_e gpr_hazard;
hazard_e lsu_hazard;
special_val_e rs1_special_val;
special_val_e rs2_special_val;
special_val_e rs3_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;
// TODO, remove it?
//`VECTOR_INCLUDE("riscv_instr_cov_item_inc_declares.sv")
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);
rs3_sign = get_operand_sign(rs3_value);
rd_sign = get_operand_sign(rd_value);
fs1_sign = get_operand_sign(fs1_value);
fs2_sign = get_operand_sign(fs2_value);
fs3_sign = get_operand_sign(fs2_value);
fd_sign = get_operand_sign(fd_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);
rs3_special_val = get_operand_special_val(rs3_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
mem_addr = rs1_value + imm;
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_HIGH)
end
end
if (category == LOGICAL) begin
logical_similarity = get_logical_similarity();
end
if (category == BRANCH) begin
branch_hit = is_branch_hit();
end
if (instr_name inside {DIV, DIVU, REM, REMU, DIVW, DIVUW, REMW, REMUW}) begin
div_result = get_div_result();
end
endfunction
virtual 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
virtual 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
virtual function operand_sign_e get_imm_sign(bit [31:0] value);
if (value[31]) begin
return NEGATIVE;
end else begin
return POSITIVE;
end
endfunction
virtual function div_result_e get_div_result();
if (rs2_value == 0) begin
return DIV_BY_ZERO;
end else if ((rs2_value == '1) && (rs1_value == (1'b1 << (XLEN-1))))
return DIV_OVERFLOW;
else
return DIV_NORMAL;
endfunction
virtual 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
virtual function special_val_e get_imm_special_val(bit [31:0] value);
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
virtual 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
virtual 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);
default: `uvm_error(get_name(), $sformatf("Unexpected instr %0s", instr_name.name()))
endcase
return is_branch_hit;
endfunction
virtual 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 check_hazard_condition(riscv_instr pre_instr);
riscv_reg_t gpr;
if (pre_instr.has_rd) begin
if ((has_rs1 && (rs1 == pre_instr.rd)) || (has_rs2 && (rs2 == pre_instr.rd))) begin
gpr_hazard = RAW_HAZARD;
end else if (has_rd && (rd == pre_instr.rd)) begin
gpr_hazard = WAW_HAZARD;
end else if (has_rd && ((pre_instr.has_rs1 && (pre_instr.rs1 == rd)) ||
(pre_instr.has_rs2 && (pre_instr.rs2 == rd)))) begin
gpr_hazard = WAR_HAZARD;
end else begin
gpr_hazard = NO_HAZARD;
end
end
if (category == LOAD) begin
if ((pre_instr.category == STORE) && (pre_instr.mem_addr == mem_addr)) begin
lsu_hazard = RAW_HAZARD;
end else begin
lsu_hazard = NO_HAZARD;
end
end
if (category == STORE) begin
if ((pre_instr.category == STORE) && (pre_instr.mem_addr == mem_addr)) begin
lsu_hazard = WAW_HAZARD;
end else if ((pre_instr.category == LOAD) && (pre_instr.mem_addr == mem_addr)) begin
lsu_hazard = WAR_HAZARD;
end else begin
lsu_hazard = NO_HAZARD;
end
end
`uvm_info(`gfn, $sformatf("Pre:%0s, Cur:%0s, Hazard: %0s/%0s",
pre_instr.convert2asm(), this.convert2asm(),
gpr_hazard.name(), lsu_hazard.name()), UVM_FULL)
endfunction
virtual function void sample_cov();
pre_sample();
endfunction
virtual function void update_src_regs(string operands[$]);
privileged_reg_t preg;
case(format)
J_FORMAT, U_FORMAT : begin
// instr rd,imm
`DV_CHECK_FATAL(operands.size() == 2)
get_val(operands[1], imm);
end
I_FORMAT: begin
// TODO, support I_FORMAT floating point later
// if (group == RV32F) return;
if (instr_name inside {FSRI, FSRIW}) begin
`DV_CHECK_FATAL(operands.size() == 4, instr_name)
end else begin
`DV_CHECK_FATAL(operands.size() == 3, instr_name)
end
if(category == LOAD) begin
// load rd, imm(rs1)
rs1 = get_gpr(operands[2]);
rs1_value = get_gpr_state(operands[2]);
get_val(operands[1], imm);
end else if(category == CSR) begin
// csrrwi rd, csr, imm
get_val(operands[2], imm);
if (preg_enum::from_name(operands[1].toupper(), preg)) begin
csr = preg;
end else begin
get_val(operands[1], csr);
end
//end else if (instr_name inside {FSRI, FSRIW}) begin
// // fsri rd, rs1, rs3, imm
// rs1 = get_gpr(operands[1]);
// rs1_value = get_gpr_state(operands[1]);
// rs3 = get_gpr(operands[2]);
// rs3_value = get_gpr_state(operands[2]);
// get_val(operands[3], imm);
end else begin
// addi rd, rs1, imm
rs1 = get_gpr(operands[1]);
rs1_value = get_gpr_state(operands[1]);
get_val(operands[2], imm);
end
end
S_FORMAT, B_FORMAT: begin
`DV_CHECK_FATAL(operands.size() == 3)
if(category == STORE) begin
// sw rs2,imm(rs1)
//update_instr_reg_by_abi_name(operands[0], // FSW rs2 is fp, TODO
// rs2, rs2_value,
// fs2, fs2_value);
rs2 = get_gpr(operands[0]);
rs2_value = get_gpr_state(operands[0]);
rs1 = get_gpr(operands[2]);
rs1_value = get_gpr_state(operands[2]);
get_val(operands[1], imm);
end else begin
// bne rs1, rs2, imm
rs1 = get_gpr(operands[0]);
rs1_value = get_gpr_state(operands[0]);
rs2 = get_gpr(operands[1]);
rs2_value = get_gpr_state(operands[1]);
get_val(operands[2], imm);
end
end
R_FORMAT: begin
if ((has_rs2 || category == CSR) &&
!(instr_name inside {FCLASS_S, FCLASS_D})) begin
`DV_CHECK_FATAL(operands.size() == 3)
end else begin
`DV_CHECK_FATAL(operands.size() == 2)
end
if(category == CSR) begin
// csrrw rd, csr, rs1
if (preg_enum::from_name(operands[1].toupper(), preg)) begin
csr = preg;
end else begin
get_val(operands[1], csr);
end
rs1 = get_gpr(operands[2]);
rs1_value = get_gpr_state(operands[2]);
end
//else if (group inside {RV32F, RV64F, RV32D, RV64D}) begin // TODO
// // fs1
// fs1 = get_fpr(operands[1]);
// fs1_value = get_gpr_state(operands[1]);
// // fs2
// if (!instr_name inside {FCLASS_S, FCLASS_D}) begin
// fs2 = get_fpr(operands[2]);
// fs2_value = get_gpr_state(operands[2]);
// end
//end
else begin
// add rd, rs1, rs2
rs1 = get_gpr(operands[1]);
rs1_value = get_gpr_state(operands[1]);
if (has_rs2) begin
rs2 = get_gpr(operands[2]);
rs2_value = get_gpr_state(operands[2]);
end
end
end
R4_FORMAT: begin
`DV_CHECK_FATAL(operands.size() == 4)
//update_instr_reg_by_abi_name(operands[1], // TODO
// rs1, rs1_value,
// fs1, fs1_value);
//update_instr_reg_by_abi_name(operands[2],
// rs2, rs2_value,
// fs2, fs2_value);
//update_instr_reg_by_abi_name(operands[3],
// rs3, rs3_value,
// fs3, fs3_value);
rs1 = get_gpr(operands[1]);
rs1_value = get_gpr_state(operands[1]);
rs2 = get_gpr(operands[2]);
rs2_value = get_gpr_state(operands[2]);
rs2 = get_gpr(operands[3]);
rs2_value = get_gpr_state(operands[3]);
end
CI_FORMAT, CIW_FORMAT: begin
if (instr_name == C_ADDI16SP) begin
get_val(operands[1], imm);
rs1 = SP;
rs1_value = get_gpr_state("sp");
end else if (instr_name == C_ADDI4SPN) begin
rs1 = SP;
rs1_value = get_gpr_state("sp");
end else if (instr_name inside {C_LDSP, C_LWSP, C_LQSP}) begin
// c.ldsp rd, imm
get_val(operands[1], imm);
rs1 = SP;
rs1_value = get_gpr_state("sp");
end else begin
// c.lui rd, imm
get_val(operands[1], imm);
end
end
CL_FORMAT: begin
// c.lw rd, imm(rs1)
get_val(operands[1], imm);
rs1 = get_gpr(operands[2]);
rs1_value = get_gpr_state(operands[2]);
end
CS_FORMAT: begin
// c.sw rs2,imm(rs1)
rs2 = get_gpr(operands[0]);
rs2_value = get_gpr_state(operands[0]);
rs1 = get_gpr(operands[2]);
rs1_value = get_gpr_state(operands[2]);
get_val(operands[1], imm);
end
CA_FORMAT: begin
// c.and rd, rs2 (rs1 == rd)
rs2 = get_gpr(operands[1]);
rs2_value = get_gpr_state(operands[1]);
rs1 = get_gpr(operands[0]);
rs1_value = get_gpr_state(operands[0]);
end
CB_FORMAT: begin
// c.beqz rs1, imm
rs1 = get_gpr(operands[0]);
rs1_value = get_gpr_state(operands[0]);
get_val(operands[1], imm);
end
CSS_FORMAT: begin
// c.swsp rs2, imm
rs2 = get_gpr(operands[0]);
rs2_value = get_gpr_state(operands[0]);
rs1 = SP;
rs1_value = get_gpr_state("sp");
get_val(operands[1], imm);
end
CR_FORMAT: begin
if (instr_name inside {C_JR, C_JALR}) begin
// c.jalr rs1
rs1 = get_gpr(operands[0]);
rs1_value = get_gpr_state(operands[0]);
end else begin
// c.add rd, rs2
rs2 = get_gpr(operands[1]);
rs2_value = get_gpr_state(operands[1]);
end
end
CJ_FORMAT: begin
// c.j imm
get_val(operands[0], imm);
end
endcase
endfunction : update_src_regs
virtual function void update_dst_regs(string reg_name, string val_str);
// update_instr_reg_by_abi_name(pair[0], instr.rd, instr.rd_value, instr.fd, instr.fd_value);
get_val(val_str, gpr_state[reg_name], .hex(1));
rd = get_gpr(reg_name);
rd_value = get_gpr_state(reg_name);
endfunction : update_dst_regs
function riscv_reg_t get_gpr(input string str);
str = str.toupper();
if (!gpr_enum::from_name(str, get_gpr)) begin
`uvm_fatal(`gfn, $sformatf("Cannot convert %0s to GPR", str))
end
endfunction : get_gpr
virtual function bit [XLEN-1:0] get_gpr_state(string name);
if (name inside {"zero", "x0"}) begin
return 0;
end else if (gpr_state.exists(name)) begin
return gpr_state[name];
end else begin
`uvm_warning(`gfn, $sformatf("Cannot find GPR state: %0s", name))
return 0;
end
endfunction : get_gpr_state
// TODO
// virtual function riscv_fpr_t get_fpr(input string str);
// str = str.toupper();
// if (!fpr_enum::from_name(str, get_fpr)) begin
// `uvm_fatal(`gfn, $sformatf("Cannot convert %0s to FPR", str))
// end
// endfunction : get_fpr
//
// function bit is_fp_reg(input string str);
// riscv_fpr_t tmp;
// str = str.toupper();
// return fpr_enum::from_name(str, tmp);
// endfunction : is_fp_reg
//
// virtual function void update_instr_reg_by_abi_name(string abi_name,
// ref riscv_reg_t rs,
// ref bit [XLEN-1:0] rs_value,
// ref riscv_fpr_t fs,
// ref bit [XLEN-1:0] fs_value);
// if (is_fp_reg(abi_name)) begin
// fs = get_fpr(abi_name);
// fs_value = get_gpr_state(abi_name);
// end else begin
// rs = get_gpr(abi_name);
// rs_value = get_gpr_state(abi_name);
// end
// endfunction : update_instr_reg_by_abi_name

View file

@ -357,7 +357,7 @@ class riscv_asm_program_gen extends uvm_object;
// Generate the user stack section
virtual function void gen_stack_section(int hart);
string hart_prefix_string = hart_prefix(hart);
string hart_prefix_string = hart_prefix(hart);
if (cfg.use_push_data_section) begin
instr_stream.push_back($sformatf(".pushsection .%0suser_stack,\"aw\",@progbits;",
hart_prefix_string));
@ -383,7 +383,7 @@ class riscv_asm_program_gen extends uvm_object;
// The kernal stack is used to save user program context before executing exception handling
virtual function void gen_kernel_stack_section(int hart);
string hart_prefix_string = hart_prefix(hart);
string hart_prefix_string = hart_prefix(hart);
if (cfg.use_push_data_section) begin
instr_stream.push_back($sformatf(".pushsection .%0skernel_stack,\"aw\",@progbits;",
hart_prefix_string));

View file

@ -1,270 +0,0 @@
class riscv_instr_cov_item extends riscv_instr;
typedef enum bit[1:0] {
POSITIVE, NEGATIVE
} operand_sign_e;
typedef enum bit[1:0] {
DIV_NORMAL, DIV_BY_ZERO, DIV_OVERFLOW
} div_result_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 riscv_reg_t rs3;
rand bit [XLEN-1:0] rs1_value;
rand bit [XLEN-1:0] rs2_value;
rand bit [XLEN-1:0] rs3_value;
rand bit [XLEN-1:0] rd_value;
rand riscv_fpr_t fs1;
rand riscv_fpr_t fs2;
rand riscv_fpr_t fs3;
rand riscv_fpr_t fd;
rand bit [XLEN-1:0] fs1_value;
rand bit [XLEN-1:0] fs2_value;
rand bit [XLEN-1:0] fs3_value;
rand bit [XLEN-1:0] fd_value;
bit [31:0] binary;
bit [XLEN-1:0] pc;
bit [XLEN-1:0] mem_addr;
bit unaligned_pc;
bit unaligned_mem_access;
bit compressed;
bit branch_hit;
div_result_e div_result;
operand_sign_e rs1_sign;
operand_sign_e rs2_sign;
operand_sign_e rs3_sign;
operand_sign_e fs1_sign;
operand_sign_e fs2_sign;
operand_sign_e fs3_sign;
operand_sign_e imm_sign;
operand_sign_e rd_sign;
operand_sign_e fd_sign;
hazard_e gpr_hazard;
hazard_e lsu_hazard;
special_val_e rs1_special_val;
special_val_e rs2_special_val;
special_val_e rs3_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;
`VECTOR_INCLUDE("riscv_instr_cov_item_inc_declares.sv")
`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);
rs3_sign = get_operand_sign(rs3_value);
rd_sign = get_operand_sign(rd_value);
fs1_sign = get_operand_sign(fs1_value);
fs2_sign = get_operand_sign(fs2_value);
fs3_sign = get_operand_sign(fs2_value);
fd_sign = get_operand_sign(fd_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);
rs3_special_val = get_operand_special_val(rs3_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
mem_addr = rs1_value + imm;
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_HIGH)
end
end
if (category == LOGICAL) begin
logical_similarity = get_logical_similarity();
end
if (category == BRANCH) begin
branch_hit = is_branch_hit();
end
if (instr_name inside {DIV, DIVU, REM, REMU, DIVW, DIVUW, REMW, REMUW}) begin
div_result = get_div_result();
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 div_result_e get_div_result();
if (rs2_value == 0) begin
return DIV_BY_ZERO;
end else if ((rs2_value == '1) && (rs1_value == (1'b1 << (XLEN-1))))
return DIV_OVERFLOW;
else
return DIV_NORMAL;
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);
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);
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
function void check_hazard_condition(riscv_instr_cov_item pre_instr);
riscv_reg_t gpr;
if (pre_instr.has_rd) begin
if ((has_rs1 && (rs1 == pre_instr.rd)) || (has_rs2 && (rs2 == pre_instr.rd))) begin
gpr_hazard = RAW_HAZARD;
end else if (has_rd && (rd == pre_instr.rd)) begin
gpr_hazard = WAW_HAZARD;
end else if (has_rd && ((pre_instr.has_rs1 && (pre_instr.rs1 == rd)) ||
(pre_instr.has_rs2 && (pre_instr.rs2 == rd)))) begin
gpr_hazard = WAR_HAZARD;
end else begin
gpr_hazard = NO_HAZARD;
end
end
if (category == LOAD) begin
if ((pre_instr.category == STORE) && (pre_instr.mem_addr == mem_addr)) begin
lsu_hazard = RAW_HAZARD;
end else begin
lsu_hazard = NO_HAZARD;
end
end
if (category == STORE) begin
if ((pre_instr.category == STORE) && (pre_instr.mem_addr == mem_addr)) begin
lsu_hazard = WAW_HAZARD;
end else if ((pre_instr.category == LOAD) && (pre_instr.mem_addr == mem_addr)) begin
lsu_hazard = WAR_HAZARD;
end else begin
lsu_hazard = NO_HAZARD;
end
end
`uvm_info(`gfn, $sformatf("Pre:%0s, Cur:%0s, Hazard: %0s/%0s",
pre_instr.convert2asm(), this.convert2asm(),
gpr_hazard.name(), lsu_hazard.name()), UVM_FULL)
endfunction
virtual function void sample_cov();
pre_sample();
endfunction
endclass

View file

@ -23,8 +23,20 @@
`define SAMPLE(cg, val) \
if (cg != null) cg.sample(val);
`define INSTR_CG_BEGIN(INSTR_NAME) \
covergroup ``INSTR_NAME``_cg with function sample(riscv_instr_cov_item instr);
// sample with type cast
`define SAMPLE_W_TYPE(cg, val, typ = riscv_instr) \
if (cg != null) begin \
typ t; \
`DV_CHECK_FATAL($cast(t, val), $sformatf("Cannot cast %0s to %0s", `"val`", `"typ`"), \
"riscv_instr_cover_group") \
cg.sample(t); \
end
`define SAMPLE_F(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_floating_point_instr)
`define SAMPLE_B(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_b_instr)
`define INSTR_CG_BEGIN(INSTR_NAME, INSTR_CLASS = riscv_instr) \
covergroup ``INSTR_NAME``_cg with function sample(INSTR_CLASS instr);
`define R_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
@ -92,12 +104,6 @@
cp_imm_sign : coverpoint instr.imm_sign; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
`define B_I_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rs1 : coverpoint instr.rs1; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
`define U_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rd : coverpoint instr.rd; \
@ -233,7 +239,7 @@
}
`define FP_R_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_floating_point_instr) \
cp_fs1 : coverpoint instr.fs1; \
cp_fs2 : coverpoint instr.fs2; \
cp_fd : coverpoint instr.fd; \
@ -243,7 +249,7 @@
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define FP_R4_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_floating_point_instr) \
cp_fs1 : coverpoint instr.fs1; \
cp_fs2 : coverpoint instr.fs2; \
cp_fs3 : coverpoint instr.fs3; \
@ -256,35 +262,40 @@
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define FSQRT_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_floating_point_instr) \
cp_fs1 : coverpoint instr.fs1; \
cp_fd : coverpoint instr.fd; \
cp_fs1_sign : coverpoint instr.fs1_sign; \
cp_fd_sign : coverpoint instr.fd_sign; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define B_I_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_b_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
`define B_R_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_b_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rs2 : coverpoint instr.rs2; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define B_R_INSTR_NO_RS2_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_b_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define B_R4_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_b_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rs2 : coverpoint instr.rs2; \
cp_rs3 : coverpoint instr.rs3; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
// only enable the coverpoint for a particular XLEN (32, 64, 128)
`define ENABLE_CP_BY_XLEN(XLEN_VAL) \
option.weight = (XLEN == XLEN_VAL); \
@ -306,8 +317,8 @@
class riscv_instr_cover_group;
riscv_instr_gen_config cfg;
riscv_instr_cov_item cur_instr;
riscv_instr_cov_item pre_instr;
riscv_instr cur_instr;
riscv_instr pre_instr;
riscv_instr_name_t instr_list[$];
int unsigned instr_cnt;
int unsigned branch_instr_cnt;
@ -526,7 +537,7 @@ class riscv_instr_cover_group;
`CG_END
// floating instructions
`INSTR_CG_BEGIN(flw)
`INSTR_CG_BEGIN(flw, riscv_floating_point_instr)
cp_rs1 : coverpoint instr.rs1 {
`DV(ignore_bins zero = {ZERO};)
}
@ -538,7 +549,7 @@ class riscv_instr_cover_group;
})
`CG_END
`INSTR_CG_BEGIN(fsw)
`INSTR_CG_BEGIN(fsw, riscv_floating_point_instr)
cp_rs1 : coverpoint instr.rs1 {
`DV(ignore_bins zero = {ZERO};)
}
@ -1006,13 +1017,13 @@ class riscv_instr_cover_group;
`CSR_INSTR_CG_BEGIN(csrrci)
`CG_END
covergroup rv32i_misc_cg with function sample(riscv_instr_cov_item instr);
covergroup rv32i_misc_cg with function sample(riscv_instr instr);
cp_misc : coverpoint instr.instr_name {
bins instr[] = {FENCE, FENCE_I, EBREAK, ECALL, MRET};
}
endgroup
covergroup wfi_cg with function sample(riscv_instr_cov_item instr);
covergroup wfi_cg with function sample(riscv_instr instr);
cp_misc : coverpoint instr.instr_name {
bins wfi = {WFI};
}
@ -1042,7 +1053,7 @@ class riscv_instr_cover_group;
`R_INSTR_CG_BEGIN(divu)
cp_div_result: coverpoint instr.div_result {
ignore_bins no_overflow = {riscv_instr_cov_item::DIV_OVERFLOW};
ignore_bins no_overflow = {riscv_instr::DIV_OVERFLOW};
}
cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign;
`CG_END
@ -1054,7 +1065,7 @@ class riscv_instr_cover_group;
`R_INSTR_CG_BEGIN(remu)
cp_div_result: coverpoint instr.div_result {
ignore_bins no_overflow = {riscv_instr_cov_item::DIV_OVERFLOW};
ignore_bins no_overflow = {riscv_instr::DIV_OVERFLOW};
}
cp_sign_cross: cross cp_rs1_sign, cp_rs2_sign;
`CG_END
@ -1078,7 +1089,7 @@ class riscv_instr_cover_group;
`R_INSTR_CG_BEGIN(divuw)
cp_div_result: coverpoint instr.div_result {
ignore_bins no_overflow = {riscv_instr_cov_item::DIV_OVERFLOW};
ignore_bins no_overflow = {riscv_instr::DIV_OVERFLOW};
}
cp_div_zero : coverpoint instr.rs2_value iff (instr.rs2_value[31:0] == 0) {
bins zero = {0};
@ -1098,7 +1109,7 @@ class riscv_instr_cover_group;
`R_INSTR_CG_BEGIN(remuw)
cp_div_result: coverpoint instr.div_result {
ignore_bins no_overflow = {riscv_instr_cov_item::DIV_OVERFLOW};
ignore_bins no_overflow = {riscv_instr::DIV_OVERFLOW};
}
cp_div_zero : coverpoint instr.rs2_value iff (instr.rs2_value[31:0] == 0) {
bins zero = {0};
@ -1451,8 +1462,8 @@ class riscv_instr_cover_group;
function new(riscv_instr_gen_config cfg);
string opts;
this.cfg = cfg;
cur_instr = riscv_instr_cov_item::type_id::create("cur_instr");
pre_instr = riscv_instr_cov_item::type_id::create("pre_instr");
cur_instr = riscv_instr::type_id::create("cur_instr");
pre_instr = riscv_instr::type_id::create("pre_instr");
build_instr_list();
`ifdef COMPLIANCE_MODE
compliance_mode = 1;
@ -1777,7 +1788,7 @@ class riscv_instr_cover_group;
end
endfunction
function void sample(riscv_instr_cov_item instr);
function void sample(riscv_instr instr);
instr_cnt += 1;
if (instr_cnt > 1) begin
instr.check_hazard_condition(pre_instr);
@ -1901,113 +1912,113 @@ class riscv_instr_cover_group;
C_SUBW : `SAMPLE(c_subw_cg, instr)
C_ADDW : `SAMPLE(c_addw_cg, instr)
C_ADDIW : `SAMPLE(c_addiw_cg, instr)
FLW : `SAMPLE(flw_cg, instr)
FSW : `SAMPLE(fsw_cg, instr)
FADD_S : `SAMPLE(fadd_s_cg, instr)
FSUB_S : `SAMPLE(fsub_s_cg, instr)
FMUL_S : `SAMPLE(fmul_s_cg, instr)
FDIV_S : `SAMPLE(fdiv_s_cg, instr)
FSQRT_S : `SAMPLE(fsqrt_s_cg, instr)
FMIN_S : `SAMPLE(fmin_s_cg, instr)
FMAX_S : `SAMPLE(fmax_s_cg, instr)
FMADD_S : `SAMPLE(fmadd_s_cg, instr)
FNMADD_S : `SAMPLE(fnmadd_s_cg, instr)
FMSUB_S : `SAMPLE(fmsub_s_cg, instr)
FNMSUB_S : `SAMPLE(fnmsub_s_cg, instr)
FLW : `SAMPLE_F(flw_cg, instr)
FSW : `SAMPLE_F(fsw_cg, instr)
FADD_S : `SAMPLE_F(fadd_s_cg, instr)
FSUB_S : `SAMPLE_F(fsub_s_cg, instr)
FMUL_S : `SAMPLE_F(fmul_s_cg, instr)
FDIV_S : `SAMPLE_F(fdiv_s_cg, instr)
FSQRT_S : `SAMPLE_F(fsqrt_s_cg, instr)
FMIN_S : `SAMPLE_F(fmin_s_cg, instr)
FMAX_S : `SAMPLE_F(fmax_s_cg, instr)
FMADD_S : `SAMPLE_F(fmadd_s_cg, instr)
FNMADD_S : `SAMPLE_F(fnmadd_s_cg, instr)
FMSUB_S : `SAMPLE_F(fmsub_s_cg, instr)
FNMSUB_S : `SAMPLE_F(fnmsub_s_cg, instr)
// RV32B
CLZ : `SAMPLE(clz_cg, instr)
CTZ : `SAMPLE(ctz_cg, instr)
PCNT : `SAMPLE(pcnt_cg, instr)
ANDN : `SAMPLE(andn_cg, instr)
ORN : `SAMPLE(orn_cg, instr)
XNOR : `SAMPLE(xnor_cg, instr)
PACK : `SAMPLE(pack_cg, instr)
PACKH : `SAMPLE(packh_cg, instr)
MIN : `SAMPLE(min_cg, instr)
MAX : `SAMPLE(max_cg, instr)
MINU : `SAMPLE(minu_cg, instr)
MAXU : `SAMPLE(maxu_cg, instr)
SEXT_B : `SAMPLE(sext_b_cg, instr)
SEXT_H : `SAMPLE(sext_h_cg, instr)
SBSET : `SAMPLE(sbset_cg, instr)
SBCLR : `SAMPLE(sbclr_cg, instr)
SBINV : `SAMPLE(sbinv_cg, instr)
SBEXT : `SAMPLE(sbext_cg, instr)
SBSETI : `SAMPLE(sbseti_cg, instr)
SBCLRI : `SAMPLE(sbclri_cg, instr)
SBINVI : `SAMPLE(sbinvi_cg, instr)
SBEXTI : `SAMPLE(sbexti_cg, instr)
SLO : `SAMPLE(slo_cg, instr)
SRO : `SAMPLE(sro_cg, instr)
SLOI : `SAMPLE(sloi_cg, instr)
SROI : `SAMPLE(sroi_cg, instr)
ROR : `SAMPLE(ror_cg, instr)
ROL : `SAMPLE(rol_cg, instr)
RORI : `SAMPLE(rori_cg, instr)
GREV : `SAMPLE(grev_cg, instr)
GREVI : `SAMPLE(grevi_cg, instr)
SHFLI : `SAMPLE(shfli_cg, instr)
UNSHFLI : `SAMPLE(unshfli_cg, instr)
SHFL : `SAMPLE(shfl_cg, instr)
UNSHFL : `SAMPLE(unshfl_cg, instr)
GORC : `SAMPLE(gorc_cg, instr)
GORCI : `SAMPLE(gorci_cg, instr)
BFP : `SAMPLE(bfp_cg, instr)
BEXT : `SAMPLE(bext_cg, instr)
BDEP : `SAMPLE(bdep_cg, instr)
CLMUL : `SAMPLE(clmul_cg, instr)
CLMULH : `SAMPLE(clmulh_cg, instr)
CLMULR : `SAMPLE(clmulr_cg, instr)
CRC32_B : `SAMPLE(crc32_b_cg, instr)
CRC32_H : `SAMPLE(crc32_h_cg, instr)
CRC32_W : `SAMPLE(crc32_w_cg, instr)
CRC32C_B : `SAMPLE(crc32c_b_cg, instr)
CRC32C_H : `SAMPLE(crc32c_h_cg, instr)
CRC32C_W : `SAMPLE(crc32c_w_cg, instr)
CMIX : `SAMPLE(cmix_cg, instr)
CMOV : `SAMPLE(cmov_cg, instr)
FSL : `SAMPLE(fsl_cg, instr)
FSR : `SAMPLE(fsr_cg, instr)
FSRI : `SAMPLE(fsri_cg, instr)
CLZ : `SAMPLE_B(clz_cg, instr)
CTZ : `SAMPLE_B(ctz_cg, instr)
PCNT : `SAMPLE_B(pcnt_cg, instr)
ANDN : `SAMPLE_B(andn_cg, instr)
ORN : `SAMPLE_B(orn_cg, instr)
XNOR : `SAMPLE_B(xnor_cg, instr)
PACK : `SAMPLE_B(pack_cg, instr)
PACKH : `SAMPLE_B(packh_cg, instr)
MIN : `SAMPLE_B(min_cg, instr)
MAX : `SAMPLE_B(max_cg, instr)
MINU : `SAMPLE_B(minu_cg, instr)
MAXU : `SAMPLE_B(maxu_cg, instr)
SEXT_B : `SAMPLE_B(sext_b_cg, instr)
SEXT_H : `SAMPLE_B(sext_h_cg, instr)
SBSET : `SAMPLE_B(sbset_cg, instr)
SBCLR : `SAMPLE_B(sbclr_cg, instr)
SBINV : `SAMPLE_B(sbinv_cg, instr)
SBEXT : `SAMPLE_B(sbext_cg, instr)
SBSETI : `SAMPLE_B(sbseti_cg, instr)
SBCLRI : `SAMPLE_B(sbclri_cg, instr)
SBINVI : `SAMPLE_B(sbinvi_cg, instr)
SBEXTI : `SAMPLE_B(sbexti_cg, instr)
SLO : `SAMPLE_B(slo_cg, instr)
SRO : `SAMPLE_B(sro_cg, instr)
SLOI : `SAMPLE_B(sloi_cg, instr)
SROI : `SAMPLE_B(sroi_cg, instr)
ROR : `SAMPLE_B(ror_cg, instr)
ROL : `SAMPLE_B(rol_cg, instr)
RORI : `SAMPLE_B(rori_cg, instr)
GREV : `SAMPLE_B(grev_cg, instr)
GREVI : `SAMPLE_B(grevi_cg, instr)
SHFLI : `SAMPLE_B(shfli_cg, instr)
UNSHFLI : `SAMPLE_B(unshfli_cg, instr)
SHFL : `SAMPLE_B(shfl_cg, instr)
UNSHFL : `SAMPLE_B(unshfl_cg, instr)
GORC : `SAMPLE_B(gorc_cg, instr)
GORCI : `SAMPLE_B(gorci_cg, instr)
BFP : `SAMPLE_B(bfp_cg, instr)
BEXT : `SAMPLE_B(bext_cg, instr)
BDEP : `SAMPLE_B(bdep_cg, instr)
CLMUL : `SAMPLE_B(clmul_cg, instr)
CLMULH : `SAMPLE_B(clmulh_cg, instr)
CLMULR : `SAMPLE_B(clmulr_cg, instr)
CRC32_B : `SAMPLE_B(crc32_b_cg, instr)
CRC32_H : `SAMPLE_B(crc32_h_cg, instr)
CRC32_W : `SAMPLE_B(crc32_w_cg, instr)
CRC32C_B : `SAMPLE_B(crc32c_b_cg, instr)
CRC32C_H : `SAMPLE_B(crc32c_h_cg, instr)
CRC32C_W : `SAMPLE_B(crc32c_w_cg, instr)
CMIX : `SAMPLE_B(cmix_cg, instr)
CMOV : `SAMPLE_B(cmov_cg, instr)
FSL : `SAMPLE_B(fsl_cg, instr)
FSR : `SAMPLE_B(fsr_cg, instr)
FSRI : `SAMPLE_B(fsri_cg, instr)
// RV64B
CLZW : `SAMPLE(clzw_cg, instr)
CTZW : `SAMPLE(ctzw_cg, instr)
PCNTW : `SAMPLE(pcntw_cg, instr)
PACKW : `SAMPLE(packw_cg, instr)
PACKUW : `SAMPLE(packuw_cg, instr)
SLOW : `SAMPLE(slow_cg, instr)
SROW : `SAMPLE(srow_cg, instr)
SLOIW : `SAMPLE(sloiw_cg, instr)
SROIW : `SAMPLE(sroiw_cg, instr)
RORW : `SAMPLE(rorw_cg, instr)
ROLW : `SAMPLE(rolw_cg, instr)
RORIW : `SAMPLE(roriw_cg, instr)
GREVW : `SAMPLE(grevw_cg, instr)
GREVIW : `SAMPLE(greviw_cg, instr)
SHFLW : `SAMPLE(shflw_cg, instr)
UNSHFLW : `SAMPLE(unshflw_cg, instr)
GORCW : `SAMPLE(gorcw_cg, instr)
GORCIW : `SAMPLE(gorciw_cg, instr)
BFPW : `SAMPLE(bfpw_cg, instr)
BEXTW : `SAMPLE(bextw_cg, instr)
BDEPW : `SAMPLE(bdepw_cg, instr)
CLMULW : `SAMPLE(clmulw_cg, instr)
CLMULHW : `SAMPLE(clmulhw_cg, instr)
CLMULRW : `SAMPLE(clmulrw_cg, instr)
CRC32_D : `SAMPLE(crc32_d_cg, instr)
CRC32C_D : `SAMPLE(crc32c_d_cg, instr)
BMATOR : `SAMPLE(bmator_cg, instr)
BMATXOR : `SAMPLE(bmatxor_cg, instr)
BMATFLIP : `SAMPLE(bmatflip_cg, instr)
FSLW : `SAMPLE(fslw_cg, instr)
FSRW : `SAMPLE(fsrw_cg, instr)
FSRIW : `SAMPLE(fsriw_cg, instr)
ADDWU : `SAMPLE(addwu_cg, instr)
SUBWU : `SAMPLE(subwu_cg, instr)
ADDIWU : `SAMPLE(addiwu_cg, instr)
ADDU_W : `SAMPLE(addu_w_cg, instr)
SUBU_W : `SAMPLE(subu_w_cg, instr)
SLLIU_W : `SAMPLE(slliu_w_cg, instr)
CLZW : `SAMPLE_B(clzw_cg, instr)
CTZW : `SAMPLE_B(ctzw_cg, instr)
PCNTW : `SAMPLE_B(pcntw_cg, instr)
PACKW : `SAMPLE_B(packw_cg, instr)
PACKUW : `SAMPLE_B(packuw_cg, instr)
SLOW : `SAMPLE_B(slow_cg, instr)
SROW : `SAMPLE_B(srow_cg, instr)
SLOIW : `SAMPLE_B(sloiw_cg, instr)
SROIW : `SAMPLE_B(sroiw_cg, instr)
RORW : `SAMPLE_B(rorw_cg, instr)
ROLW : `SAMPLE_B(rolw_cg, instr)
RORIW : `SAMPLE_B(roriw_cg, instr)
GREVW : `SAMPLE_B(grevw_cg, instr)
GREVIW : `SAMPLE_B(greviw_cg, instr)
SHFLW : `SAMPLE_B(shflw_cg, instr)
UNSHFLW : `SAMPLE_B(unshflw_cg, instr)
GORCW : `SAMPLE_B(gorcw_cg, instr)
GORCIW : `SAMPLE_B(gorciw_cg, instr)
BFPW : `SAMPLE_B(bfpw_cg, instr)
BEXTW : `SAMPLE_B(bextw_cg, instr)
BDEPW : `SAMPLE_B(bdepw_cg, instr)
CLMULW : `SAMPLE_B(clmulw_cg, instr)
CLMULHW : `SAMPLE_B(clmulhw_cg, instr)
CLMULRW : `SAMPLE_B(clmulrw_cg, instr)
CRC32_D : `SAMPLE_B(crc32_d_cg, instr)
CRC32C_D : `SAMPLE_B(crc32c_d_cg, instr)
BMATOR : `SAMPLE_B(bmator_cg, instr)
BMATXOR : `SAMPLE_B(bmatxor_cg, instr)
BMATFLIP : `SAMPLE_B(bmatflip_cg, instr)
FSLW : `SAMPLE_B(fslw_cg, instr)
FSRW : `SAMPLE_B(fsrw_cg, instr)
FSRIW : `SAMPLE_B(fsriw_cg, instr)
ADDWU : `SAMPLE_B(addwu_cg, instr)
SUBWU : `SAMPLE_B(subwu_cg, instr)
ADDIWU : `SAMPLE_B(addiwu_cg, instr)
ADDU_W : `SAMPLE_B(addu_w_cg, instr)
SUBU_W : `SAMPLE_B(subu_w_cg, instr)
SLLIU_W : `SAMPLE_B(slliu_w_cg, instr)
`VECTOR_INCLUDE("riscv_instr_cover_group_inc_cg_sample.sv")
default: begin
if (instr.group == RV32I) begin

View file

@ -245,7 +245,8 @@ class riscv_instr_gen_config extends uvm_object;
bit enable_vector_extension;
// Bit manipulation extension support
bit enable_b_extension;
b_ext_group_t enable_bitmanip_groups[] = {ZBB, ZBS, ZBP, ZBE, ZBF, ZBC, ZBR, ZBM, ZBT};
b_ext_group_t enable_bitmanip_groups[] = {ZBB, ZBS, ZBP, ZBE, ZBF, ZBC, ZBR, ZBM, ZBT,
ZB_TMP};
//-----------------------------------------------------------------------------
// Command line options for instruction distribution control

View file

@ -1111,7 +1111,8 @@ package riscv_instr_pkg;
ZBC,
ZBR,
ZBM,
ZBT
ZBT,
ZB_TMP // for uncategorized instructions
} b_ext_group_t;
`VECTOR_INCLUDE("riscv_instr_pkg_inc_variables.sv")
@ -1298,6 +1299,28 @@ package riscv_instr_pkg;
SYNCH, SYSTEM, COUNTER, CSR, CHANGELEVEL, TRAP, INTERRUPT, AMO
};
function automatic void get_val(input string str, output bit [XLEN-1:0] val, input hex = 0);
if (str.len() > 2) begin
if (str.substr(0, 1) == "0x") begin
str = str.substr(2, str.len() -1);
val = str.atohex();
return;
end
end
if (hex) begin
val = str.atohex();
end else begin
if (str.substr(0, 0) == "-") begin
str = str.substr(1, str.len() - 1);
val = -str.atoi();
end else begin
val = str.atoi();
end
end
`uvm_info("riscv_instr_pkg", $sformatf("imm:%0s -> 0x%0x/%0d", str, val, $signed(val)),
UVM_FULL)
endfunction : get_val
`include "riscv_vector_cfg.sv"
`include "riscv_pmp_cfg.sv"
typedef class riscv_instr;
@ -1352,7 +1375,6 @@ package riscv_instr_pkg;
`include "riscv_instr_sequence.sv"
`include "riscv_asm_program_gen.sv"
`include "riscv_debug_rom_gen.sv"
`include "riscv_instr_cov_item.sv"
`include "riscv_instr_cover_group.sv"
`include "user_extension.svh"

View file

@ -2,20 +2,15 @@
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#(riscv_fpr_t) fpr_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 unexpected_illegal_instr_cnt;
bit [XLEN-1:0] gpr_state[string];
`uvm_component_utils(riscv_instr_cov_test)
`uvm_component_new
@ -41,8 +36,6 @@ class riscv_instr_cov_test extends uvm_test;
// disable_compressed_instr is not relevant to coverage test
cfg.disable_compressed_instr = 0;
riscv_instr::create_instr_list(cfg);
instr = riscv_instr_cov_item::type_id::create("instr");
instr.rand_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
@ -136,7 +129,8 @@ class riscv_instr_cov_test extends uvm_test;
end
if (instr_enum::from_name(process_instr_name(trace["instr"]), instr_name)) begin
if (riscv_instr::instr_template.exists(instr_name)) begin
instr.copy(riscv_instr::instr_template[instr_name]);
riscv_instr instr;
instr = riscv_instr::get_instr(instr_name);
if (instr.group inside {RV32I, RV32M, RV32C, RV64I, RV64M, RV64C,
RV32F, RV32B, RV64B}) begin
assign_trace_info_to_instr(instr);
@ -150,12 +144,11 @@ class riscv_instr_cov_test extends uvm_test;
process_instr_name(trace["instr"])), UVM_LOW)
endfunction
virtual function void assign_trace_info_to_instr(riscv_instr_cov_item instr);
virtual function void assign_trace_info_to_instr(riscv_instr instr);
riscv_reg_t gpr;
string operands[$];
string gpr_update[$];
string pair[$];
privileged_reg_t preg;
get_val(trace["pc"], instr.pc, .hex(1));
get_val(trace["binary"], instr.binary, .hex(1));
instr.trace = trace["instr_str"];
@ -163,262 +156,20 @@ class riscv_instr_cov_test extends uvm_test;
ECALL, C_NOP, MRET, SRET, URET}) begin
return;
end
split_string(trace["operand"], ",", operands);
case(instr.format)
J_FORMAT, U_FORMAT : begin
// instr rd,imm
`DV_CHECK_FATAL(operands.size() == 2)
get_val(operands[1], instr.imm);
end
I_FORMAT: begin
// TODO, support I_FORMAT floating point later
if (instr.group == RV32F) return;
if (instr.instr_name inside {FSRI, FSRIW}) begin
`DV_CHECK_FATAL(operands.size() == 4, trace["instr_str"])
end else begin
`DV_CHECK_FATAL(operands.size() == 3, trace["instr_str"])
end
if(instr.category == LOAD) begin
// load rd, imm(rs1)
instr.rs1 = get_gpr(operands[2]);
instr.rs1_value = get_gpr_state(operands[2]);
get_val(operands[1], instr.imm);
end else if(instr.category == CSR) begin
// csrrwi rd, csr, imm
get_val(operands[2], instr.imm);
if (preg_enum::from_name(operands[1].toupper(), preg)) begin
instr.csr = preg;
end else begin
get_val(operands[1], instr.csr);
end
end else if (instr.instr_name inside {FSRI, FSRIW}) begin
// fsri rd, rs1, rs3, imm
instr.rs1 = get_gpr(operands[1]);
instr.rs1_value = get_gpr_state(operands[1]);
instr.rs3 = get_gpr(operands[2]);
instr.rs3_value = get_gpr_state(operands[2]);
get_val(operands[3], instr.imm);
end else begin
// addi rd, rs1, imm
instr.rs1 = get_gpr(operands[1]);
instr.rs1_value = get_gpr_state(operands[1]);
get_val(operands[2], instr.imm);
end
end
S_FORMAT, B_FORMAT: begin
`DV_CHECK_FATAL(operands.size() == 3)
if(instr.category == STORE) begin
// sw rs2,imm(rs1)
update_instr_reg_by_abi_name(operands[0], // FSW rs2 is fp
instr.rs2, instr.rs2_value,
instr.fs2, instr.fs2_value);
instr.rs1 = get_gpr(operands[2]);
instr.rs1_value = get_gpr_state(operands[2]);
get_val(operands[1], instr.imm);
end else begin
// bne rs1, rs2, imm
instr.rs1 = get_gpr(operands[0]);
instr.rs1_value = get_gpr_state(operands[0]);
instr.rs2 = get_gpr(operands[1]);
instr.rs2_value = get_gpr_state(operands[1]);
get_val(operands[2], instr.imm);
end
end
R_FORMAT: begin
if ((instr.has_rs2 || instr.category == CSR) &&
!(instr.instr_name inside {FCLASS_S, FCLASS_D})) begin
`DV_CHECK_FATAL(operands.size() == 3)
end else begin
`DV_CHECK_FATAL(operands.size() == 2)
end
if(instr.category == CSR) begin
// csrrw rd, csr, rs1
if (preg_enum::from_name(operands[1].toupper(), preg)) begin
instr.csr = preg;
end else begin
get_val(operands[1], instr.csr);
end
instr.rs1 = get_gpr(operands[2]);
instr.rs1_value = get_gpr_state(operands[2]);
end
else if (instr.group inside {RV32F, RV64F, RV32D, RV64D}) begin
// fs1
instr.fs1 = get_fpr(operands[1]);
instr.fs1_value = get_gpr_state(operands[1]);
// fs2
if (!instr.instr_name inside {FCLASS_S, FCLASS_D}) begin
instr.fs2 = get_fpr(operands[2]);
instr.fs2_value = get_gpr_state(operands[2]);
end
end else begin
// add rd, rs1, rs2
instr.rs1 = get_gpr(operands[1]);
instr.rs1_value = get_gpr_state(operands[1]);
if (instr.has_rs2) begin
instr.rs2 = get_gpr(operands[2]);
instr.rs2_value = get_gpr_state(operands[2]);
end
end
end
R4_FORMAT: begin
`DV_CHECK_FATAL(operands.size() == 4)
update_instr_reg_by_abi_name(operands[1],
instr.rs1, instr.rs1_value,
instr.fs1, instr.fs1_value);
update_instr_reg_by_abi_name(operands[2],
instr.rs2, instr.rs2_value,
instr.fs2, instr.fs2_value);
update_instr_reg_by_abi_name(operands[3],
instr.rs3, instr.rs3_value,
instr.fs3, instr.fs3_value);
end
CI_FORMAT, CIW_FORMAT: begin
if (instr.instr_name == C_ADDI16SP) begin
get_val(operands[1], instr.imm);
instr.rs1 = SP;
instr.rs1_value = get_gpr_state("sp");
end else if (instr.instr_name == C_ADDI4SPN) begin
instr.rs1 = SP;
instr.rs1_value = get_gpr_state("sp");
end else if (instr.instr_name inside {C_LDSP, C_LWSP, C_LQSP}) begin
// c.ldsp rd, imm
get_val(operands[1], instr.imm);
instr.rs1 = SP;
instr.rs1_value = get_gpr_state("sp");
end else begin
// c.lui rd, imm
get_val(operands[1], instr.imm);
end
end
CL_FORMAT: begin
// c.lw rd, imm(rs1)
get_val(operands[1], instr.imm);
instr.rs1 = get_gpr(operands[2]);
instr.rs1_value = get_gpr_state(operands[2]);
end
CS_FORMAT: begin
// c.sw rs2,imm(rs1)
instr.rs2 = get_gpr(operands[0]);
instr.rs2_value = get_gpr_state(operands[0]);
instr.rs1 = get_gpr(operands[2]);
instr.rs1_value = get_gpr_state(operands[2]);
get_val(operands[1], instr.imm);
end
CA_FORMAT: begin
// c.and rd, rs2 (rs1 == rd)
instr.rs2 = get_gpr(operands[1]);
instr.rs2_value = get_gpr_state(operands[1]);
instr.rs1 = get_gpr(operands[0]);
instr.rs1_value = get_gpr_state(operands[0]);
end
CB_FORMAT: begin
// c.beqz rs1, imm
instr.rs1 = get_gpr(operands[0]);
instr.rs1_value = get_gpr_state(operands[0]);
get_val(operands[1], instr.imm);
end
CSS_FORMAT: begin
// c.swsp rs2, imm
instr.rs2 = get_gpr(operands[0]);
instr.rs2_value = get_gpr_state(operands[0]);
instr.rs1 = SP;
instr.rs1_value = get_gpr_state("sp");
get_val(operands[1], instr.imm);
end
CR_FORMAT: begin
if (instr.instr_name inside {C_JR, C_JALR}) begin
// c.jalr rs1
instr.rs1 = get_gpr(operands[0]);
instr.rs1_value = get_gpr_state(operands[0]);
end else begin
// c.add rd, rs2
instr.rs2 = get_gpr(operands[1]);
instr.rs2_value = get_gpr_state(operands[1]);
end
end
CJ_FORMAT: begin
// c.j imm
get_val(operands[0], instr.imm);
end
endcase
split_string(trace["operand"], ",", operands);
instr.update_src_regs(operands);
split_string(trace["gpr"], ";", gpr_update);
foreach (gpr_update[i]) begin
split_string(gpr_update[i], ":", pair);
if (pair.size() != 2) begin
`uvm_fatal(`gfn, $sformatf("Illegal gpr update format: %0s", gpr_update[i]))
end
get_val(pair[1], gpr_state[pair[0]], .hex(1));
update_instr_reg_by_abi_name(pair[0], instr.rd, instr.rd_value, instr.fd, instr.fd_value);
instr.update_dst_regs(pair[0], pair[1]);
end
endfunction : assign_trace_info_to_instr
function riscv_reg_t get_gpr(input string str);
str = str.toupper();
if (!gpr_enum::from_name(str, get_gpr)) begin
`uvm_fatal(`gfn, $sformatf("Cannot convert %0s to GPR", str))
end
endfunction : get_gpr
function riscv_fpr_t get_fpr(input string str);
str = str.toupper();
if (!fpr_enum::from_name(str, get_fpr)) begin
`uvm_fatal(`gfn, $sformatf("Cannot convert %0s to FPR", str))
end
endfunction : get_fpr
function bit [XLEN-1:0] get_gpr_state(string name);
if (name inside {"zero", "x0"}) begin
return 0;
end else if (gpr_state.exists(name)) begin
return gpr_state[name];
end else begin
`uvm_warning(`gfn, $sformatf("Cannot find GPR state: %0s", name))
return 0;
end
endfunction : get_gpr_state
function void get_val(input string str, output bit [XLEN-1:0] val, input hex = 0);
if (str.len() > 2) begin
if (str.substr(0, 1) == "0x") begin
str = str.substr(2, str.len() -1);
val = str.atohex();
return;
end
end
if (hex) begin
val = str.atohex();
end else begin
if (str.substr(0, 0) == "-") begin
str = str.substr(1, str.len() - 1);
val = -str.atoi();
end else begin
val = str.atoi();
end
end
`uvm_info(`gfn, $sformatf("imm:%0s -> 0x%0x/%0d", str, val, $signed(val)), UVM_FULL)
endfunction : get_val
function bit is_fp_reg(input string str);
riscv_fpr_t tmp;
str = str.toupper();
return fpr_enum::from_name(str, tmp);
endfunction : is_fp_reg
function void update_instr_reg_by_abi_name(string abi_name,
ref riscv_reg_t rs,
ref bit [XLEN-1:0] rs_value,
ref riscv_fpr_t fs,
ref bit [XLEN-1:0] fs_value);
if (is_fp_reg(abi_name)) begin
fs = get_fpr(abi_name);
fs_value = get_gpr_state(abi_name);
end else begin
rs = get_gpr(abi_name);
rs_value = get_gpr_state(abi_name);
end
endfunction : update_instr_reg_by_abi_name
function string process_instr_name(string instr_name);
instr_name = instr_name.toupper();
foreach (instr_name[i]) begin

View file

@ -5,3 +5,4 @@ riscv_instr_cover_group.sv
riscv_instr_pkg.sv
# tool does not support included file very well. Issue at github.com/google/verible/issues/178
riscv_custom_instr_enum.sv
isa/riscv_instr_cov.svh