mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-23 13:27:10 -04:00
Update google_riscv-dv to google/riscv-dv@39797b2
Update code from upstream repository https://github.com/google/riscv- dv to revision 39797b2f07784e775149a4f05c90fee2427124e5 * coverage flow updates (Udi Jonnalagadda) * Update src/riscv_debug_rom_gen.sv (Tom Roberts) * debug_rom_gen: Fix return address issue (Tom Roberts) * Add sfence.vma after PTE process (google/riscv-dv#731) (taoliug) * generate gen_config data in tabular format (aneels3) * Fix coverage issue for ml target (google/riscv-dv#729) (taoliug) * Fix index offset constraint conflict (google/riscv-dv#728) (taoliug) * Fix rcs import and create_instr function (aneels3) * Fix setup_misa and formatting issue (aneels3) * Fix SPIKE ISSUE google/riscv-dv#722 (aneels3) * Fix coverage issue (aneels3) * fix google/riscv-dv#725 (Udi Jonnalagadda) * Fix formatting and linting issue (aneels3) * Add function setup_misa (ShraddhaDevaiya) * Fix gen_trap_handler_section (aneels3) * Add constraint (ShraddhaDevaiya) * Fixed push_gpr_to_kernel def (Saurabh Singh) * Add ic file to the target dir (aneels3) * Fix timeout issue (aneels3) * add mtvec constraint (pvipsyash) * Fix create_instr issue (aneels3) * Add function push_gpr_to_kernel (ishitapvips) * Fix invalid CSR test for RV64GCV target (google/riscv-dv#720) (taoliug) * Fix solve...before... on non-rand variables issue (google/riscv- dv#719) (taoliug) * Add rv32c instructions (aneels3) * Modify riscv_instr class fields (aneels3) * Fix import issue (aneels3) * Significantly improves performance of pyflow functional coverage (through changing the way that covergroups are instantiated & data are sampled) (Hodjat Asghari Esfeden) * fix jumps to `test_done` and `init_[m/s/u]_mode` (google/riscv- dv#710) (udinator) * Fix multi-harts program generation with PMP enabled (google/riscv- dv#716) (taoliug) * Fix google/riscv-dv#681 (google/riscv-dv#715) (taoliug) * Add initial support for rv32imc (aneels3) * resolve conflicts (aneels3) * add rv32imc core setting (pvipsyash) * changes for core settings (pvipsyash) * add riscv_compressed_instr (aneels3) * Convert code to be PEP8 compliant (Hodjat Asghari Esfeden) * Add riscv_data_page_gen (aneels3) * Integrates functional coverage side of pyflow into cov.py (google/riscv-dv#708) (Hodjat Asghari Esfeden) * Workaround of the SV compilation problem caused by assigning the const array variable with the empty concatenation. (google/riscv- dv#704) (Dariusz Stachańczyk) * Add rv32m and rv32c instr defines (ShraddhaDevaiya) * Fix logging issue along with other minor fixes (Hodjat Asghari Esfeden) * Add push_stack and pop_stack instr. (ShraddhaDevaiya) * Fix minor issues (aneels3) * Add a target for RV32IMC with SV32 address translation (google/riscv-dv#699) (taoliug) * Fixes a minot import issue (Hodjat Asghari Esfeden) * Fix LR/SC sequence issue (google/riscv-dv#698) (taoliug) * fix ebreak generation bug (google/riscv-dv#689) (udinator) * Update vector extension to v0.9 (google/riscv-dv#697) (taoliug) * Fixes a few issues in riscv_asm_program_gen and riscv_instr_gen_config (Hodjat Asghari Esfeden) * fix iterate over args dict (pvipsyash) * fix parse_args (pvipsyash) * fix cmdline argparse for directed stream (pvipsyash) * [pygen/riscv_instr_stream] Fix ebreak generation (Udi Jonnalagadda) * Fix flake8 related formatting (aneels3) * Add jal instr (aneels3) * Fixes for same rd for main instructions (Saurabh Singh) * Fixes to resolve label issue for directed class (Saurabh Singh) * Add constraint on jump_start (ShraddhaDevaiya) * Add Constraint for jump instructions. (ShraddhaDevaiya) * fix minor issue in directed_lib (pvipsyash) * Add riscv_jal_instr to directed_lib (pvipsyash) * Fix forward branch label compilation error (aneels3) Signed-off-by: Udi Jonnalagadda <udij@google.com>
This commit is contained in:
parent
5d4c9aebe2
commit
9b656a0a2c
63 changed files with 5509 additions and 3731 deletions
2
vendor/google_riscv-dv.lock.hjson
vendored
2
vendor/google_riscv-dv.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/google/riscv-dv
|
||||
rev: 2e5251846efb5fa42882a2b6b571ef8693e8cd60
|
||||
rev: 39797b2f07784e775149a4f05c90fee2427124e5
|
||||
}
|
||||
}
|
||||
|
|
532
vendor/google_riscv-dv/cov.py
vendored
532
vendor/google_riscv-dv/cov.py
vendored
|
@ -30,279 +30,315 @@ from types import SimpleNamespace
|
|||
|
||||
LOGGER = logging.getLogger()
|
||||
|
||||
def build_cov(out, cfg, cwd, opts_vec, opts_cov):
|
||||
"""Building the coverage collection framework
|
||||
|
||||
Args:
|
||||
out : Output directory
|
||||
cfg : Loaded configuration dictionary.
|
||||
cwd : Filesystem path to RISCV-DV repo
|
||||
opts_vec : Vector options
|
||||
opts_cov : Coverage options
|
||||
"""
|
||||
# Convert key dictionary to argv variable
|
||||
argv= SimpleNamespace(**cfg)
|
||||
logging.info("Building the coverage collection framework")
|
||||
build_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s "
|
||||
" --co -o %s --cov -tl %s %s --cmp_opts \"%s %s\" --noclean" %
|
||||
(cwd, argv.simulator, argv.simulator_yaml, out, argv.testlist, argv.opts,
|
||||
opts_vec, opts_cov))
|
||||
if argv.target:
|
||||
build_cmd += (" --target %s" % argv.target)
|
||||
if argv.custom_target:
|
||||
build_cmd += (" --custom_target %s" % argv.custom_target)
|
||||
if argv.stop_on_first_error:
|
||||
build_cmd += (" --stop_on_first_error")
|
||||
if argv.lsf_cmd != "":
|
||||
build_cmd += (" --lsf_cmd \"%s\"" % argv.lsf_cmd)
|
||||
run_parallel_cmd([build_cmd], argv.timeout, debug_cmd = argv.debug)
|
||||
else:
|
||||
run_cmd(build_cmd, debug_cmd = argv.debug)
|
||||
def build_cov(out, cfg, cwd, opts_vec, opts_cov):
|
||||
"""Building the coverage collection framework
|
||||
|
||||
Args:
|
||||
out : Output directory
|
||||
cfg : Loaded configuration dictionary.
|
||||
cwd : Filesystem path to RISCV-DV repo
|
||||
opts_vec : Vector options
|
||||
opts_cov : Coverage options
|
||||
"""
|
||||
# Convert key dictionary to argv variable
|
||||
argv = SimpleNamespace(**cfg)
|
||||
logging.info("Building the coverage collection framework")
|
||||
build_cmd = ("python3 {}/run.py --simulator {} --simulator_yaml {} "
|
||||
" --co -o {} --cov -tl {} {} --cmp_opts \"{} {}\" --noclean".format(
|
||||
cwd, argv.simulator, argv.simulator_yaml, out,
|
||||
argv.testlist, argv.opts, opts_vec, opts_cov))
|
||||
if argv.target:
|
||||
build_cmd += (" --target {}".format(argv.target))
|
||||
if argv.custom_target:
|
||||
build_cmd += (" --custom_target {}".format(argv.custom_target))
|
||||
if argv.stop_on_first_error:
|
||||
build_cmd += " --stop_on_first_error"
|
||||
if argv.lsf_cmd != "":
|
||||
build_cmd += (" --lsf_cmd \"{}\"".format(argv.lsf_cmd))
|
||||
run_parallel_cmd([build_cmd], argv.timeout, debug_cmd=argv.debug)
|
||||
else:
|
||||
run_cmd(build_cmd, debug_cmd=argv.debug)
|
||||
|
||||
|
||||
def sim_cov(out, cfg, cwd, opts_vec, opts_cov, csv_list):
|
||||
"""Simulation the coverage collection
|
||||
"""Simulation the coverage collection
|
||||
|
||||
Args:
|
||||
out : Output directory
|
||||
cfg : Loaded configuration dictionary.
|
||||
cwd : Filesystem path to RISCV-DV repo
|
||||
opts_vec : Vector options
|
||||
opts_cov : Coverage options
|
||||
csv_list : The list of trace csv
|
||||
"""
|
||||
# Convert key dictionary to argv variable
|
||||
argv= SimpleNamespace(**cfg)
|
||||
logging.info("Collecting functional coverage from %0d trace CSV" % len(csv_list))
|
||||
test_name = "riscv_instr_cov_test"
|
||||
base_sim_cmd = ("python3 %s/run.py --simulator %s --simulator_yaml %s --noclean "
|
||||
"--so -o %s --cov -tl %s %s "
|
||||
"-tn %s --steps gen --sim_opts \"<trace_csv_opts> %s %s\" " %
|
||||
(cwd, argv.simulator, argv.simulator_yaml, out, argv.testlist,
|
||||
argv.opts, test_name, opts_vec, opts_cov))
|
||||
if argv.target:
|
||||
base_sim_cmd += (" --target %s" % argv.target)
|
||||
if argv.custom_target:
|
||||
base_sim_cmd += (" --custom_target %s" % argv.custom_target)
|
||||
if argv.stop_on_first_error:
|
||||
base_sim_cmd += (" --stop_on_first_error")
|
||||
file_idx = 0
|
||||
trace_idx = 0
|
||||
trace_csv_opts = ""
|
||||
batch_cnt = 1
|
||||
sim_cmd_list = []
|
||||
if argv.batch_size > 0:
|
||||
batch_cnt = (len(csv_list) + argv.batch_size - 1)/ argv.batch_size;
|
||||
logging.info("Batch size: %0d, Batch cnt:%0d" % (argv.batch_size, batch_cnt))
|
||||
for i in range(len(csv_list)):
|
||||
file_idx = 0
|
||||
trace_idx = i
|
||||
Args:
|
||||
out : Output directory
|
||||
cfg : Loaded configuration dictionary.
|
||||
cwd : Filesystem path to RISCV-DV repo
|
||||
opts_vec : Vector options
|
||||
opts_cov : Coverage options
|
||||
csv_list : The list of trace csv
|
||||
"""
|
||||
# Convert key dictionary to argv variable
|
||||
argv = SimpleNamespace(**cfg)
|
||||
logging.info(
|
||||
"Collecting functional coverage from {} trace CSV".format(len(csv_list)))
|
||||
test_name = "riscv_instr_cov_test"
|
||||
base_sim_cmd = (
|
||||
"python3 {}/run.py --simulator {} --simulator_yaml {} --noclean "
|
||||
"--so -o {} --cov -tl {} {} "
|
||||
"-tn {} --steps gen --sim_opts \"<trace_csv_opts> {} {} <visualization>\" "
|
||||
.format(cwd, argv.simulator, argv.simulator_yaml, out,
|
||||
argv.testlist,
|
||||
argv.opts, test_name, opts_vec, opts_cov))
|
||||
if argv.simulator == "pyflow" and argv.enable_visualization:
|
||||
base_sim_cmd = re.sub("<visualization>", "--enable_visualization",
|
||||
base_sim_cmd)
|
||||
else:
|
||||
base_sim_cmd = re.sub("<visualization>", "", base_sim_cmd)
|
||||
if argv.target:
|
||||
base_sim_cmd += (" --target {}".format(argv.target))
|
||||
if argv.custom_target:
|
||||
base_sim_cmd += (" --custom_target {}".format(argv.custom_target))
|
||||
if argv.stop_on_first_error:
|
||||
base_sim_cmd += " --stop_on_first_error"
|
||||
trace_csv_opts = ""
|
||||
batch_cnt = 1
|
||||
sim_cmd_list = []
|
||||
if argv.batch_size > 0:
|
||||
file_idx = i / argv.batch_size;
|
||||
trace_idx = i % argv.batch_size;
|
||||
trace_csv_opts += (" +trace_csv_%0d=%s" % (trace_idx, csv_list[i]))
|
||||
if ((i == len(csv_list)-1) or ((argv.batch_size > 0) and (trace_idx == argv.batch_size-1))):
|
||||
sim_cmd = base_sim_cmd.replace("<trace_csv_opts>", trace_csv_opts)
|
||||
sim_cmd += (" --log_suffix _%d" % file_idx)
|
||||
if argv.lsf_cmd == "":
|
||||
logging.info("Processing batch %0d/%0d" % (file_idx+1, batch_cnt))
|
||||
run_cmd(sim_cmd, debug_cmd = argv.debug)
|
||||
else:
|
||||
sim_cmd += (" --lsf_cmd \"%s\"" % argv.lsf_cmd)
|
||||
sim_cmd_list.append(sim_cmd)
|
||||
trace_csv_opts = ""
|
||||
if argv.lsf_cmd != "":
|
||||
run_parallel_cmd(sim_cmd_list, argv.timeout)
|
||||
logging.info("Collecting functional coverage from %0d trace CSV...done" % len(csv_list))
|
||||
batch_cnt = (len(csv_list) + argv.batch_size - 1) / argv.batch_size
|
||||
logging.info(
|
||||
"Batch size: {}, Batch cnt: {}".format(argv.batch_size, batch_cnt))
|
||||
for i in range(len(csv_list)):
|
||||
file_idx = 0
|
||||
trace_idx = i
|
||||
if argv.batch_size > 0:
|
||||
file_idx = i / argv.batch_size
|
||||
trace_idx = i % argv.batch_size
|
||||
if argv.simulator == "pyflow":
|
||||
if i == 0:
|
||||
trace_csv_opts += (" --trace_csv={}".format(csv_list[i]))
|
||||
else:
|
||||
trace_csv_opts += (",{}".format(csv_list[i]))
|
||||
else:
|
||||
trace_csv_opts += (" +trace_csv_{}={}".format(trace_idx, csv_list[i]))
|
||||
if (i == len(csv_list) - 1) or (
|
||||
(argv.batch_size > 0) and (trace_idx == argv.batch_size - 1)):
|
||||
sim_cmd = base_sim_cmd.replace("<trace_csv_opts>", trace_csv_opts)
|
||||
sim_cmd += (" --log_suffix _{}".format(file_idx))
|
||||
if argv.lsf_cmd == "":
|
||||
logging.info(
|
||||
"Processing batch {}/{}".format(file_idx + 1, batch_cnt))
|
||||
run_cmd(sim_cmd, debug_cmd=argv.debug)
|
||||
else:
|
||||
sim_cmd += (" --lsf_cmd \"{}\"".format(argv.lsf_cmd))
|
||||
sim_cmd_list.append(sim_cmd)
|
||||
trace_csv_opts = ""
|
||||
if argv.lsf_cmd != "":
|
||||
run_parallel_cmd(sim_cmd_list, argv.timeout)
|
||||
logging.info(
|
||||
"Collecting functional coverage from {} trace CSV...done".format(len(
|
||||
csv_list)))
|
||||
|
||||
|
||||
def collect_cov(out, cfg, cwd):
|
||||
"""Collect functional coverage from the instruction trace
|
||||
"""Collect functional coverage from the instruction trace
|
||||
|
||||
Args:
|
||||
out : Output directory
|
||||
cfg : Loaded configuration dictionary.
|
||||
cwd : Filesystem path to RISCV-DV repo
|
||||
"""
|
||||
# Convert key dictionary to argv variable
|
||||
argv= SimpleNamespace(**cfg)
|
||||
log_list = []
|
||||
csv_list = []
|
||||
if not argv.dir:
|
||||
logging.error("Missing directory of trace log files")
|
||||
sys.exit(RET_FAIL)
|
||||
logging.info("Processing trace log under %s" % argv.dir)
|
||||
if not os.path.isdir(argv.dir) or not os.listdir(argv.dir):
|
||||
if not argv.debug:
|
||||
logging.error("Cannot find %s directory, or it is empty", argv.dir)
|
||||
sys.exit(RET_FAIL)
|
||||
if argv.core:
|
||||
Args:
|
||||
out : Output directory
|
||||
cfg : Loaded configuration dictionary.
|
||||
cwd : Filesystem path to RISCV-DV repo
|
||||
"""
|
||||
If functional coverage is being collected from an RTL core implementation,
|
||||
the flow assumes that the core's trace logs have already been converted to
|
||||
CSV files by the post_compare step of the flow.
|
||||
"""
|
||||
trace_log = ("%s/%s_trace_log" % (out, argv.core))
|
||||
run_cmd("find %s -name \"*.csv\" | sort > %s" % (argv.dir, trace_log))
|
||||
else:
|
||||
trace_log = ("%s/%s_trace_log" % (out, argv.iss))
|
||||
run_cmd("find %s -name \"*.log\" | sort > %s" % (argv.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 argv.steps == "all" or re.match("csv", argv.steps):
|
||||
for i in range(len(log_list)):
|
||||
log = log_list[i]
|
||||
csv = csv_list[i]
|
||||
# If a core target is defined, prioritize over ISS
|
||||
if argv.core:
|
||||
logging.info("Process %0s log[%0d/%0d] : %s" % (argv.core, i+1, len(log_list), log))
|
||||
else:
|
||||
logging.info("Process %0s log[%0d/%0d] : %s" % (argv.iss, i+1, len(log_list), log))
|
||||
if argv.iss == "spike":
|
||||
process_spike_sim_log(log, csv, 1)
|
||||
elif argv.iss == "ovpsim":
|
||||
process_ovpsim_sim_log(log, csv, argv.stop_on_first_error,
|
||||
argv.dont_truncate_after_first_ecall, 1)
|
||||
else:
|
||||
logging.error("Full trace for %s is not supported yet" % argv.iss)
|
||||
sys.exit(RET_FAIL)
|
||||
if argv.steps == "all" or re.match("cov", argv.steps):
|
||||
opts_vec = ""
|
||||
opts_cov = ""
|
||||
if argv.vector_options:
|
||||
opts_vec = ("%0s" % argv.vector_options)
|
||||
if argv.coverage_options:
|
||||
opts_cov = ("%0s" % argv.coverage_options)
|
||||
if argv.compliance_mode:
|
||||
opts_cov += " +define+COMPLIANCE_MODE"
|
||||
# Building the coverage collection framework
|
||||
build_cov(out, cfg, cwd, opts_vec, opts_cov)
|
||||
# Simulation the coverage collection
|
||||
sim_cov(out, cfg, cwd, opts_vec, opts_cov, csv_list)
|
||||
# Convert key dictionary to argv variable
|
||||
argv = SimpleNamespace(**cfg)
|
||||
log_list = []
|
||||
csv_list = []
|
||||
if not argv.dir:
|
||||
logging.error("Missing directory of trace log files")
|
||||
sys.exit(RET_FAIL)
|
||||
logging.info("Processing trace log under {}".format(argv.dir))
|
||||
if not os.path.isdir(argv.dir) or not os.listdir(argv.dir):
|
||||
if not argv.debug:
|
||||
logging.error("Cannot find {} directory, or it is empty".format(argv.dir))
|
||||
sys.exit(RET_FAIL)
|
||||
if argv.core:
|
||||
"""If functional coverage is being collected from an RTL core
|
||||
implementation, the flow assumes that the core's trace logs have
|
||||
already been converted to CSV files by the post_compare step of the
|
||||
flow. """
|
||||
trace_log = ("{}/{}_trace_log".format(out, argv.core))
|
||||
run_cmd("find {} -name \"*.csv\" | sort > {}".format(argv.dir, trace_log))
|
||||
else:
|
||||
trace_log = ("{}/{}_trace_log".format(out, argv.iss))
|
||||
run_cmd("find {} -name \"*.log\" | sort > {}".format(argv.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 argv.steps == "all" or re.match("csv", argv.steps):
|
||||
for i in range(len(log_list)):
|
||||
log = log_list[i]
|
||||
csv = csv_list[i]
|
||||
# If a core target is defined, prioritize over ISS
|
||||
if argv.core:
|
||||
logging.info("Process {} log[{}/{}] : {}".format(
|
||||
argv.core, i + 1, len(log_list), log))
|
||||
else:
|
||||
logging.info("Process {} log[{}/{}] : {}".format(
|
||||
argv.iss, i + 1, len(log_list), log))
|
||||
if argv.iss == "spike":
|
||||
process_spike_sim_log(log, csv, 1)
|
||||
elif argv.iss == "ovpsim":
|
||||
process_ovpsim_sim_log(log, csv, argv.stop_on_first_error,
|
||||
argv.dont_truncate_after_first_ecall,
|
||||
1)
|
||||
else:
|
||||
logging.error(
|
||||
"Full trace for {} is not supported yet".format(argv.iss))
|
||||
sys.exit(RET_FAIL)
|
||||
if argv.steps == "all" or re.match("cov", argv.steps):
|
||||
opts_vec = ""
|
||||
opts_cov = ""
|
||||
if argv.vector_options:
|
||||
opts_vec = ("{}".format(argv.vector_options))
|
||||
if argv.coverage_options:
|
||||
opts_cov = ("{}".format(argv.coverage_options))
|
||||
if argv.compliance_mode:
|
||||
opts_cov += " +define+COMPLIANCE_MODE"
|
||||
# Building the coverage collection framework
|
||||
if argv.simulator != "pyflow":
|
||||
build_cov(out, cfg, cwd, opts_vec, opts_cov)
|
||||
# Simulation the coverage collection
|
||||
sim_cov(out, cfg, cwd, opts_vec, opts_cov, csv_list)
|
||||
|
||||
|
||||
def setup_parser():
|
||||
"""Create a command line 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", default=False,
|
||||
help="Verbose logging")
|
||||
parser.add_argument("--dir", type=str,
|
||||
help="Directory of trace log files")
|
||||
parser.add_argument("-bz", "--batch_size", dest="batch_size", type=int, default=0,
|
||||
help="Number of CSV to process per run")
|
||||
parser.add_argument("--compliance_mode", action="store_true", default=False,
|
||||
help="Run the coverage model in compliance test mode")
|
||||
parser.add_argument("-i", "--instr_cnt", dest="instr_cnt", type=int, default=0,
|
||||
help="Random instruction count for debug mode")
|
||||
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("--core", type=str, default="",
|
||||
help="Name of target core")
|
||||
parser.add_argument("--isa", type=str, default="",
|
||||
help="RISC-V ISA variant")
|
||||
parser.add_argument("--iss", type=str, default="spike",
|
||||
help="RISC-V instruction set simulator: spike,ovpsim,sail")
|
||||
parser.add_argument("-tl", "--testlist", type=str, default="",
|
||||
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 \
|
||||
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",
|
||||
default=False,
|
||||
help="Verbose logging")
|
||||
parser.add_argument("--dir", type=str,
|
||||
help="Directory of trace log files")
|
||||
parser.add_argument("-bz", "--batch_size", dest="batch_size", type=int,
|
||||
default=0,
|
||||
help="Number of CSV to process per run")
|
||||
parser.add_argument("--compliance_mode", action="store_true", default=False,
|
||||
help="Run the coverage model in compliance test mode")
|
||||
parser.add_argument("-i", "--instr_cnt", dest="instr_cnt", type=int,
|
||||
default=0,
|
||||
help="Random instruction count for debug mode")
|
||||
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("--core", type=str, default="",
|
||||
help="Name of target core")
|
||||
parser.add_argument("--isa", type=str, default="",
|
||||
help="RISC-V ISA variant")
|
||||
parser.add_argument("--iss", type=str, default="spike",
|
||||
help="RISC-V instruction set simulator: spike,ovpsim,sail")
|
||||
parser.add_argument("-tl", "--testlist", type=str, default="",
|
||||
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.add_argument("--target", type=str, default="rv32imc",
|
||||
help="Run the generator with pre-defined targets: \
|
||||
parser.add_argument("--target", type=str, default="rv32imc",
|
||||
help="Run the generator with pre-defined targets: \
|
||||
rv32imc, rv32i, rv64imc, rv64gc")
|
||||
parser.add_argument("-si", "--simulator", type=str, default="vcs",
|
||||
help="Simulator used to run the generator, \
|
||||
parser.add_argument("-si", "--simulator", type=str, default="vcs",
|
||||
help="Simulator used to run the generator, \
|
||||
default VCS", dest="simulator")
|
||||
parser.add_argument("--simulator_yaml", type=str, default="",
|
||||
help="RTL simulator setting YAML")
|
||||
parser.add_argument("-ct", "--custom_target", type=str, default="",
|
||||
help="Directory name of the custom target")
|
||||
parser.add_argument("-cs", "--core_setting_dir", type=str, default="",
|
||||
help="Path for the riscv_core_setting.sv")
|
||||
parser.add_argument("--stop_on_first_error", dest="stop_on_first_error",
|
||||
action="store_true", default=False,
|
||||
help="Stop on detecting first error")
|
||||
parser.add_argument("--dont_truncate_after_first_ecall", dest="dont_truncate_after_first_ecall",
|
||||
action="store_true", default=False,
|
||||
help="Do not truncate log and csv file on first ecall")
|
||||
parser.add_argument("--noclean", action="store_true", default=False,
|
||||
help="Do not clean the output of the previous runs")
|
||||
parser.add_argument("--vector_options", type=str, default="",
|
||||
help="Enable Vectors and set options")
|
||||
parser.add_argument("--coverage_options", type=str, default="",
|
||||
help="Controlling coverage coverpoints")
|
||||
parser.add_argument("--exp", action="store_true", default=False,
|
||||
help="Run generator with experimental features")
|
||||
parser.add_argument("-d", "--debug", type=str, default="",
|
||||
help="Generate debug command log file")
|
||||
return parser
|
||||
parser.add_argument("--simulator_yaml", type=str, default="",
|
||||
help="RTL simulator setting YAML")
|
||||
parser.add_argument("-ct", "--custom_target", type=str, default="",
|
||||
help="Directory name of the custom target")
|
||||
parser.add_argument("-cs", "--core_setting_dir", type=str, default="",
|
||||
help="Path for the riscv_core_setting.sv")
|
||||
parser.add_argument("--stop_on_first_error", dest="stop_on_first_error",
|
||||
action="store_true", default=False,
|
||||
help="Stop on detecting first error")
|
||||
parser.add_argument("--dont_truncate_after_first_ecall",
|
||||
dest="dont_truncate_after_first_ecall",
|
||||
action="store_true", default=False,
|
||||
help="Do not truncate log and csv file on first ecall")
|
||||
parser.add_argument("--noclean", action="store_true", default=False,
|
||||
help="Do not clean the output of the previous runs")
|
||||
parser.add_argument("--vector_options", type=str, default="",
|
||||
help="Enable Vectors and set options")
|
||||
parser.add_argument("--coverage_options", type=str, default="",
|
||||
help="Controlling coverage coverpoints")
|
||||
parser.add_argument("--exp", action="store_true", default=False,
|
||||
help="Run generator with experimental features")
|
||||
parser.add_argument("-d", "--debug", type=str, default="",
|
||||
help="Generate debug command log file")
|
||||
parser.add_argument("--enable_visualization", action="store_true",
|
||||
default=False,
|
||||
help="Enabling coverage report visualization for pyflow")
|
||||
return parser
|
||||
|
||||
|
||||
def load_config(args, cwd):
|
||||
"""
|
||||
Load configuration from the command line and the configuration file.
|
||||
"""
|
||||
Load configuration from the command line and the configuration file.
|
||||
|
||||
Args:
|
||||
args: Parsed command-line configuration
|
||||
Returns:
|
||||
Loaded configuration dictionary.
|
||||
"""
|
||||
if args.debug:
|
||||
args.debug = open(args.debug, "w")
|
||||
if args.verbose:
|
||||
args.opts += "-v"
|
||||
Args:
|
||||
args: Parsed command-line configuration
|
||||
Returns:
|
||||
Loaded configuration dictionary.
|
||||
"""
|
||||
if args.debug:
|
||||
args.debug = open(args.debug, "w")
|
||||
if args.verbose:
|
||||
args.opts += "-v"
|
||||
|
||||
if not args.simulator_yaml:
|
||||
args.simulator_yaml = cwd + "/yaml/simulator.yaml"
|
||||
if not args.simulator_yaml:
|
||||
args.simulator_yaml = cwd + "/yaml/simulator.yaml"
|
||||
|
||||
# Disable ISS coverage if a core is passed in
|
||||
if args.core:
|
||||
args.iss = ""
|
||||
# Disable ISS coverage if a core is passed in
|
||||
if args.core:
|
||||
args.iss = ""
|
||||
|
||||
# Keep the core_setting_dir option to be backward compatible, suggest to use
|
||||
# --custom_target
|
||||
if args.core_setting_dir:
|
||||
if not args.custom_target:
|
||||
args.custom_target = args.core_setting_dir
|
||||
else:
|
||||
args.core_setting_dir = args.custom_target
|
||||
|
||||
# Keep the core_setting_dir option to be backward compatible, suggest to use
|
||||
# --custom_target
|
||||
if args.core_setting_dir:
|
||||
if not args.custom_target:
|
||||
args.custom_target = args.core_setting_dir
|
||||
else:
|
||||
args.core_setting_dir = args.custom_target
|
||||
args.core_setting_dir = cwd + "/target/" + args.target
|
||||
|
||||
if not args.custom_target:
|
||||
args.core_setting_dir = cwd + "/target/"+ args.target
|
||||
args.testlist = cwd + "/yaml/cov_testlist.yaml" ## needed if need to force
|
||||
# Create loaded configuration dictionary.
|
||||
cfg = vars(args)
|
||||
return cfg
|
||||
|
||||
args.testlist = cwd + "/yaml/cov_testlist.yaml" ## needed if need to force
|
||||
# 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__))
|
||||
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, "cov_out_")
|
||||
# Collect coverage for the trace CSV
|
||||
collect_cov(output_dir, cfg ,cwd)
|
||||
logging.info("Coverage results are saved to %s" % output_dir)
|
||||
sys.exit(RET_SUCCESS)
|
||||
except KeyboardInterrupt:
|
||||
logging.info("\nExited Ctrl-C from user request.")
|
||||
sys.exit(130)
|
||||
"""This is the main entry point."""
|
||||
try:
|
||||
parser = setup_parser()
|
||||
args = parser.parse_args()
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
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, "cov_out_")
|
||||
# Collect coverage for the trace CSV
|
||||
collect_cov(output_dir, cfg, cwd)
|
||||
logging.info("Coverage results are saved to {}".format(output_dir))
|
||||
sys.exit(RET_SUCCESS)
|
||||
except KeyboardInterrupt:
|
||||
logging.info("\nExited Ctrl-C from user request.")
|
||||
sys.exit(130)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
228
vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_compressed_instr.py
vendored
Normal file
228
vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_compressed_instr.py
vendored
Normal file
|
@ -0,0 +1,228 @@
|
|||
"""
|
||||
Copyright 2020 Google LLC
|
||||
Copyright 2020 PerfectVIPs Inc.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import vsc
|
||||
from pygen_src.isa.riscv_instr import riscv_instr
|
||||
from pygen_src.riscv_instr_pkg import (riscv_instr_name_t, riscv_instr_format_t,
|
||||
riscv_instr_category_t, riscv_reg_t, imm_t, pkg_ins)
|
||||
|
||||
|
||||
@vsc.randobj
|
||||
class riscv_compressed_instr(riscv_instr):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.imm_align = 0
|
||||
self.rs1 = riscv_reg_t.S0
|
||||
self.rs2 = riscv_reg_t.S0
|
||||
self.rd = riscv_reg_t.S0
|
||||
self.is_compressed = 1
|
||||
|
||||
@vsc.constraint
|
||||
def rvc_csr_c(self):
|
||||
# Registers specified by the three-bit rs1’, rs2’, and rd’
|
||||
with vsc.implies(self.format.inside(vsc.rangelist(riscv_instr_format_t.CIW_FORMAT,
|
||||
riscv_instr_format_t.CL_FORMAT,
|
||||
riscv_instr_format_t.CS_FORMAT,
|
||||
riscv_instr_format_t.CB_FORMAT,
|
||||
riscv_instr_format_t.CA_FORMAT))):
|
||||
with vsc.implies(self.has_rs1 == 1):
|
||||
self.rs1.inside(vsc.rangelist(riscv_reg_t.S0, riscv_reg_t.S1, riscv_reg_t.A0,
|
||||
riscv_reg_t.A1, riscv_reg_t.A2, riscv_reg_t.A3,
|
||||
riscv_reg_t.A4, riscv_reg_t.A5))
|
||||
with vsc.implies(self.has_rs2 == 1):
|
||||
self.rs2.inside(vsc.rangelist(riscv_reg_t.S0, riscv_reg_t.S1, riscv_reg_t.A0,
|
||||
riscv_reg_t.A1, riscv_reg_t.A2, riscv_reg_t.A3,
|
||||
riscv_reg_t.A4, riscv_reg_t.A5))
|
||||
with vsc.implies(self.has_rd == 1):
|
||||
self.rd.inside(vsc.rangelist(riscv_reg_t.S0, riscv_reg_t.S1, riscv_reg_t.A0,
|
||||
riscv_reg_t.A1, riscv_reg_t.A2, riscv_reg_t.A3,
|
||||
riscv_reg_t.A4, riscv_reg_t.A5))
|
||||
# _ADDI16SP is only valid when rd == SP
|
||||
with vsc.implies(self.instr_name == riscv_instr_name_t.C_ADDI16SP):
|
||||
self.rd == riscv_reg_t.SP
|
||||
with vsc.implies(self.instr_name.inside(vsc.rangelist(riscv_instr_name_t.C_JR,
|
||||
riscv_instr_name_t.C_JALR))):
|
||||
self.rs1 != riscv_reg_t.ZERO
|
||||
self.rs2 == riscv_reg_t.ZERO
|
||||
|
||||
@vsc.constraint
|
||||
def imm_val_c(self):
|
||||
with vsc.implies(self.imm_type.inside(vsc.rangelist(imm_t.NZIMM, imm_t.NZUIMM))):
|
||||
self.imm[5:0] != 0
|
||||
with vsc.implies(self.instr_name == riscv_instr_name_t.C_LUI):
|
||||
self.imm[31:5] == 0
|
||||
with vsc.implies(self.instr_name.inside(vsc.rangelist(riscv_instr_name_t.C_SRAI,
|
||||
riscv_instr_name_t.C_SRLI,
|
||||
riscv_instr_name_t.C_SLLI))):
|
||||
self.imm[31:5] == 0
|
||||
with vsc.implies(self.instr_name == riscv_instr_name_t.C_ADDI4SPN):
|
||||
self.imm[1:0] == 0
|
||||
|
||||
# C_JAL is RV32C only instruction
|
||||
@vsc.constraint
|
||||
def jal_c(self):
|
||||
with vsc.implies(self.XLEN != 32):
|
||||
self.instr_name != riscv_instr_name_t.C_JAL
|
||||
|
||||
# Avoid generating HINT or illegal instruction by default as it's not supported by the compiler
|
||||
@vsc.constraint
|
||||
def no_hint_illegal_instr_c(self):
|
||||
with vsc.implies(self.instr_name.inside(vsc.rangelist(riscv_instr_name_t.C_ADDI,
|
||||
riscv_instr_name_t.C_ADDIW,
|
||||
riscv_instr_name_t.C_LI,
|
||||
riscv_instr_name_t.C_LUI,
|
||||
riscv_instr_name_t.C_SLLI,
|
||||
riscv_instr_name_t.C_SLLI64,
|
||||
riscv_instr_name_t.C_LQSP,
|
||||
riscv_instr_name_t.C_LDSP,
|
||||
riscv_instr_name_t.C_MV,
|
||||
riscv_instr_name_t.C_ADD,
|
||||
riscv_instr_name_t.C_LWSP))):
|
||||
self.rd != riscv_reg_t.ZERO
|
||||
with vsc.implies(self.instr_name == riscv_instr_name_t.C_JR):
|
||||
self.rs1 != riscv_reg_t.ZERO
|
||||
with vsc.implies(self.instr_name.inside(vsc.rangelist(riscv_instr_name_t.C_ADD,
|
||||
riscv_instr_name_t.C_MV))):
|
||||
self.rs2 != riscv_reg_t.ZERO
|
||||
with vsc.implies(self.instr_name == riscv_instr_name_t.C_LUI):
|
||||
self.rd != riscv_reg_t.SP
|
||||
|
||||
def set_imm_len(self):
|
||||
if self.format in [riscv_instr_format_t.CI_FORMAT, riscv_instr_format_t.CSS_FORMAT]:
|
||||
self.imm_len = 6
|
||||
elif self.format in [riscv_instr_format_t.CL_FORMAT, riscv_instr_format_t.CS_FORMAT]:
|
||||
self.imm_len = 5
|
||||
elif self.format in [riscv_instr_format_t.CJ_FORMAT]:
|
||||
self.imm_len = 11
|
||||
elif self.format in [riscv_instr_format_t.CB_FORMAT]:
|
||||
if self.instr_name == riscv_instr_name_t.C_ANDI:
|
||||
self.imm_len = 6
|
||||
else:
|
||||
self.imm_len = 7
|
||||
elif self.format in [riscv_instr_format_t.CB_FORMAT, riscv_instr_format_t.CIW_FORMAT]:
|
||||
self.imm_len = 8
|
||||
if self.instr_name in [riscv_instr_name_t.C_SQ, riscv_instr_name_t.C_LQ,
|
||||
riscv_instr_name_t.C_LQSP, riscv_instr_name_t.C_SQSP,
|
||||
riscv_instr_name_t.C_ADDI16SP]:
|
||||
self.imm_align = 4
|
||||
elif self.instr_name in [riscv_instr_name_t.C_SD, riscv_instr_name_t.C_LD,
|
||||
riscv_instr_name_t.C_LDSP, riscv_instr_name_t.C_SDSP]:
|
||||
self.imm_align = 3
|
||||
elif self.instr_name in [riscv_instr_name_t.C_SW, riscv_instr_name_t.C_LW,
|
||||
riscv_instr_name_t.C_LWSP, riscv_instr_name_t.C_SWSP,
|
||||
riscv_instr_name_t.C_ADDI4SPN]:
|
||||
self.imm_align = 2
|
||||
elif self.instr_name in [riscv_instr_name_t.C_LUI]:
|
||||
self.imm_align = 12
|
||||
elif self.instr_name in [riscv_instr_name_t.C_J, riscv_instr_name_t.C_JAL,
|
||||
riscv_instr_name_t.C_BNEZ, riscv_instr_name_t.C_BEQZ]:
|
||||
self.imm_align = 1
|
||||
|
||||
def extend_imm(self):
|
||||
if self.instr_name != riscv_instr_name_t.C_LUI:
|
||||
super().extend_imm()
|
||||
self.imm = self.imm << self.imm_align
|
||||
|
||||
def set_rand_mode(self):
|
||||
if self.format in [riscv_instr_format_t.CR_FORMAT]:
|
||||
if self.category in [riscv_instr_category_t.JUMP]:
|
||||
self.has_rd = 0
|
||||
else:
|
||||
self.has_rs1 = 0
|
||||
self.has_imm = 0
|
||||
elif self.format in [riscv_instr_format_t.CI_FORMAT, riscv_instr_format_t.CIW_FORMAT]:
|
||||
self.has_rs2 = 0
|
||||
self.has_rs1 = 0
|
||||
elif self.format in [riscv_instr_format_t.CSS_FORMAT]:
|
||||
self.has_rs1 = 0
|
||||
self.has_rd = 0
|
||||
elif self.format in [riscv_instr_format_t.CL_FORMAT]:
|
||||
self.has_rs2 = 0
|
||||
elif self.format in [riscv_instr_format_t.CS_FORMAT]:
|
||||
self.has_rd = 0
|
||||
elif self.format in [riscv_instr_format_t.CA_FORMAT]:
|
||||
self.has_rs1 = 0
|
||||
self.has_imm = 0
|
||||
elif self.format == riscv_instr_format_t.CJ_FORMAT:
|
||||
self.has_rs1 = 0
|
||||
self.has_rs2 = 0
|
||||
self.has_rd = 0
|
||||
elif self.format == riscv_instr_format_t.CB_FORMAT:
|
||||
if self.instr_name != riscv_instr_name_t.C_ANDI:
|
||||
self.has_rd = 0
|
||||
self.has_rs2 = 0
|
||||
|
||||
def convert2asm(self, prefix=""):
|
||||
asm_str = pkg_ins.format_string(string=self.get_instr_name(),
|
||||
length=pkg_ins.MAX_INSTR_STR_LEN)
|
||||
if self.category != riscv_instr_category_t.SYSTEM:
|
||||
if self.format in [riscv_instr_format_t.CI_FORMAT, riscv_instr_format_t.CIW_FORMAT]:
|
||||
if self.instr_name is riscv_instr_name_t.C_NOP:
|
||||
asm_str = "c.nop"
|
||||
elif self.instr_name is riscv_instr_name_t.C_ADDI16SP:
|
||||
asm_str = "{} sp, {}".format(asm_str, self.get_imm())
|
||||
elif self.instr_name is riscv_instr_name_t.C_ADDI4SPN:
|
||||
asm_str = "{} {}, sp, {}".format(asm_str, self.rd.name, self.get_imm())
|
||||
elif self.instr_name in [riscv_instr_name_t.C_LDSP, riscv_instr_name_t.C_LWSP,
|
||||
riscv_instr_name_t.C_LQSP]:
|
||||
asm_str = "{} {}, {}(sp)".format(asm_str, self.rd.name, self.get_imm())
|
||||
else:
|
||||
asm_str = "{} {}, {}".format(asm_str, self.rd.name, self.get_imm())
|
||||
elif self.format is riscv_instr_format_t.CL_FORMAT:
|
||||
asm_str = "{} {}, {}({})".format(
|
||||
asm_str, self.rd.name, self.get_imm(), self.rs1.name)
|
||||
elif self.format is riscv_instr_format_t.CS_FORMAT:
|
||||
if self.category is riscv_instr_category_t.STORE:
|
||||
asm_str = "{} {}, {}({})".format(
|
||||
asm_str, self.rs2.name, self.get_imm(), self.rs1.name)
|
||||
else:
|
||||
asm_str = "{} {}, {}".format(asm_str, self.rs1.name, self.rs2.name)
|
||||
elif self.format is riscv_instr_format_t.CA_FORMAT:
|
||||
asm_str = "{} {}, {}".format(asm_str, self.rd.name, self.rs2.name)
|
||||
elif self.format is riscv_instr_format_t.CB_FORMAT:
|
||||
asm_str = "{} {}, {}".format(asm_str, self.rs1.name, self.get_imm())
|
||||
elif self.format is riscv_instr_format_t.CSS_FORMAT:
|
||||
if self.category is riscv_instr_category_t.STORE:
|
||||
asm_str = "{} {}, {}(sp)".format(asm_str, self.rs2.name, self.get_imm())
|
||||
else:
|
||||
asm_str = "{} {}, {}".format(asm_str, self.rs2.name, self.get_imm())
|
||||
elif self.format is riscv_instr_format_t.CR_FORMAT:
|
||||
if self.instr_name in [riscv_instr_name_t.C_JR, riscv_instr_name_t.C_JALR]:
|
||||
asm_str = "{} {}".format(asm_str, self.rs1.name)
|
||||
else:
|
||||
asm_str = "{} {}, {}".format(asm_str, self.rd.name, self.rs2.name)
|
||||
elif self.format is riscv_instr_format_t.CJ_FORMAT:
|
||||
asm_str = "{} {}".format(asm_str, self.get_imm())
|
||||
else:
|
||||
logging.info("Unsupported format {}".format(self.format.name))
|
||||
else:
|
||||
# For EBREAK,C.EBREAK, making sure pc+4 is a valid instruction boundary
|
||||
# This is needed to resume execution from epc+4 after ebreak handling
|
||||
if self.instr_name is riscv_instr_name_t.C_EBREAK:
|
||||
asm_str = "c.ebreak;c.nop;"
|
||||
if self.comment != "":
|
||||
asm_str = asm_str + " #" + self.comment
|
||||
return asm_str.lower()
|
||||
|
||||
# TODO
|
||||
def conver2bin(self, prefix=""):
|
||||
pass
|
||||
|
||||
# TODO
|
||||
def get_c_opcode(self):
|
||||
pass
|
||||
|
||||
# TOD0
|
||||
def get_func3(self):
|
||||
pass
|
|
@ -17,11 +17,12 @@ import os
|
|||
import sys
|
||||
import vsc
|
||||
import logging
|
||||
from importlib import import_module
|
||||
from enum import Enum, IntEnum, auto
|
||||
from bitstring import BitArray
|
||||
from pygen.pygen_src.target.rv32i import riscv_core_setting as rcs
|
||||
from pygen.pygen_src.riscv_instr_pkg import *
|
||||
|
||||
from pygen_src.riscv_instr_pkg import *
|
||||
from pygen_src.riscv_instr_gen_config import cfg
|
||||
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
|
||||
|
||||
class operand_sign_e(IntEnum):
|
||||
POSITIVE = 0
|
||||
|
|
|
@ -11,50 +11,63 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import copy
|
||||
import sys
|
||||
import random
|
||||
import os
|
||||
import vsc
|
||||
from imp import reload
|
||||
from collections import defaultdict
|
||||
from bitstring import BitArray
|
||||
from pygen_src.riscv_instr_pkg import pkg_ins, riscv_reg_t, riscv_instr_name_t
|
||||
from pygen_src.isa import rv32i_instr # NOQA
|
||||
from pygen_src.target.rv32i import riscv_core_setting as rcs
|
||||
|
||||
logging.basicConfig(filename = os.path.abspath('../test/out/logname.log'), filemode ='w',
|
||||
format = "%(asctime)s %(filename)s %(lineno)s %(levelname)s %(message)s",
|
||||
level = logging.DEBUG)
|
||||
from importlib import import_module
|
||||
from pygen_src.riscv_instr_pkg import (pkg_ins, riscv_instr_category_t, riscv_reg_t,
|
||||
riscv_instr_name_t, riscv_instr_format_t,
|
||||
riscv_instr_group_t, imm_t)
|
||||
from pygen_src.riscv_instr_gen_config import cfg
|
||||
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
|
||||
reload(logging)
|
||||
logging.basicConfig(filename='{}'.format(cfg.argv.log_file_name),
|
||||
filemode='w',
|
||||
format="%(asctime)s %(filename)s %(lineno)s %(levelname)s %(message)s",
|
||||
level=logging.DEBUG)
|
||||
|
||||
|
||||
@vsc.randobj
|
||||
class riscv_instr:
|
||||
# All derived instructions
|
||||
instr_registry = {}
|
||||
|
||||
# Instruction list
|
||||
instr_names = []
|
||||
|
||||
# Categorized instruction list
|
||||
instr_group = defaultdict(list)
|
||||
instr_category = defaultdict(list)
|
||||
basic_instr = []
|
||||
instr_template = {}
|
||||
|
||||
# Privileged CSR filter
|
||||
exclude_reg = []
|
||||
include_reg = []
|
||||
|
||||
def __init__(self):
|
||||
self.instr_names = []
|
||||
self.instr_group = defaultdict(list)
|
||||
self.instr_category = defaultdict(list)
|
||||
self.basic_instr = []
|
||||
self.instr_template = {}
|
||||
|
||||
self.exclude_reg = []
|
||||
self.include_reg = []
|
||||
|
||||
self.group = None
|
||||
self.format = None
|
||||
self.category = None
|
||||
self.instr_name = None
|
||||
self.imm_type = None
|
||||
self.imm_len = 0
|
||||
# Instruction attributes
|
||||
self.group = vsc.enum_t(riscv_instr_group_t)
|
||||
self.format = vsc.enum_t(riscv_instr_format_t)
|
||||
self.category = vsc.enum_t(riscv_instr_category_t)
|
||||
self.instr_name = vsc.enum_t(riscv_instr_name_t)
|
||||
self.imm_type = vsc.enum_t(imm_t)
|
||||
self.imm_len = vsc.bit_t(5)
|
||||
|
||||
# Operands
|
||||
self.csr = vsc.rand_bit_t(12)
|
||||
self.rs2 = vsc.rand_enum_t(riscv_reg_t)
|
||||
self.rs1 = vsc.rand_enum_t(riscv_reg_t)
|
||||
self.rd = vsc.rand_enum_t(riscv_reg_t)
|
||||
self.imm = vsc.rand_bit_t(32)
|
||||
|
||||
# Helper Fields
|
||||
self.imm_mask = vsc.uint32_t(0xffffffff)
|
||||
self.is_branch_target = None
|
||||
self.has_label = 1
|
||||
|
@ -70,99 +83,123 @@ class riscv_instr:
|
|||
self.label = ""
|
||||
self.is_local_numeric_label = None
|
||||
self.idx = -1
|
||||
self.has_rs1 = vsc.bit_t(1)
|
||||
self.has_rs2 = vsc.bit_t(1)
|
||||
self.has_rd = vsc.bit_t(1)
|
||||
self.has_imm = vsc.bit_t(1)
|
||||
self.has_rs1 = 1
|
||||
self.has_rs2 = 1
|
||||
self.has_rd = 1
|
||||
self.has_imm = 1
|
||||
self.shift_t = vsc.uint32_t(0xffffffff)
|
||||
self.XLEN = vsc.uint32_t(32) # XLEN is used in constraint throughout the generator.
|
||||
# Hence, XLEN should be of PyVSC type in order to use it in a constraint block
|
||||
self.XLEN = rcs.XLEN
|
||||
|
||||
@vsc.constraint
|
||||
def imm_c(self):
|
||||
with vsc.implies(self.instr_name.inside(vsc.rangelist(riscv_instr_name_t.SLLIW,
|
||||
riscv_instr_name_t.SRLIW,
|
||||
riscv_instr_name_t.SRAIW))):
|
||||
self.imm[11:5] == 0
|
||||
with vsc.implies(self.instr_name.inside(vsc.rangelist(riscv_instr_name_t.SLLI,
|
||||
riscv_instr_name_t.SRLI,
|
||||
riscv_instr_name_t.SRAI))):
|
||||
with vsc.implies(self.XLEN == 32):
|
||||
self.imm[11:5] == 0
|
||||
with vsc.implies(self.XLEN != 32):
|
||||
self.imm[11:6] == 0
|
||||
|
||||
@classmethod
|
||||
def register(cls, instr_name):
|
||||
logging.info("Registering %s", instr_name.name)
|
||||
cls.instr_registry[instr_name.name] = 1
|
||||
if(instr_name is None):
|
||||
cls.instr_registry[instr_name] = 1
|
||||
if instr_name is None:
|
||||
print("\n")
|
||||
return 1
|
||||
|
||||
def create_instr_list(self, cfg):
|
||||
self.instr_names.clear()
|
||||
self.instr_group.clear()
|
||||
self.instr_category.clear()
|
||||
for instr_name, values in self.instr_registry.items():
|
||||
if(instr_name in rcs.unsupported_instr):
|
||||
@classmethod
|
||||
def create_instr_list(cls, cfg):
|
||||
cls.instr_names.clear()
|
||||
cls.instr_group.clear()
|
||||
cls.instr_category.clear()
|
||||
for instr_name, values in cls.instr_registry.items():
|
||||
if instr_name in rcs.unsupported_instr:
|
||||
continue
|
||||
instr_inst = self.create_instr(instr_name)
|
||||
self.instr_template[instr_name] = instr_inst
|
||||
instr_inst = cls.create_instr(instr_name)
|
||||
cls.instr_template[instr_name] = instr_inst
|
||||
|
||||
if (not instr_inst.is_supported(cfg)):
|
||||
if not instr_inst.is_supported(cfg):
|
||||
continue
|
||||
if ((rcs.XLEN != 32) and (instr_name == "C_JAL")):
|
||||
if ((rcs.XLEN != 32) and (instr_name == riscv_instr_name_t.C_JAL)):
|
||||
continue
|
||||
if ((riscv_reg_t.SP in cfg.reserved_regs) and (instr_name == "C_ADDI16SP")):
|
||||
if ((riscv_reg_t.SP in cfg.reserved_regs) and
|
||||
(instr_name == riscv_instr_name_t.C_ADDI16SP)):
|
||||
continue
|
||||
if (cfg.enable_sfence and instr_name == "SFENCE_VMA"):
|
||||
if (cfg.enable_sfence and instr_name == riscv_instr_name_t.SFENCE_VMA):
|
||||
continue
|
||||
if (instr_name in ["FENCE", "FENCE_I", "SFENCE_VMA"]):
|
||||
if instr_name in [riscv_instr_name_t.FENCE, riscv_instr_name_t.FENCE_I,
|
||||
riscv_instr_name_t.SFENCE_VMA]:
|
||||
continue
|
||||
if (instr_inst.group.name in rcs.supported_isa and
|
||||
not(cfg.disable_compressed_instr and
|
||||
instr_inst.group in ["RV32C", "RV64C", "RV32DC", "RV32FC", "RV128C"]) and
|
||||
not(not(cfg.enable_floating_point) and instr_inst.group in
|
||||
["RV32F", "RV64F", "RV32D", "RV64D"])):
|
||||
self.instr_category[instr_inst.category.name].append(instr_name)
|
||||
self.instr_group[instr_inst.group.name].append(instr_name)
|
||||
self.instr_names.append(instr_name)
|
||||
self.build_basic_instruction_list(cfg)
|
||||
self.create_csr_filter(cfg)
|
||||
instr_inst.group.name in ["RV32C", "RV64C", "RV32DC", "RV32FC", "RV128C"]) and
|
||||
not(not(cfg.enable_floating_point) and instr_inst.group.name in
|
||||
["RV32F", "RV64F", "RV32D", "RV64D"])):
|
||||
cls.instr_category[instr_inst.category.name].append(instr_name)
|
||||
cls.instr_group[instr_inst.group.name].append(instr_name)
|
||||
cls.instr_names.append(instr_name)
|
||||
cls.build_basic_instruction_list(cfg)
|
||||
cls.create_csr_filter(cfg)
|
||||
|
||||
def create_instr(self, instr_name):
|
||||
"""TODO This method is specific to RV32I instruction only.
|
||||
It must be scaled to all instruction extensions."""
|
||||
try:
|
||||
instr_inst = eval("rv32i_instr.riscv_" + instr_name + "_instr()")
|
||||
except Exception:
|
||||
logging.critical("Failed to create instr: %0s", instr_name)
|
||||
sys.exit(1)
|
||||
@classmethod
|
||||
def create_instr(cls, instr_name):
|
||||
# Importing get_object here to eliminate the Cyclic dependency for DEFINE_INSTR
|
||||
from pygen_src.riscv_utils import get_object
|
||||
instr_inst = get_object(instr_name)
|
||||
return instr_inst
|
||||
|
||||
def is_supported(self, cfg):
|
||||
return 1
|
||||
|
||||
def build_basic_instruction_list(self, cfg):
|
||||
self.basic_instr = (self.instr_category["SHIFT"] + self.instr_category["ARITHMETIC"] +
|
||||
self.instr_category["LOGICAL"] + self.instr_category["COMPARE"])
|
||||
if(cfg.no_ebreak == 0):
|
||||
self.basic_instr.append("EBREAK")
|
||||
@classmethod
|
||||
def build_basic_instruction_list(cls, cfg):
|
||||
cls.basic_instr = (cls.instr_category["SHIFT"] + cls.instr_category["ARITHMETIC"] +
|
||||
cls.instr_category["LOGICAL"] + cls.instr_category["COMPARE"])
|
||||
if cfg.no_ebreak == 0:
|
||||
cls.basic_instr.append("EBREAK")
|
||||
for items in rcs.supported_isa:
|
||||
if("RV32C" in rcs.supported_isa and not(cfg.disable_compressed_instr)):
|
||||
self.basic_instr.append("C_EBREAK")
|
||||
cls.basic_instr.append("C_EBREAK")
|
||||
break
|
||||
if(cfg.no_dret == 0):
|
||||
self.basic_instr.append("DRET")
|
||||
if(cfg.no_fence == 0):
|
||||
self.basic_instr.append(self.instr_category["SYNCH"])
|
||||
if cfg.no_dret == 0:
|
||||
cls.basic_instr.append("DRET")
|
||||
if cfg.no_fence == 0:
|
||||
cls.basic_instr.append(cls.instr_category["SYNCH"])
|
||||
if(cfg.no_csr_instr == 0 and cfg.init_privileged_mode == "MACHINE_MODE"):
|
||||
self.basic_instr.append(self.instr_category["CSR"])
|
||||
if(cfg.no_wfi == 0):
|
||||
self.basic_instr.append("WFI")
|
||||
cls.basic_instr.append(cls.instr_category["CSR"])
|
||||
if cfg.no_wfi == 0:
|
||||
cls.basic_instr.append("WFI")
|
||||
|
||||
def create_csr_filter(self, cfg):
|
||||
self.include_reg.clear()
|
||||
self.exclude_reg.clear()
|
||||
@classmethod
|
||||
def create_csr_filter(cls, cfg):
|
||||
cls.include_reg.clear()
|
||||
cls.exclude_reg.clear()
|
||||
|
||||
if(cfg.enable_illegal_csr_instruction):
|
||||
self.exclude_reg = rcs.implemented_csr
|
||||
elif(cfg.enable_access_invalid_csr_level):
|
||||
self.include_reg = cfg.invalid_priv_mode_csrs
|
||||
if cfg.enable_illegal_csr_instruction:
|
||||
cls.exclude_reg = rcs.implemented_csr
|
||||
elif cfg.enable_access_invalid_csr_level:
|
||||
cls.include_reg = cfg.invalid_priv_mode_csrs
|
||||
else:
|
||||
if(cfg.init_privileged_mode == "MACHINE_MODE"): # Machine Mode
|
||||
self.include_reg.append("MSCRATCH")
|
||||
elif(cfg.init_privileged_mode == "SUPERVISOR_MODE"): # Supervisor Mode
|
||||
self.include_reg.append("SSCRATCH")
|
||||
else: # User Mode
|
||||
self.include_reg.append("USCRATCH")
|
||||
if cfg.init_privileged_mode == "MACHINE_MODE": # Machine Mode
|
||||
cls.include_reg.append("MSCRATCH")
|
||||
elif cfg.init_privileged_mode == "SUPERVISOR_MODE": # Supervisor Mode
|
||||
cls.include_reg.append("SSCRATCH")
|
||||
else: # User Mode
|
||||
cls.include_reg.append("USCRATCH")
|
||||
|
||||
def get_rand_instr(self, include_instr=[], exclude_instr=[],
|
||||
@classmethod
|
||||
def get_rand_instr(cls, include_instr=[], exclude_instr=[],
|
||||
include_category=[], exclude_category=[],
|
||||
include_group=[], exclude_group=[]):
|
||||
idx = BitArray(uint = 0, length = 32)
|
||||
|
@ -170,41 +207,43 @@ class riscv_instr:
|
|||
allowed_instr = []
|
||||
disallowed_instr = []
|
||||
# allowed_categories = []
|
||||
|
||||
for items in include_category:
|
||||
allowed_instr.extend(self.instr_category[items])
|
||||
allowed_instr.extend(cls.instr_category[items])
|
||||
for items in exclude_category:
|
||||
if(items in self.instr_category):
|
||||
disallowed_instr.extend(self.instr_category[items])
|
||||
if items in cls.instr_category:
|
||||
disallowed_instr.extend(cls.instr_category[items])
|
||||
for items in include_group:
|
||||
allowed_instr.extend(self.instr_group[items])
|
||||
allowed_instr.extend(cls.instr_group[items])
|
||||
for items in exclude_group:
|
||||
if(items in self.instr_group):
|
||||
disallowed_instr.extend(self.instr_group[items])
|
||||
if items in cls.instr_group:
|
||||
disallowed_instr.extend(cls.instr_group[items])
|
||||
|
||||
disallowed_instr.extend(exclude_instr)
|
||||
|
||||
# TODO Randomization logic needs to be frame with PyVSC library
|
||||
if(len(disallowed_instr) == 0):
|
||||
if len(disallowed_instr) == 0:
|
||||
try:
|
||||
if(len(include_instr) > 0):
|
||||
idx = random.randrange(0, len(include_instr) - 1)
|
||||
if len(include_instr) > 0:
|
||||
if len(include_instr) == 1:
|
||||
idx = 0
|
||||
else:
|
||||
idx = random.randrange(0, len(include_instr) - 1)
|
||||
name = include_instr[idx]
|
||||
elif(len(allowed_instr) > 0):
|
||||
elif len(allowed_instr) > 0:
|
||||
idx = random.randrange(0, len(allowed_instr) - 1)
|
||||
name = allowed_instr[idx]
|
||||
else:
|
||||
idx = random.randrange(0, len(self.instr_names) - 1)
|
||||
name = self.instr_names[idx]
|
||||
idx = random.randrange(0, len(cls.instr_names) - 1)
|
||||
name = cls.instr_names[idx]
|
||||
except Exception:
|
||||
logging.critical("[%s] Cannot generate random instruction", riscv_instr.__name__)
|
||||
sys.exit(1)
|
||||
else:
|
||||
try:
|
||||
name = random.choice(self.instr_names)
|
||||
if(len(include_instr) > 0):
|
||||
name = random.choice(cls.instr_names)
|
||||
if len(include_instr) > 0:
|
||||
name = random.choice(include_instr)
|
||||
if(len(allowed_instr) > 0):
|
||||
if len(allowed_instr) > 0:
|
||||
name = random.choice(allowed_instr)
|
||||
except Exception:
|
||||
logging.critical("[%s] Cannot generate random instruction", riscv_instr.__name__)
|
||||
|
@ -212,52 +251,60 @@ class riscv_instr:
|
|||
# rs1 rs2 values are overwriting and the last generated values are
|
||||
# getting assigned for a particular instruction hence creating different
|
||||
# object address and id to ratain the randomly generated values.
|
||||
instr_h = copy.deepcopy(self.instr_template[name])
|
||||
instr_h = copy.deepcopy(cls.instr_template[name])
|
||||
return instr_h
|
||||
|
||||
def get_load_store_instr(self, load_store_instr):
|
||||
@classmethod
|
||||
def get_load_store_instr(cls, load_store_instr):
|
||||
instr_h = riscv_instr()
|
||||
if(len(load_store_instr) == 0):
|
||||
load_store_instr = self.instr_category["LOAD"] + \
|
||||
self.instr_category["STORE"]
|
||||
self.idx = random.randrange(0, len(load_store_instr) - 1)
|
||||
name = load_store_instr[self.idx]
|
||||
instr_h = copy(self.instr_template[name])
|
||||
if len(load_store_instr) == 0:
|
||||
load_store_instr = cls.instr_category["LOAD"] + \
|
||||
cls.instr_category["STORE"]
|
||||
cls.idx = random.randrange(0, len(load_store_instr) - 1)
|
||||
name = load_store_instr[cls.idx]
|
||||
instr_h = copy.copy(cls.instr_template[name])
|
||||
return instr_h
|
||||
|
||||
def get_instr(self, name):
|
||||
if (not self.instr_template.get(name)):
|
||||
@classmethod
|
||||
def get_instr(cls, name):
|
||||
if not cls.instr_template.get(name):
|
||||
logging.critical("Cannot get instr %s", name)
|
||||
sys.exit(1)
|
||||
instr_h = copy.copy(self.instr_template[name])
|
||||
instr_h = copy.copy(cls.instr_template[name])
|
||||
return instr_h
|
||||
|
||||
def set_rand_mode(self):
|
||||
# rand_mode setting for Instruction Format
|
||||
if(self.format.name == "R_FORMAT"):
|
||||
if self.format.name == "R_FORMAT":
|
||||
self.has_imm = 0
|
||||
if(self.format.name == "I_FORMAT"):
|
||||
if self.format.name == "I_FORMAT":
|
||||
self.has_rs2 = 0
|
||||
if(self.format.name in ["S_FORMAT", "B_FORMAT"]):
|
||||
if self.format.name in ["S_FORMAT", "B_FORMAT"]:
|
||||
self.has_rd = 0
|
||||
if(self.format.name in ["U_FORMAT", "J_FORMAT"]):
|
||||
if self.format.name in ["U_FORMAT", "J_FORMAT"]:
|
||||
self.has_rs1 = 0
|
||||
self.has_rs2 = 0
|
||||
|
||||
# rand_mode setting for Instruction Category
|
||||
if(self.category.name == "CSR"):
|
||||
if self.category.name == "CSR":
|
||||
self.has_rs2 = 0
|
||||
if(self.format.name == "I_FORMAT"):
|
||||
if self.format.name == "I_FORMAT":
|
||||
self.has_rs1 = 0
|
||||
|
||||
def pre_randomize(self):
|
||||
pass # TODO
|
||||
with vsc.raw_mode():
|
||||
self.rs1.rand_mode = bool(self.has_rs1)
|
||||
self.rs2.rand_mode = bool(self.has_rs2)
|
||||
self.rd.rand_mode = bool(self.has_rd)
|
||||
self.imm.rand_mode = bool(self.has_imm)
|
||||
if self.category != riscv_instr_category_t.CSR:
|
||||
self.csr.rand_mode = False
|
||||
|
||||
def set_imm_len(self):
|
||||
if(self.format.name in ["U_FORMAT", "J_FORMAT"]):
|
||||
if self.format.name in ["U_FORMAT", "J_FORMAT"]:
|
||||
self.imm_len = 20
|
||||
elif(self.format.name in ["I_FORMAT", "S_FORMAT", "B_FORMAT"]):
|
||||
if(self.imm_type.name == "UIMM"):
|
||||
elif self.format.name in ["I_FORMAT", "S_FORMAT", "B_FORMAT"]:
|
||||
if self.imm_type.name == "UIMM":
|
||||
self.imm_len = 5
|
||||
else:
|
||||
self.imm_len = 11
|
||||
|
@ -274,174 +321,158 @@ class riscv_instr:
|
|||
(self.imm_type.name in ["UIMM", "NZUIMM"]))):
|
||||
self.imm = self.imm_mask | self.imm
|
||||
|
||||
def imm_c(self):
|
||||
imm_t = BitArray(uint = self.imm, length = 32)
|
||||
if self.instr_name in [riscv_instr_name_t.SLLIW.name, riscv_instr_name_t.SRLIW.name,
|
||||
riscv_instr_name_t.SRAIW.name]:
|
||||
imm_t[20:27:1] = 0
|
||||
self.imm = imm_t.uint
|
||||
if self.instr_name in [riscv_instr_name_t.SLLI.name, riscv_instr_name_t.SRLI.name,
|
||||
riscv_instr_name_t.SRAI.name]:
|
||||
if rcs.XLEN == 32:
|
||||
imm_t[20:27:1] = 0
|
||||
self.imm = imm_t.uint
|
||||
else:
|
||||
self.imm_t[20:26:1] = 0
|
||||
self.imm = imm_t.uint
|
||||
|
||||
def post_randomize(self):
|
||||
self.imm_c()
|
||||
self.extend_imm()
|
||||
self.update_imm_str()
|
||||
|
||||
def convert2asm(self, prefix = " "):
|
||||
asm_str = pkg_ins.format_string(string = self.get_instr_name(),
|
||||
length = pkg_ins.MAX_INSTR_STR_LEN)
|
||||
if(self.category.name != "SYSTEM"):
|
||||
if self.format.name == "J_FORMAT":
|
||||
if self.category != riscv_instr_category_t.SYSTEM:
|
||||
if self.format == riscv_instr_format_t.J_FORMAT:
|
||||
asm_str = '{} {}, {}'.format(asm_str, self.rd.name, self.get_imm())
|
||||
elif self.format.name == "U_FORMAT":
|
||||
elif self.format == riscv_instr_format_t.U_FORMAT:
|
||||
asm_str = '{} {}, {}'.format(asm_str, self.rd.name, self.get_imm())
|
||||
elif self.format.name == "I_FORMAT":
|
||||
if(self.instr_name == "NOP"):
|
||||
elif self.format == riscv_instr_format_t.I_FORMAT:
|
||||
if self.instr_name == riscv_instr_name_t.NOP:
|
||||
asm_str = "nop"
|
||||
elif(self.instr_name == "WFI"):
|
||||
elif self.instr_name == riscv_instr_name_t.WFI:
|
||||
asm_str = "wfi"
|
||||
elif(self.instr_name == "FENCE"):
|
||||
elif self.instr_name == riscv_instr_name_t.FENCE:
|
||||
asm_str = "fence"
|
||||
elif(self.instr_name == "FENCE_I"):
|
||||
elif self.instr_name == riscv_instr_name_t.FENCE_I:
|
||||
asm_str = "fence.i"
|
||||
elif(self.category.name == "LOAD"):
|
||||
elif self.category == riscv_instr_category_t.LOAD:
|
||||
asm_str = '{} {}, {} ({})'.format(
|
||||
asm_str, self.rd.name, self.get_imm(), self.rs1.name)
|
||||
elif(self.category.name == "CSR"):
|
||||
elif self.category == riscv_instr_category_t.CSR:
|
||||
asm_str = '{} {}, 0x{}, {}'.format(
|
||||
asm_str, self.rd.name, self.csr, self.get_imm())
|
||||
else:
|
||||
asm_str = '{} {}, {}, {}'.format(
|
||||
asm_str, self.rd.name, self.rs1.name, self.get_imm())
|
||||
elif self.format.name == "S_FORMAT":
|
||||
if(self.category.name == "STORE"):
|
||||
elif self.format == riscv_instr_format_t.S_FORMAT:
|
||||
if self.category == riscv_instr_category_t.STORE:
|
||||
asm_str = '{} {}, {} ({})'.format(
|
||||
asm_str, self.rs2.name, self.get_imm(), self.rs1.name)
|
||||
else:
|
||||
asm_str = '{} {}, {}, {}'.format(
|
||||
asm_str, self.rs1.name, self.rs2.name, self.get_imm())
|
||||
|
||||
elif self.format.name == "B_FORMAT":
|
||||
if(self.category.name == "STORE"):
|
||||
elif self.format == riscv_instr_format_t.B_FORMAT:
|
||||
if self.category == riscv_instr_category_t.STORE:
|
||||
asm_str = '{} {}, {} ({})'.format(
|
||||
asm_str, self.rs2.name, self.get_imm(), self.rs1.name)
|
||||
else:
|
||||
asm_str = '{} {}, {}, {}'.format(
|
||||
asm_str, self.rs1.name, self.rs2.name, self.get_imm())
|
||||
|
||||
elif self.format.name == "R_FORMAT":
|
||||
if(self.category.name == "CSR"):
|
||||
elif self.format == riscv_instr_format_t.R_FORMAT:
|
||||
if self.category == riscv_instr_category_t.CSR:
|
||||
asm_str = '{} {}, 0x{}, {}'.format(
|
||||
asm_str, self.rd.name, self.csr, self.rs1.name)
|
||||
elif(self.instr_name == "SFENCE_VMA"):
|
||||
elif self.instr_name == riscv_instr_name_t.SFENCE_VMA:
|
||||
asm_str = "sfence.vma x0, x0"
|
||||
else:
|
||||
asm_str = '{} {}, {}, {}'.format(
|
||||
asm_str, self.rd.name, self.rs1.name, self.rs2.name)
|
||||
else:
|
||||
asm_str = 'Fatal_unsupported_format: {} {}'.format(
|
||||
self.format.name, self.instr_name)
|
||||
self.format.name, self.instr_name.name)
|
||||
|
||||
else:
|
||||
if(self.instr_name == "EBREAK"):
|
||||
if self.instr_name == riscv_instr_name_t.EBREAK:
|
||||
asm_str = ".4byte 0x00100073 # ebreak"
|
||||
|
||||
if(self.comment != ""):
|
||||
if self.comment != "":
|
||||
asm_str = asm_str + " #" + self.comment
|
||||
return asm_str.lower()
|
||||
|
||||
def get_opcode(self):
|
||||
if(self.instr_name == "LUI"):
|
||||
if self.instr_name == "LUI":
|
||||
return (BitArray(uint = 55, length = 7).bin)
|
||||
elif(self.instr_name == "AUIPC"):
|
||||
elif self.instr_name == "AUIPC":
|
||||
return (BitArray(uint = 23, length = 7).bin)
|
||||
elif(self.instr_name == "JAL"):
|
||||
elif self.instr_name == "JAL":
|
||||
return (BitArray(uint = 23, length = 7).bin)
|
||||
elif(self.instr_name == "JALR"):
|
||||
elif self.instr_name == "JALR":
|
||||
return (BitArray(uint = 111, length = 7).bin)
|
||||
elif(self.instr_name in ["BEQ", "BNE", "BLT", "BGE", "BLTU", "BGEU"]):
|
||||
elif self.instr_name in ["BEQ", "BNE", "BLT", "BGE", "BLTU", "BGEU"]:
|
||||
return (BitArray(uint = 103, length = 7).bin)
|
||||
elif(self.instr_name in ["LB", "LH", "LW", "LBU", "LHU", "LWU", "LD"]):
|
||||
elif self.instr_name in ["LB", "LH", "LW", "LBU", "LHU", "LWU", "LD"]:
|
||||
return (BitArray(uint = 99, length = 7).bin)
|
||||
elif(self.instr_name in ["SB", "SH", "SW", "SD"]):
|
||||
elif self.instr_name in ["SB", "SH", "SW", "SD"]:
|
||||
return (BitArray(uint = 35, length = 7).bin)
|
||||
elif(self.instr_name in ["ADDI", "SLTI", "SLTIU", "XORI", "ORI", "ANDI",
|
||||
"SLLI", "SRLI", "SRAI", "NOP"]):
|
||||
elif self.instr_name in ["ADDI", "SLTI", "SLTIU", "XORI", "ORI", "ANDI",
|
||||
"SLLI", "SRLI", "SRAI", "NOP"]:
|
||||
return (BitArray(uint = 19, length = 7).bin)
|
||||
elif(self.instr_name in ["ADD", "SUB", "SLL", "SLT", "SLTU", "XOR", "SRL",
|
||||
elif self.instr_name in ["ADD", "SUB", "SLL", "SLT", "SLTU", "XOR", "SRL",
|
||||
"SRA", "OR", "AND", "MUL", "MULH", "MULHSU", "MULHU",
|
||||
"DIV", "DIVU", "REM", "REMU"]):
|
||||
"DIV", "DIVU", "REM", "REMU"]:
|
||||
return (BitArray(uint = 51, length = 7).bin)
|
||||
elif(self.instr_name in ["ADDIW", "SLLIW", "SRLIW", "SRAIW"]):
|
||||
elif self.instr_name in ["ADDIW", "SLLIW", "SRLIW", "SRAIW"]:
|
||||
return (BitArray(uint = 27, length = 7).bin)
|
||||
elif(self.instr_name in ["MULH", "MULHSU", "MULHU", "DIV", "DIVU", "REM", "REMU"]):
|
||||
elif self.instr_name in ["MULH", "MULHSU", "MULHU", "DIV", "DIVU", "REM", "REMU"]:
|
||||
return (BitArray(uint = 51, length = 7).bin)
|
||||
elif(self.instr_name in ["FENCE", "FENCE_I"]):
|
||||
elif self.instr_name in ["FENCE", "FENCE_I"]:
|
||||
return (BitArray(uint = 15, length = 7).bin)
|
||||
elif(self.instr_name in ["ECALL", "EBREAK", "CSRRW", "CSRRS", "CSRRC", "CSRRWI",
|
||||
"CSRRSI", "CSRRCI"]):
|
||||
elif self.instr_name in ["ECALL", "EBREAK", "CSRRW", "CSRRS", "CSRRC", "CSRRWI",
|
||||
"CSRRSI", "CSRRCI"]:
|
||||
return (BitArray(uint = 115, length = 7).bin)
|
||||
elif(self.instr_name in ["ADDW", "SUBW", "SLLW", "SRLW", "SRAW", "MULW", "DIVW",
|
||||
"DIVUW", "REMW", "REMUW"]):
|
||||
elif self.instr_name in ["ADDW", "SUBW", "SLLW", "SRLW", "SRAW", "MULW", "DIVW",
|
||||
"DIVUW", "REMW", "REMUW"]:
|
||||
return (BitArray(uint = 59, length = 7).bin)
|
||||
elif(self.instr_name in ["ECALL", "EBREAK", "URET", "SRET", "MRET", "DRET", "WFI",
|
||||
"SFENCE_VMA"]):
|
||||
elif self.instr_name in ["ECALL", "EBREAK", "URET", "SRET", "MRET", "DRET", "WFI",
|
||||
"SFENCE_VMA"]:
|
||||
return (BitArray(uint = 115, length = 7).bin)
|
||||
else:
|
||||
logging.critical("Unsupported instruction %0s", self.instr_name)
|
||||
sys.exit(1)
|
||||
|
||||
def get_func3(self):
|
||||
if(self.instr_name in ["JALR", "BEQ", "LB", "SB", "ADDI", "NOP", "ADD", "SUB",
|
||||
if self.instr_name in ["JALR", "BEQ", "LB", "SB", "ADDI", "NOP", "ADD", "SUB",
|
||||
"FENCE", "ECALL", "EBREAK", "ADDIW", "ADDW", "SUBW", "MUL",
|
||||
"MULW", "ECALL", "EBREAK", "URET", "SRET", "MRET", "DRET",
|
||||
"WFI", "SFENCE_VMA"]):
|
||||
"WFI", "SFENCE_VMA"]:
|
||||
return (BitArray(uint = 0, length = 3).bin)
|
||||
elif(self.instr_name in ["BNE", "LH", "SH", "SLLI", "SLL", "FENCE_I", "CSRRW", "SLLIW",
|
||||
"SLLW", "MULH"]):
|
||||
elif self.instr_name in ["BNE", "LH", "SH", "SLLI", "SLL", "FENCE_I", "CSRRW", "SLLIW",
|
||||
"SLLW", "MULH"]:
|
||||
return (BitArray(uint = 1, length = 3).bin)
|
||||
elif(self.instr_name in ["LW", "SW", "SLTI", "SLT", "CSRRS", "MULHS"]):
|
||||
elif self.instr_name in ["LW", "SW", "SLTI", "SLT", "CSRRS", "MULHS"]:
|
||||
return (BitArray(uint = 2, length = 3).bin)
|
||||
elif(self.instr_name in ["SLTIU", "SLTU", "CSRRC", "LD", "SD", "MULHU"]):
|
||||
elif self.instr_name in ["SLTIU", "SLTU", "CSRRC", "LD", "SD", "MULHU"]:
|
||||
return (BitArray(uint = 3, length = 3).bin)
|
||||
elif(self.instr_name in ["BLT", "LBU", "XORI", "XOR", "DIV", "DIVW"]):
|
||||
elif self.instr_name in ["BLT", "LBU", "XORI", "XOR", "DIV", "DIVW"]:
|
||||
return (BitArray(uint = 4, length = 3).bin)
|
||||
elif(self.instr_name in ["BGE", "LHU", "SRLI", "SRAI", "SRL", "SRA", "CSRRWI", "SRLIW",
|
||||
elif self.instr_name in ["BGE", "LHU", "SRLI", "SRAI", "SRL", "SRA", "CSRRWI", "SRLIW",
|
||||
"SRAIW", "SRLW",
|
||||
"SRAW", "DIVU", "DIVUW"]):
|
||||
"SRAW", "DIVU", "DIVUW"]:
|
||||
return (BitArray(uint = 5, length = 3).bin)
|
||||
elif(self.instr_name in ["BLTU", "ORI", "OR", "CSRRSI", "LWU", "REM", "REMW"]):
|
||||
elif self.instr_name in ["BLTU", "ORI", "OR", "CSRRSI", "LWU", "REM", "REMW"]:
|
||||
return (BitArray(uint = 6, length = 3).bin)
|
||||
elif(self.instr_name in ["BGEU", "ANDI", "AND", "CSRRCI", "REMU", "REMUW"]):
|
||||
elif self.instr_name in ["BGEU", "ANDI", "AND", "CSRRCI", "REMU", "REMUW"]:
|
||||
return (BitArray(uint = 7, length = 3).bin)
|
||||
else:
|
||||
logging.critical("Unsupported instruction %0s", self.instr_name)
|
||||
sys.exit(1)
|
||||
|
||||
def get_func7(self):
|
||||
if(self.instr_name in ["SLLI", "SRLI", "ADD", "SLL", "SLT", "SLTU", "XOR",
|
||||
if self.instr_name in ["SLLI", "SRLI", "ADD", "SLL", "SLT", "SLTU", "XOR",
|
||||
"SRL", "OR", "AND", "FENCE", "FENCE_I", "SLLIW",
|
||||
"SRLIW", "ADDW", "SLLW", "SRLW", "ECALL", "EBREAK", "URET"]):
|
||||
"SRLIW", "ADDW", "SLLW", "SRLW", "ECALL", "EBREAK", "URET"]:
|
||||
return (BitArray(uint = 0, length = 7).bin)
|
||||
elif(self.instr_name in ["SUB", "SRA", "SRAIW", "SUBW", "SRAW"]):
|
||||
elif self.instr_name in ["SUB", "SRA", "SRAIW", "SUBW", "SRAW"]:
|
||||
return (BitArray(uint = 32, length = 7).bin)
|
||||
elif(self.instr_name in ["MUL", "MULH", "MULHSU", "MULHU", "DIV", "DIVU", "REM",
|
||||
"REMU", "MULW", "DIVW", "DIVUW", "REMW", "REMUW"]):
|
||||
elif self.instr_name in ["MUL", "MULH", "MULHSU", "MULHU", "DIV", "DIVU", "REM",
|
||||
"REMU", "MULW", "DIVW", "DIVUW", "REMW", "REMUW"]:
|
||||
return (BitArray(uint = 1, length = 7).bin)
|
||||
elif(self.instr_name in ["SRET", "WFI"]):
|
||||
elif self.instr_name in ["SRET", "WFI"]:
|
||||
return (BitArray(uint = 8, length = 7).bin)
|
||||
elif(self.instr_name == "MRET"):
|
||||
elif self.instr_name == "MRET":
|
||||
return (BitArray(uint = 24, length = 7).bin)
|
||||
elif(self.instr_name == "DRET"):
|
||||
elif self.instr_name == "DRET":
|
||||
return (BitArray(uint = 61, length = 7).bin)
|
||||
elif(self.instr_name == "SFENCE_VMA"):
|
||||
elif self.instr_name == "SFENCE_VMA":
|
||||
return (BitArray(uint = 9, length = 7).bin)
|
||||
else:
|
||||
logging.critical("Unsupported instruction %0s", self.instr_name)
|
||||
|
@ -451,10 +482,8 @@ class riscv_instr:
|
|||
pass # TODO
|
||||
|
||||
def get_instr_name(self):
|
||||
get_instr_name = self.instr_name
|
||||
for i in get_instr_name:
|
||||
if(i == "_"):
|
||||
get_instr_name = get_instr_name.replace(i, ".")
|
||||
get_instr_name = self.instr_name.name
|
||||
get_instr_name = get_instr_name.replace("_", ".")
|
||||
return get_instr_name
|
||||
|
||||
def get_c_gpr(self, gpr):
|
||||
|
@ -479,6 +508,3 @@ class riscv_instr:
|
|||
else:
|
||||
signed_x = x - 2 ** rcs.XLEN
|
||||
return signed_x
|
||||
|
||||
|
||||
riscv_instr_ins = riscv_instr()
|
||||
|
|
77
vendor/google_riscv-dv/pygen/pygen_src/isa/rv32c_instr.py
vendored
Normal file
77
vendor/google_riscv-dv/pygen/pygen_src/isa/rv32c_instr.py
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
"""
|
||||
Copyright 2020 Google LLC
|
||||
Copyright 2020 PerfectVIPs Inc.
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
from pygen_src.riscv_defines import DEFINE_C_INSTR
|
||||
from pygen_src.riscv_instr_pkg import (riscv_instr_name_t, riscv_instr_format_t,
|
||||
riscv_instr_category_t, riscv_instr_group_t, imm_t)
|
||||
|
||||
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_LW, riscv_instr_format_t.CL_FORMAT,
|
||||
riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32C, imm_t.UIMM, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_SW, riscv_instr_format_t.CS_FORMAT,
|
||||
riscv_instr_category_t.STORE, riscv_instr_group_t.RV32C, imm_t.UIMM, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_LWSP, riscv_instr_format_t.CI_FORMAT,
|
||||
riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32C, imm_t.UIMM, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_SWSP, riscv_instr_format_t.CSS_FORMAT,
|
||||
riscv_instr_category_t.STORE, riscv_instr_group_t.RV32C, imm_t.UIMM, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_ADDI4SPN, riscv_instr_format_t.CIW_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32C, imm_t.NZUIMM,
|
||||
g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_ADDI, riscv_instr_format_t.CI_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32C, imm_t.NZIMM,
|
||||
g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_ADDI16SP, riscv_instr_format_t.CI_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32C, imm_t.NZIMM,
|
||||
g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_LI, riscv_instr_format_t.CI_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_LUI, riscv_instr_format_t.CI_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32C, imm_t.NZIMM,
|
||||
g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_SUB, riscv_instr_format_t.CA_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_ADD, riscv_instr_format_t.CR_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_NOP, riscv_instr_format_t.CI_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_MV, riscv_instr_format_t.CR_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_ANDI, riscv_instr_format_t.CB_FORMAT,
|
||||
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_XOR, riscv_instr_format_t.CA_FORMAT,
|
||||
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_OR, riscv_instr_format_t.CA_FORMAT,
|
||||
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_AND, riscv_instr_format_t.CA_FORMAT,
|
||||
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_BEQZ, riscv_instr_format_t.CB_FORMAT,
|
||||
riscv_instr_category_t.BRANCH, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_BNEZ, riscv_instr_format_t.CB_FORMAT,
|
||||
riscv_instr_category_t.BRANCH, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_SRLI, riscv_instr_format_t.CB_FORMAT,
|
||||
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32C, imm_t.NZUIMM, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_SRAI, riscv_instr_format_t.CB_FORMAT,
|
||||
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32C, imm_t.NZUIMM, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_SLLI, riscv_instr_format_t.CI_FORMAT,
|
||||
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32C, imm_t.NZUIMM, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_J, riscv_instr_format_t.CJ_FORMAT,
|
||||
riscv_instr_category_t.JUMP, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_JAL, riscv_instr_format_t.CJ_FORMAT,
|
||||
riscv_instr_category_t.JUMP, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_JR, riscv_instr_format_t.CR_FORMAT,
|
||||
riscv_instr_category_t.JUMP, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_JALR, riscv_instr_format_t.CR_FORMAT,
|
||||
riscv_instr_category_t.JUMP, riscv_instr_group_t.RV32C, g=globals())
|
||||
DEFINE_C_INSTR(riscv_instr_name_t.C_EBREAK, riscv_instr_format_t.CI_FORMAT,
|
||||
riscv_instr_category_t.SYSTEM, riscv_instr_group_t.RV32C, g=globals())
|
35
vendor/google_riscv-dv/pygen/pygen_src/isa/rv32m_instr.py
vendored
Normal file
35
vendor/google_riscv-dv/pygen/pygen_src/isa/rv32m_instr.py
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
"""
|
||||
Copyright 2020 Google LLC
|
||||
Copyright 2020 PerfectVIPs Inc.
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
from pygen_src.riscv_defines import DEFINE_INSTR
|
||||
from pygen_src.riscv_instr_pkg import (riscv_instr_name_t, riscv_instr_format_t,
|
||||
riscv_instr_category_t, riscv_instr_group_t)
|
||||
|
||||
# Multiplication and Division Instructions
|
||||
DEFINE_INSTR(riscv_instr_name_t.MUL, riscv_instr_format_t.R_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32M, g=globals())
|
||||
DEFINE_INSTR(riscv_instr_name_t.MULH, riscv_instr_format_t.R_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32M, g=globals())
|
||||
DEFINE_INSTR(riscv_instr_name_t.MULHSU, riscv_instr_format_t.R_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32M, g=globals())
|
||||
DEFINE_INSTR(riscv_instr_name_t.MULHU, riscv_instr_format_t.R_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32M, g=globals())
|
||||
DEFINE_INSTR(riscv_instr_name_t.DIV, riscv_instr_format_t.R_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32M, g=globals())
|
||||
DEFINE_INSTR(riscv_instr_name_t.DIVU, riscv_instr_format_t.R_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32M, g=globals())
|
||||
DEFINE_INSTR(riscv_instr_name_t.REM, riscv_instr_format_t.R_FORMAT,
|
||||
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32M, g=globals())
|
||||
DEFINE_INSTR(riscv_instr_name_t.REMU, riscv_instr_format_t.R_FORMAT,
|
||||
riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32M, g=globals())
|
|
@ -12,18 +12,22 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import logging
|
||||
import random
|
||||
import copy
|
||||
import sys
|
||||
import vsc
|
||||
from bitstring import BitArray
|
||||
from importlib import import_module
|
||||
from pygen_src.riscv_instr_sequence import riscv_instr_sequence
|
||||
from pygen_src.riscv_instr_pkg import pkg_ins, privileged_reg_t, privileged_mode_t, mtvec_mode_t
|
||||
from pygen_src.riscv_instr_gen_config import cfg, args, args_dict
|
||||
from pygen_src.target.rv32i import riscv_core_setting as rcs
|
||||
from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
|
||||
from pygen_src.riscv_instr_pkg import (pkg_ins, privileged_reg_t,
|
||||
privileged_mode_t, mtvec_mode_t,
|
||||
misa_ext_t, riscv_instr_group_t)
|
||||
from pygen_src.riscv_instr_gen_config import cfg
|
||||
from pygen_src.riscv_data_page_gen import riscv_data_page_gen
|
||||
from pygen_src.riscv_utils import factory
|
||||
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
|
||||
|
||||
'''
|
||||
RISC-V assembly program generator
|
||||
|
||||
|
@ -42,6 +46,7 @@ class riscv_asm_program_gen:
|
|||
self.page_table_list = []
|
||||
self.main_program = []
|
||||
self.sub_program = []
|
||||
self.data_page_gen = None
|
||||
|
||||
# Main function to generate the whole program
|
||||
|
||||
|
@ -116,8 +121,8 @@ class riscv_asm_program_gen:
|
|||
self.gen_program_end(hart)
|
||||
for hart in range(cfg.num_of_harts):
|
||||
self.gen_data_page_begin(hart)
|
||||
if(cfg.no_data_page):
|
||||
self.gen_data_page()
|
||||
if not cfg.no_data_page:
|
||||
self.gen_data_page(hart)
|
||||
|
||||
if((hart == 0) and ("RV32A" in rcs.supported_isa)):
|
||||
self.gen_data_page(hart, amo = 1)
|
||||
|
@ -137,7 +142,7 @@ class riscv_asm_program_gen:
|
|||
self.gen_all_trap_handler(hart)
|
||||
for mode in rcs.supported_privileged_mode:
|
||||
self.gen_interrupt_handler_section(mode, hart)
|
||||
|
||||
self.instr_stream.append(pkg_ins.get_label("kernel_instr_end: nop", hart))
|
||||
self.gen_kernel_stack_section(hart)
|
||||
|
||||
def gen_kernel_program(self, hart, seq):
|
||||
|
@ -185,7 +190,9 @@ class riscv_asm_program_gen:
|
|||
self.instr_stream.append(".align 6; .global fromhost; fromhost: .dword 0;")
|
||||
|
||||
def gen_data_page(self, hart, is_kernel = 0, amo = 0):
|
||||
pass
|
||||
self.data_page_gen = riscv_data_page_gen()
|
||||
self.data_page_gen.gen_data_page(hart, cfg.data_page_pattern, is_kernel, amo)
|
||||
self.instr_stream.extend(self.data_page_gen.data_page_str)
|
||||
|
||||
def gen_stack_section(self, hart):
|
||||
hart_prefix_string = pkg_ins.hart_prefix(hart)
|
||||
|
@ -201,7 +208,7 @@ class riscv_asm_program_gen:
|
|||
self.instr_stream.append(".align 2")
|
||||
|
||||
self.instr_stream.append(pkg_ins.get_label("user_stack_start:", hart))
|
||||
self.instr_stream.append(".rept {}".format(cfg.kernel_stack_len - 1))
|
||||
self.instr_stream.append(".rept {}".format(cfg.stack_len - 1))
|
||||
self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
|
||||
self.instr_stream.append(".endr")
|
||||
self.instr_stream.append(pkg_ins.get_label("user_stack_end:", hart))
|
||||
|
@ -250,11 +257,57 @@ class riscv_asm_program_gen:
|
|||
string = pkg_ins.indent + "j main"
|
||||
self.instr_stream.append(string)
|
||||
|
||||
# Setup MISA based on supported extensions
|
||||
def setup_misa(self):
|
||||
# TO DO
|
||||
misa = 0b01000000
|
||||
self.instr_stream.append("{}li x{}, {}".format(pkg_ins.indent, cfg.gpr[0].value, hex(misa)))
|
||||
self.instr_stream.append("{}csrw misa, x{}".format(pkg_ins.indent, cfg.gpr[0].value))
|
||||
misa = vsc.bit_t(rcs.XLEN)
|
||||
if rcs.XLEN == 32:
|
||||
misa[rcs.XLEN - 1:rcs.XLEN - 2] = 1
|
||||
elif rcs.XLEN == 64:
|
||||
misa[rcs.XLEN - 1:rcs.XLEN - 2] = 2
|
||||
else:
|
||||
misa[rcs.XLEN - 1:rcs.XLEN - 2] = 3
|
||||
if cfg.check_misa_init_val:
|
||||
self.instr_stream.append("{}csrr x15, {}".format(pkg_ins.indent,
|
||||
hex(privileged_reg_t.MISA)))
|
||||
for i in range(len(rcs.supported_isa)):
|
||||
if rcs.supported_isa[i] in [riscv_instr_group_t.RV32C.name,
|
||||
riscv_instr_group_t.RV64C.name,
|
||||
riscv_instr_group_t.RV128C.name]:
|
||||
misa[misa_ext_t.MISA_EXT_C] = 1
|
||||
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32I.name,
|
||||
riscv_instr_group_t.RV64I.name,
|
||||
riscv_instr_group_t.RV128I.name]:
|
||||
misa[misa_ext_t.MISA_EXT_I] = 1
|
||||
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32M.name,
|
||||
riscv_instr_group_t.RV64M.name]:
|
||||
misa[misa_ext_t.MISA_EXT_M] = 1
|
||||
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32A.name,
|
||||
riscv_instr_group_t.RV64A.name]:
|
||||
misa[misa_ext_t.MISA_EXT_A] = 1
|
||||
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32B.name,
|
||||
riscv_instr_group_t.RV64B.name]:
|
||||
misa[misa_ext_t.MISA_EXT_B] = 1
|
||||
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32F.name,
|
||||
riscv_instr_group_t.RV64F.name,
|
||||
riscv_instr_group_t.RV32FC.name]:
|
||||
misa[misa_ext_t.MISA_EXT_F] = 1
|
||||
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32D.name,
|
||||
riscv_instr_group_t.RV64D.name,
|
||||
riscv_instr_group_t.RV32DC.name]:
|
||||
misa[misa_ext_t.MISA_EXT_D] = 1
|
||||
elif rcs.supported_isa[i] in [riscv_instr_group_t.RVV.name]:
|
||||
misa[misa_ext_t.MISA_EXT_V] = 1
|
||||
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32X.name,
|
||||
riscv_instr_group_t.RV64X.name]:
|
||||
misa[misa_ext_t.MISA_EXT_X] = 1
|
||||
else:
|
||||
logging.error("{} is not yet supported".format(rcs.supported_isa[i]))
|
||||
if privileged_mode_t.SUPERVISOR_MODE.name in rcs.supported_privileged_mode:
|
||||
misa[misa_ext_t.MISA_EXT_S] = 1
|
||||
self.instr_stream.append("{}li x{}, {}".format(pkg_ins.indent, cfg.gpr[0].value,
|
||||
hex(misa.get_val())))
|
||||
self.instr_stream.append("{}csrw {}, x{}".format(pkg_ins.indent,
|
||||
hex(privileged_reg_t.MISA), cfg.gpr[0].value))
|
||||
|
||||
def core_is_initialized(self):
|
||||
pass
|
||||
|
@ -264,26 +317,24 @@ class riscv_asm_program_gen:
|
|||
|
||||
def init_gpr(self):
|
||||
reg_val = BitArray(uint = 0, length = pkg_ins.DATA_WIDTH)
|
||||
dist_lst = []
|
||||
|
||||
for dist_val in range(5):
|
||||
if dist_val == 0:
|
||||
# TODO Map the function with PyVSC std::randomize()
|
||||
for i in range(rcs.NUM_GPR):
|
||||
if i in [cfg.sp.value, cfg.tp.value]:
|
||||
continue
|
||||
if i == 0:
|
||||
reg_val = BitArray(hex='0x0')
|
||||
elif dist_val == 1:
|
||||
elif i == 1:
|
||||
reg_val = BitArray(hex='0x80000000')
|
||||
elif dist_val == 2:
|
||||
elif i == 2:
|
||||
temp = random.randrange(0x1, 0xf)
|
||||
reg_val = BitArray(hex(temp), length=32)
|
||||
elif dist_val == 3:
|
||||
elif i == 3:
|
||||
temp = random.randrange(0x10, 0xefffffff)
|
||||
reg_val = BitArray(hex(temp), length=32)
|
||||
else:
|
||||
temp = random.randrange(0xf0000000, 0xffffffff)
|
||||
reg_val = BitArray(hex(temp), length=32)
|
||||
dist_lst.append(reg_val)
|
||||
|
||||
for i in range(32):
|
||||
init_string = "{}li x{}, {}".format(pkg_ins.indent, i, random.choice(dist_lst))
|
||||
init_string = "{}li x{}, {}".format(pkg_ins.indent, i, reg_val)
|
||||
self.instr_stream.append(init_string)
|
||||
|
||||
def init_floating_point_gpr(self):
|
||||
|
@ -325,7 +376,7 @@ class riscv_asm_program_gen:
|
|||
string.append("la x{}, {}kernel_stack_end".format(cfg.tp.value, pkg_ins.hart_prefix(hart)))
|
||||
self.gen_section(pkg_ins.get_label("kernel_sp", hart), string)
|
||||
|
||||
if(not cfg.no_delegation and (cfg.init_privileged_mode != "MACHINE_MODE")):
|
||||
if not cfg.no_delegation and (cfg.init_privileged_mode != privileged_mode_t.MACHINE_MODE):
|
||||
self.gen_delegation(hart)
|
||||
self.trap_vector_init(hart)
|
||||
self.setup_pmp(hart)
|
||||
|
@ -436,6 +487,16 @@ class riscv_asm_program_gen:
|
|||
# TODO
|
||||
pkg_ins.push_gpr_to_kernel_stack(
|
||||
status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr)
|
||||
# Checking xStatus can be optional if ISS (like spike) has different implementation of
|
||||
# certain fields compared with the RTL processor.
|
||||
if cfg.check_xstatus:
|
||||
instr.append("csrr x{}, {} # {}".format(
|
||||
cfg.gpr[0].value, hex(status.value), status.name))
|
||||
instr.append("csrr x{}, {} # {}\n".format(cfg.gpr[0].value, hex(cause.value),
|
||||
cause.name) +
|
||||
"{}srli x{}, x{}, {}\n".format(pkg_ins.indent, cfg.gpr[0].value,
|
||||
cfg.gpr[0].value, rcs.XLEN - 1) + "{}bne x{}, x0, {}{}mode_instr_handler"
|
||||
.format(pkg_ins.indent, cfg.gpr[0].value, pkg_ins.hart_prefix(hart), mode))
|
||||
# The trap handler will occupy one 4KB page, it will be allocated one entry in
|
||||
# the page table with a specific privileged mode.
|
||||
|
||||
|
@ -448,6 +509,10 @@ class riscv_asm_program_gen:
|
|||
self.gen_section(pkg_ins.get_label("{}_handler".format(tvec_name.lower()), hart), instr)
|
||||
|
||||
# TODO Exception handler
|
||||
instr = []
|
||||
if cfg.mtvec_mode == mtvec_mode_t.VECTORED:
|
||||
pkg_ins.push_gpr_to_kernel_stack(
|
||||
status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr)
|
||||
|
||||
def gen_interrupt_vector_table(self, hart, mode, status, cause, ie,
|
||||
ip, scratch, instr):
|
||||
|
@ -546,7 +611,7 @@ class riscv_asm_program_gen:
|
|||
ip.name)]
|
||||
interrupt_handler_instr.extend(to_extend_interrupt_hanlder_instr)
|
||||
self.gen_plic_section(interrupt_handler_instr)
|
||||
pkg_ins.pop_gpr_from_kernel_stack(status.name, scratch.name, cfg.mstatus_mprv,
|
||||
pkg_ins.pop_gpr_from_kernel_stack(status, scratch, cfg.mstatus_mprv,
|
||||
cfg.sp, cfg.tp, interrupt_handler_instr)
|
||||
interrupt_handler_instr.append("%0sret;" % (mode_prefix))
|
||||
|
||||
|
@ -555,7 +620,7 @@ class riscv_asm_program_gen:
|
|||
else:
|
||||
self.instr_stream.append(".align 2")
|
||||
|
||||
self.gen_section(pkg_ins.get_label("%0smode_intr_handler" %
|
||||
self.gen_section(pkg_ins.get_label("%0smode_instr_handler" %
|
||||
(mode_prefix), hart), interrupt_handler_instr)
|
||||
|
||||
def format_section(self, instr):
|
||||
|
@ -574,8 +639,7 @@ class riscv_asm_program_gen:
|
|||
pass
|
||||
|
||||
def gen_test_file(self, test_name):
|
||||
subprocess.run(["mkdir", "-p", "out/asm_tests"])
|
||||
file = open("./out/asm_tests/{}".format(test_name), "w+")
|
||||
file = open(test_name, "w+")
|
||||
for items in self.instr_stream:
|
||||
file.write("{}\n".format(items))
|
||||
|
||||
|
@ -596,17 +660,18 @@ class riscv_asm_program_gen:
|
|||
arg = "directed_instr_{}".format(i)
|
||||
stream_name_opts = "stream_name_{}".format(i)
|
||||
stream_freq_opts = "stream_freq_{}".format(i)
|
||||
if(arg in args):
|
||||
val = args_dict[arg]
|
||||
if cfg.args_dict[arg]:
|
||||
val = cfg.args_dict[arg]
|
||||
opts = val.split(",")
|
||||
if(len(opts) != 2):
|
||||
if len(opts) != 2:
|
||||
logging.critical(
|
||||
"Incorrect directed instruction format : %0s, expect: name,ratio", val)
|
||||
sys.exit(1)
|
||||
else:
|
||||
self.add_directed_instr_stream(opts[0], int(opts[1]))
|
||||
elif(stream_name_opts in args and stream_freq_opts in args):
|
||||
stream_name = args_dict[stream_name_opts]
|
||||
stream_freq = args_dict[stream_freq_opts]
|
||||
elif cfg.args_dict[stream_name_opts] and cfg.args_dict[stream_freq_opts]:
|
||||
stream_name = cfg.args_dict[stream_name_opts]
|
||||
stream_freq = cfg.args_dict[stream_freq_opts]
|
||||
self.add_directed_instr_stream(stream_name, stream_freq)
|
||||
|
||||
def generate_directed_instr_stream(self, hart = 0, label = "", original_instr_cnt = 0,
|
||||
|
@ -629,7 +694,7 @@ class riscv_asm_program_gen:
|
|||
if(object_h is None):
|
||||
logging.critical("Cannot create instr stream %0s", name)
|
||||
sys.exit(1)
|
||||
new_instr_stream = copy.copy(object_h)
|
||||
new_instr_stream = copy.deepcopy(object_h)
|
||||
if(new_instr_stream):
|
||||
new_instr_stream.hart = hart
|
||||
new_instr_stream.label = "{}_{}".format(label, idx)
|
||||
|
|
87
vendor/google_riscv-dv/pygen/pygen_src/riscv_data_page_gen.py
vendored
Normal file
87
vendor/google_riscv-dv/pygen/pygen_src/riscv_data_page_gen.py
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
"""
|
||||
Copyright 2020 Google LLC
|
||||
Copyright 2020 PerfectVIPs Inc.
|
||||
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.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import vsc
|
||||
import random
|
||||
from collections import defaultdict
|
||||
from pygen_src.riscv_instr_pkg import pkg_ins, data_pattern_t
|
||||
from pygen_src.riscv_instr_gen_config import cfg
|
||||
|
||||
|
||||
@vsc.randobj
|
||||
class riscv_data_page_gen:
|
||||
def __init__(self):
|
||||
self.data_page_str = []
|
||||
self.mem_region_setting = defaultdict(list)
|
||||
@staticmethod
|
||||
def gen_data(idx, pattern, num_of_bytes, data):
|
||||
temp_data = 0
|
||||
data = [0] * num_of_bytes
|
||||
for i in range(len(data)):
|
||||
if pattern == data_pattern_t.RAND_DATA:
|
||||
temp_data = random.randrange(0, (2**8) - 1)
|
||||
data[i] = temp_data
|
||||
elif pattern == data_pattern_t.INCR_VAL:
|
||||
data[i] = (idx + i) % 256
|
||||
return data
|
||||
|
||||
def gen_data_page(self, hart_id, pattern, is_kernel=0, amo=0):
|
||||
tmp_str = ""
|
||||
temp_data = []
|
||||
tmp_data = []
|
||||
page_cnt = 0
|
||||
page_size = 0
|
||||
self.data_page_str.clear()
|
||||
if is_kernel:
|
||||
self.mem_region_setting = cfg.s_mem_region
|
||||
elif amo:
|
||||
self.mem_region_setting = cfg.amo_region
|
||||
else:
|
||||
self.mem_region_setting = cfg.mem_region
|
||||
for i in range(len(self.mem_region_setting)):
|
||||
logging.info("Generate data section: {} size:0x{} xwr:0x{}".format(
|
||||
self.mem_region_setting[i]["name"],
|
||||
self.mem_region_setting[i]["size_in_bytes"],
|
||||
self.mem_region_setting[i]["xwr"]))
|
||||
if amo:
|
||||
if cfg.use_push_data_section:
|
||||
self.data_page_str.append(".pushsection .{},\"aw\",@progbits;"
|
||||
.format(self.mem_region_setting[i]["name"]))
|
||||
else:
|
||||
self.data_page_str.append(".section .{},\"aw\",@progbits;"
|
||||
.format(self.mem_region_setting[i]["name"]))
|
||||
self.data_page_str.append("{}:".format(self.mem_region_setting[i]["name"]))
|
||||
else:
|
||||
if cfg.use_push_data_section:
|
||||
self.data_page_str.append(".pushsection .{},\"aw\",@progbits;"
|
||||
.format(pkg_ins.hart_prefix(hart_id) +
|
||||
self.mem_region_setting[i]["name"]))
|
||||
else:
|
||||
self.data_page_str.append(".section .{},\"aw\",@progbits;"
|
||||
.format(pkg_ins.hart_prefix(hart_id) +
|
||||
self.mem_region_setting[i]["name"]))
|
||||
self.data_page_str.append("{}:".format(pkg_ins.hart_prefix(hart_id) +
|
||||
self.mem_region_setting[i]["name"]))
|
||||
page_size = self.mem_region_setting[i]["size_in_bytes"]
|
||||
for i in range(0, page_size, 32):
|
||||
if page_size - 1 >= 32:
|
||||
temp_data = self.gen_data(idx=i, pattern=pattern,
|
||||
num_of_bytes=32, data=temp_data)
|
||||
else:
|
||||
temp_data = self.gen_data(idx=i, pattern=pattern,
|
||||
num_of_bytes=page_size - 1, data=temp_data)
|
||||
tmp_str = pkg_ins.format_string(".word {}".format(pkg_ins.format_data(temp_data)),
|
||||
pkg_ins.LABEL_STR_LEN)
|
||||
self.data_page_str.append(tmp_str)
|
||||
if cfg.use_push_data_section:
|
||||
self.data_page_str.append(".popsection")
|
|
@ -14,14 +14,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
||||
from pygen_src.riscv_instr_pkg import imm_t
|
||||
from pygen_src.isa.riscv_instr import riscv_instr
|
||||
from pygen_src.isa.riscv_compressed_instr import riscv_compressed_instr
|
||||
|
||||
|
||||
def DEFINE_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp=imm_t.IMM, g=globals()):
|
||||
class_name = f"riscv_{instr_n.name}_instr"
|
||||
class_name = "riscv_{}_instr".format(instr_n.name)
|
||||
|
||||
def __init__(self):
|
||||
riscv_instr.__init__(self)
|
||||
self.instr_name = instr_n.name
|
||||
self.instr_name = instr_n
|
||||
self.format = instr_format
|
||||
self.category = instr_category
|
||||
self.group = instr_group
|
||||
|
@ -36,6 +37,25 @@ def DEFINE_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp=imm_
|
|||
g[class_name] = NewClass
|
||||
|
||||
|
||||
def DEFINE_C_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp=imm_t.IMM, g=globals()):
|
||||
class_name = "riscv_{}_instr".format(instr_n.name)
|
||||
|
||||
def __init__(self):
|
||||
riscv_compressed_instr.__init__(self)
|
||||
self.instr_name = instr_n
|
||||
self.format = instr_format
|
||||
self.category = instr_category
|
||||
self.group = instr_group
|
||||
self.imm_type = imm_tp
|
||||
self.set_imm_len()
|
||||
self.set_rand_mode()
|
||||
NewClass = type(class_name, (riscv_compressed_instr,), {
|
||||
"__init__": __init__,
|
||||
"valid": riscv_compressed_instr.register(instr_n)
|
||||
})
|
||||
g[class_name] = NewClass
|
||||
|
||||
|
||||
'''
|
||||
TODO
|
||||
@vsc.constraint
|
||||
|
|
|
@ -11,22 +11,28 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import random
|
||||
import logging
|
||||
import vsc
|
||||
from importlib import import_module
|
||||
from enum import IntEnum, auto
|
||||
from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
|
||||
from pygen_src.isa.riscv_instr import riscv_instr_ins
|
||||
from pygen_src.isa.riscv_instr import riscv_instr
|
||||
from pygen_src.riscv_instr_gen_config import cfg
|
||||
from pygen_src.riscv_instr_pkg import riscv_reg_t, riscv_pseudo_instr_name_t
|
||||
from pygen_src.target.rv32i import riscv_core_setting as rcs
|
||||
from pygen_src.riscv_instr_pkg import (riscv_reg_t,
|
||||
riscv_pseudo_instr_name_t, riscv_instr_name_t, pkg_ins)
|
||||
from pygen_src.riscv_pseudo_instr import riscv_pseudo_instr
|
||||
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
|
||||
|
||||
|
||||
class riscv_directed_instr_stream(riscv_rand_instr_stream):
|
||||
|
||||
label = ""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = ""
|
||||
self.label = ""
|
||||
|
||||
def post_randomize(self):
|
||||
for i in range(len(self.instr_list)):
|
||||
|
@ -34,11 +40,74 @@ class riscv_directed_instr_stream(riscv_rand_instr_stream):
|
|||
self.instr_list[i].atomic = 1
|
||||
self.instr_list[0].comment = "Start %0s" % (self.name)
|
||||
self.instr_list[-1].comment = "End %0s" % (self.name)
|
||||
if self.label != "":
|
||||
self.instr_list[0].label = self.label
|
||||
if riscv_directed_instr_stream.label != "":
|
||||
self.instr_list[0].label = riscv_directed_instr_stream.label
|
||||
self.instr_list[0].has_label = 1
|
||||
|
||||
|
||||
@vsc.randobj
|
||||
class riscv_jal_instr(riscv_rand_instr_stream):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = ""
|
||||
self.jump = []
|
||||
self.jump_start = riscv_instr()
|
||||
self.jump_end = riscv_instr()
|
||||
self.num_of_jump_instr = vsc.rand_int_t()
|
||||
|
||||
@vsc.constraint
|
||||
def instr_c(self):
|
||||
self.num_of_jump_instr in vsc.rangelist(vsc.rng(10, 30))
|
||||
|
||||
def post_randomize(self):
|
||||
order = []
|
||||
RA = cfg.ra
|
||||
order = [0] * self.num_of_jump_instr
|
||||
self.jump = [0] * self.num_of_jump_instr
|
||||
for i in range(len(order)):
|
||||
order[i] = i
|
||||
random.shuffle(order)
|
||||
self.setup_allowed_instr(1, 1)
|
||||
jal = [riscv_instr_name_t.JAL]
|
||||
if not cfg.disable_compressed_instr:
|
||||
jal.append(riscv_instr_name_t.C_J)
|
||||
if rcs.XLEN == 32:
|
||||
jal.append(riscv_instr_name_t.C_JAL)
|
||||
self.jump_start = riscv_instr.get_instr(riscv_instr_name_t.JAL.name)
|
||||
with self.jump_start.randomize_with() as it:
|
||||
self.jump_start.rd == RA
|
||||
self.jump_start.imm_str = "{}f".format(order[0])
|
||||
self.jump_start.label = self.label
|
||||
|
||||
# Last instruction
|
||||
self.jump_end = self.randomize_instr(self.jump_end)
|
||||
self.jump_end.label = "{}".format(self.num_of_jump_instr)
|
||||
for i in range(self.num_of_jump_instr):
|
||||
self.jump[i] = riscv_instr.get_rand_instr(include_instr = [jal[0].name])
|
||||
with self.jump[i].randomize_with() as it:
|
||||
if self.jump[i].has_rd:
|
||||
vsc.dist(self.jump[i].rd, [vsc.weight(riscv_reg_t.RA, 5), vsc.weight(
|
||||
vsc.rng(riscv_reg_t.SP, riscv_reg_t.T0), 1),
|
||||
vsc.weight(vsc.rng(riscv_reg_t.T2, riscv_reg_t.T6), 2)])
|
||||
self.jump[i].rd.not_inside(cfg.reserved_regs)
|
||||
self.jump[i].label = "{}".format(i)
|
||||
|
||||
for i in range(len(order)):
|
||||
if i == self.num_of_jump_instr - 1:
|
||||
self.jump[order[i]].imm_str = "{}f".format(self.num_of_jump_instr)
|
||||
else:
|
||||
if order[i + 1] > order[i]:
|
||||
self.jump[order[i]].imm_str = "{}f".format(order[i + 1])
|
||||
else:
|
||||
self.jump[order[i]].imm_str = "{}b".format(order[i + 1])
|
||||
self.instr_list.append(self.jump_start)
|
||||
self.instr_list.extend(self.jump)
|
||||
self.instr_list.append(self.jump_end)
|
||||
for i in range(len(self.instr_list)):
|
||||
self.instr_list[i].has_label = 1
|
||||
self.instr_list[i].atomic = 1
|
||||
|
||||
|
||||
class int_numeric_e(IntEnum):
|
||||
NormalValue = auto()
|
||||
Zero = auto()
|
||||
|
@ -90,9 +159,140 @@ class riscv_int_numeric_corner_stream(riscv_directed_instr_stream):
|
|||
self.init_instr[i].imm_str = "0x%0x" % (self.init_val[i])
|
||||
self.instr_list.append(self.init_instr[i])
|
||||
for i in range(self.num_of_instr):
|
||||
instr = riscv_instr_ins.get_rand_instr(
|
||||
instr = riscv_instr.get_rand_instr(
|
||||
include_category = ['ARITHMETIC'],
|
||||
exclude_group = ['RV32C', 'RV64C', 'RV32F', 'RV64F', 'RV32D', 'RV64D'])
|
||||
instr = self.randomize_gpr(instr)
|
||||
self.instr_list.append(instr)
|
||||
super().post_randomize()
|
||||
|
||||
|
||||
# Push Stack Instructions
|
||||
class riscv_push_stack_instr(riscv_rand_instr_stream):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.stack_len = 0
|
||||
self.num_of_reg_to_save = 0
|
||||
self.num_of_redundant_instr = 0
|
||||
self.push_stack_instr = []
|
||||
self.saved_regs = []
|
||||
self.branch_instr = riscv_instr()
|
||||
self.enable_branch = vsc.rand_bit_t()
|
||||
self.push_start_label = ''
|
||||
|
||||
def init(self):
|
||||
self.reserved_rd = [cfg.ra]
|
||||
self.saved_regs = [cfg.ra]
|
||||
self.num_of_reg_to_save = len(self.saved_regs)
|
||||
if self.num_of_reg_to_save * (rcs.XLEN / 8) > self.stack_len:
|
||||
logging.error('stack len [%0d] is not enough to store %d regs',
|
||||
self.stack_len, self.num_of_reg_to_save)
|
||||
sys.exit(1)
|
||||
self.num_of_redundant_instr = random.randrange(3, 10)
|
||||
self.initialize_instr_list(self.num_of_redundant_instr)
|
||||
|
||||
def gen_push_stack_instr(self, stack_len, allow_branch=1):
|
||||
self.stack_len = stack_len
|
||||
self.init()
|
||||
self.push_stack_instr = [0] * (self.num_of_reg_to_save + 1)
|
||||
for i in range(len(self.push_stack_instr)):
|
||||
self.push_stack_instr[i] = riscv_instr()
|
||||
self.push_stack_instr[0] = \
|
||||
riscv_instr.get_instr(riscv_instr_name_t.ADDI.name)
|
||||
with self.push_stack_instr[0].randomize_with() as it:
|
||||
self.push_stack_instr[0].rd == cfg.sp
|
||||
self.push_stack_instr[0].rs1 == cfg.sp
|
||||
self.push_stack_instr[0].imm == (~cfg.stack_len) + 1
|
||||
|
||||
self.push_stack_instr[0].imm_str = '-{}'.format(self.stack_len)
|
||||
for i in range(len(self.saved_regs)):
|
||||
if rcs.XLEN == 32:
|
||||
self.push_stack_instr[i + 1] = riscv_instr.get_instr(riscv_instr_name_t.SW.name)
|
||||
with self.push_stack_instr[i + 1].randomize_with() as it:
|
||||
self.push_stack_instr[i + 1].rs2 == self.saved_regs[i]
|
||||
self.push_stack_instr[i + 1].rs1 == cfg.sp
|
||||
self.push_stack_instr[i + 1].imm == 4 * (i + 1)
|
||||
else:
|
||||
self.push_stack_instr[i + 1] = riscv_instr.get_instr(riscv_instr_name_t.SD.name)
|
||||
with self.push_stack_instr[i + 1].randomize_with() as it:
|
||||
self.push_stack_instr[i + 1].rs2 == self.saved_regs[i]
|
||||
self.push_stack_instr[i + 1].rs1 == cfg.sp
|
||||
self.push_stack_instr[i + 1].imm == 8 * (i + 1)
|
||||
|
||||
self.push_stack_instr[i + 1].process_load_store = 0
|
||||
if allow_branch:
|
||||
# TODO `DV_CHECK_STD_RANDOMIZE_FATAL(enable_branch)
|
||||
pass
|
||||
else:
|
||||
self.enable_branch = 0
|
||||
if self.enable_branch:
|
||||
self.branch_instr = \
|
||||
riscv_instr.get_rand_instr(include_category=[riscv_instr_name_t.BRANCH.name])
|
||||
# `DV_CHECK_STD_RANDOMIZE_FATAL(branch_instr)
|
||||
self.branch_instr.imm_str = self.push_start_label
|
||||
self.branch_instr.brach_assigned = 1
|
||||
self.push_stack_instr[0].label = self.push_start_label
|
||||
self.push_stack_instr[0].has_label = 1
|
||||
self.branch_instr.extend(self.push_stack_instr)
|
||||
self.mix_instr_stream(self.push_stack_instr)
|
||||
for i in range(len(self.instr_list)):
|
||||
self.instr_list[i].atomic = 1
|
||||
if self.instr_list[i].label == '':
|
||||
self.instr_list[i].has_label = 0
|
||||
|
||||
|
||||
# Pop stack instruction stream
|
||||
class riscv_pop_stack_instr(riscv_rand_instr_stream):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.stack_len = 0
|
||||
self.num_of_reg_to_save = 0
|
||||
self.num_of_redundant_instr = 0
|
||||
self.pop_stack_instr = []
|
||||
self.saved_regs = []
|
||||
|
||||
def init(self):
|
||||
self.reserved_rd = [cfg.ra]
|
||||
self.num_of_reg_to_save = len(self.saved_regs)
|
||||
if self.num_of_reg_to_save * 4 > self.stack_len:
|
||||
logging.error('stack len [%0d] is not enough to store %d regs',
|
||||
self.stack_len, self.num_of_reg_to_save)
|
||||
sys.exit(1)
|
||||
self.num_of_redundant_instr = random.randrange(3, 10)
|
||||
self.initialize_instr_list(self.num_of_redundant_instr)
|
||||
|
||||
def gen_pop_stack_instr(self, stack_len, saved_regs):
|
||||
self.stack_len = stack_len
|
||||
self.saved_regs = saved_regs
|
||||
self.init()
|
||||
self.gen_instr(1)
|
||||
self.pop_stack_instr = [None] * (self.num_of_reg_to_save + 1)
|
||||
for i in range(len(self.pop_stack_instr)):
|
||||
self.pop_stack_instr[i] = riscv_instr()
|
||||
for i in range(len(self.saved_regs)):
|
||||
if rcs.XLEN == 32:
|
||||
self.pop_stack_instr[i] = riscv_instr.get_instr(riscv_instr_name_t.LW.name)
|
||||
with self.pop_stack_instr[i].randomize_with() as it:
|
||||
self.rd == self.saved_regs[i]
|
||||
self.rs1 == cfg.sp
|
||||
self.imm == 4 * (i + 1)
|
||||
else:
|
||||
self.pop_stack_instr[i] = riscv_instr.get_instr(riscv_instr_name_t.LD.name)
|
||||
with self.pop_stack_instr[i].randomize_with() as it:
|
||||
self.rd == self.saved_regs[i]
|
||||
self.rs1 == cfg.sp
|
||||
self.imm == 8 * (i + 1)
|
||||
self.pop_stack_instr[i].process_load_store = 0
|
||||
# addi sp,sp,imm
|
||||
''' TODO `DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[num_of_reg_to_save],
|
||||
rd == cfg.sp; rs1 == cfg.sp; imm == stack_len;) '''
|
||||
self.pop_stack_instr[self.num_of_reg_to_save] = riscv_instr.get_instr(
|
||||
riscv_instr_name_t.ADDI.name)
|
||||
self.pop_stack_instr[self.num_of_reg_to_save].imm_str = pkg_ins.format_string(
|
||||
'{}', self.stack_len)
|
||||
self.mix_instr_stream(self.pop_stack_instr)
|
||||
for i in range(len(self.instr_list)):
|
||||
self.instr_list[i].atomic = 1
|
||||
self.instr_list[i].has_label = 0
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,24 +17,27 @@ import logging
|
|||
import sys
|
||||
import vsc
|
||||
from bitstring import BitArray
|
||||
from pygen_src.riscv_instr_pkg import mtvec_mode_t, f_rounding_mode_t, \
|
||||
riscv_reg_t, privileged_mode_t, \
|
||||
riscv_instr_group_t
|
||||
from pygen_src.target.rv32i import riscv_core_setting as rcs
|
||||
from importlib import import_module
|
||||
from pygen_src.riscv_instr_pkg import (mtvec_mode_t, f_rounding_mode_t,
|
||||
riscv_reg_t, privileged_mode_t,
|
||||
riscv_instr_group_t, data_pattern_t)
|
||||
|
||||
|
||||
@vsc.randobj
|
||||
class riscv_instr_gen_config:
|
||||
def __init__(self, argv):
|
||||
def __init__(self):
|
||||
# TODO Support for command line argument
|
||||
self.main_program_instr_cnt = 100 # count of main_prog
|
||||
self.sub_program_instr_cnt = [] # count of sub_prog
|
||||
self.debug_program_instr_cnt = 0 # count of debug_rom
|
||||
self.debug_sub_program_instr_cnt = [] # count of debug sub_progrms
|
||||
# Commenting out for now
|
||||
# self.data_page_pattern = list(
|
||||
# map(lambda dta_pg: dta_pg.name, data_pattern_t))
|
||||
# dicts for exception_cause_t & interrupt_cause_t Enum classes
|
||||
self.max_directed_instr_stream_seq = 20
|
||||
self.data_page_pattern = vsc.rand_enum_t(data_pattern_t)
|
||||
self.argv = self.parse_args()
|
||||
self.args_dict = vars(self.argv)
|
||||
|
||||
global rcs
|
||||
rcs = import_module("pygen_src.target." + self.argv.target + ".riscv_core_setting")
|
||||
|
||||
self.m_mode_exception_delegation = {}
|
||||
self.s_mode_exception_delegation = {}
|
||||
|
@ -59,7 +62,7 @@ class riscv_instr_gen_config:
|
|||
self.mstatus_vs = BitArray(bin(0b0), length=2)
|
||||
self.mtvec_mode = vsc.rand_enum_t(mtvec_mode_t)
|
||||
|
||||
self.tvec_alignment = argv.tvec_alignment
|
||||
self.tvec_alignment = vsc.rand_uint8_t(self.argv.tvec_alignment)
|
||||
|
||||
self.fcsr_rm = list(map(lambda csr_rm: csr_rm.name, f_rounding_mode_t))
|
||||
self.enable_sfence = 0
|
||||
|
@ -83,99 +86,114 @@ class riscv_instr_gen_config:
|
|||
# Commenting out for now
|
||||
# vector_cfg = riscv_vector_cfg # TODO
|
||||
# pmp_cfg = riscv_pmp_cfg # TODO
|
||||
# self.mem_region = [] # TODO
|
||||
# Self.amo_region = [] # TODO
|
||||
|
||||
self.mem_region = {
|
||||
0: {'name': "region_0", 'size_in_bytes': 4096, 'xwr': 8},
|
||||
1: {'name': "region_1", 'size_in_bytes': 4096 * 16, 'xwr': 8}
|
||||
}
|
||||
self.amo_region = {
|
||||
0: {'name': "amo_0", 'size_in_bytes': 64, 'xwr': 8}
|
||||
}
|
||||
self.stack_len = 5000
|
||||
|
||||
# Self.s_mem_region = [] # TODO
|
||||
self.s_mem_region = {
|
||||
0: {'name': "s_region_0", 'size_in_bytes': 4096, 'xwr': 8},
|
||||
1: {'name': "s_region_1", 'size_in_bytes': 4096, 'xwr': 8}
|
||||
}
|
||||
|
||||
self.kernel_stack_len = 4000
|
||||
self.kernel_program_instr_cnt = 400
|
||||
# list of main implemented CSRs
|
||||
self.invalid_priv_mode_csrs = []
|
||||
self.num_of_sub_program = argv.num_of_sub_program
|
||||
self.instr_cnt = argv.instr_cnt
|
||||
self.num_of_tests = argv.num_of_tests
|
||||
self.no_data_page = argv.no_data_page
|
||||
self.no_branch_jump = argv.no_branch_jump
|
||||
self.no_load_store = argv.no_load_store
|
||||
self.no_csr_instr = argv.no_csr_instr
|
||||
self.no_ebreak = argv.no_ebreak
|
||||
self.no_dret = argv.no_dret
|
||||
self.no_fence = argv.no_fence
|
||||
self.no_wfi = argv.no_wfi
|
||||
self.enable_unaligned_load_store = argv.enable_unaligned_load_store
|
||||
self.illegal_instr_ratio = argv.illegal_instr_ratio
|
||||
self.hint_instr_ratio = argv.hint_instr_ratio
|
||||
self.num_of_harts = argv.num_of_harts
|
||||
self.fix_sp = argv.fix_sp
|
||||
self.use_push_data_section = argv.use_push_data_section
|
||||
self.boot_mode_opts = argv.boot_mode_opts
|
||||
self.num_of_sub_program = self.argv.num_of_sub_program
|
||||
self.instr_cnt = self.argv.instr_cnt
|
||||
self.num_of_tests = self.argv.num_of_tests
|
||||
self.no_data_page = self.argv.no_data_page
|
||||
self.no_branch_jump = self.argv.no_branch_jump
|
||||
self.no_load_store = self.argv.no_load_store
|
||||
self.no_csr_instr = self.argv.no_csr_instr
|
||||
self.no_ebreak = self.argv.no_ebreak
|
||||
self.no_dret = self.argv.no_dret
|
||||
self.no_fence = self.argv.no_fence
|
||||
self.no_wfi = self.argv.no_wfi
|
||||
self.enable_unaligned_load_store = self.argv.enable_unaligned_load_store
|
||||
self.illegal_instr_ratio = self.argv.illegal_instr_ratio
|
||||
self.hint_instr_ratio = self.argv.hint_instr_ratio
|
||||
self.num_of_harts = self.argv.num_of_harts
|
||||
self.fix_sp = self.argv.fix_sp
|
||||
self.use_push_data_section = self.argv.use_push_data_section
|
||||
self.boot_mode_opts = self.argv.boot_mode
|
||||
# self.isa = self.argv.isa
|
||||
|
||||
if(self.boot_mode_opts):
|
||||
if self.boot_mode_opts:
|
||||
logging.info("Got boot mode option - %0s", self.boot_mode_opts)
|
||||
if(self.boot_mode_opts == "m"):
|
||||
self.init_privileged_mode = privileged_mode_t.MACHINE_MODE.name
|
||||
elif(self.boot_mode_opts == "s"):
|
||||
self.init_privileged_mode = privileged_mode_t.SUPERVISOR_MODE.name
|
||||
elif(self.boot_mode_opts == "u"):
|
||||
self.init_privileged_mode = privileged_mode_t.USER_MODE.name
|
||||
if self.boot_mode_opts == "m":
|
||||
self.init_privileged_mode = privileged_mode_t.MACHINE_MODE
|
||||
elif self.boot_mode_opts == "s":
|
||||
self.init_privileged_mode = privileged_mode_t.SUPERVISOR_MODE
|
||||
elif self.boot_mode_opts == "u":
|
||||
self.init_privileged_mode = privileged_mode_t.USER_MODE
|
||||
else:
|
||||
logging.error("Illegal boot mode option - %0s", self.boot_mode_opts)
|
||||
|
||||
self.enable_page_table_exception = argv.enable_page_table_exception
|
||||
self.no_directed_instr = argv.no_directed_instr
|
||||
self.asm_test_suffix = argv.asm_test_suffix
|
||||
self.enable_interrupt = argv.enable_interrupt
|
||||
self.enable_nested_interrupt = argv.enable_nested_interrupt
|
||||
self.enable_timer_irq = argv.enable_timer_irq
|
||||
self.bare_program_mode = argv.bare_program_mode
|
||||
self.enable_illegal_csr_instruction = argv.enable_illegal_csr_instruction
|
||||
self.enable_access_invalid_csr_level = argv.enable_access_invalid_csr_level
|
||||
self.enable_misaligned_instr = argv.enable_misaligned_instr
|
||||
self.enable_dummy_csr_write = argv.enable_dummy_csr_write
|
||||
self.randomize_csr = argv.randomize_csr
|
||||
self.allow_sfence_exception = argv.allow_sfence_exception
|
||||
self.no_delegation = argv.no_delegation
|
||||
self.force_m_delegation = argv.force_m_delegation
|
||||
self.force_s_delegation = argv.force_s_delegation
|
||||
self.enable_page_table_exception = self.argv.enable_page_table_exception
|
||||
self.no_directed_instr = self.argv.no_directed_instr
|
||||
self.asm_test_suffix = self.argv.asm_test_suffix
|
||||
self.enable_interrupt = self.argv.enable_interrupt
|
||||
self.enable_nested_interrupt = self.argv.enable_nested_interrupt
|
||||
self.enable_timer_irq = self.argv.enable_timer_irq
|
||||
self.bare_program_mode = self.argv.bare_program_mode
|
||||
self.enable_illegal_csr_instruction = self.argv.enable_illegal_csr_instruction
|
||||
self.enable_access_invalid_csr_level = self.argv.enable_access_invalid_csr_level
|
||||
self.enable_misaligned_instr = self.argv.enable_misaligned_instr
|
||||
self.enable_dummy_csr_write = self.argv.enable_dummy_csr_write
|
||||
self.randomize_csr = self.argv.randomize_csr
|
||||
self.allow_sfence_exception = self.argv.allow_sfence_exception
|
||||
self.no_delegation = self.argv.no_delegation
|
||||
self.force_m_delegation = self.argv.force_m_delegation
|
||||
self.force_s_delegation = self.argv.force_s_delegation
|
||||
self.support_supervisor_mode = 0
|
||||
self.disable_compressed_instr = argv.disable_compressed_instr
|
||||
self.require_signature_addr = argv.require_signature_addr
|
||||
self.disable_compressed_instr = self.argv.disable_compressed_instr
|
||||
self.require_signature_addr = self.argv.require_signature_addr
|
||||
|
||||
if(self.require_signature_addr):
|
||||
self.signature_addr = int(argv.signature_addr, 16)
|
||||
if self.require_signature_addr:
|
||||
self.signature_addr = int(self.argv.signature_addr, 16)
|
||||
else:
|
||||
self.signature_addr = 0xdeadbeef
|
||||
|
||||
self.gen_debug_section = argv.gen_debug_section
|
||||
self.enable_ebreak_in_debug_rom = argv.enable_ebreak_in_debug_rom
|
||||
self.set_dcsr_ebreak = argv.set_dcsr_ebreak
|
||||
self.num_debug_sub_program = argv.num_debug_sub_program
|
||||
self.enable_debug_single_step = argv.enable_debug_single_step
|
||||
self.gen_debug_section = self.argv.gen_debug_section
|
||||
self.enable_ebreak_in_debug_rom = self.argv.enable_ebreak_in_debug_rom
|
||||
self.set_dcsr_ebreak = self.argv.set_dcsr_ebreak
|
||||
self.num_debug_sub_program = self.argv.num_debug_sub_program
|
||||
self.enable_debug_single_step = self.argv.enable_debug_single_step
|
||||
self.single_step_iterations = 0
|
||||
self.set_mstatus_tw = argv.set_mstatus_tw
|
||||
self.set_mstatus_mprv = argv.set_mstatus_mprv
|
||||
self.set_mstatus_tw = self.argv.set_mstatus_tw
|
||||
self.set_mstatus_mprv = self.argv.set_mstatus_mprv
|
||||
self.min_stack_len_per_program = 10 * (rcs.XLEN / 8)
|
||||
self.max_stack_len_per_program = 16 * (rcs.XLEN / 8)
|
||||
self.max_branch_step = 20
|
||||
self.max_directed_instr_stream_seq = 20
|
||||
self.reserved_regs = vsc.list_t(vsc.enum_t(riscv_reg_t))
|
||||
self.enable_floating_point = argv.enable_floating_point
|
||||
self.enable_vector_extension = argv.enable_vector_extension
|
||||
self.enable_b_extension = argv.enable_b_extension
|
||||
self.enable_bitmanip_groups = argv.enable_bitmanip_groups
|
||||
self.enable_floating_point = self.argv.enable_floating_point
|
||||
self.enable_vector_extension = self.argv.enable_vector_extension
|
||||
self.enable_b_extension = self.argv.enable_b_extension
|
||||
self.enable_bitmanip_groups = self.argv.enable_bitmanip_groups
|
||||
self.dist_control_mode = 0
|
||||
self.category_dist = {}
|
||||
self.march_isa = argv.march_isa
|
||||
self.march_isa = self.argv.march_isa
|
||||
|
||||
if(len(self.march_isa) != 0):
|
||||
if len(self.march_isa) != 0:
|
||||
rcs.supported_isa = self.march_isa
|
||||
|
||||
if(rcs.supported_isa != 'RV32C'):
|
||||
if "RV32C" not in rcs.supported_isa:
|
||||
self.disable_compressed_instr = 1
|
||||
|
||||
@vsc.constraint
|
||||
def sp_tp_c(self):
|
||||
if self.fix_sp:
|
||||
self.sp == riscv_reg_t.SP
|
||||
self.sp != self.tp
|
||||
self.sp.not_inside(vsc.rangelist(riscv_reg_t.GP,
|
||||
riscv_reg_t.RA, riscv_reg_t.ZERO))
|
||||
self.tp.not_inside(vsc.rangelist(riscv_reg_t.GP,
|
||||
riscv_reg_t.RA, riscv_reg_t.ZERO))
|
||||
|
||||
@vsc.constraint
|
||||
def gpr_c(self):
|
||||
self.gpr0.not_inside(vsc.rangelist(self.sp, self.tp, self.scratch_reg, self.pmp_reg,
|
||||
|
@ -188,6 +206,25 @@ class riscv_instr_gen_config:
|
|||
riscv_reg_t.ZERO, riscv_reg_t.RA, riscv_reg_t.GP))
|
||||
vsc.unique(self.gpr0, self.gpr1, self.gpr2, self.gpr3)
|
||||
|
||||
@vsc.constraint
|
||||
def ra_c(self):
|
||||
self.ra != riscv_reg_t.SP
|
||||
self.ra != riscv_reg_t.TP
|
||||
self.ra != riscv_reg_t.ZERO
|
||||
|
||||
@vsc.constraint
|
||||
def reserve_scratch_reg_c(self):
|
||||
self.scratch_reg.not_inside(vsc.rangelist(riscv_reg_t.ZERO, self.sp,
|
||||
self.tp, self.ra, riscv_reg_t.GP))
|
||||
|
||||
@vsc.constraint
|
||||
def mtvec_c(self):
|
||||
self.mtvec_mode.inside(vsc.rangelist(mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED))
|
||||
if(self.mtvec_mode == mtvec_mode_t.DIRECT):
|
||||
vsc.soft(self.tvec_alignment == 2)
|
||||
else:
|
||||
vsc.soft(self.tvec_alignment == (rcs.XLEN * 4) / 8)
|
||||
|
||||
def check_setting(self):
|
||||
support_64b = 0
|
||||
support_128b = 0
|
||||
|
@ -257,13 +294,14 @@ class riscv_instr_gen_config:
|
|||
# As it is being extended in post_randomize function.
|
||||
self.gpr.clear()
|
||||
for x in rcs.supported_privileged_mode:
|
||||
if(x == "SUPERVISOR_MODE"):
|
||||
if x == privileged_mode_t.SUPERVISOR_MODE:
|
||||
self.support_supervisor_mode = 1
|
||||
|
||||
def get_non_reserved_gpr(self):
|
||||
pass
|
||||
|
||||
def post_randomize(self):
|
||||
self.reserved_regs = []
|
||||
# Temporary fix for gpr_c constraint.
|
||||
self.gpr.extend((self.gpr0, self.gpr1, self.gpr2, self.gpr3))
|
||||
|
||||
|
@ -273,10 +311,9 @@ class riscv_instr_gen_config:
|
|||
self.min_stack_len_per_program = 2 * (rcs.XLEN / 8)
|
||||
logging.info("min_stack_len_per_program value = %d"
|
||||
% self.min_stack_len_per_program)
|
||||
self.check_setting() # to check the setting is legal
|
||||
self.check_setting() # check if the setting is legal
|
||||
|
||||
# TODO, Need to change the logic once the constraints are up.
|
||||
if "USER_MODE" == self.init_privileged_mode:
|
||||
if self.init_privileged_mode == privileged_mode_t.USER_MODE:
|
||||
logging.info("mode=%s" % "USER_MODE")
|
||||
self.no_wfi = 1
|
||||
|
||||
|
@ -288,13 +325,13 @@ class riscv_instr_gen_config:
|
|||
|
||||
# TODO Need to change the logic once the constraints are up.
|
||||
for mode in self.init_privileged_mode:
|
||||
if mode == "MACHINE_MODE":
|
||||
if mode == privileged_mode_t.MACHINE_MODE:
|
||||
continue
|
||||
if mode == 'SUPERVISOR_MODE':
|
||||
if mode == privileged_mode_t.SUPERVISOR_MODE:
|
||||
invalid_lvl.append('M')
|
||||
logging.info("supr_mode---")
|
||||
logging.debug(invalid_lvl)
|
||||
elif mode == 'USER_MODE':
|
||||
elif mode == privileged_mode_t.USER_MODE:
|
||||
invalid_lvl.append('S')
|
||||
invalid_lvl.append('M')
|
||||
logging.info("usr_mode---")
|
||||
|
@ -315,123 +352,142 @@ class riscv_instr_gen_config:
|
|||
# self.setup_instr_distribution() # TODO
|
||||
self.get_invalid_priv_lvl_csr()
|
||||
|
||||
def parse_args(self):
|
||||
parse = argparse.ArgumentParser()
|
||||
parse.add_argument('--num_of_tests', help = 'num_of_tests', type = int, default = 1)
|
||||
parse.add_argument('--enable_page_table_exception',
|
||||
help = 'enable_page_table_exception', type = int, default = 0)
|
||||
parse.add_argument('--enable_interrupt', help = 'enable_interrupt',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_nested_interrupt', help = 'enable_nested_interrupt',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_timer_irq', help = 'enable_timer_irq',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--num_of_sub_program', help = 'num_of_sub_program',
|
||||
type = int, default = 5)
|
||||
parse.add_argument('--instr_cnt', help = 'instr_cnt', type = int, default = 200)
|
||||
parse.add_argument('--tvec_alignment', help = 'tvec_alignment', type = int, default = 2)
|
||||
parse.add_argument('--no_ebreak', help = 'no_ebreak',
|
||||
choices = [0, 1], type = int, default = 1)
|
||||
parse.add_argument('--no_dret', help = 'no_dret', choices = [0, 1], type = int, default = 1)
|
||||
parse.add_argument('--no_wfi', help = 'no_wfi', choices = [0, 1], type = int, default = 1)
|
||||
|
||||
def parse_args():
|
||||
parse = argparse.ArgumentParser()
|
||||
parse.add_argument('--num_of_tests', help = 'num_of_tests', type = int, default = 1)
|
||||
parse.add_argument('--enable_page_table_exception',
|
||||
help = 'enable_page_table_exception', type = int, default = 0)
|
||||
parse.add_argument('--enable_interrupt', help = 'enable_interrupt',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_nested_interrupt', help = 'enable_nested_interrupt',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_timer_irq', help = 'enable_timer_irq',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--num_of_sub_program', help = 'num_of_sub_program', type = int, default = 5)
|
||||
parse.add_argument('--instr_cnt', help = 'instr_cnt', type = int, default = 200)
|
||||
parse.add_argument('--tvec_alignment', help = 'tvec_alignment', type = int, default = 2)
|
||||
parse.add_argument('--no_ebreak', help = 'no_ebreak', choices = [0, 1], type = int, default = 1)
|
||||
parse.add_argument('--no_dret', help = 'no_dret', choices = [0, 1], type = int, default = 1)
|
||||
parse.add_argument('--no_wfi', help = 'no_wfi', choices = [0, 1], type = int, default = 1)
|
||||
parse.add_argument('--no_branch_jump', help = 'no_branch_jump',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--no_load_store', help = 'no_load_store',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--no_csr_instr', help = 'no_csr_instr',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--fix_sp', help = 'fix_sp',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--use_push_data_section', help = 'use_push_data_section',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_illegal_csr_instruction',
|
||||
help = 'enable_illegal_csr_instruction', choices = [0, 1],
|
||||
type = int, default = 0)
|
||||
parse.add_argument('--enable_access_invalid_csr_level',
|
||||
help = 'enable_access_invalid_csr_level', choices = [0, 1],
|
||||
type = int, default = 0)
|
||||
parse.add_argument('--enable_misaligned_instr', help = 'enable_misaligned_instr',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_dummy_csr_write', help = 'enable_dummy_csr_write',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--allow_sfence_exception', help = 'allow_sfence_exception',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--no_data_page', help = 'no_data_page',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--no_directed_instr', help = 'no_directed_instr',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--no_fence', help = 'no_fence',
|
||||
choices = [0, 1], type = int, default = 1)
|
||||
parse.add_argument('--no_delegation', help = 'no_delegation',
|
||||
choices = [0, 1], type = int, default = 1)
|
||||
parse.add_argument('--illegal_instr_ratio',
|
||||
help = 'illegal_instr_ratio', type = int, default = 0)
|
||||
parse.add_argument('--hint_instr_ratio', help = 'hint_instr_ratio', type = int, default = 0)
|
||||
# TODO map it with rcs NUM_HARTS. After solving the cyclic issue for core setting.
|
||||
# rcs is out of scope while using in the default value of num_of_harts
|
||||
parse.add_argument('--num_of_harts', help = 'num_of_harts',
|
||||
type = int, default = 1)
|
||||
parse.add_argument('--enable_unaligned_load_store',
|
||||
help = 'enable_unaligned_load_store', choices = [0, 1],
|
||||
type = int, default = 0)
|
||||
parse.add_argument('--force_m_delegation', help = 'force_m_delegation',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--force_s_delegation', help = 'force_s_delegation',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--require_signature_addr', help = 'require_signature_addr',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--signature_addr', help = 'signature_addr', default = 0xdeadbeef)
|
||||
parse.add_argument('--disable_compressed_instr',
|
||||
help = 'disable_compressed_instr', choices = [0, 1],
|
||||
type = int, default = 0)
|
||||
parse.add_argument('--randomize_csr', help = 'randomize_csr',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--gen_debug_section', help = 'gen_debug_section',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--bare_program_mode', help = 'bare_program_mode',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--num_debug_sub_program',
|
||||
help = 'num_debug_sub_program', type = int, default = 0)
|
||||
parse.add_argument('--enable_ebreak_in_debug_rom',
|
||||
help = 'enable_ebreak_in_debug_rom', choices = [0, 1],
|
||||
type = int, default = 0)
|
||||
parse.add_argument('--set_dcsr_ebreak', help = 'set_dcsr_ebreak',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_debug_single_step',
|
||||
help = 'enable_debug_single_step', choices = [0, 1],
|
||||
type = int, default = 0)
|
||||
parse.add_argument('--set_mstatus_tw', help = 'set_mstatus_tw',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--set_mstatus_mprv', help = 'set_mstatus_mprv',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_floating_point', help = 'enable_floating_point',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_vector_extension', help = 'enable_vector_extension',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_b_extension', help = 'enable_b_extension',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_bitmanip_groups', help = 'enable_bitmanip_groups',
|
||||
default = ['ZBB', 'ZBS', 'ZBP', 'ZBE', 'ZBF',
|
||||
'ZBC', 'ZBR', 'ZBM', 'ZBT', 'ZB_TMP'], nargs = '*')
|
||||
parse.add_argument('--boot_mode', help = 'boot_mode', default = "")
|
||||
parse.add_argument('--asm_test_suffix', help = 'asm_test_suffix', default = "")
|
||||
parse.add_argument('--march_isa', help = 'march_isa', default = [],
|
||||
choices = [i.name for i in riscv_instr_group_t], nargs = '*')
|
||||
for i in range(self.max_directed_instr_stream_seq):
|
||||
parse.add_argument('--directed_instr_{}'.format(i),
|
||||
help = 'directed_instr_{}'.format(i), default = "")
|
||||
parse.add_argument('--stream_name_{}'.format(i),
|
||||
help = 'stream_name_{}'.format(i), default = "")
|
||||
parse.add_argument('--stream_freq_{}'.format(i),
|
||||
help = 'stream_freq_{}'.format(i), default = 4)
|
||||
parse.add_argument('--start_idx', help='start index', type=int, default=0)
|
||||
parse.add_argument('--asm_file_name', help='asm file name',
|
||||
default="riscv_asm_test")
|
||||
parse.add_argument('--log_file_name', help='log file name',
|
||||
default="")
|
||||
parse.add_argument('--target', help='target', default="rv32imc")
|
||||
parse.add_argument("--enable_visualization", action="store_true", default=False,
|
||||
help="Enabling coverage report visualization for pyflow")
|
||||
parse.add_argument('--trace_csv', help='List of csv traces', default="")
|
||||
args, unknown = parse.parse_known_args()
|
||||
# TODO
|
||||
'''
|
||||
if ($value$plusargs("tvec_alignment=%0d", tvec_alignment)) begin
|
||||
tvec_alignment.rand_mode(0);
|
||||
end
|
||||
|
||||
parse.add_argument('--no_branch_jump', help = 'no_branch_jump',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--no_load_store', help = 'no_load_store',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--no_csr_instr', help = 'no_csr_instr',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--fix_sp', help = 'fix_sp', choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--use_push_data_section', help = 'use_push_data_section',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_illegal_csr_instruction',
|
||||
help = 'enable_illegal_csr_instruction', choices = [0, 1],
|
||||
type = int, default = 0)
|
||||
parse.add_argument('--enable_access_invalid_csr_level',
|
||||
help = 'enable_access_invalid_csr_level', choices = [0, 1],
|
||||
type = int, default = 0)
|
||||
parse.add_argument('--enable_misaligned_instr', help = 'enable_misaligned_instr',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_dummy_csr_write', help = 'enable_dummy_csr_write',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--allow_sfence_exception', help = 'allow_sfence_exception',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--no_data_page', help = 'no_data_page',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--no_directed_instr', help = 'no_directed_instr',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--no_fence', help = 'no_fence', choices = [0, 1], type = int, default = 1)
|
||||
parse.add_argument('--no_delegation', help = 'no_delegation',
|
||||
choices = [0, 1], type = int, default = 1)
|
||||
parse.add_argument('--illegal_instr_ratio',
|
||||
help = 'illegal_instr_ratio', type = int, default = 0)
|
||||
parse.add_argument('--hint_instr_ratio', help = 'hint_instr_ratio', type = int, default = 0)
|
||||
parse.add_argument('--num_of_harts', help = 'num_of_harts', type = int, default = rcs.NUM_HARTS)
|
||||
parse.add_argument('--enable_unaligned_load_store',
|
||||
help = 'enable_unaligned_load_store', choices = [0, 1],
|
||||
type = int, default = 0)
|
||||
parse.add_argument('--force_m_delegation', help = 'force_m_delegation',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--force_s_delegation', help = 'force_s_delegation',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--require_signature_addr', help = 'require_signature_addr',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--signature_addr', help = 'signature_addr', default = 0xdeadbeef)
|
||||
parse.add_argument('--disable_compressed_instr',
|
||||
help = 'disable_compressed_instr', choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--randomize_csr', help = 'randomize_csr',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--gen_debug_section', help = 'gen_debug_section',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--bare_program_mode', help = 'bare_program_mode',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--num_debug_sub_program',
|
||||
help = 'num_debug_sub_program', type = int, default = 0)
|
||||
parse.add_argument('--enable_ebreak_in_debug_rom',
|
||||
help = 'enable_ebreak_in_debug_rom', choices = [0, 1],
|
||||
type = int, default = 0)
|
||||
parse.add_argument('--set_dcsr_ebreak', help = 'set_dcsr_ebreak',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_debug_single_step',
|
||||
help = 'enable_debug_single_step', choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--set_mstatus_tw', help = 'set_mstatus_tw',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--set_mstatus_mprv', help = 'set_mstatus_mprv',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_floating_point', help = 'enable_floating_point',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_vector_extension', help = 'enable_vector_extension',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_b_extension', help = 'enable_b_extension',
|
||||
choices = [0, 1], type = int, default = 0)
|
||||
parse.add_argument('--enable_bitmanip_groups', help = 'enable_bitmanip_groups',
|
||||
default = ['ZBB', 'ZBS', 'ZBP', 'ZBE', 'ZBF',
|
||||
'ZBC', 'ZBR', 'ZBM', 'ZBT', 'ZB_TMP'], nargs = '*')
|
||||
parse.add_argument('--boot_mode_opts', help = 'boot_mode_opts', default = "")
|
||||
parse.add_argument('--asm_test_suffix', help = 'asm_test_suffix', default = "")
|
||||
parse.add_argument('--march_isa', help = 'march_isa', default = [],
|
||||
choices = [i.name for i in riscv_instr_group_t], nargs = '*')
|
||||
parse.add_argument('--directed_instr_0', help = 'directed_instr_0',
|
||||
default = "riscv_int_numeric_corner_stream,4")
|
||||
parse.add_argument('--stream_name_opts', help = 'stream_name_0',
|
||||
default = "riscv_load_store_rand_instr_stream")
|
||||
parse.add_argument('--stream_freq_opts', help = 'stream_freq_0', default = 4)
|
||||
# TODO
|
||||
'''
|
||||
if ($value$plusargs("tvec_alignment=%0d", tvec_alignment)) begin
|
||||
tvec_alignment.rand_mode(0);
|
||||
end
|
||||
vector_cfg = riscv_vector_cfg::type_id::create("vector_cfg");
|
||||
pmp_cfg = riscv_pmp_cfg::type_id::create("pmp_cfg");
|
||||
pmp_cfg.rand_mode(pmp_cfg.pmp_randomize);
|
||||
pmp_cfg.initialize(require_signature_addr);
|
||||
setup_instr_distribution()
|
||||
get_invalid_priv_lvl_csr();
|
||||
'''
|
||||
args = parse.parse_args()
|
||||
|
||||
vector_cfg = riscv_vector_cfg::type_id::create("vector_cfg");
|
||||
pmp_cfg = riscv_pmp_cfg::type_id::create("pmp_cfg");
|
||||
pmp_cfg.rand_mode(pmp_cfg.pmp_randomize);
|
||||
pmp_cfg.initialize(require_signature_addr);
|
||||
setup_instr_distribution();
|
||||
get_invalid_priv_lvl_csr();
|
||||
'''
|
||||
args = parse.parse_args()
|
||||
return args
|
||||
return args
|
||||
|
||||
|
||||
args = parse_args()
|
||||
args_dict = vars(args)
|
||||
cfg = riscv_instr_gen_config(args)
|
||||
cfg = riscv_instr_gen_config()
|
||||
|
|
|
@ -15,7 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
import logging
|
||||
from enum import Enum, IntEnum, auto
|
||||
from bitstring import BitArray
|
||||
from pygen.pygen_src.target.rv32i import riscv_core_setting as rcs
|
||||
from importlib import import_module
|
||||
|
||||
|
||||
class mem_region_t:
|
||||
|
@ -83,6 +83,7 @@ class riscv_instr_group_t(IntEnum):
|
|||
RV64B = auto()
|
||||
RV32X = auto()
|
||||
RV64X = auto()
|
||||
RVV = auto()
|
||||
|
||||
|
||||
class riscv_instr_name_t(IntEnum):
|
||||
|
@ -1081,6 +1082,8 @@ class rv32i_misc_instrs(IntEnum):
|
|||
MRET = auto()
|
||||
|
||||
# Ignore RAW_HAZARD for store lsu hazard
|
||||
|
||||
|
||||
class store_lsu_hazard_e(IntEnum):
|
||||
NO_HAZARD = 0
|
||||
WAR_HAZARD = auto()
|
||||
|
@ -1432,21 +1435,24 @@ def add_functions_as_methods(function):
|
|||
|
||||
|
||||
class riscv_instr_pkg:
|
||||
def __init__(self):
|
||||
self.MPRV_BIT_MASK = BitArray(uint=0x1 << 0x17, length=rcs.XLEN)
|
||||
self.SUM_BIT_MASK = BitArray(uint=0x1 << 0x18, length=rcs.XLEN)
|
||||
self.MPP_BIT_MASK = BitArray(uint=0x3 << 0x11, length=rcs.XLEN)
|
||||
self.MAX_USED_VADDR_BITS = 30
|
||||
self.IMM25_WIDTH = 25
|
||||
self.IMM12_WIDTH = 12
|
||||
self.INSTR_WIDTH = 32
|
||||
self.DATA_WIDTH = 32
|
||||
self.MAX_INSTR_STR_LEN = 11
|
||||
self.LABEL_STR_LEN = 18
|
||||
self.MAX_CALLSTACK_DEPTH = 20
|
||||
self.MAX_SUB_PROGRAM_CNT = 20
|
||||
self.MAX_CALL_PER_FUNC = 5
|
||||
self.indent = self.LABEL_STR_LEN * " "
|
||||
global rcs
|
||||
from pygen_src.riscv_instr_gen_config import cfg
|
||||
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
|
||||
|
||||
MPRV_BIT_MASK = BitArray(uint=0x1 << 0x17, length=rcs.XLEN)
|
||||
SUM_BIT_MASK = BitArray(uint=0x1 << 0x18, length=rcs.XLEN)
|
||||
MPP_BIT_MASK = BitArray(uint=0x3 << 0x11, length=rcs.XLEN)
|
||||
MAX_USED_VADDR_BITS = 30
|
||||
IMM25_WIDTH = 25
|
||||
IMM12_WIDTH = 12
|
||||
INSTR_WIDTH = 32
|
||||
DATA_WIDTH = 32
|
||||
MAX_INSTR_STR_LEN = 11
|
||||
LABEL_STR_LEN = 18
|
||||
MAX_CALLSTACK_DEPTH = 20
|
||||
MAX_SUB_PROGRAM_CNT = 20
|
||||
MAX_CALL_PER_FUNC = 5
|
||||
indent = LABEL_STR_LEN * " "
|
||||
|
||||
def hart_prefix(self, hart=0):
|
||||
if (rcs.NUM_HARTS <= 1):
|
||||
|
@ -1470,14 +1476,73 @@ class riscv_instr_pkg:
|
|||
if ((i % byte_per_group == 0) and (i != len(data) - 1) and (
|
||||
i != 0)):
|
||||
string = string + ", 0x"
|
||||
string = string + f"{hex(data[i])}"
|
||||
string = string + "{:02x}".format(data[i])
|
||||
return string
|
||||
|
||||
def push_gpr_to_kernel_stack(self, status, scratch, mprv, sp, tp, instr):
|
||||
pass
|
||||
store_instr = ''
|
||||
if(rcs.XLEN == 32):
|
||||
store_instr = "sw"
|
||||
else:
|
||||
store_instr = "sd"
|
||||
if (scratch.name in rcs.implemented_csr):
|
||||
# Use kernal stack for handling exceptions. Save the user mode stack
|
||||
# pointer to the scratch register
|
||||
instr.append(pkg_ins.format_string(
|
||||
"csrrw x{}, {}, x{}".format(sp, hex(scratch.value), sp)))
|
||||
# Move TP to SP
|
||||
instr.append(pkg_ins.format_string("add x{}, x{}, zero".format(sp, tp)))
|
||||
# If MPRV is set and MPP is S/U mode, it means the address translation and
|
||||
# memory protection for load/store instruction is the same as the mode indicated
|
||||
# by MPP. In this case, we need to use the virtual address to access the kernel stack.
|
||||
if((status.name == "MSTATUS") and (rcs.SATP_MODE != "BARE")):
|
||||
# We temporarily use tp to check mstatus to avoid changing other GPR. The value
|
||||
# of sp has been saved to xScratch and can be restored later.
|
||||
if(mprv):
|
||||
instr.append(pkg_ins.format_string(
|
||||
"csrr x{}, 0x{} // MSTATUS".format(tp, status.value)))
|
||||
instr.append(pkg_ins.format_string(
|
||||
"srli x{}, x{}, 11".format(tp, tp))) # Move MPP to bit 0
|
||||
instr.append(pkg_ins.format_string(
|
||||
"andi x{}, x{}, 0x3".format(tp, tp))) # keep the MPP bits
|
||||
# Check if MPP equals to M-mode('b11)
|
||||
instr.append(pkg_ins.format_string("xori x{}, x{}, 0x3".format(tp, tp)))
|
||||
# Use physical address for kernel SP
|
||||
instr.append(pkg_ins.format_string("bnez x{}, 1f".format(tp)))
|
||||
# Use virtual address for stack pointer
|
||||
instr.append(pkg_ins.format_string(
|
||||
"slli x{}, x{}, {}".format(sp, sp,
|
||||
rcs.XLEN - riscv_instr_pkg.MAX_USED_VADDR_BITS)))
|
||||
instr.append(pkg_ins.format_string(
|
||||
"srli x{}, x{}, {}".format(sp, sp,
|
||||
rcs.XLEN - riscv_instr_pkg.MAX_USED_VADDR_BITS)))
|
||||
# Reserve space from kernel stack to save all 32 GPR except for x0
|
||||
instr.append(pkg_ins.format_string(
|
||||
"1: addi x{}, x{}, -{}".format(sp, sp, int(31 * (rcs.XLEN / 8)))))
|
||||
# Push all GPRs to kernel stack
|
||||
for i in range(1, 32):
|
||||
instr.append(pkg_ins.format_string("{} x{}, {}(x{})".format(
|
||||
store_instr, i, int(i * (rcs.XLEN / 8)), sp)))
|
||||
|
||||
def pop_gpr_from_kernel_stack(self, status, scratch, mprv, sp, tp, instr):
|
||||
pass
|
||||
load_instr = ''
|
||||
if(rcs.XLEN == 32):
|
||||
load_instr = "lw"
|
||||
else:
|
||||
load_instr = "ld"
|
||||
# Pop user mode GPRs from kernel stack
|
||||
for i in range(1, 32):
|
||||
instr.append(pkg_ins.format_string("{} x{}, {}(x{})".format(
|
||||
load_instr, i, int(i * (rcs.XLEN / 8)), sp)))
|
||||
# Restore kernel stack pointer
|
||||
instr.append(pkg_ins.format_string(
|
||||
"addi x{}, x{}, {}".format(sp, sp, int(31 * (rcs.XLEN / 8)))))
|
||||
if (scratch in rcs.implemented_csr):
|
||||
# Move SP to TP
|
||||
instr.append(pkg_ins.format_string("add x{}, x{}, zero".format(tp, sp)))
|
||||
# Restore user mode stack pointer
|
||||
instr.append(pkg_ins.format_string(
|
||||
"csrrw x{}, 0x{}, x{}".format(sp, scratch.value, sp)))
|
||||
|
||||
|
||||
pkg_ins = riscv_instr_pkg()
|
||||
|
|
|
@ -11,12 +11,19 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
"""
|
||||
import re
|
||||
import logging
|
||||
import random
|
||||
import sys
|
||||
import vsc
|
||||
from importlib import import_module
|
||||
from collections import defaultdict
|
||||
from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
|
||||
from pygen_src.riscv_instr_gen_config import cfg
|
||||
from pygen_src.riscv_instr_pkg import pkg_ins, riscv_instr_category_t
|
||||
from pygen_src.riscv_instr_pkg import (pkg_ins, riscv_instr_name_t, riscv_reg_t,
|
||||
riscv_instr_category_t)
|
||||
from pygen_src.riscv_directed_instr_lib import riscv_pop_stack_instr, riscv_push_stack_instr
|
||||
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
|
||||
|
||||
|
||||
class riscv_instr_sequence:
|
||||
|
@ -33,6 +40,8 @@ class riscv_instr_sequence:
|
|||
self.illegal_instr_pct = 0 # Percentage of illegal instructions
|
||||
self.hint_instr_pct = 0 # Percentage of hint instructions
|
||||
self.branch_idx = [None] * 30
|
||||
self.instr_stack_enter = riscv_push_stack_instr()
|
||||
self.instr_stack_exit = riscv_pop_stack_instr()
|
||||
|
||||
def gen_instr(self, is_main_program, no_branch = 1):
|
||||
self.is_main_program = is_main_program
|
||||
|
@ -49,9 +58,12 @@ class riscv_instr_sequence:
|
|||
def gen_stack_enter_instr(self):
|
||||
pass
|
||||
|
||||
# TODO
|
||||
# Recover the saved GPR from the stack
|
||||
# Advance the stack pointer(SP) to release the allocated stack space.
|
||||
def gen_stack_exit_instr(self):
|
||||
pass
|
||||
self.instr_stack_exit.cfg = cfg
|
||||
self.instr_stack_exit.gen_pop_stack_instr(self.program_stack_len,
|
||||
self.instr_stack_enter.saved_regs)
|
||||
|
||||
'''
|
||||
----------------------------------------------------------------------------------------------
|
||||
|
@ -139,6 +151,7 @@ class riscv_instr_sequence:
|
|||
logging.info("Processing branch instruction[%0d]:%0s # %0d -> %0d", j,
|
||||
self.instr_stream.instr_list[j].convert2asm(),
|
||||
self.instr_stream.instr_list[j].idx, branch_target_label)
|
||||
logging.info("Branch", branch_target_label)
|
||||
self.instr_stream.instr_list[j].imm_str = "{}f".format(branch_target_label)
|
||||
self.instr_stream.instr_list[j].branch_assigned = 1
|
||||
branch_target[branch_target_label] = 1
|
||||
|
@ -177,11 +190,38 @@ class riscv_instr_sequence:
|
|||
prefix = pkg_ins.format_string(string = " ", length = pkg_ins.LABEL_STR_LEN)
|
||||
string = prefix + self.instr_stream.instr_list[i].convert2asm()
|
||||
self.instr_string_list.append(string)
|
||||
if(rcs.support_pmp and not re.search("main", self.label_name)):
|
||||
self.instr_string_list.insert(0, ".align 2")
|
||||
self.insert_illegal_hint_instr()
|
||||
prefix = pkg_ins.format_string(str(i), pkg_ins.LABEL_STR_LEN)
|
||||
if not self.is_main_program:
|
||||
self.generate_return_routine(prefix)
|
||||
|
||||
# TODO
|
||||
def generate_return_routine(self):
|
||||
pass
|
||||
def generate_return_routine(self, prefix):
|
||||
string = ''
|
||||
jump_instr = [riscv_instr_name_t.JALR]
|
||||
rand_lsb = random.randrange(0, 1)
|
||||
ra = vsc.enum_t(riscv_reg_t)
|
||||
# TODO
|
||||
# `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(ra,!(ra inside {cfg.reserved_regs}) ra != ZERO)
|
||||
string = (prefix + pkg_ins.format_string("{}addi x{} x{} {}".format(ra.name,
|
||||
cfg.ra.name, rand_lsb)))
|
||||
self.instr_string_list.append(string)
|
||||
if(not cfg.disable_compressed_instr):
|
||||
jump_instr.append(riscv_instr_name_t.C_JR)
|
||||
if(not (riscv_reg_t.RA in {cfg.reserved_regs})):
|
||||
jump_instr.append(riscv_instr_name_t.C_JALR)
|
||||
i = random.randrange(0, len(jump_instr) - 1)
|
||||
if (jump_instr[i] == riscv_instr_name_t.C_JAL):
|
||||
string = prefix + pkg_ins.format_string("{}c.jalr x{}".format(ra.name))
|
||||
elif(jump_instr[i] == riscv_instr_name_t.C_JR):
|
||||
string = prefix + pkg_ins.format_string("{}c.jr x{}".format(ra.name))
|
||||
elif(jump_instr[i] == riscv_instr_name_t.JALR):
|
||||
string = prefix + pkg_ins.format_string("{}c.jalr x{} x{} 0".format(ra.name, ra.name))
|
||||
else:
|
||||
logging.critical("Unsupported jump_instr: %0s" % (jump_instr[i]))
|
||||
sys.exit(1)
|
||||
self.instr_string_list.append(string)
|
||||
|
||||
# TODO
|
||||
def insert_illegal_hint_instr(self):
|
||||
|
|
|
@ -15,8 +15,8 @@ import logging
|
|||
import sys
|
||||
import vsc
|
||||
from pygen_src.riscv_instr_pkg import riscv_instr_name_t,\
|
||||
riscv_instr_category_t, riscv_reg_t
|
||||
from pygen_src.isa.riscv_instr import riscv_instr, riscv_instr_ins
|
||||
riscv_instr_category_t, riscv_instr_format_t, riscv_reg_t
|
||||
from pygen_src.isa.riscv_instr import riscv_instr
|
||||
from pygen_src.riscv_instr_gen_config import cfg
|
||||
|
||||
|
||||
|
@ -34,10 +34,10 @@ class riscv_instr_stream:
|
|||
self.instr_cnt = 0
|
||||
self.label = ""
|
||||
# User can specify a small group of available registers to generate various hazard condition
|
||||
self.avail_regs = vsc.randsz_list_t(vsc.enum_t(riscv_reg_t))
|
||||
self.avail_regs = vsc.rand_list_t(vsc.enum_t(riscv_reg_t), sz = 10)
|
||||
# Some additional reserved registers that should not be used as rd register
|
||||
# by this instruction stream
|
||||
self.reserved_rd = []
|
||||
self.reserved_rd = vsc.list_t(vsc.enum_t(riscv_reg_t))
|
||||
self.hart = 0
|
||||
|
||||
def initialize_instr_list(self, instr_cnt):
|
||||
|
@ -106,16 +106,16 @@ class riscv_instr_stream:
|
|||
new_instr[0].label = self.instr_list[idx].label
|
||||
new_instr[0].has_label = self.instr_list[idx].has_label
|
||||
if idx == 0:
|
||||
self.instr_list = new_instr + self.instr_list[idx + 1:current_instr_cnt - 1]
|
||||
else:
|
||||
self.instr_list = self.instr_list[0:idx - 1] + new_instr + \
|
||||
self.instr_list[idx + 1:current_instr_cnt - 1]
|
||||
else:
|
||||
if idx == 0:
|
||||
self.instr_list = new_instr + self.instr_list[idx:current_instr_cnt - 1]
|
||||
self.instr_list = new_instr + self.instr_list[idx + 1:current_instr_cnt]
|
||||
else:
|
||||
self.instr_list = self.instr_list[0:idx] + new_instr + \
|
||||
self.instr_list[idx:current_instr_cnt - 1]
|
||||
self.instr_list[idx + 1:current_instr_cnt]
|
||||
else:
|
||||
if idx == 0:
|
||||
self.instr_list = new_instr + self.instr_list[idx:current_instr_cnt]
|
||||
else:
|
||||
self.instr_list = self.instr_list[0:idx] + new_instr + \
|
||||
self.instr_list[idx:current_instr_cnt]
|
||||
|
||||
def mix_instr_stream(self, new_instr, contained = 0):
|
||||
"""
|
||||
|
@ -170,15 +170,15 @@ class riscv_rand_instr_stream(riscv_instr_stream):
|
|||
self.instr_list.append(None)
|
||||
|
||||
def setup_allowed_instr(self, no_branch = 0, no_load_store = 1):
|
||||
self.allowed_instr = riscv_instr_ins.basic_instr
|
||||
self.allowed_instr = riscv_instr.basic_instr
|
||||
if no_branch == 0:
|
||||
self.allowed_instr.extend(
|
||||
riscv_instr_ins.instr_category[riscv_instr_category_t.BRANCH.name])
|
||||
riscv_instr.instr_category[riscv_instr_category_t.BRANCH.name])
|
||||
if no_load_store == 0:
|
||||
self.allowed_instr.extend(
|
||||
riscv_instr_ins.instr_category[riscv_instr_category_t.LOAD.name])
|
||||
riscv_instr.instr_category[riscv_instr_category_t.LOAD.name])
|
||||
self.allowed_instr.extend(
|
||||
riscv_instr_ins.instr_category[riscv_instr_category_t.STORE.name])
|
||||
riscv_instr.instr_category[riscv_instr_category_t.STORE.name])
|
||||
self.setup_instruction_dist(no_branch, no_load_store)
|
||||
|
||||
# TODO
|
||||
|
@ -215,20 +215,39 @@ class riscv_rand_instr_stream(riscv_instr_stream):
|
|||
exclude_instr.append(riscv_instr_name_t.C_ADDI16SP.name)
|
||||
exclude_instr.append(riscv_instr_name_t.C_LWSP.name)
|
||||
exclude_instr.append(riscv_instr_name_t.C_LDSP.name)
|
||||
if is_in_debug and (not cfg.enable_ebreak_in_debug_rom):
|
||||
exclude_instr.append(riscv_instr_name_t.EBREAK.name)
|
||||
exclude_instr.append(riscv_instr_name_t.C_EBREAK.name)
|
||||
instr = riscv_instr_ins.get_rand_instr(
|
||||
# Post-process the allowed_instr and exclude_instr lists to handle
|
||||
# adding ebreak instructions into the debug ROM.
|
||||
if is_in_debug:
|
||||
if (cfg.no_ebreak and cfg.enable_ebreak_in_debug_rom):
|
||||
self.allowed_instr.extend([riscv_instr_name_t.EBREAK.name,
|
||||
riscv_instr_name_t.C_EBREAK.name])
|
||||
elif (not cfg.no_ebreak and not cfg.enable_ebreak_in_debug_rom):
|
||||
exclude_instr.extend([riscv_instr_name_t.EBREAK.name,
|
||||
riscv_instr_name_t.C_EBREAK.name])
|
||||
instr = riscv_instr.get_rand_instr(
|
||||
include_instr = self.allowed_instr, exclude_instr = exclude_instr)
|
||||
instr = self.randomize_gpr(instr)
|
||||
return instr
|
||||
|
||||
def randomize_gpr(self, instr):
|
||||
# TODO
|
||||
"""
|
||||
PyVSC library doesn't support inline randomization for list of enum types.
|
||||
The randomization is done directly here.
|
||||
it will be updated once randomization for list of enum types supports in PyVSC.
|
||||
"""
|
||||
instr.randomize()
|
||||
with instr.randomize_with() as it:
|
||||
if self.avail_regs.size > 0:
|
||||
if instr.has_rs1:
|
||||
instr.rs1.inside(vsc.rangelist(self.avail_regs))
|
||||
if instr.has_rs2:
|
||||
instr.rs2.inside(vsc.rangelist(self.avail_regs))
|
||||
if instr.has_rd:
|
||||
instr.rd.inside(vsc.rangelist(self.avail_regs))
|
||||
with vsc.foreach(self.reserved_rd, idx = True) as i:
|
||||
if instr.has_rd == 1:
|
||||
instr.rd != self.reserved_rd[i]
|
||||
if instr.format == riscv_instr_format_t.CB_FORMAT:
|
||||
instr.rs1 != self.reserved_rd[i]
|
||||
|
||||
with vsc.foreach(cfg.reserved_regs, idx = True) as i:
|
||||
with vsc.if_then(instr.has_rd == 1):
|
||||
instr.rd != cfg.reserved_regs[i]
|
||||
with vsc.if_then(instr.format == riscv_instr_format_t.CB_FORMAT):
|
||||
instr.rs1 != cfg.reserved_regs[i]
|
||||
# TODO: Add constraint for CSR, floating point register
|
||||
return instr
|
||||
|
|
|
@ -13,14 +13,22 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
"""
|
||||
import sys
|
||||
import logging
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
from pygen_src.isa import rv32i_instr
|
||||
from pygen_src.isa import rv32m_instr
|
||||
from pygen_src.isa import rv32c_instr
|
||||
from pygen_src.riscv_instr_gen_config import cfg
|
||||
from pygen_src.riscv_directed_instr_lib import (riscv_directed_instr_stream,
|
||||
riscv_int_numeric_corner_stream)
|
||||
riscv_int_numeric_corner_stream,
|
||||
riscv_jal_instr)
|
||||
|
||||
|
||||
def factory(obj_of):
|
||||
objs = {
|
||||
"riscv_directed_instr_stream": riscv_directed_instr_stream,
|
||||
"riscv_int_numeric_corner_stream": riscv_int_numeric_corner_stream
|
||||
"riscv_int_numeric_corner_stream": riscv_int_numeric_corner_stream,
|
||||
"riscv_jal_instr": riscv_jal_instr
|
||||
}
|
||||
|
||||
try:
|
||||
|
@ -28,3 +36,157 @@ def factory(obj_of):
|
|||
except KeyError:
|
||||
logging.critical("Cannot Create object of %s", obj_of)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_object(instr):
|
||||
try:
|
||||
instr_inst = eval("rv32i_instr.riscv_" + instr.name + "_instr()")
|
||||
except Exception:
|
||||
try:
|
||||
instr_inst = eval("rv32m_instr.riscv_" + instr.name + "_instr()")
|
||||
except Exception:
|
||||
try:
|
||||
instr_inst = eval("rv32c_instr.riscv_" + instr.name + "_instr()")
|
||||
except Exception:
|
||||
logging.critical("Failed to create instr: %0s", instr.name)
|
||||
sys.exit(1)
|
||||
return instr_inst
|
||||
|
||||
|
||||
def gen_config_table():
|
||||
data = []
|
||||
data.append(['main_program_instr_cnt', type(cfg.main_program_instr_cnt),
|
||||
sys.getsizeof(cfg.main_program_instr_cnt), cfg.main_program_instr_cnt])
|
||||
data.append(['sub_program_instr_cnt', type(cfg.sub_program_instr_cnt),
|
||||
sys.getsizeof(cfg.sub_program_instr_cnt), cfg.sub_program_instr_cnt])
|
||||
data.append(['debug_program_instr_cnt', type(cfg.debug_program_instr_cnt),
|
||||
sys.getsizeof(cfg.debug_program_instr_cnt), cfg.debug_program_instr_cnt])
|
||||
data.append(['debug_sub_program_instr_cnt', type(cfg.debug_sub_program_instr_cnt),
|
||||
sys.getsizeof(cfg.debug_sub_program_instr_cnt),
|
||||
cfg.debug_sub_program_instr_cnt])
|
||||
data.append(['max_directed_instr_stream_seq', type(cfg.max_directed_instr_stream_seq),
|
||||
sys.getsizeof(cfg.max_directed_instr_stream_seq),
|
||||
cfg.max_directed_instr_stream_seq])
|
||||
data.append(['data_page_pattern', type(cfg.data_page_pattern),
|
||||
sys.getsizeof(cfg.data_page_pattern), cfg.data_page_pattern])
|
||||
data.append(['init_privileged_mode', type(cfg.init_privileged_mode),
|
||||
sys.getsizeof(cfg.init_privileged_mode), cfg.init_privileged_mode])
|
||||
data.append(['scratch_reg', type(cfg.scratch_reg),
|
||||
sys.getsizeof(cfg.scratch_reg), cfg.scratch_reg])
|
||||
data.append(['pmp_reg', type(cfg.pmp_reg), sys.getsizeof(cfg.pmp_reg), cfg.pmp_reg])
|
||||
data.append(['reserved_regs', type(cfg.reserved_regs),
|
||||
sys.getsizeof(cfg.reserved_regs), cfg.reserved_regs])
|
||||
data.append(['sp', type(cfg.sp), sys.getsizeof(cfg.sp), cfg.sp])
|
||||
data.append(['tp', type(cfg.tp), sys.getsizeof(cfg.tp), cfg.tp])
|
||||
data.append(['ra', type(cfg.ra), sys.getsizeof(cfg.ra), cfg.ra])
|
||||
data.append(['check_misa_init_val', type(cfg.check_misa_init_val),
|
||||
sys.getsizeof(cfg.check_misa_init_val), cfg.check_misa_init_val])
|
||||
data.append(['check_xstatus', type(cfg.check_xstatus),
|
||||
sys.getsizeof(cfg.check_xstatus), cfg.check_xstatus])
|
||||
data.append(['virtual_addr_translation_on', type(cfg.virtual_addr_translation_on),
|
||||
sys.getsizeof(cfg.virtual_addr_translation_on),
|
||||
cfg.virtual_addr_translation_on])
|
||||
data.append(['kernel_stack_len', type(cfg.kernel_stack_len),
|
||||
sys.getsizeof(cfg.kernel_stack_len), cfg.kernel_stack_len])
|
||||
data.append(['kernel_program_instr_cnt', type(cfg.kernel_program_instr_cnt),
|
||||
sys.getsizeof(cfg.kernel_program_instr_cnt), cfg.kernel_program_instr_cnt])
|
||||
data.append(['num_of_sub_program', type(cfg.num_of_sub_program),
|
||||
sys.getsizeof(cfg.num_of_sub_program), cfg.num_of_sub_program])
|
||||
data.append(['instr_cnt', type(cfg.instr_cnt), sys.getsizeof(cfg.instr_cnt), cfg.instr_cnt])
|
||||
data.append(['num_of_tests', type(cfg.num_of_tests),
|
||||
sys.getsizeof(cfg.num_of_tests), cfg.num_of_tests])
|
||||
data.append(['no_data_page', type(cfg.no_data_page),
|
||||
sys.getsizeof(cfg.no_data_page), cfg.no_data_page])
|
||||
data.append(['no_branch_jump', type(cfg.no_branch_jump),
|
||||
sys.getsizeof(cfg.no_branch_jump), cfg.no_branch_jump])
|
||||
data.append(['no_load_store', type(cfg.no_load_store),
|
||||
sys.getsizeof(cfg.no_load_store), cfg.no_load_store])
|
||||
data.append(['no_csr_instr', type(cfg.no_csr_instr),
|
||||
sys.getsizeof(cfg.no_csr_instr), cfg.no_csr_instr])
|
||||
data.append(['no_ebreak', type(cfg.no_ebreak), sys.getsizeof(cfg.no_ebreak), cfg.no_ebreak])
|
||||
data.append(['no_dret', type(cfg.no_dret), sys.getsizeof(cfg.no_dret), cfg.no_dret])
|
||||
data.append(['no_fence', type(cfg.no_fence), sys.getsizeof(cfg.no_fence), cfg.no_fence])
|
||||
data.append(['no_wfi', type(cfg.no_wfi), sys.getsizeof(cfg.no_wfi), cfg.no_wfi])
|
||||
data.append(['enable_unaligned_load_store', type(cfg.enable_unaligned_load_store),
|
||||
sys.getsizeof(cfg.enable_unaligned_load_store),
|
||||
cfg.enable_unaligned_load_store])
|
||||
data.append(['illegal_instr_ratio', type(cfg.illegal_instr_ratio),
|
||||
sys.getsizeof(cfg.illegal_instr_ratio), cfg.illegal_instr_ratio])
|
||||
data.append(['hint_instr_ratio', type(cfg.hint_instr_ratio),
|
||||
sys.getsizeof(cfg.hint_instr_ratio), cfg.hint_instr_ratio])
|
||||
data.append(['num_of_harts', type(cfg.num_of_harts),
|
||||
sys.getsizeof(cfg.num_of_harts), cfg.num_of_harts])
|
||||
data.append(['fix_sp', type(cfg.fix_sp), sys.getsizeof(cfg.fix_sp), cfg.fix_sp])
|
||||
data.append(['use_push_data_section', type(cfg.use_push_data_section),
|
||||
sys.getsizeof(cfg.use_push_data_section), cfg.use_push_data_section])
|
||||
data.append(['boot_mode_opts', type(cfg.boot_mode_opts),
|
||||
sys.getsizeof(cfg.boot_mode_opts), cfg.boot_mode_opts])
|
||||
data.append(['enable_page_table_exception', type(cfg.enable_page_table_exception),
|
||||
sys.getsizeof(cfg.enable_page_table_exception),
|
||||
cfg.enable_page_table_exception])
|
||||
data.append(['no_directed_instr', type(cfg.no_directed_instr),
|
||||
sys.getsizeof(cfg.no_directed_instr), cfg.no_directed_instr])
|
||||
data.append(['asm_test_suffix', type(cfg.asm_test_suffix),
|
||||
sys.getsizeof(cfg.asm_test_suffix), cfg.asm_test_suffix])
|
||||
data.append(['enable_interrupt', type(cfg.enable_interrupt),
|
||||
sys.getsizeof(cfg.enable_interrupt), cfg.enable_interrupt])
|
||||
data.append(['enable_nested_interrupt', type(cfg.enable_nested_interrupt),
|
||||
sys.getsizeof(cfg.enable_nested_interrupt), cfg.enable_nested_interrupt])
|
||||
data.append(['enable_timer_irq', type(cfg.enable_timer_irq),
|
||||
sys.getsizeof(cfg.enable_timer_irq), cfg.enable_timer_irq])
|
||||
data.append(['bare_program_mode', type(cfg.bare_program_mode),
|
||||
sys.getsizeof(cfg.bare_program_mode), cfg.bare_program_mode])
|
||||
data.append(['enable_illegal_csr_instruction', type(cfg.enable_illegal_csr_instruction),
|
||||
sys.getsizeof(cfg.enable_illegal_csr_instruction),
|
||||
cfg.enable_illegal_csr_instruction])
|
||||
data.append(['enable_access_invalid_csr_level', type(cfg.enable_access_invalid_csr_level),
|
||||
sys.getsizeof(cfg.enable_access_invalid_csr_level),
|
||||
cfg.enable_access_invalid_csr_level])
|
||||
data.append(['enable_misaligned_instr', type(cfg.enable_misaligned_instr),
|
||||
sys.getsizeof(cfg.enable_misaligned_instr), cfg.enable_misaligned_instr])
|
||||
data.append(['enable_dummy_csr_write', type(cfg.enable_dummy_csr_write),
|
||||
sys.getsizeof(cfg.enable_dummy_csr_write), cfg.enable_dummy_csr_write])
|
||||
data.append(['randomize_csr', type(cfg.randomize_csr),
|
||||
sys.getsizeof(cfg.randomize_csr), cfg.randomize_csr])
|
||||
data.append(['allow_sfence_exception', type(cfg.allow_sfence_exception),
|
||||
sys.getsizeof(cfg.allow_sfence_exception), cfg.allow_sfence_exception])
|
||||
data.append(['no_delegation', type(cfg.no_delegation),
|
||||
sys.getsizeof(cfg.no_delegation), cfg.no_delegation])
|
||||
data.append(['force_m_delegation', type(cfg.force_m_delegation),
|
||||
sys.getsizeof(cfg.force_m_delegation), cfg.force_m_delegation])
|
||||
data.append(['force_s_delegation', type(cfg.force_s_delegation),
|
||||
sys.getsizeof(cfg.force_s_delegation), cfg.force_s_delegation])
|
||||
data.append(['support_supervisor_mode', type(cfg.support_supervisor_mode),
|
||||
sys.getsizeof(cfg.support_supervisor_mode), cfg.support_supervisor_mode])
|
||||
data.append(['disable_compressed_instr', type(cfg.disable_compressed_instr),
|
||||
sys.getsizeof(cfg.disable_compressed_instr), cfg.disable_compressed_instr])
|
||||
data.append(['require_signature_addr', type(cfg.require_signature_addr),
|
||||
sys.getsizeof(cfg.require_signature_addr), cfg.require_signature_addr])
|
||||
data.append(['signature_addr', type(cfg.signature_addr),
|
||||
sys.getsizeof(cfg.signature_addr), cfg.signature_addr])
|
||||
data.append(['gen_debug_section', type(cfg.gen_debug_section),
|
||||
sys.getsizeof(cfg.gen_debug_section), cfg.force_s_delegation])
|
||||
data.append(['enable_ebreak_in_debug_rom', type(cfg.enable_ebreak_in_debug_rom),
|
||||
sys.getsizeof(cfg.enable_ebreak_in_debug_rom), cfg.enable_ebreak_in_debug_rom])
|
||||
data.append(['set_dcsr_ebreak', type(cfg.set_dcsr_ebreak),
|
||||
sys.getsizeof(cfg.set_dcsr_ebreak), cfg.set_dcsr_ebreak])
|
||||
data.append(['num_debug_sub_program', type(cfg.num_debug_sub_program),
|
||||
sys.getsizeof(cfg.num_debug_sub_program), cfg.num_debug_sub_program])
|
||||
data.append(['enable_debug_single_step', type(cfg.enable_debug_single_step),
|
||||
sys.getsizeof(cfg.enable_debug_single_step), cfg.enable_debug_single_step])
|
||||
data.append(['single_step_iterations', type(cfg.single_step_iterations),
|
||||
sys.getsizeof(cfg.single_step_iterations), cfg.single_step_iterations])
|
||||
data.append(['set_mstatus_tw', type(cfg.set_mstatus_tw),
|
||||
sys.getsizeof(cfg.set_mstatus_tw), cfg.set_mstatus_tw])
|
||||
data.append(['set_mstatus_mprv', type(cfg.set_mstatus_mprv),
|
||||
sys.getsizeof(cfg.set_mstatus_mprv), cfg.set_mstatus_mprv])
|
||||
data.append(['enable_floating_point', type(cfg.enable_floating_point),
|
||||
sys.getsizeof(cfg.enable_floating_point), cfg.enable_floating_point])
|
||||
data.append(['enable_vector_extension', type(cfg.enable_vector_extension),
|
||||
sys.getsizeof(cfg.enable_vector_extension), cfg.enable_vector_extension])
|
||||
data.append(['enable_b_extension', type(cfg.enable_b_extension),
|
||||
sys.getsizeof(cfg.enable_b_extension), cfg.enable_b_extension])
|
||||
|
||||
df = pd.DataFrame(data, columns=['Name', 'Type', 'Size', 'Value'])
|
||||
df['Value'] = df['Value'].apply(str)
|
||||
logging.info('\n' + tabulate(df, headers='keys', tablefmt='psql'))
|
||||
|
|
21
vendor/google_riscv-dv/pygen/pygen_src/target/rv32i/riscvOVPsim.ic
vendored
Normal file
21
vendor/google_riscv-dv/pygen/pygen_src/target/rv32i/riscvOVPsim.ic
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
# riscOVPsim configuration file converted from YAML
|
||||
--variant RV32I
|
||||
--override riscvOVPsim/cpu/misa_MXL=1
|
||||
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/unaligned=T
|
||||
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/user_version=2.3
|
||||
--override riscvOVPsim/cpu/priv_version=1.11
|
||||
--override riscvOVPsim/cpu/mvendorid=0
|
||||
--override riscvOVPsim/cpu/marchid=0
|
||||
--override riscvOVPsim/cpu/mimpid=0
|
||||
--override riscvOVPsim/cpu/mhartid=0
|
||||
--override riscvOVPsim/cpu/cycle_undefined=F
|
||||
--override riscvOVPsim/cpu/instret_undefined=F
|
||||
--override riscvOVPsim/cpu/time_undefined=T
|
||||
--override riscvOVPsim/cpu/reset_address=0x80000000
|
||||
--override riscvOVPsim/cpu/simulateexceptions=T
|
||||
--override riscvOVPsim/cpu/defaultsemihost=F
|
||||
--override riscvOVPsim/cpu/wfi_is_nop=T
|
||||
--exitonsymbol _exit
|
|
@ -29,3 +29,8 @@ support_pmp = 0
|
|||
unsupported_instr = []
|
||||
|
||||
support_umode_trap = 0
|
||||
|
||||
# GPR Setting
|
||||
NUM_FLOAT_GPR = 32
|
||||
NUM_GPR = 32
|
||||
NUM_VEC_GPR = 32
|
||||
|
|
22
vendor/google_riscv-dv/pygen/pygen_src/target/rv32imc/riscvOVPsim.ic
vendored
Normal file
22
vendor/google_riscv-dv/pygen/pygen_src/target/rv32imc/riscvOVPsim.ic
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
# riscOVPsim configuration file converted from YAML
|
||||
--variant RV32I
|
||||
--override riscvOVPsim/cpu/add_Extensions=MC
|
||||
--override riscvOVPsim/cpu/misa_MXL=1
|
||||
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/unaligned=T
|
||||
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/user_version=2.3
|
||||
--override riscvOVPsim/cpu/priv_version=1.11
|
||||
--override riscvOVPsim/cpu/mvendorid=0
|
||||
--override riscvOVPsim/cpu/marchid=0
|
||||
--override riscvOVPsim/cpu/mimpid=0
|
||||
--override riscvOVPsim/cpu/mhartid=0
|
||||
--override riscvOVPsim/cpu/cycle_undefined=F
|
||||
--override riscvOVPsim/cpu/instret_undefined=F
|
||||
--override riscvOVPsim/cpu/time_undefined=T
|
||||
--override riscvOVPsim/cpu/reset_address=0x80000000
|
||||
--override riscvOVPsim/cpu/simulateexceptions=T
|
||||
--override riscvOVPsim/cpu/defaultsemihost=F
|
||||
--override riscvOVPsim/cpu/wfi_is_nop=T
|
||||
--exitonsymbol _exit
|
62
vendor/google_riscv-dv/pygen/pygen_src/target/rv32imc/riscv_core_setting.py
vendored
Normal file
62
vendor/google_riscv-dv/pygen/pygen_src/target/rv32imc/riscv_core_setting.py
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
"""
|
||||
Copyright 2020 Google LLC
|
||||
Copyright 2020 PerfectVIPs Inc.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
XLEN = 32
|
||||
|
||||
implemented_csr = ['MVENDORID', 'MARCHID', 'MIMPID', 'MHARTID', 'MSTATUS', 'MISA', 'MIE',
|
||||
'MTVEC', 'MCOUNTEREN', 'MSCRATCH', 'MEPC', 'MCAUSE', 'MTVAL', 'MIP']
|
||||
|
||||
SATP_MODE = 'BARE'
|
||||
|
||||
supported_isa = ['RV32I', 'RV32M', 'RV32C']
|
||||
|
||||
supported_privileged_mode = ['MACHINE_MODE']
|
||||
|
||||
supported_interrupt_mode = ['DIRECT', 'VECTORED']
|
||||
|
||||
max_interrupt_vector_num = 16
|
||||
|
||||
support_debug_mode = 0
|
||||
|
||||
NUM_HARTS = 1
|
||||
|
||||
support_pmp = 0
|
||||
|
||||
unsupported_instr = []
|
||||
|
||||
support_umode_trap = 0
|
||||
|
||||
support_sfence = 0
|
||||
|
||||
support_unaligned_load_store = 1
|
||||
|
||||
# GPR Setting
|
||||
NUM_FLOAT_GPR = 32
|
||||
NUM_GPR = 32
|
||||
NUM_VEC_GPR = 32
|
||||
|
||||
VECTOR_EXTENSION_ENABLE = 0
|
||||
|
||||
VLEN = 512
|
||||
|
||||
ELEN = 32
|
||||
|
||||
SELEN = 0
|
||||
|
||||
MAX_MUL = 8
|
||||
|
||||
implemented_interrupt = ['M_SOFTWARE_INTR', 'M_TIMER_INTR', 'M_EXTERNAL_INTR']
|
||||
|
||||
implemented_exception = ['INSTRUCTION_ACCESS_FAULT', 'ILLEGAL_INSTRUCTION',
|
||||
'BREAKPOINT', 'LOAD_ADDRESS_MISALIGNED', 'LOAD_ACCESS_FAULT',
|
||||
'ECALL_MMODE']
|
|
@ -12,22 +12,40 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
"""
|
||||
|
||||
import sys
|
||||
sys.path.append("../../")
|
||||
sys.path.append("pygen/")
|
||||
from pygen_src.riscv_instr_pkg import *
|
||||
from pygen_src.riscv_instr_gen_config import cfg # NOQA
|
||||
from pygen_src.isa.rv32i_instr import * # NOQA
|
||||
from pygen_src.isa.riscv_instr import riscv_instr_ins # NOQA
|
||||
if cfg.argv.target == "rv32i":
|
||||
from pygen_src.isa.rv32i_instr import * # NOQA
|
||||
if cfg.argv.target == "rv32imc":
|
||||
from pygen_src.isa.rv32i_instr import * # NOQA
|
||||
from pygen_src.isa.rv32m_instr import * # NOQA
|
||||
from pygen_src.isa.rv32c_instr import * # NOQA
|
||||
from pygen_src.isa.riscv_instr import riscv_instr # NOQA
|
||||
from pygen_src.riscv_asm_program_gen import riscv_asm_program_gen # NOQA
|
||||
from pygen_src.riscv_utils import gen_config_table
|
||||
|
||||
|
||||
class riscv_instr_base_test:
|
||||
def __init__(self):
|
||||
pass
|
||||
self.start_idx = cfg.argv.start_idx
|
||||
self.asm_file_name = cfg.argv.asm_file_name
|
||||
|
||||
for _ in range(cfg.num_of_tests):
|
||||
cfg.randomize()
|
||||
asm = riscv_asm_program_gen()
|
||||
riscv_instr_ins.create_instr_list(cfg)
|
||||
test_name = "riscv_arithmetic_basic_test_{}.S".format(_)
|
||||
asm.get_directed_instr_stream()
|
||||
asm.gen_program()
|
||||
asm.gen_test_file(test_name)
|
||||
def run_phase(self):
|
||||
for _ in range(cfg.num_of_tests):
|
||||
cfg.randomize()
|
||||
gen_config_table()
|
||||
asm = riscv_asm_program_gen()
|
||||
riscv_instr.create_instr_list(cfg)
|
||||
if cfg.asm_test_suffix != "":
|
||||
self.asm_file_name = "{}.{}".format(self.asm_file_name,
|
||||
cfg.asm_test_suffix)
|
||||
test_name = "{}_{}.S".format(self.asm_file_name,
|
||||
_ + self.start_idx)
|
||||
asm.get_directed_instr_stream()
|
||||
asm.gen_program()
|
||||
asm.gen_test_file(test_name)
|
||||
|
||||
|
||||
riscv_instr_base_test = riscv_instr_base_test()
|
||||
riscv_instr_base_test.run_phase()
|
||||
|
|
|
@ -17,32 +17,33 @@ import sys
|
|||
import vsc
|
||||
import csv
|
||||
from tabulate import *
|
||||
from pygen.pygen_src.isa.riscv_cov_instr import riscv_cov_instr
|
||||
from pygen.pygen_src.riscv_instr_cover_group import *
|
||||
from pygen.pygen_src.riscv_instr_pkg import *
|
||||
|
||||
logging.basicConfig(filename='logging_two_files_new.log', filemode='w',
|
||||
format="%(filename)s %(lineno)s %(levelname)s %(message)s",
|
||||
level=logging.ERROR)
|
||||
sys.path.append("pygen/")
|
||||
from pygen_src.riscv_instr_pkg import *
|
||||
from pygen_src.isa.riscv_cov_instr import riscv_cov_instr
|
||||
from pygen_src.riscv_instr_cover_group import *
|
||||
|
||||
|
||||
class riscv_instr_cov_test:
|
||||
""" Main class for applying the functional coverage test """
|
||||
|
||||
def __init__(self, argv):
|
||||
def __init__(self):
|
||||
self.instr_cg = riscv_instr_cover_group()
|
||||
self.trace = {}
|
||||
self.csv_trace = argv
|
||||
self.csv_trace = []
|
||||
self.entry_cnt, self.total_entry_cnt, self.skipped_cnt, \
|
||||
self.unexpected_illegal_instr_cnt = 0, 0, 0, 0
|
||||
logging.basicConfig(filename='{}'.format(cfg.argv.log_file_name),
|
||||
filemode='w',
|
||||
format="%(filename)s %(lineno)s %(levelname)s %(message)s",
|
||||
level=logging.DEBUG)
|
||||
|
||||
def run_phase(self):
|
||||
self.csv_trace = cfg.argv.trace_csv.split(",")
|
||||
if not self.csv_trace:
|
||||
sys.exit("No CSV file found!")
|
||||
logging.info("{} CSV trace files to be "
|
||||
"processed...\n".format(len(self.csv_trace)))
|
||||
expect_illegal_instr = False
|
||||
# Assuming we get list of csv files pathname from cov.py in argv
|
||||
for csv_file in self.csv_trace:
|
||||
with open("{}".format(csv_file)) as trace_file:
|
||||
self.entry_cnt = 0
|
||||
|
@ -102,10 +103,10 @@ class riscv_instr_cov_test:
|
|||
self.unexpected_illegal_instr_cnt))
|
||||
self.get_coverage_report()
|
||||
|
||||
@staticmethod
|
||||
def get_coverage_report():
|
||||
def get_coverage_report(self):
|
||||
model = vsc.get_coverage_report_model()
|
||||
file = open('CoverageReport.txt', 'w')
|
||||
cov_dir = cfg.argv.log_file_name.split("/")[0]
|
||||
file = open('{}/CoverageReport.txt'.format(cov_dir), 'w')
|
||||
file.write("Groups Coverage Summary\n")
|
||||
file.write("Total groups in report: {}\n".format(
|
||||
len(model.covergroups)))
|
||||
|
@ -116,8 +117,9 @@ class riscv_instr_cov_test:
|
|||
file.write(tabulate(table, headers, tablefmt="grid",
|
||||
numalign="center", stralign="center"))
|
||||
file.close()
|
||||
# Write in xml format to be read by pyucis-viewer (visualization)
|
||||
vsc.write_coverage_db("cov_db.xml")
|
||||
# If enabled, write in xml format to be read by pyucis-viewer (visualization)
|
||||
if cfg.argv.enable_visualization:
|
||||
vsc.write_coverage_db("{}/cov_db.xml".format(cov_dir))
|
||||
|
||||
def post_process_trace(self):
|
||||
pass
|
||||
|
@ -200,10 +202,7 @@ class riscv_instr_cov_test:
|
|||
return instruction
|
||||
|
||||
|
||||
def main(argv):
|
||||
cov_test = riscv_instr_cov_test(argv)
|
||||
cov_test.run_phase()
|
||||
|
||||
cov_test = riscv_instr_cov_test()
|
||||
cov_test.run_phase()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
||||
|
|
1
vendor/google_riscv-dv/requirements.txt
vendored
1
vendor/google_riscv-dv/requirements.txt
vendored
|
@ -9,3 +9,4 @@ rst2pdf
|
|||
flake8
|
||||
pyvsc
|
||||
tabulate
|
||||
pandas
|
||||
|
|
1817
vendor/google_riscv-dv/run.py
vendored
1817
vendor/google_riscv-dv/run.py
vendored
File diff suppressed because it is too large
Load diff
545
vendor/google_riscv-dv/scripts/gen_csr_test.py
vendored
545
vendor/google_riscv-dv/scripts/gen_csr_test.py
vendored
|
@ -21,7 +21,6 @@ in the CSR at this point, allowing for the test to self-check in order to
|
|||
determine success or failure.
|
||||
"""
|
||||
|
||||
|
||||
"""
|
||||
To install the bitstring library:
|
||||
1) sudo apt-get install python3-bitstring OR
|
||||
|
@ -35,325 +34,361 @@ import copy
|
|||
from lib import *
|
||||
|
||||
try:
|
||||
from bitstring import BitArray as bitarray
|
||||
from bitstring import BitArray as bitarray
|
||||
except ImportError as e:
|
||||
logging.error("Please install bitstring package: sudo apt-get install python3-bitstring")
|
||||
sys.exit(RET_FAIL)
|
||||
logging.error(
|
||||
"Please install bitstring package: sudo apt-get install python3-bitstring")
|
||||
sys.exit(RET_FAIL)
|
||||
|
||||
"""
|
||||
Defines the test's success/failure values, one of which will be written to
|
||||
the chosen signature address to indicate the test's result.
|
||||
"""
|
||||
TEST_RESULT = 1
|
||||
TEST_PASS = 0
|
||||
TEST_FAIL = 1
|
||||
TEST_PASS = 0
|
||||
TEST_FAIL = 1
|
||||
|
||||
|
||||
def get_csr_map(csr_file, xlen):
|
||||
"""
|
||||
Parses the YAML file containing CSR descriptions.
|
||||
"""
|
||||
Parses the YAML file containing CSR descriptions.
|
||||
|
||||
Args:
|
||||
csr_file: The CSR YAML file.
|
||||
xlen: The current RISC-V ISA bit length.
|
||||
Args:
|
||||
csr_file: The CSR YAML file.
|
||||
xlen: The current RISC-V ISA bit length.
|
||||
|
||||
Returns:
|
||||
A dictionary contining mappings for each CSR, of the form:
|
||||
{ csr_name : [csr_address, csr_val_bitarray, csr_write_mask_bitarray, csr_read_mask_bitarray] }
|
||||
"""
|
||||
rv_string = "rv{}".format(str(xlen))
|
||||
csrs = {}
|
||||
with open(csr_file, "r") as c:
|
||||
csr_description = yaml.safe_load(c)
|
||||
for csr_dict in csr_description:
|
||||
csr_name = csr_dict.get("csr")
|
||||
csr_address = csr_dict.get("address")
|
||||
assert(rv_string in csr_dict), "The {} CSR must be configured for rv{}".format(csr_name, str(rv))
|
||||
csr_value = bitarray(uintbe=0, length=xlen)
|
||||
csr_write_mask = []
|
||||
csr_read_mask = bitarray(uintbe=0, length=xlen)
|
||||
csr_field_list = csr_dict.get(rv_string)
|
||||
for csr_field_detail_dict in csr_field_list:
|
||||
field_type = csr_field_detail_dict.get("type")
|
||||
field_val = csr_field_detail_dict.get("reset_val")
|
||||
field_msb = csr_field_detail_dict.get("msb")
|
||||
field_lsb = csr_field_detail_dict.get("lsb")
|
||||
field_size = field_msb - field_lsb + 1
|
||||
if field_type != "WPRI":
|
||||
val_bitarray = bitarray(uint=field_val, length=field_size)
|
||||
mask_bitarray = bitarray(uint=1, length=1) * field_size
|
||||
start_pos = xlen - 1 - field_msb
|
||||
end_pos = xlen - 1 - field_lsb
|
||||
csr_read_mask.overwrite(mask_bitarray, xlen - 1 - field_msb)
|
||||
csr_value.overwrite(val_bitarray, xlen - 1 - field_msb)
|
||||
access = True if field_type == "R" else False
|
||||
csr_write_mask.append([mask_bitarray, (start_pos, end_pos), access])
|
||||
csrs.update({csr_name : [csr_address, csr_value, csr_write_mask, csr_read_mask]})
|
||||
return csrs
|
||||
Returns:
|
||||
A dictionary contining mappings for each CSR, of the form:
|
||||
{ csr_name : [csr_address, csr_val_bitarray, csr_write_mask_bitarray, csr_read_mask_bitarray] }
|
||||
"""
|
||||
rv_string = "rv{}".format(str(xlen))
|
||||
csrs = {}
|
||||
with open(csr_file, "r") as c:
|
||||
csr_description = yaml.safe_load(c)
|
||||
for csr_dict in csr_description:
|
||||
csr_name = csr_dict.get("csr")
|
||||
csr_address = csr_dict.get("address")
|
||||
assert (rv_string in csr_dict), "The {} CSR must be configured for rv{}".format(
|
||||
csr_name, str(rv))
|
||||
csr_value = bitarray(uintbe=0, length=xlen)
|
||||
csr_write_mask = []
|
||||
csr_read_mask = bitarray(uintbe=0, length=xlen)
|
||||
csr_field_list = csr_dict.get(rv_string)
|
||||
for csr_field_detail_dict in csr_field_list:
|
||||
field_type = csr_field_detail_dict.get("type")
|
||||
field_val = csr_field_detail_dict.get("reset_val")
|
||||
field_msb = csr_field_detail_dict.get("msb")
|
||||
field_lsb = csr_field_detail_dict.get("lsb")
|
||||
field_size = field_msb - field_lsb + 1
|
||||
if field_type != "WPRI":
|
||||
val_bitarray = bitarray(uint=field_val, length=field_size)
|
||||
mask_bitarray = bitarray(uint=1, length=1) * field_size
|
||||
start_pos = xlen - 1 - field_msb
|
||||
end_pos = xlen - 1 - field_lsb
|
||||
csr_read_mask.overwrite(mask_bitarray, xlen - 1 - field_msb)
|
||||
csr_value.overwrite(val_bitarray, xlen - 1 - field_msb)
|
||||
access = True if field_type == "R" else False
|
||||
csr_write_mask.append(
|
||||
[mask_bitarray, (start_pos, end_pos), access])
|
||||
csrs.update({csr_name: [csr_address, csr_value, csr_write_mask,
|
||||
csr_read_mask]})
|
||||
return csrs
|
||||
|
||||
|
||||
def get_rs1_val(iteration, xlen):
|
||||
"""
|
||||
Calculates and returns the 3 test RS1 values that will be used
|
||||
to exercise the CSR.
|
||||
"""
|
||||
Calculates and returns the 3 test RS1 values that will be used
|
||||
to exercise the CSR.
|
||||
|
||||
Args:
|
||||
iteration: Integer between 0 and 2 inclusive, indicates which
|
||||
test value to return.
|
||||
xlen: The currnet RISC-V ISA bit length.
|
||||
Args:
|
||||
iteration: Integer between 0 and 2 inclusive, indicates which
|
||||
test value to return.
|
||||
xlen: The currnet RISC-V ISA bit length.
|
||||
|
||||
Returns:
|
||||
A bitarray encoding the value that will be written to the CSR to test it.
|
||||
Will be one of 3 values:
|
||||
1) 0xa5a5...
|
||||
2) 0x5a5a...
|
||||
3) A randomly generated number
|
||||
"""
|
||||
if iteration == 0:
|
||||
return bitarray(hex="0x{}".format('a5'*int(xlen/8)))
|
||||
elif iteration == 1:
|
||||
return bitarray(hex="0x{}".format('5a'*int(xlen/8)))
|
||||
elif iteration == 2:
|
||||
val = bitarray(uint=0, length=xlen)
|
||||
# Must randomize all 32 bits, due to randomization library limitations
|
||||
for i in range(32):
|
||||
bit = random.randint(0, 1)
|
||||
val.set(bit, i)
|
||||
return val
|
||||
Returns:
|
||||
A bitarray encoding the value that will be written to the CSR to test it.
|
||||
Will be one of 3 values:
|
||||
1) 0xa5a5...
|
||||
2) 0x5a5a...
|
||||
3) A randomly generated number
|
||||
"""
|
||||
if iteration == 0:
|
||||
return bitarray(hex="0x{}".format('a5' * int(xlen / 8)))
|
||||
elif iteration == 1:
|
||||
return bitarray(hex="0x{}".format('5a' * int(xlen / 8)))
|
||||
elif iteration == 2:
|
||||
val = bitarray(uint=0, length=xlen)
|
||||
# Must randomize all 32 bits, due to randomization library limitations
|
||||
for i in range(32):
|
||||
bit = random.randint(0, 1)
|
||||
val.set(bit, i)
|
||||
return val
|
||||
|
||||
|
||||
def csr_write(val, csr_val, csr_write_mask):
|
||||
"""
|
||||
Performs a CSR write.
|
||||
"""
|
||||
Performs a CSR write.
|
||||
|
||||
Args:
|
||||
val: A bitarray containing the value to be written.
|
||||
csr_val: A bitarray containing the current CSR value.
|
||||
csr_write_mask: A bitarray containing the CSR's mask.
|
||||
"""
|
||||
for bitslice in csr_write_mask:
|
||||
read_only = bitslice[2]
|
||||
start_index = bitslice[1][0]
|
||||
end_index = bitslice[1][1]
|
||||
length = end_index - start_index + 1
|
||||
mask_val = bitslice[0]
|
||||
# only write if not read only
|
||||
if not read_only:
|
||||
val_slice = val[start_index:end_index+1]
|
||||
csr_val.overwrite(mask_val & val_slice, start_index)
|
||||
Args:
|
||||
val: A bitarray containing the value to be written.
|
||||
csr_val: A bitarray containing the current CSR value.
|
||||
csr_write_mask: A bitarray containing the CSR's mask.
|
||||
"""
|
||||
for bitslice in csr_write_mask:
|
||||
read_only = bitslice[2]
|
||||
start_index = bitslice[1][0]
|
||||
end_index = bitslice[1][1]
|
||||
length = end_index - start_index + 1
|
||||
mask_val = bitslice[0]
|
||||
# only write if not read only
|
||||
if not read_only:
|
||||
val_slice = val[start_index:end_index + 1]
|
||||
csr_val.overwrite(mask_val & val_slice, start_index)
|
||||
|
||||
|
||||
"""
|
||||
CSR Read:
|
||||
Reads the given CSR, after applying the bitmask
|
||||
"""
|
||||
|
||||
|
||||
def csr_read(csr_val, csr_read_mask):
|
||||
"""
|
||||
Performs a CSR read.
|
||||
"""
|
||||
Performs a CSR read.
|
||||
|
||||
Args:
|
||||
csr_val: A bitarray containing the current CSR value.
|
||||
csr_read_mask: A bitarray containing the CSR's read mask.
|
||||
Args:
|
||||
csr_val: A bitarray containing the current CSR value.
|
||||
csr_read_mask: A bitarray containing the CSR's read mask.
|
||||
|
||||
Returns:
|
||||
A bitarray of the logical AND of csr_val and csr_read_mask.
|
||||
"""
|
||||
return csr_val & csr_read_mask
|
||||
Returns:
|
||||
A bitarray of the logical AND of csr_val and csr_read_mask.
|
||||
"""
|
||||
return csr_val & csr_read_mask
|
||||
|
||||
|
||||
def predict_csr_val(csr_op, rs1_val, csr_val, csr_write_mask, csr_read_mask):
|
||||
"""
|
||||
Predicts the CSR reference value, based on the current CSR operation.
|
||||
"""
|
||||
Predicts the CSR reference value, based on the current CSR operation.
|
||||
|
||||
Args:
|
||||
csr_op: A string of the CSR operation being performed.
|
||||
rs1_val: A bitarray containing the value to be written to the CSR.
|
||||
csr_val: A bitarray containing the current value of the CSR.
|
||||
csr_write_mask: A bitarray containing the CSR's write mask.
|
||||
csr_read_mask: A bitarray containing the CSR's read mask
|
||||
Args:
|
||||
csr_op: A string of the CSR operation being performed.
|
||||
rs1_val: A bitarray containing the value to be written to the CSR.
|
||||
csr_val: A bitarray containing the current value of the CSR.
|
||||
csr_write_mask: A bitarray containing the CSR's write mask.
|
||||
csr_read_mask: A bitarray containing the CSR's read mask
|
||||
|
||||
Returns:
|
||||
A hexadecimal string of the predicted CSR value.
|
||||
"""
|
||||
prediction = None
|
||||
# create a zero bitarray to zero extend immediates
|
||||
zero = bitarray(uint=0, length=csr_val.len - 5)
|
||||
prediction = csr_read(csr_val, csr_read_mask)
|
||||
if csr_op == 'csrrw':
|
||||
csr_write(rs1_val, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrs':
|
||||
csr_write(rs1_val | prediction, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrc':
|
||||
csr_write((~rs1_val) & prediction, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrwi':
|
||||
zero.append(rs1_val[-5:])
|
||||
csr_write(zero, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrsi':
|
||||
zero.append(rs1_val[-5:])
|
||||
csr_write(zero | prediction, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrci':
|
||||
zero.append(rs1_val[-5:])
|
||||
csr_write((~zero) & prediction, csr_val, csr_write_mask)
|
||||
return "0x{}".format(prediction.hex)
|
||||
Returns:
|
||||
A hexadecimal string of the predicted CSR value.
|
||||
"""
|
||||
prediction = None
|
||||
# create a zero bitarray to zero extend immediates
|
||||
zero = bitarray(uint=0, length=csr_val.len - 5)
|
||||
prediction = csr_read(csr_val, csr_read_mask)
|
||||
if csr_op == 'csrrw':
|
||||
csr_write(rs1_val, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrs':
|
||||
csr_write(rs1_val | prediction, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrc':
|
||||
csr_write((~rs1_val) & prediction, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrwi':
|
||||
zero.append(rs1_val[-5:])
|
||||
csr_write(zero, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrsi':
|
||||
zero.append(rs1_val[-5:])
|
||||
csr_write(zero | prediction, csr_val, csr_write_mask)
|
||||
elif csr_op == 'csrrci':
|
||||
zero.append(rs1_val[-5:])
|
||||
csr_write((~zero) & prediction, csr_val, csr_write_mask)
|
||||
return "0x{}".format(prediction.hex)
|
||||
|
||||
|
||||
def gen_setup(test_file):
|
||||
"""
|
||||
Generates the setup code for the CSR test.
|
||||
"""
|
||||
Generates the setup code for the CSR test.
|
||||
|
||||
Args:
|
||||
test_file: the file containing the generated assembly code.
|
||||
"""
|
||||
test_file.write(".macro init\n")
|
||||
test_file.write(".endm\n")
|
||||
test_file.write(".section .text.init\n")
|
||||
test_file.write(".globl _start\n")
|
||||
test_file.write(".option norvc\n")
|
||||
test_file.write("_start:\n")
|
||||
Args:
|
||||
test_file: the file containing the generated assembly code.
|
||||
"""
|
||||
test_file.write(".macro init\n")
|
||||
test_file.write(".endm\n")
|
||||
test_file.write(".section .text.init\n")
|
||||
test_file.write(".globl _start\n")
|
||||
test_file.write(".option norvc\n")
|
||||
test_file.write("_start:\n")
|
||||
|
||||
|
||||
def gen_csr_test_fail(test_file, end_addr):
|
||||
"""
|
||||
Generates code to handle a test failure.
|
||||
This code consists of writing 1 to the GP register in an infinite loop.
|
||||
The testbench will poll this register at the end of the test to detect failure.
|
||||
"""
|
||||
Generates code to handle a test failure.
|
||||
This code consists of writing 1 to the GP register in an infinite loop.
|
||||
The testbench will poll this register at the end of the test to detect failure.
|
||||
|
||||
Args:
|
||||
test_file: the file containing the generated assembly test code.
|
||||
end_addr: address that should be written to at end of test
|
||||
"""
|
||||
test_file.write("csr_fail:\n")
|
||||
test_file.write("\tli x1, {}\n".format(TEST_FAIL))
|
||||
test_file.write("\tslli x1, x1, 8\n")
|
||||
test_file.write("\taddi x1, x1, {}\n".format(TEST_RESULT))
|
||||
test_file.write("\tli x2, 0x{}\n".format(end_addr))
|
||||
test_file.write("\tsw x1, 0(x2)\n")
|
||||
test_file.write("\tj csr_fail\n")
|
||||
Args:
|
||||
test_file: the file containing the generated assembly test code.
|
||||
end_addr: address that should be written to at end of test
|
||||
"""
|
||||
test_file.write("csr_fail:\n")
|
||||
test_file.write("\tli x1, {}\n".format(TEST_FAIL))
|
||||
test_file.write("\tslli x1, x1, 8\n")
|
||||
test_file.write("\taddi x1, x1, {}\n".format(TEST_RESULT))
|
||||
test_file.write("\tli x2, 0x{}\n".format(end_addr))
|
||||
test_file.write("\tsw x1, 0(x2)\n")
|
||||
test_file.write("\tj csr_fail\n")
|
||||
|
||||
|
||||
def gen_csr_test_pass(test_file, end_addr):
|
||||
"""
|
||||
Generates code to handle test success.
|
||||
This code consists of writing 2 to the GP register in an infinite loop.
|
||||
The testbench will poll this register at the end of the test to detect success.
|
||||
"""
|
||||
Generates code to handle test success.
|
||||
This code consists of writing 2 to the GP register in an infinite loop.
|
||||
The testbench will poll this register at the end of the test to detect success.
|
||||
|
||||
Args:
|
||||
test_file: the file containing the generated assembly test code.
|
||||
end_addr: address that should be written to at end of test
|
||||
"""
|
||||
test_file.write("csr_pass:\n")
|
||||
test_file.write("\tli x1, {}\n".format(TEST_PASS))
|
||||
test_file.write("\tslli x1, x1, 8\n")
|
||||
test_file.write("\taddi x1, x1, {}\n".format(TEST_RESULT))
|
||||
test_file.write("\tli x2, 0x{}\n".format(end_addr))
|
||||
test_file.write("\tsw x1, 0(x2)\n")
|
||||
test_file.write("\tj csr_pass\n")
|
||||
Args:
|
||||
test_file: the file containing the generated assembly test code.
|
||||
end_addr: address that should be written to at end of test
|
||||
"""
|
||||
test_file.write("csr_pass:\n")
|
||||
test_file.write("\tli x1, {}\n".format(TEST_PASS))
|
||||
test_file.write("\tslli x1, x1, 8\n")
|
||||
test_file.write("\taddi x1, x1, {}\n".format(TEST_RESULT))
|
||||
test_file.write("\tli x2, 0x{}\n".format(end_addr))
|
||||
test_file.write("\tsw x1, 0(x2)\n")
|
||||
test_file.write("\tj csr_pass\n")
|
||||
|
||||
|
||||
def gen_csr_instr(original_csr_map, csr_instructions, xlen,
|
||||
iterations, out, end_signature_addr):
|
||||
"""
|
||||
Uses the information in the map produced by get_csr_map() to generate
|
||||
test CSR instructions operating on the generated random values.
|
||||
"""
|
||||
Uses the information in the map produced by get_csr_map() to generate
|
||||
test CSR instructions operating on the generated random values.
|
||||
|
||||
Args:
|
||||
original_csr_map: The dictionary containing CSR mappings generated by get_csr_map()
|
||||
csr_instructions: A list of all supported CSR instructions in string form.
|
||||
xlen: The RISC-V ISA bit length.
|
||||
iterations: Indicates how many randomized test files will be generated.
|
||||
out: A string containing the directory path that the tests will be generated in.
|
||||
end_signature_addr: The address the test should write to upon terminating
|
||||
Args:
|
||||
original_csr_map: The dictionary containing CSR mappings generated by get_csr_map()
|
||||
csr_instructions: A list of all supported CSR instructions in string form.
|
||||
xlen: The RISC-V ISA bit length.
|
||||
iterations: Indicates how many randomized test files will be generated.
|
||||
out: A string containing the directory path that the tests will be generated in.
|
||||
end_signature_addr: The address the test should write to upon terminating
|
||||
|
||||
Returns:
|
||||
No explicit return value, but will write the randomized assembly test code
|
||||
to the specified number of files.
|
||||
"""
|
||||
for i in range(iterations):
|
||||
# pick two GPRs at random to act as source and destination registers
|
||||
# for CSR operations
|
||||
csr_map = copy.deepcopy(original_csr_map)
|
||||
source_reg, dest_reg = ["x{}".format(i) for i in random.sample(range(1, 16), 2)]
|
||||
csr_list = list(csr_map.keys())
|
||||
with open("{}/riscv_csr_test_{}.S".format(out, i), "w") as csr_test_file:
|
||||
gen_setup(csr_test_file)
|
||||
for csr in csr_list:
|
||||
csr_address, csr_val, csr_write_mask, csr_read_mask = csr_map.get(csr)
|
||||
csr_test_file.write("\t# {}\n".format(csr))
|
||||
for op in csr_instructions:
|
||||
for i in range(3):
|
||||
# hex string
|
||||
rand_rs1_val = get_rs1_val(i, xlen)
|
||||
# I type CSR instruction
|
||||
first_li = ""
|
||||
if op[-1] == "i":
|
||||
imm = rand_rs1_val[-5:]
|
||||
csr_inst = "\t{} {}, {}, 0b{}\n".format(op, dest_reg, csr_address, imm.bin)
|
||||
imm_val = bitarray(uint=0, length=xlen-5)
|
||||
imm_val.append(imm)
|
||||
predict_li = ("\tli {}, "
|
||||
"{}\n".format(source_reg, predict_csr_val(op, imm_val, csr_val, csr_write_mask, csr_read_mask)))
|
||||
else:
|
||||
first_li = "\tli {}, 0x{}\n".format(source_reg, rand_rs1_val.hex)
|
||||
csr_inst = "\t{} {}, {}, {}\n".format(op, dest_reg, csr_address, source_reg)
|
||||
predict_li = ("\tli {}, "
|
||||
"{}\n".format(source_reg, predict_csr_val(op, rand_rs1_val, csr_val, csr_write_mask, csr_read_mask)))
|
||||
branch_check = "\tbne {}, {}, csr_fail\n".format(source_reg, dest_reg)
|
||||
csr_test_file.write(first_li)
|
||||
csr_test_file.write(csr_inst)
|
||||
csr_test_file.write(predict_li)
|
||||
csr_test_file.write(branch_check)
|
||||
"""
|
||||
Returns:
|
||||
No explicit return value, but will write the randomized assembly test code
|
||||
to the specified number of files.
|
||||
"""
|
||||
for i in range(iterations):
|
||||
# pick two GPRs at random to act as source and destination registers
|
||||
# for CSR operations
|
||||
csr_map = copy.deepcopy(original_csr_map)
|
||||
source_reg, dest_reg = ["x{}".format(i) for i in
|
||||
random.sample(range(1, 16), 2)]
|
||||
csr_list = list(csr_map.keys())
|
||||
with open("{}/riscv_csr_test_{}.S".format(out, i),
|
||||
"w") as csr_test_file:
|
||||
gen_setup(csr_test_file)
|
||||
for csr in csr_list:
|
||||
csr_address, csr_val, csr_write_mask, csr_read_mask = csr_map.get(
|
||||
csr)
|
||||
csr_test_file.write("\t# {}\n".format(csr))
|
||||
for op in csr_instructions:
|
||||
for i in range(3):
|
||||
# hex string
|
||||
rand_rs1_val = get_rs1_val(i, xlen)
|
||||
# I type CSR instruction
|
||||
first_li = ""
|
||||
if op[-1] == "i":
|
||||
imm = rand_rs1_val[-5:]
|
||||
csr_inst = "\t{} {}, {}, 0b{}\n".format(op,
|
||||
dest_reg,
|
||||
csr_address,
|
||||
imm.bin)
|
||||
imm_val = bitarray(uint=0, length=xlen - 5)
|
||||
imm_val.append(imm)
|
||||
predict_li = ("\tli {}, "
|
||||
"{}\n".format(source_reg,
|
||||
predict_csr_val(op,
|
||||
imm_val,
|
||||
csr_val,
|
||||
csr_write_mask,
|
||||
csr_read_mask)))
|
||||
else:
|
||||
first_li = "\tli {}, 0x{}\n".format(source_reg,
|
||||
rand_rs1_val.hex)
|
||||
csr_inst = "\t{} {}, {}, {}\n".format(op, dest_reg,
|
||||
csr_address,
|
||||
source_reg)
|
||||
predict_li = ("\tli {}, "
|
||||
"{}\n".format(source_reg,
|
||||
predict_csr_val(op,
|
||||
rand_rs1_val,
|
||||
csr_val,
|
||||
csr_write_mask,
|
||||
csr_read_mask)))
|
||||
branch_check = "\tbne {}, {}, csr_fail\n".format(
|
||||
source_reg, dest_reg)
|
||||
csr_test_file.write(first_li)
|
||||
csr_test_file.write(csr_inst)
|
||||
csr_test_file.write(predict_li)
|
||||
csr_test_file.write(branch_check)
|
||||
"""
|
||||
We must hardcode in one final CSR check, as the value that has last
|
||||
been written to the CSR has not been tested.
|
||||
"""
|
||||
if csr == csr_list[-1] and op == csr_instructions[-1] and i == 2:
|
||||
final_csr_read = "\tcsrr {}, {}\n".format(dest_reg, csr_address)
|
||||
csrrs_read_mask = bitarray(uint=0, length=xlen)
|
||||
final_li = ("\tli {}, "
|
||||
"{}\n".format(source_reg, predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_write_mask, csr_read_mask)))
|
||||
final_branch_check = "\tbne {}, {}, csr_fail\n".format(source_reg, dest_reg)
|
||||
csr_test_file.write(final_csr_read)
|
||||
csr_test_file.write(final_li)
|
||||
csr_test_file.write(final_branch_check)
|
||||
gen_csr_test_pass(csr_test_file, end_signature_addr)
|
||||
gen_csr_test_fail(csr_test_file, end_signature_addr)
|
||||
if csr == csr_list[-1] and op == csr_instructions[
|
||||
-1] and i == 2:
|
||||
final_csr_read = "\tcsrr {}, {}\n".format(dest_reg,
|
||||
csr_address)
|
||||
csrrs_read_mask = bitarray(uint=0, length=xlen)
|
||||
final_li = ("\tli {}, "
|
||||
"{}\n".format(source_reg,
|
||||
predict_csr_val('csrrs',
|
||||
csrrs_read_mask,
|
||||
csr_val,
|
||||
csr_write_mask,
|
||||
csr_read_mask)))
|
||||
final_branch_check = "\tbne {}, {}, csr_fail\n".format(
|
||||
source_reg, dest_reg)
|
||||
csr_test_file.write(final_csr_read)
|
||||
csr_test_file.write(final_li)
|
||||
csr_test_file.write(final_branch_check)
|
||||
gen_csr_test_pass(csr_test_file, end_signature_addr)
|
||||
gen_csr_test_fail(csr_test_file, end_signature_addr)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point of CSR test generation script.
|
||||
"""Main entry point of CSR test generation script.
|
||||
Will set up a list of all supported CSR instructions,
|
||||
and seed the RNG."""
|
||||
|
||||
# define command line arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--csr_file", type=str, default="yaml/csr_template.yaml",
|
||||
help="The YAML file contating descriptions of all processor supported CSRs")
|
||||
parser.add_argument("--xlen", type=int, default=32,
|
||||
help="Specify the ISA width, e.g. 32 or 64 or 128")
|
||||
parser.add_argument("--iterations", type=int, default=1,
|
||||
help="Specify how many tests to be generated")
|
||||
parser.add_argument("--out", type=str, default="./",
|
||||
help="Specify output directory")
|
||||
parser.add_argument("--end_signature_addr", type=str, default="0",
|
||||
help="Address that should be written to at end of this test")
|
||||
parser.add_argument("--seed", type=int, default=None,
|
||||
help="""Value used to seed the random number generator. If no value is passed in,
|
||||
# define command line arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--csr_file", type=str,
|
||||
default="yaml/csr_template.yaml",
|
||||
help="The YAML file contating descriptions of all processor supported CSRs")
|
||||
parser.add_argument("--xlen", type=int, default=32,
|
||||
help="Specify the ISA width, e.g. 32 or 64 or 128")
|
||||
parser.add_argument("--iterations", type=int, default=1,
|
||||
help="Specify how many tests to be generated")
|
||||
parser.add_argument("--out", type=str, default="./",
|
||||
help="Specify output directory")
|
||||
parser.add_argument("--end_signature_addr", type=str, default="0",
|
||||
help="Address that should be written to at end of this test")
|
||||
parser.add_argument("--seed", type=int, default=None,
|
||||
help="""Value used to seed the random number generator. If no value is passed in,
|
||||
the RNG will be seeded from an internal source of randomness.""")
|
||||
args = parser.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
"""All supported CSR operations"""
|
||||
csr_ops = ['csrrw', 'csrrs', 'csrrc', 'csrrwi', 'csrrsi', 'csrrci']
|
||||
"""All supported CSR operations"""
|
||||
csr_ops = ['csrrw', 'csrrs', 'csrrc', 'csrrwi', 'csrrsi', 'csrrci']
|
||||
|
||||
"""
|
||||
Seed the RNG.
|
||||
If args.seed is None, seed will be drawn from some internal random source.
|
||||
If args.seed is defined, this will be used to seed the RNG for user reproducibility.
|
||||
"""
|
||||
random.seed(args.seed)
|
||||
"""
|
||||
Seed the RNG.
|
||||
If args.seed is None, seed will be drawn from some internal random source.
|
||||
If args.seed is defined, this will be used to seed the RNG for user reproducibility.
|
||||
"""
|
||||
random.seed(args.seed)
|
||||
|
||||
gen_csr_instr(get_csr_map(args.csr_file, args.xlen),
|
||||
csr_ops, args.xlen, args.iterations, args.out,
|
||||
args.end_signature_addr)
|
||||
gen_csr_instr(get_csr_map(args.csr_file, args.xlen),
|
||||
csr_ops, args.xlen, args.iterations, args.out,
|
||||
args.end_signature_addr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
|
@ -25,194 +25,201 @@ sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
|||
|
||||
from riscv_trace_csv import *
|
||||
|
||||
|
||||
def compare_trace_csv(csv1, csv2, name1, name2, log,
|
||||
in_order_mode = 1,
|
||||
coalescing_limit = 0,
|
||||
verbose = 0,
|
||||
mismatch_print_limit = 5,
|
||||
compare_final_value_only = 0):
|
||||
"""Compare two trace CSV file"""
|
||||
matched_cnt = 0
|
||||
mismatch_cnt = 0
|
||||
|
||||
# ensure that in order mode is disabled if necessary
|
||||
if compare_final_value_only:
|
||||
in_order_mode = 0
|
||||
|
||||
if log:
|
||||
fd = open(log, 'a+')
|
||||
else:
|
||||
fd = sys.stdout
|
||||
|
||||
fd.write("%s : %s\n" % (name1, csv1))
|
||||
fd.write("%s : %s\n" % (name2, csv2))
|
||||
|
||||
with open(csv1, "r") as fd1, open(csv2, "r") as fd2:
|
||||
instr_trace_1 = []
|
||||
instr_trace_2 = []
|
||||
trace_csv_1 = RiscvInstructionTraceCsv(fd1)
|
||||
trace_csv_2 = RiscvInstructionTraceCsv(fd2)
|
||||
trace_csv_1.read_trace(instr_trace_1)
|
||||
trace_csv_2.read_trace(instr_trace_2)
|
||||
trace_1_index = 0
|
||||
trace_2_index = 0
|
||||
mismatch_cnt = 0
|
||||
in_order_mode=1,
|
||||
coalescing_limit=0,
|
||||
verbose=0,
|
||||
mismatch_print_limit=5,
|
||||
compare_final_value_only=0):
|
||||
"""Compare two trace CSV file"""
|
||||
matched_cnt = 0
|
||||
if in_order_mode:
|
||||
gpr_val_1 = {}
|
||||
gpr_val_2 = {}
|
||||
for trace in instr_trace_1:
|
||||
trace_1_index += 1
|
||||
if len(trace.gpr) == 0:
|
||||
continue
|
||||
# Check if there's a GPR change caused by this instruction
|
||||
gpr_state_change_1 = check_update_gpr(trace.gpr, gpr_val_1)
|
||||
if gpr_state_change_1 == 0:
|
||||
continue
|
||||
# Move forward the other trace until a GPR update happens
|
||||
gpr_state_change_2 = 0
|
||||
while (gpr_state_change_2 == 0 and trace_2_index < len(instr_trace_2)):
|
||||
gpr_state_change_2 = check_update_gpr(instr_trace_2[trace_2_index].gpr,
|
||||
gpr_val_2)
|
||||
trace_2_index += 1
|
||||
# Check if the GPR update is the same between trace 1 and 2
|
||||
if gpr_state_change_2 == 0:
|
||||
mismatch_cnt += 1
|
||||
fd.write("Mismatch[%d]:\n[%d] %s : %s\n" %
|
||||
(mismatch_cnt, trace_1_index, name1, trace.get_trace_string()))
|
||||
fd.write("%0d instructions left in trace %0s\n" %
|
||||
(len(instr_trace_1) - trace_1_index + 1, name1))
|
||||
elif len(trace.gpr) != len(instr_trace_2[trace_2_index-1].gpr):
|
||||
mismatch_cnt += 1
|
||||
# print first few mismatches
|
||||
if mismatch_cnt <= mismatch_print_limit:
|
||||
fd.write("Mismatch[%d]:\n%s[%d] : %s\n" %
|
||||
(mismatch_cnt, name1, trace_2_index - 1,
|
||||
trace.get_trace_string()))
|
||||
fd.write("%s[%d] : %s\n" %
|
||||
(name2, trace_2_index - 1,
|
||||
instr_trace_2[trace_2_index-1].get_trace_string()))
|
||||
else:
|
||||
found_mismatch = 0
|
||||
for i in range(len(trace.gpr)):
|
||||
if trace.gpr[i] != instr_trace_2[trace_2_index-1].gpr[i]:
|
||||
mismatch_cnt += 1
|
||||
found_mismatch = 1
|
||||
# print first few mismatches
|
||||
if mismatch_cnt <= mismatch_print_limit:
|
||||
fd.write("Mismatch[%d]:\n%s[%d] : %s\n" %
|
||||
(mismatch_cnt, name1, trace_2_index - 1,
|
||||
trace.get_trace_string()))
|
||||
fd.write("%s[%d] : %s\n" %
|
||||
(name2, trace_2_index - 1,
|
||||
instr_trace_2[trace_2_index-1].get_trace_string()))
|
||||
break
|
||||
if not found_mismatch:
|
||||
matched_cnt += 1
|
||||
# Break the loop if it reaches the end of trace 2
|
||||
if trace_2_index == len(instr_trace_2):
|
||||
break
|
||||
# Check if there's remaining instruction that change architectural state
|
||||
if trace_2_index != len(instr_trace_2):
|
||||
while (trace_2_index < len(instr_trace_2)):
|
||||
gpr_state_change_2 = check_update_gpr(
|
||||
instr_trace_2[trace_2_index].gpr,
|
||||
gpr_val_2)
|
||||
if gpr_state_change_2 == 1:
|
||||
fd.write("%0d instructions left in trace %0s\n" %
|
||||
(len(instr_trace_2) - trace_2_index, name2))
|
||||
mismatch_cnt += len(instr_trace_2) - trace_2_index
|
||||
break
|
||||
trace_2_index += 1
|
||||
else:
|
||||
pass
|
||||
# TODO: Enable out of order comparison
|
||||
# # For processors which can commit multiple instructions in one cycle, the
|
||||
# # ordering between different GPR update on that cycle could be
|
||||
# # non-deterministic. If multiple instructions try to update the same GPR on
|
||||
# # the same cycle, these updates could be coalesced to one update.
|
||||
# gpr_trace_1 = {}
|
||||
# gpr_trace_2 = {}
|
||||
# parse_gpr_update_from_trace(instr_trace_1, gpr_trace_1)
|
||||
# parse_gpr_update_from_trace(instr_trace_2, gpr_trace_2)
|
||||
# if not compare_final_value_only:
|
||||
# if len(gpr_trace_1) != len(gpr_trace_2):
|
||||
# fd.write("Mismatch: affected GPR count mismtach %s:%d VS %s:%d\n" %
|
||||
# (name1, len(gpr_trace_1), name2, len(gpr_trace_2)))
|
||||
# mismatch_cnt += 1
|
||||
# for gpr in gpr_trace_1:
|
||||
# coalesced_updates = 0
|
||||
# if (len(gpr_trace_1[gpr]) != len(gpr_trace_2[gpr]) and
|
||||
# coalescing_limit == 0):
|
||||
# fd.write("Mismatch: GPR[%s] trace count mismtach %s:%d VS %s:%d\n" %
|
||||
# (gpr, name1, len(gpr_trace_1[gpr]),
|
||||
# name2, len(gpr_trace_2[gpr])))
|
||||
# mismatch_cnt += 1
|
||||
# trace_2_index = 0
|
||||
# coalesced_updates = 0
|
||||
# for trace_1_index in range(0, len(gpr_trace_1[gpr])-1):
|
||||
# if (trace_2_index == len(gpr_trace_2[gpr])):
|
||||
# break
|
||||
# if int(gpr_trace_1[gpr][trace_1_index].rd_val, 16) != \
|
||||
# int(gpr_trace_2[gpr][trace_2_index].rd_val, 16):
|
||||
# if coalesced_updates >= coalescing_limit:
|
||||
# coalesced_updates = 0
|
||||
# mismatch_cnt += 1
|
||||
# if mismatch_cnt <= mismatch_print_limit:
|
||||
# fd.write("Mismatch:\n")
|
||||
# fd.write("%s[%d] : %s\n" % (name1, trace_1_index,
|
||||
# gpr_trace_1[gpr][trace_1_index].get_trace_string()))
|
||||
# fd.write("%s[%d] : %s\n" % (name2, trace_2_index,
|
||||
# gpr_trace_2[gpr][trace_2_index].get_trace_string()))
|
||||
# trace_2_index += 1
|
||||
# else:
|
||||
# if verbose:
|
||||
# fd.write("Skipping %s[%d] : %s\n" %
|
||||
# (name1, trace_1_index,
|
||||
# gpr_trace_1[gpr][trace_1_index].get_trace_string()))
|
||||
# coalesced_updates += 1
|
||||
# else:
|
||||
# coalesced_updates = 0
|
||||
# matched_cnt += 1
|
||||
# if verbose:
|
||||
# fd.write("Matched [%0d]: %s : %s\n" %
|
||||
# (trace_1_index, name1,
|
||||
# gpr_trace_1[gpr][trace_1_index].get_trace_string()))
|
||||
# trace_2_index += 1
|
||||
# # Check the final value match between the two traces
|
||||
# for gpr in gpr_trace_1:
|
||||
# if not compare_final_value_only:
|
||||
# if (len(gpr_trace_1[gpr]) == 0 or len(gpr_trace_2[gpr]) == 0):
|
||||
# mismatch_cnt += 1
|
||||
# fd.write("Zero GPR[%s] updates observed: %s:%d, %s:%d\n" % (gpr,
|
||||
# name1, len(gpr_trace_1[gpr]), name2, len(gpr_trace_2[gpr])))
|
||||
# else:
|
||||
# if not gpr_trace_2.get(gpr):
|
||||
# trace = RiscvInstructionTraceEntry()
|
||||
# trace.rd_val = "0"
|
||||
# trace.rd = gpr
|
||||
# trace.instr_str = ""
|
||||
# trace.binary = ""
|
||||
# trace.addr = ""
|
||||
# gpr_trace_2[gpr] = [trace]
|
||||
# if int(gpr_trace_1[gpr][-1].rd_val, 16) != \
|
||||
# int(gpr_trace_2[gpr][-1].rd_val, 16):
|
||||
# mismatch_cnt += 1
|
||||
# if mismatch_cnt <= mismatch_print_limit:
|
||||
# fd.write("Mismatch final value:\n")
|
||||
# fd.write("%s : %s\n" % (name1, gpr_trace_1[gpr][-1].get_trace_string()))
|
||||
# fd.write("%s : %s\n" % (name2, gpr_trace_2[gpr][-1].get_trace_string()))
|
||||
if mismatch_cnt == 0:
|
||||
compare_result = "[PASSED]: %d matched\n" % ( matched_cnt)
|
||||
else:
|
||||
compare_result = "[FAILED]: %d matched, %d mismatch\n" % ( matched_cnt, mismatch_cnt)
|
||||
fd.write(compare_result + "\n")
|
||||
mismatch_cnt = 0
|
||||
|
||||
# ensure that in order mode is disabled if necessary
|
||||
if compare_final_value_only:
|
||||
in_order_mode = 0
|
||||
|
||||
if log:
|
||||
fd.close()
|
||||
return compare_result
|
||||
fd = open(log, 'a+')
|
||||
else:
|
||||
fd = sys.stdout
|
||||
|
||||
fd.write("{} : {}\n".format(name1, csv1))
|
||||
fd.write("{} : {}\n".format(name2, csv2))
|
||||
|
||||
with open(csv1, "r") as fd1, open(csv2, "r") as fd2:
|
||||
instr_trace_1 = []
|
||||
instr_trace_2 = []
|
||||
trace_csv_1 = RiscvInstructionTraceCsv(fd1)
|
||||
trace_csv_2 = RiscvInstructionTraceCsv(fd2)
|
||||
trace_csv_1.read_trace(instr_trace_1)
|
||||
trace_csv_2.read_trace(instr_trace_2)
|
||||
trace_1_index = 0
|
||||
trace_2_index = 0
|
||||
mismatch_cnt = 0
|
||||
matched_cnt = 0
|
||||
if in_order_mode:
|
||||
gpr_val_1 = {}
|
||||
gpr_val_2 = {}
|
||||
for trace in instr_trace_1:
|
||||
trace_1_index += 1
|
||||
if len(trace.gpr) == 0:
|
||||
continue
|
||||
# Check if there's a GPR change caused by this instruction
|
||||
gpr_state_change_1 = check_update_gpr(trace.gpr, gpr_val_1)
|
||||
if gpr_state_change_1 == 0:
|
||||
continue
|
||||
# Move forward the other trace until a GPR update happens
|
||||
gpr_state_change_2 = 0
|
||||
while (gpr_state_change_2 == 0 and trace_2_index < len(
|
||||
instr_trace_2)):
|
||||
gpr_state_change_2 = check_update_gpr(
|
||||
instr_trace_2[trace_2_index].gpr,
|
||||
gpr_val_2)
|
||||
trace_2_index += 1
|
||||
# Check if the GPR update is the same between trace 1 and 2
|
||||
if gpr_state_change_2 == 0:
|
||||
mismatch_cnt += 1
|
||||
fd.write("Mismatch[{}]:\n[{}] {} : {}\n".format(
|
||||
mismatch_cnt, trace_1_index, name1,trace.get_trace_string()))
|
||||
fd.write("{} instructions left in trace {}\n".format(
|
||||
len(instr_trace_1) - trace_1_index + 1, name1))
|
||||
elif len(trace.gpr) != len(
|
||||
instr_trace_2[trace_2_index - 1].gpr):
|
||||
mismatch_cnt += 1
|
||||
# print first few mismatches
|
||||
if mismatch_cnt <= mismatch_print_limit:
|
||||
fd.write("Mismatch[{}]:\n{}[{}] : {}\n".format(
|
||||
mismatch_cnt, name1, trace_2_index - 1,
|
||||
trace.get_trace_string()))
|
||||
fd.write("{}[{}] : {}\n".format(
|
||||
name2, trace_2_index - 1,
|
||||
instr_trace_2[
|
||||
trace_2_index - 1].get_trace_string()))
|
||||
else:
|
||||
found_mismatch = 0
|
||||
for i in range(len(trace.gpr)):
|
||||
if trace.gpr[i] != instr_trace_2[trace_2_index - 1].gpr[i]:
|
||||
mismatch_cnt += 1
|
||||
found_mismatch = 1
|
||||
# print first few mismatches
|
||||
if mismatch_cnt <= mismatch_print_limit:
|
||||
fd.write("Mismatch[{}]:\n{}[{}] : {}\n".format(
|
||||
mismatch_cnt, name1, trace_2_index - 1,
|
||||
trace.get_trace_string()))
|
||||
fd.write("{}[{}] : {}\n".format(
|
||||
name2, trace_2_index - 1,
|
||||
instr_trace_2[
|
||||
trace_2_index - 1].get_trace_string()))
|
||||
break
|
||||
if not found_mismatch:
|
||||
matched_cnt += 1
|
||||
# Break the loop if it reaches the end of trace 2
|
||||
if trace_2_index == len(instr_trace_2):
|
||||
break
|
||||
# Check if there's remaining instruction that change architectural state
|
||||
if trace_2_index != len(instr_trace_2):
|
||||
while trace_2_index < len(instr_trace_2):
|
||||
gpr_state_change_2 = check_update_gpr(
|
||||
instr_trace_2[trace_2_index].gpr,
|
||||
gpr_val_2)
|
||||
if gpr_state_change_2 == 1:
|
||||
fd.write("{} instructions left in trace {}\n".format(
|
||||
len(instr_trace_2) - trace_2_index, name2))
|
||||
mismatch_cnt += len(instr_trace_2) - trace_2_index
|
||||
break
|
||||
trace_2_index += 1
|
||||
else:
|
||||
pass
|
||||
# TODO: Enable out of order comparison
|
||||
# # For processors which can commit multiple instructions in one cycle, the
|
||||
# # ordering between different GPR update on that cycle could be
|
||||
# # non-deterministic. If multiple instructions try to update the same GPR on
|
||||
# # the same cycle, these updates could be coalesced to one update.
|
||||
# gpr_trace_1 = {}
|
||||
# gpr_trace_2 = {}
|
||||
# parse_gpr_update_from_trace(instr_trace_1, gpr_trace_1)
|
||||
# parse_gpr_update_from_trace(instr_trace_2, gpr_trace_2)
|
||||
# if not compare_final_value_only:
|
||||
# if len(gpr_trace_1) != len(gpr_trace_2):
|
||||
# fd.write("Mismatch: affected GPR count mismtach %s:%d VS %s:%d\n" %
|
||||
# (name1, len(gpr_trace_1), name2, len(gpr_trace_2)))
|
||||
# mismatch_cnt += 1
|
||||
# for gpr in gpr_trace_1:
|
||||
# coalesced_updates = 0
|
||||
# if (len(gpr_trace_1[gpr]) != len(gpr_trace_2[gpr]) and
|
||||
# coalescing_limit == 0):
|
||||
# fd.write("Mismatch: GPR[%s] trace count mismtach %s:%d VS %s:%d\n" %
|
||||
# (gpr, name1, len(gpr_trace_1[gpr]),
|
||||
# name2, len(gpr_trace_2[gpr])))
|
||||
# mismatch_cnt += 1
|
||||
# trace_2_index = 0
|
||||
# coalesced_updates = 0
|
||||
# for trace_1_index in range(0, len(gpr_trace_1[gpr])-1):
|
||||
# if (trace_2_index == len(gpr_trace_2[gpr])):
|
||||
# break
|
||||
# if int(gpr_trace_1[gpr][trace_1_index].rd_val, 16) != \
|
||||
# int(gpr_trace_2[gpr][trace_2_index].rd_val, 16):
|
||||
# if coalesced_updates >= coalescing_limit:
|
||||
# coalesced_updates = 0
|
||||
# mismatch_cnt += 1
|
||||
# if mismatch_cnt <= mismatch_print_limit:
|
||||
# fd.write("Mismatch:\n")
|
||||
# fd.write("%s[%d] : %s\n" % (name1, trace_1_index,
|
||||
# gpr_trace_1[gpr][trace_1_index].get_trace_string()))
|
||||
# fd.write("%s[%d] : %s\n" % (name2, trace_2_index,
|
||||
# gpr_trace_2[gpr][trace_2_index].get_trace_string()))
|
||||
# trace_2_index += 1
|
||||
# else:
|
||||
# if verbose:
|
||||
# fd.write("Skipping %s[%d] : %s\n" %
|
||||
# (name1, trace_1_index,
|
||||
# gpr_trace_1[gpr][trace_1_index].get_trace_string()))
|
||||
# coalesced_updates += 1
|
||||
# else:
|
||||
# coalesced_updates = 0
|
||||
# matched_cnt += 1
|
||||
# if verbose:
|
||||
# fd.write("Matched [%0d]: %s : %s\n" %
|
||||
# (trace_1_index, name1,
|
||||
# gpr_trace_1[gpr][trace_1_index].get_trace_string()))
|
||||
# trace_2_index += 1
|
||||
# # Check the final value match between the two traces
|
||||
# for gpr in gpr_trace_1:
|
||||
# if not compare_final_value_only:
|
||||
# if (len(gpr_trace_1[gpr]) == 0 or len(gpr_trace_2[gpr]) == 0):
|
||||
# mismatch_cnt += 1
|
||||
# fd.write("Zero GPR[%s] updates observed: %s:%d, %s:%d\n" % (gpr,
|
||||
# name1, len(gpr_trace_1[gpr]), name2, len(gpr_trace_2[gpr])))
|
||||
# else:
|
||||
# if not gpr_trace_2.get(gpr):
|
||||
# trace = RiscvInstructionTraceEntry()
|
||||
# trace.rd_val = "0"
|
||||
# trace.rd = gpr
|
||||
# trace.instr_str = ""
|
||||
# trace.binary = ""
|
||||
# trace.addr = ""
|
||||
# gpr_trace_2[gpr] = [trace]
|
||||
# if int(gpr_trace_1[gpr][-1].rd_val, 16) != \
|
||||
# int(gpr_trace_2[gpr][-1].rd_val, 16):
|
||||
# mismatch_cnt += 1
|
||||
# if mismatch_cnt <= mismatch_print_limit:
|
||||
# fd.write("Mismatch final value:\n")
|
||||
# fd.write("%s : %s\n" % (name1, gpr_trace_1[gpr][-1].get_trace_string()))
|
||||
# fd.write("%s : %s\n" % (name2, gpr_trace_2[gpr][-1].get_trace_string()))
|
||||
if mismatch_cnt == 0:
|
||||
compare_result = "[PASSED]: {} matched\n".format(matched_cnt)
|
||||
else:
|
||||
compare_result = "[FAILED]: {} matched, {} mismatch\n".format(
|
||||
matched_cnt, mismatch_cnt)
|
||||
fd.write(compare_result + "\n")
|
||||
if log:
|
||||
fd.close()
|
||||
return compare_result
|
||||
|
||||
|
||||
#def parse_gpr_update_from_trace(trace_csv, gpr_trace):
|
||||
# def parse_gpr_update_from_trace(trace_csv, gpr_trace):
|
||||
# prev_val = {}
|
||||
# for trace in trace_csv:
|
||||
# if trace.rd != "":
|
||||
|
@ -225,57 +232,61 @@ def compare_trace_csv(csv1, csv2, name1, name2, log,
|
|||
|
||||
|
||||
def check_update_gpr(gpr_update, gpr):
|
||||
gpr_state_change = 0
|
||||
for update in gpr_update:
|
||||
if update == "":
|
||||
return 0
|
||||
item = update.split(":")
|
||||
if len(item) != 2:
|
||||
sys.exit("Illegal GPR update format:" + update)
|
||||
rd = item[0]
|
||||
rd_val = item[1]
|
||||
if rd in gpr:
|
||||
if rd_val != gpr[rd]:
|
||||
gpr_state_change = 1
|
||||
else:
|
||||
if int(rd_val, 16) != 0:
|
||||
gpr_state_change = 1
|
||||
gpr[rd] = rd_val
|
||||
return gpr_state_change
|
||||
gpr_state_change = 0
|
||||
for update in gpr_update:
|
||||
if update == "":
|
||||
return 0
|
||||
item = update.split(":")
|
||||
if len(item) != 2:
|
||||
sys.exit("Illegal GPR update format:" + update)
|
||||
rd = item[0]
|
||||
rd_val = item[1]
|
||||
if rd in gpr:
|
||||
if rd_val != gpr[rd]:
|
||||
gpr_state_change = 1
|
||||
else:
|
||||
if int(rd_val, 16) != 0:
|
||||
gpr_state_change = 1
|
||||
gpr[rd] = rd_val
|
||||
return gpr_state_change
|
||||
|
||||
|
||||
def main():
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--csv_file_1", type=str, help="Instruction trace 1 CSV")
|
||||
parser.add_argument("--csv_file_2", type=str, help="Instruction trace 2 CSV")
|
||||
parser.add_argument("--csv_name_1", type=str, help="Instruction trace 1 name")
|
||||
parser.add_argument("--csv_name_2", type=str, help="Instruction trace 2 name")
|
||||
# optional arguments
|
||||
parser.add_argument("--log", type=str, default="",
|
||||
help="Log file")
|
||||
parser.add_argument("--in_order_mode", type=int, default=1,
|
||||
help="In order comparison mode")
|
||||
parser.add_argument("--gpr_update_coalescing_limit", type=int, default=1,
|
||||
help="Allow the core to merge multiple updates to the \
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--csv_file_1", type=str,
|
||||
help="Instruction trace 1 CSV")
|
||||
parser.add_argument("--csv_file_2", type=str,
|
||||
help="Instruction trace 2 CSV")
|
||||
parser.add_argument("--csv_name_1", type=str,
|
||||
help="Instruction trace 1 name")
|
||||
parser.add_argument("--csv_name_2", type=str,
|
||||
help="Instruction trace 2 name")
|
||||
# optional arguments
|
||||
parser.add_argument("--log", type=str, default="",
|
||||
help="Log file")
|
||||
parser.add_argument("--in_order_mode", type=int, default=1,
|
||||
help="In order comparison mode")
|
||||
parser.add_argument("--gpr_update_coalescing_limit", type=int, default=1,
|
||||
help="Allow the core to merge multiple updates to the \
|
||||
same GPR into one. This option only applies to \
|
||||
trace 2")
|
||||
parser.add_argument("--mismatch_print_limit", type=int, default=5,
|
||||
help="Max number of mismatches printed")
|
||||
parser.add_argument("--verbose", type=int, default=0,
|
||||
help="Verbose logging")
|
||||
parser.add_argument("--compare_final_value_only", type=int, default=0,
|
||||
help="Only compare the final value of the GPR")
|
||||
parser.add_argument("--mismatch_print_limit", type=int, default=5,
|
||||
help="Max number of mismatches printed")
|
||||
parser.add_argument("--verbose", type=int, default=0,
|
||||
help="Verbose logging")
|
||||
parser.add_argument("--compare_final_value_only", type=int, default=0,
|
||||
help="Only compare the final value of the GPR")
|
||||
|
||||
args = parser.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Compare trace CSV
|
||||
compare_trace_csv(args.csv_file_1, args.csv_file_2,
|
||||
args.csv_name_1, args.csv_name_2, args.log,
|
||||
args.in_order_mode, args.gpr_update_coalescing_limit,
|
||||
args.verbose, args.mismatch_print_limit,
|
||||
args.compare_final_value_only)
|
||||
# Compare trace CSV
|
||||
compare_trace_csv(args.csv_file_1, args.csv_file_2,
|
||||
args.csv_name_1, args.csv_name_2, args.log,
|
||||
args.in_order_mode, args.gpr_update_coalescing_limit,
|
||||
args.verbose, args.mismatch_print_limit,
|
||||
args.compare_final_value_only)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
871
vendor/google_riscv-dv/scripts/lib.py
vendored
871
vendor/google_riscv-dv/scripts/lib.py
vendored
|
@ -31,197 +31,207 @@ RET_SUCCESS = 0
|
|||
RET_FAIL = 1
|
||||
RET_FATAL = -1
|
||||
|
||||
def setup_logging(verbose):
|
||||
"""Setup the root logger.
|
||||
|
||||
Args:
|
||||
verbose: Verbose logging
|
||||
"""
|
||||
if verbose:
|
||||
logging.basicConfig(format="%(asctime)s %(filename)s:%(lineno)-5s %(levelname)-8s %(message)s",
|
||||
datefmt='%a, %d %b %Y %H:%M:%S',
|
||||
level=logging.DEBUG)
|
||||
else:
|
||||
logging.basicConfig(format="%(asctime)s %(levelname)-8s %(message)s",
|
||||
datefmt='%a, %d %b %Y %H:%M:%S',
|
||||
level=logging.INFO)
|
||||
def setup_logging(verbose):
|
||||
"""Setup the root logger.
|
||||
|
||||
Args:
|
||||
verbose: Verbose logging
|
||||
"""
|
||||
if verbose:
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s %(filename)s:%(lineno)-5s %(levelname)-8s %(message)s",
|
||||
datefmt='%a, %d %b %Y %H:%M:%S',
|
||||
level=logging.DEBUG)
|
||||
else:
|
||||
logging.basicConfig(format="%(asctime)s %(levelname)-8s %(message)s",
|
||||
datefmt='%a, %d %b %Y %H:%M:%S',
|
||||
level=logging.INFO)
|
||||
|
||||
|
||||
def read_yaml(yaml_file):
|
||||
""" Read YAML file to a dictionary
|
||||
""" Read YAML file to a dictionary
|
||||
|
||||
Args:
|
||||
yaml_file : YAML file
|
||||
Args:
|
||||
yaml_file : YAML file
|
||||
|
||||
Returns:
|
||||
yaml_data : data read from YAML in dictionary format
|
||||
"""
|
||||
with open(yaml_file, "r") as f:
|
||||
Returns:
|
||||
yaml_data : data read from YAML in dictionary format
|
||||
"""
|
||||
with open(yaml_file, "r") as f:
|
||||
try:
|
||||
yaml_data = yaml.safe_load(f)
|
||||
except yaml.YAMLError as exc:
|
||||
logging.error(exc)
|
||||
sys.exit(RET_FAIL)
|
||||
return yaml_data
|
||||
|
||||
|
||||
def get_env_var(var, debug_cmd=None):
|
||||
"""Get the value of environment variable
|
||||
|
||||
Args:
|
||||
var : Name of the environment variable
|
||||
|
||||
Returns:
|
||||
val : Value of the environment variable
|
||||
"""
|
||||
try:
|
||||
yaml_data = yaml.safe_load(f)
|
||||
except yaml.YAMLError as exc:
|
||||
logging.error(exc)
|
||||
sys.exit(RET_FAIL)
|
||||
return yaml_data
|
||||
val = os.environ[var]
|
||||
except KeyError:
|
||||
if debug_cmd:
|
||||
return var
|
||||
else:
|
||||
logging.warning("Please set the environment variable {}".format(var))
|
||||
sys.exit(RET_FAIL)
|
||||
return val
|
||||
|
||||
|
||||
def get_env_var(var, debug_cmd = None):
|
||||
"""Get the value of environment variable
|
||||
def run_cmd(cmd, timeout_s=999, exit_on_error=1, check_return_code=True,
|
||||
debug_cmd=None):
|
||||
"""Run a command and return output
|
||||
|
||||
Args:
|
||||
var : Name of the environment variable
|
||||
Args:
|
||||
cmd : shell command to run
|
||||
|
||||
Returns:
|
||||
val : Value of the environment variable
|
||||
"""
|
||||
try:
|
||||
val = os.environ[var]
|
||||
except KeyError:
|
||||
Returns:
|
||||
command output
|
||||
"""
|
||||
logging.debug(cmd)
|
||||
if debug_cmd:
|
||||
return var
|
||||
else:
|
||||
logging.warning("Please set the environment variable %0s" % var)
|
||||
sys.exit(RET_FAIL)
|
||||
return val
|
||||
|
||||
|
||||
def run_cmd(cmd, timeout_s = 999, exit_on_error = 1, check_return_code = True, debug_cmd = None):
|
||||
"""Run a command and return output
|
||||
|
||||
Args:
|
||||
cmd : shell command to run
|
||||
|
||||
Returns:
|
||||
command output
|
||||
"""
|
||||
logging.debug(cmd)
|
||||
if debug_cmd:
|
||||
debug_cmd.write(cmd)
|
||||
debug_cmd.write("\n\n")
|
||||
return
|
||||
try:
|
||||
ps = subprocess.Popen("exec " + cmd,
|
||||
shell=True,
|
||||
executable='/bin/bash',
|
||||
universal_newlines=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError:
|
||||
logging.error(ps.communicate()[0])
|
||||
sys.exit(RET_FAIL)
|
||||
except KeyboardInterrupt:
|
||||
logging.info("\nExited Ctrl-C from user request.")
|
||||
sys.exit(130)
|
||||
try:
|
||||
output = ps.communicate(timeout = timeout_s)[0]
|
||||
except subprocess.TimeoutExpired:
|
||||
logging.error("Timeout[%ds]: %s" % (timeout_s, cmd))
|
||||
output = ""
|
||||
ps.kill()
|
||||
rc = ps.returncode
|
||||
if rc and check_return_code and rc > 0:
|
||||
logging.info(output)
|
||||
logging.error("ERROR return code: %d/%d, cmd:%s" % (check_return_code, rc, cmd))
|
||||
if exit_on_error:
|
||||
sys.exit(RET_FAIL)
|
||||
logging.debug(output)
|
||||
return output
|
||||
|
||||
|
||||
def run_parallel_cmd(cmd_list, timeout_s = 999, exit_on_error = 0,
|
||||
check_return_code = True, debug_cmd = None):
|
||||
"""Run a list of commands in parallel
|
||||
|
||||
Args:
|
||||
cmd_list: command list
|
||||
|
||||
Returns:
|
||||
command output
|
||||
"""
|
||||
if debug_cmd:
|
||||
for cmd in cmd_list:
|
||||
debug_cmd.write(cmd)
|
||||
debug_cmd.write("\n\n")
|
||||
return
|
||||
children = []
|
||||
for cmd in cmd_list:
|
||||
ps = subprocess.Popen("exec " + cmd,
|
||||
shell=True,
|
||||
executable='/bin/bash',
|
||||
universal_newlines=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
children.append(ps)
|
||||
for i in range(len(children)):
|
||||
logging.info("Command progress: %d/%d" % (i, len(children)))
|
||||
logging.debug("Waiting for command: %s" % cmd_list[i])
|
||||
debug_cmd.write(cmd)
|
||||
debug_cmd.write("\n\n")
|
||||
return
|
||||
try:
|
||||
output = children[i].communicate(timeout = timeout_s)[0]
|
||||
except KeyboardInterrupt:
|
||||
logging.info("\nExited Ctrl-C from user request.")
|
||||
sys.exit(130)
|
||||
except subprocess.TimeoutExpired:
|
||||
logging.error("Timeout[%ds]: %s" % (timeout_s, cmd))
|
||||
children[i].kill()
|
||||
rc = children[i].returncode
|
||||
if rc and check_return_code and rc > 0:
|
||||
logging.info(output)
|
||||
logging.error("ERROR return code: %d, cmd:%s" % (rc, cmd))
|
||||
if exit_on_error:
|
||||
ps = subprocess.Popen("exec " + cmd,
|
||||
shell=True,
|
||||
executable='/bin/bash',
|
||||
universal_newlines=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError:
|
||||
logging.error(ps.communicate()[0])
|
||||
sys.exit(RET_FAIL)
|
||||
# Restore stty setting otherwise the terminal may go crazy
|
||||
os.system("stty sane")
|
||||
except KeyboardInterrupt:
|
||||
logging.info("\nExited Ctrl-C from user request.")
|
||||
sys.exit(130)
|
||||
try:
|
||||
output = ps.communicate(timeout=timeout_s)[0]
|
||||
except subprocess.TimeoutExpired:
|
||||
logging.error("Timeout[{}s]: {}".format(timeout_s, cmd))
|
||||
output = ""
|
||||
ps.kill()
|
||||
rc = ps.returncode
|
||||
if rc and check_return_code and rc > 0:
|
||||
logging.info(output)
|
||||
logging.error(
|
||||
"ERROR return code: {}/{}, cmd:{}".format(check_return_code, rc, cmd))
|
||||
if exit_on_error:
|
||||
sys.exit(RET_FAIL)
|
||||
logging.debug(output)
|
||||
return output
|
||||
|
||||
def run_cmd_output(cmd, debug_cmd = None):
|
||||
"""Run a command and return output
|
||||
Args:
|
||||
cmd : Command line to execute
|
||||
"""
|
||||
logging.debug(" ".join(cmd))
|
||||
if debug_cmd:
|
||||
debug_cmd.write(" ".join(cmd))
|
||||
debug_cmd.write("\n\n")
|
||||
return
|
||||
try:
|
||||
output = subprocess.check_output(cmd)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
logging.debug(exc.output)
|
||||
raise exc
|
||||
sys.exit(RET_FAIL)
|
||||
if output:
|
||||
logging.debug(output)
|
||||
|
||||
def process_regression_list(testlist, test, iterations, matched_list, riscv_dv_root):
|
||||
""" Get the matched tests from the regression test list
|
||||
def run_parallel_cmd(cmd_list, timeout_s=999, exit_on_error=0,
|
||||
check_return_code=True, debug_cmd=None):
|
||||
"""Run a list of commands in parallel
|
||||
|
||||
Args:
|
||||
testlist : Regression test list
|
||||
test : Test to run, "all" means all tests in the list
|
||||
iterations : Number of iterations for each test
|
||||
riscv_dv_root : Root directory of RISCV-DV
|
||||
Args:
|
||||
cmd_list: command list
|
||||
|
||||
Returns:
|
||||
matched_list : A list of matched tests
|
||||
"""
|
||||
logging.info("Processing regression test list : %s, test: %s" % (testlist, test))
|
||||
yaml_data = read_yaml(testlist)
|
||||
mult_test = test.split(',')
|
||||
for entry in yaml_data:
|
||||
if 'import' in entry:
|
||||
sub_list = re.sub('<riscv_dv_root>', riscv_dv_root, entry['import'])
|
||||
process_regression_list(sub_list, test, iterations, matched_list, riscv_dv_root)
|
||||
else:
|
||||
if (entry['test'] in mult_test) or (test == "all"):
|
||||
if (iterations > 0 and entry['iterations'] > 0):
|
||||
entry['iterations'] = iterations
|
||||
if entry['iterations'] > 0:
|
||||
logging.info("Found matched tests: %s, iterations:%0d" %
|
||||
(entry['test'], entry['iterations']))
|
||||
matched_list.append(entry)
|
||||
Returns:
|
||||
command output
|
||||
"""
|
||||
if debug_cmd:
|
||||
for cmd in cmd_list:
|
||||
debug_cmd.write(cmd)
|
||||
debug_cmd.write("\n\n")
|
||||
return
|
||||
children = []
|
||||
for cmd in cmd_list:
|
||||
ps = subprocess.Popen("exec " + cmd,
|
||||
shell=True,
|
||||
executable='/bin/bash',
|
||||
universal_newlines=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
children.append(ps)
|
||||
for i in range(len(children)):
|
||||
logging.info("Command progress: {}/{}".format(i, len(children)))
|
||||
logging.debug("Waiting for command: {}".format(cmd_list[i]))
|
||||
try:
|
||||
output = children[i].communicate(timeout=timeout_s)[0]
|
||||
except KeyboardInterrupt:
|
||||
logging.info("\nExited Ctrl-C from user request.")
|
||||
sys.exit(130)
|
||||
except subprocess.TimeoutExpired:
|
||||
logging.error("Timeout[{}s]: {}".format(timeout_s, cmd))
|
||||
children[i].kill()
|
||||
rc = children[i].returncode
|
||||
if rc and check_return_code and rc > 0:
|
||||
logging.info(output)
|
||||
logging.error("ERROR return code: {}, cmd:{}".format(rc, cmd))
|
||||
if exit_on_error:
|
||||
sys.exit(RET_FAIL)
|
||||
# Restore stty setting otherwise the terminal may go crazy
|
||||
os.system("stty sane")
|
||||
logging.debug(output)
|
||||
|
||||
def create_output(output, noclean, prefix = "out_"):
|
||||
""" Create output directory
|
||||
|
||||
def run_cmd_output(cmd, debug_cmd=None):
|
||||
"""Run a command and return output
|
||||
Args:
|
||||
cmd : Command line to execute
|
||||
"""
|
||||
logging.debug(" ".join(cmd))
|
||||
if debug_cmd:
|
||||
debug_cmd.write(" ".join(cmd))
|
||||
debug_cmd.write("\n\n")
|
||||
return
|
||||
try:
|
||||
output = subprocess.check_output(cmd)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
logging.debug(exc.output)
|
||||
raise exc
|
||||
sys.exit(RET_FAIL)
|
||||
if output:
|
||||
logging.debug(output)
|
||||
|
||||
|
||||
def process_regression_list(testlist, test, iterations, matched_list,
|
||||
riscv_dv_root):
|
||||
""" Get the matched tests from the regression test list
|
||||
|
||||
Args:
|
||||
testlist : Regression test list
|
||||
test : Test to run, "all" means all tests in the list
|
||||
iterations : Number of iterations for each test
|
||||
riscv_dv_root : Root directory of RISCV-DV
|
||||
|
||||
Returns:
|
||||
matched_list : A list of matched tests
|
||||
"""
|
||||
logging.info(
|
||||
"Processing regression test list : {}, test: {}".format(testlist, test))
|
||||
yaml_data = read_yaml(testlist)
|
||||
mult_test = test.split(',')
|
||||
for entry in yaml_data:
|
||||
if 'import' in entry:
|
||||
sub_list = re.sub('<riscv_dv_root>', riscv_dv_root, entry['import'])
|
||||
process_regression_list(sub_list, test, iterations, matched_list,
|
||||
riscv_dv_root)
|
||||
else:
|
||||
if (entry['test'] in mult_test) or (test == "all"):
|
||||
if iterations > 0 and entry['iterations'] > 0:
|
||||
entry['iterations'] = iterations
|
||||
if entry['iterations'] > 0:
|
||||
logging.info("Found matched tests: {}, iterations:{}".format(
|
||||
entry['test'], entry['iterations']))
|
||||
matched_list.append(entry)
|
||||
|
||||
|
||||
def create_output(output, noclean, prefix="out_"):
|
||||
""" Create output directory
|
||||
|
||||
Args:
|
||||
output : Name of specified output directory
|
||||
|
@ -230,187 +240,356 @@ def create_output(output, noclean, prefix = "out_"):
|
|||
Returns:
|
||||
Output directory
|
||||
"""
|
||||
# Create output directory
|
||||
if output is None:
|
||||
output = prefix + str(date.today())
|
||||
if noclean is False:
|
||||
os.system("rm -rf %s" % output)
|
||||
# Create output directory
|
||||
if output is None:
|
||||
output = prefix + str(date.today())
|
||||
if noclean is False:
|
||||
os.system("rm -rf {}".format(output))
|
||||
|
||||
logging.info("Creating output directory: {}".format(output))
|
||||
subprocess.run(["mkdir", "-p", output])
|
||||
return output
|
||||
|
||||
logging.info("Creating output directory: %s" % output)
|
||||
subprocess.run(["mkdir", "-p", output])
|
||||
return output
|
||||
|
||||
def gpr_to_abi(gpr):
|
||||
"""Convert a general purpose register to its corresponding abi name"""
|
||||
switcher = {
|
||||
"x0" : "zero",
|
||||
"x1" : "ra",
|
||||
"x2" : "sp",
|
||||
"x3" : "gp",
|
||||
"x4" : "tp",
|
||||
"x5" : "t0",
|
||||
"x6" : "t1",
|
||||
"x7" : "t2",
|
||||
"x8" : "s0",
|
||||
"x9" : "s1",
|
||||
"x10" : "a0",
|
||||
"x11" : "a1",
|
||||
"x12" : "a2",
|
||||
"x13" : "a3",
|
||||
"x14" : "a4",
|
||||
"x15" : "a5",
|
||||
"x16" : "a6",
|
||||
"x17" : "a7",
|
||||
"x18" : "s2",
|
||||
"x19" : "s3",
|
||||
"x20" : "s4",
|
||||
"x21" : "s5",
|
||||
"x22" : "s6",
|
||||
"x23" : "s7",
|
||||
"x24" : "s8",
|
||||
"x25" : "s9",
|
||||
"x26" : "s10",
|
||||
"x27" : "s11",
|
||||
"x28" : "t3",
|
||||
"x29" : "t4",
|
||||
"x30" : "t5",
|
||||
"x31" : "t6",
|
||||
"f0" : "ft0",
|
||||
"f1" : "ft1",
|
||||
"f2" : "ft2",
|
||||
"f3" : "ft3",
|
||||
"f4" : "ft4",
|
||||
"f5" : "ft5",
|
||||
"f6" : "ft6",
|
||||
"f7" : "ft7",
|
||||
"f8" : "fs0",
|
||||
"f9" : "fs1",
|
||||
"f10" : "fa0",
|
||||
"f11" : "fa1",
|
||||
"f12" : "fa2",
|
||||
"f13" : "fa3",
|
||||
"f14" : "fa4",
|
||||
"f15" : "fa5",
|
||||
"f16" : "fa6",
|
||||
"f17" : "fa7",
|
||||
"f18" : "fs2",
|
||||
"f19" : "fs3",
|
||||
"f20" : "fs4",
|
||||
"f21" : "fs5",
|
||||
"f22" : "fs6",
|
||||
"f23" : "fs7",
|
||||
"f24" : "fs8",
|
||||
"f25" : "fs9",
|
||||
"f26" : "fs10",
|
||||
"f27" : "fs11",
|
||||
"f28" : "ft8",
|
||||
"f29" : "ft9",
|
||||
"f30" : "ft10",
|
||||
"f31" : "ft11",
|
||||
}
|
||||
return switcher.get(gpr, "na")
|
||||
"""Convert a general purpose register to its corresponding abi name"""
|
||||
switcher = {
|
||||
"x0" : "zero",
|
||||
"x1" : "ra",
|
||||
"x2" : "sp",
|
||||
"x3" : "gp",
|
||||
"x4" : "tp",
|
||||
"x5" : "t0",
|
||||
"x6" : "t1",
|
||||
"x7" : "t2",
|
||||
"x8" : "s0",
|
||||
"x9" : "s1",
|
||||
"x10": "a0",
|
||||
"x11": "a1",
|
||||
"x12": "a2",
|
||||
"x13": "a3",
|
||||
"x14": "a4",
|
||||
"x15": "a5",
|
||||
"x16": "a6",
|
||||
"x17": "a7",
|
||||
"x18": "s2",
|
||||
"x19": "s3",
|
||||
"x20": "s4",
|
||||
"x21": "s5",
|
||||
"x22": "s6",
|
||||
"x23": "s7",
|
||||
"x24": "s8",
|
||||
"x25": "s9",
|
||||
"x26": "s10",
|
||||
"x27": "s11",
|
||||
"x28": "t3",
|
||||
"x29": "t4",
|
||||
"x30": "t5",
|
||||
"x31": "t6",
|
||||
"f0" : "ft0",
|
||||
"f1" : "ft1",
|
||||
"f2" : "ft2",
|
||||
"f3" : "ft3",
|
||||
"f4" : "ft4",
|
||||
"f5" : "ft5",
|
||||
"f6" : "ft6",
|
||||
"f7" : "ft7",
|
||||
"f8" : "fs0",
|
||||
"f9" : "fs1",
|
||||
"f10": "fa0",
|
||||
"f11": "fa1",
|
||||
"f12": "fa2",
|
||||
"f13": "fa3",
|
||||
"f14": "fa4",
|
||||
"f15": "fa5",
|
||||
"f16": "fa6",
|
||||
"f17": "fa7",
|
||||
"f18": "fs2",
|
||||
"f19": "fs3",
|
||||
"f20": "fs4",
|
||||
"f21": "fs5",
|
||||
"f22": "fs6",
|
||||
"f23": "fs7",
|
||||
"f24": "fs8",
|
||||
"f25": "fs9",
|
||||
"f26": "fs10",
|
||||
"f27": "fs11",
|
||||
"f28": "ft8",
|
||||
"f29": "ft9",
|
||||
"f30": "ft10",
|
||||
"f31": "ft11",
|
||||
}
|
||||
return switcher.get(gpr, "na")
|
||||
|
||||
|
||||
def sint_to_hex(val):
|
||||
"""Signed integer to hex conversion"""
|
||||
return str(hex((val + (1 << 32)) % (1 << 32)))
|
||||
"""Signed integer to hex conversion"""
|
||||
return str(hex((val + (1 << 32)) % (1 << 32)))
|
||||
|
||||
|
||||
BASE_RE = re.compile(
|
||||
r"(?P<rd>[a-z0-9]+?),(?P<imm>[\-0-9]*?)\((?P<rs1>[a-z0-9]+?)\)")
|
||||
|
||||
BASE_RE = re.compile(r"(?P<rd>[a-z0-9]+?),(?P<imm>[\-0-9]*?)\((?P<rs1>[a-z0-9]+?)\)")
|
||||
|
||||
def convert_pseudo_instr(instr_name, operands, binary):
|
||||
"""Convert pseudo instruction to regular instruction"""
|
||||
if instr_name == "nop":
|
||||
instr_name = "addi"
|
||||
operands = "zero,zero,0"
|
||||
elif instr_name == "mv":
|
||||
instr_name = "addi"
|
||||
operands = operands + ",0"
|
||||
elif instr_name == "not":
|
||||
instr_name = "xori"
|
||||
operands = operands + ",-1"
|
||||
elif instr_name == "neg":
|
||||
instr_name = "sub"
|
||||
o = operands.split(",")
|
||||
operands = o[0] + ",zero," + o[1]
|
||||
elif instr_name == "negw":
|
||||
instr_name = "subw"
|
||||
o = operands.split(",")
|
||||
operands = o[0] + ",zero," + o[1]
|
||||
elif instr_name == "sext.w":
|
||||
instr_name = "addiw"
|
||||
operands = operands + ",0"
|
||||
elif instr_name == "seqz":
|
||||
instr_name = "sltiu"
|
||||
operands = operands + ",1"
|
||||
elif instr_name == "snez":
|
||||
instr_name = "sltu"
|
||||
o = operands.split(",")
|
||||
operands = o[0] + ",zero," + o[1]
|
||||
elif instr_name == "sltz":
|
||||
instr_name = "slt"
|
||||
operands = operands + ",zero"
|
||||
elif instr_name == "sgtz":
|
||||
instr_name = "slt"
|
||||
o = operands.split(",")
|
||||
operands = o[0] + ",zero," + o[1]
|
||||
elif instr_name in ["beqz", "bnez", "bgez", "bltz"]:
|
||||
instr_name = instr_name[0:3]
|
||||
o = operands.split(",")
|
||||
operands = o[0] + ",zero," + o[1]
|
||||
elif instr_name == "blez":
|
||||
instr_name = "bge";
|
||||
operands = "zero," + operands
|
||||
elif instr_name == "bgtz":
|
||||
instr_name = "blt";
|
||||
operands = "zero," + operands
|
||||
elif instr_name == "bgt":
|
||||
instr_name = "blt";
|
||||
o = operands.split(",")
|
||||
operands = o[1] + "," + o[0] + "," + o[2]
|
||||
elif instr_name == "ble":
|
||||
instr_name = "bge";
|
||||
o = operands.split(",")
|
||||
operands = o[1] + "," + o[0] + "," + o[2]
|
||||
elif instr_name == "bgtu":
|
||||
instr_name = "bltu";
|
||||
o = operands.split(",")
|
||||
operands = o[1] + "," + o[0] + "," + o[2]
|
||||
elif instr_name == "bleu":
|
||||
instr_name = "bgeu";
|
||||
o = operands.split(",")
|
||||
operands = o[1] + "," + o[0] + "," + o[2]
|
||||
elif instr_name == "csrr":
|
||||
instr_name = "csrrw"
|
||||
operands = operands + ",zero"
|
||||
elif instr_name in ["csrw", "csrs", "csrc"]:
|
||||
instr_name = "csrr" + instr_name[3:]
|
||||
operands = "zero," + operands
|
||||
elif instr_name in ["csrwi", "csrsi", "csrci"]:
|
||||
instr_name = "csrr" + instr_name[3:]
|
||||
operands = "zero," + operands
|
||||
elif instr_name == "jr":
|
||||
instr_name = "jalr"
|
||||
operands = "zero,%s,0" % operands
|
||||
elif instr_name == "j":
|
||||
instr_name = "jal"
|
||||
operands = "zero,%s" % operands
|
||||
elif instr_name == "jal":
|
||||
if not ("," in operands):
|
||||
operands = "ra,%s" % operands
|
||||
elif instr_name == "jalr":
|
||||
m = BASE_RE.search(operands)
|
||||
# jalr rd, imm(rs1)
|
||||
if m:
|
||||
operands = "%s,%s,%s" % (m.group("rd"), m.group("rs1"), m.group("imm"))
|
||||
# jalr rs1
|
||||
idx = operands.rfind(",")
|
||||
if idx == -1:
|
||||
operands = "ra," + operands + ",0"
|
||||
elif instr_name == "ret":
|
||||
if binary[-1] == "2":
|
||||
instr_name = "c.jr"
|
||||
operands = "ra"
|
||||
else:
|
||||
instr_name = "jalr"
|
||||
operands = "zero,ra,0"
|
||||
return instr_name, operands
|
||||
"""Convert pseudo instruction to regular instruction"""
|
||||
if instr_name == "nop":
|
||||
instr_name = "addi"
|
||||
operands = "zero,zero,0"
|
||||
elif instr_name == "mv":
|
||||
instr_name = "addi"
|
||||
operands = operands + ",0"
|
||||
elif instr_name == "not":
|
||||
instr_name = "xori"
|
||||
operands = operands + ",-1"
|
||||
elif instr_name == "neg":
|
||||
instr_name = "sub"
|
||||
o = operands.split(",")
|
||||
operands = o[0] + ",zero," + o[1]
|
||||
elif instr_name == "negw":
|
||||
instr_name = "subw"
|
||||
o = operands.split(",")
|
||||
operands = o[0] + ",zero," + o[1]
|
||||
elif instr_name == "sext.w":
|
||||
instr_name = "addiw"
|
||||
operands = operands + ",0"
|
||||
elif instr_name == "seqz":
|
||||
instr_name = "sltiu"
|
||||
operands = operands + ",1"
|
||||
elif instr_name == "snez":
|
||||
instr_name = "sltu"
|
||||
o = operands.split(",")
|
||||
operands = o[0] + ",zero," + o[1]
|
||||
elif instr_name == "sltz":
|
||||
instr_name = "slt"
|
||||
operands = operands + ",zero"
|
||||
elif instr_name == "sgtz":
|
||||
instr_name = "slt"
|
||||
o = operands.split(",")
|
||||
operands = o[0] + ",zero," + o[1]
|
||||
elif instr_name in ["beqz", "bnez", "bgez", "bltz"]:
|
||||
instr_name = instr_name[0:3]
|
||||
o = operands.split(",")
|
||||
operands = o[0] + ",zero," + o[1]
|
||||
elif instr_name == "blez":
|
||||
instr_name = "bge"
|
||||
operands = "zero," + operands
|
||||
elif instr_name == "bgtz":
|
||||
instr_name = "blt"
|
||||
operands = "zero," + operands
|
||||
elif instr_name == "bgt":
|
||||
instr_name = "blt"
|
||||
o = operands.split(",")
|
||||
operands = o[1] + "," + o[0] + "," + o[2]
|
||||
elif instr_name == "ble":
|
||||
instr_name = "bge"
|
||||
o = operands.split(",")
|
||||
operands = o[1] + "," + o[0] + "," + o[2]
|
||||
elif instr_name == "bgtu":
|
||||
instr_name = "bltu"
|
||||
o = operands.split(",")
|
||||
operands = o[1] + "," + o[0] + "," + o[2]
|
||||
elif instr_name == "bleu":
|
||||
instr_name = "bgeu"
|
||||
o = operands.split(",")
|
||||
operands = o[1] + "," + o[0] + "," + o[2]
|
||||
elif instr_name == "csrr":
|
||||
instr_name = "csrrw"
|
||||
operands = operands + ",zero"
|
||||
elif instr_name in ["csrw", "csrs", "csrc"]:
|
||||
instr_name = "csrr" + instr_name[3:]
|
||||
operands = "zero," + operands
|
||||
elif instr_name in ["csrwi", "csrsi", "csrci"]:
|
||||
instr_name = "csrr" + instr_name[3:]
|
||||
operands = "zero," + operands
|
||||
elif instr_name == "jr":
|
||||
instr_name = "jalr"
|
||||
operands = "zero,{},0".format(operands)
|
||||
elif instr_name == "j":
|
||||
instr_name = "jal"
|
||||
operands = "zero,{}".format(operands)
|
||||
elif instr_name == "jal":
|
||||
if not ("," in operands):
|
||||
operands = "ra,{}".format(operands)
|
||||
elif instr_name == "jalr":
|
||||
m = BASE_RE.search(operands)
|
||||
# jalr rd, imm(rs1)
|
||||
if m:
|
||||
operands = "{},{},{}".format(m.group("rd"), m.group("rs1"), m.group("imm"))
|
||||
# jalr rs1
|
||||
idx = operands.rfind(",")
|
||||
if idx == -1:
|
||||
operands = "ra," + operands + ",0"
|
||||
elif instr_name == "ret":
|
||||
if binary[-1] == "2":
|
||||
instr_name = "c.jr"
|
||||
operands = "ra"
|
||||
else:
|
||||
instr_name = "jalr"
|
||||
operands = "zero,ra,0"
|
||||
# RV32B pseudo instructions
|
||||
# TODO: support "rev", "orc", and "zip/unzip" instructions for RV64
|
||||
elif instr_name == "rev.p":
|
||||
instr_name = "grevi"
|
||||
operands += ",1"
|
||||
elif instr_name == "rev2.n":
|
||||
instr_name = "grevi"
|
||||
operands += ",2"
|
||||
elif instr_name == "rev.n":
|
||||
instr_name = "grevi"
|
||||
operands += ",3"
|
||||
elif instr_name == "rev4.b":
|
||||
instr_name = "grevi"
|
||||
operands += ",4"
|
||||
elif instr_name == "rev2.b":
|
||||
instr_name = "grevi"
|
||||
operands += ",6"
|
||||
elif instr_name == "rev.b":
|
||||
instr_name = "grevi"
|
||||
operands += ",7"
|
||||
elif instr_name == "rev8.h":
|
||||
instr_name = "grevi"
|
||||
operands += ",8"
|
||||
elif instr_name == "rev4.h":
|
||||
instr_name = "grevi"
|
||||
operands += ",12"
|
||||
elif instr_name == "rev2.h":
|
||||
instr_name = "grevi"
|
||||
operands += ",14"
|
||||
elif instr_name == "rev.h":
|
||||
instr_name = "grevi"
|
||||
operands += ",15"
|
||||
elif instr_name == "rev16":
|
||||
instr_name = "grevi"
|
||||
operands += ",16"
|
||||
elif instr_name == "rev8":
|
||||
instr_name = "grevi"
|
||||
operands += ",24"
|
||||
elif instr_name == "rev4":
|
||||
instr_name = "grevi"
|
||||
operands += ",28"
|
||||
elif instr_name == "rev2":
|
||||
instr_name = "grevi"
|
||||
operands += ",30"
|
||||
elif instr_name == "rev":
|
||||
instr_name = "grevi"
|
||||
operands += ",31"
|
||||
elif instr_name == "orc.p":
|
||||
instr_name = "gorci"
|
||||
operands += ",1"
|
||||
elif instr_name == "orc2.n":
|
||||
instr_name = "gorci"
|
||||
operands += ",2"
|
||||
elif instr_name == "orc.n":
|
||||
instr_name = "gorci"
|
||||
operands += ",3"
|
||||
elif instr_name == "orc4.b":
|
||||
instr_name = "gorci"
|
||||
operands += ",4"
|
||||
elif instr_name == "orc2.b":
|
||||
instr_name = "gorci"
|
||||
operands += ",6"
|
||||
elif instr_name == "orc.b":
|
||||
instr_name = "gorci"
|
||||
operands += ",7"
|
||||
elif instr_name == "orc8.h":
|
||||
instr_name = "gorci"
|
||||
operands += ",8"
|
||||
elif instr_name == "orc4.h":
|
||||
instr_name = "gorci"
|
||||
operands += ",12"
|
||||
elif instr_name == "orc2.h":
|
||||
instr_name = "gorci"
|
||||
operands += ",14"
|
||||
elif instr_name == "orc.h":
|
||||
instr_name = "gorci"
|
||||
operands += ",15"
|
||||
elif instr_name == "orc16":
|
||||
instr_name = "gorci"
|
||||
operands += ",16"
|
||||
elif instr_name == "orc8":
|
||||
instr_name = "gorci"
|
||||
operands += ",24"
|
||||
elif instr_name == "orc4":
|
||||
instr_name = "gorci"
|
||||
operands += ",28"
|
||||
elif instr_name == "orc2":
|
||||
instr_name = "gorci"
|
||||
operands += ",30"
|
||||
elif instr_name == "orc":
|
||||
instr_name = "gorci"
|
||||
operands += ",31"
|
||||
elif instr_name == "zext.b":
|
||||
instr_name = "andi"
|
||||
operands += ",255"
|
||||
elif instr_name == "zext.h":
|
||||
# TODO: support for RV64B
|
||||
instr_name = "pack"
|
||||
operands += ",zero"
|
||||
elif instr_name == "zext.w":
|
||||
instr_name = "pack"
|
||||
operands += ",zero"
|
||||
elif instr_name == "sext.w":
|
||||
instr_name = "addiw"
|
||||
operands += ",0"
|
||||
elif instr_name == "zip.n":
|
||||
instr_name = "shfli"
|
||||
operands += ",1"
|
||||
elif instr_name == "unzip.n":
|
||||
instr_name = "unshfli"
|
||||
operands += ",1"
|
||||
elif instr_name == "zip2.b":
|
||||
instr_name = "shfli"
|
||||
operands += ",2"
|
||||
elif instr_name == "unzip2.b":
|
||||
instr_name = "unshfli"
|
||||
operands += ",2"
|
||||
elif instr_name == "zip.b":
|
||||
instr_name = "shfli"
|
||||
operands += ",3"
|
||||
elif instr_name == "unzip.b":
|
||||
instr_name = "unshfli"
|
||||
operands += ",3"
|
||||
elif instr_name == "zip4.h":
|
||||
instr_name = "shfli"
|
||||
operands += ",4"
|
||||
elif instr_name == "unzip4.h":
|
||||
instr_name = "unshfli"
|
||||
operands += ",4"
|
||||
elif instr_name == "zip2.h":
|
||||
instr_name = "shfli"
|
||||
operands += ",6"
|
||||
elif instr_name == "unzip2.h":
|
||||
instr_name = "unshfli"
|
||||
operands += ",6"
|
||||
elif instr_name == "zip.h":
|
||||
instr_name = "shfli"
|
||||
operands += ",7"
|
||||
elif instr_name == "unzip.h":
|
||||
instr_name = "unshfli"
|
||||
operands += ",7"
|
||||
elif instr_name == "zip8":
|
||||
instr_name = "shfli"
|
||||
operands += ",8"
|
||||
elif instr_name == "unzip8":
|
||||
instr_name = "unshfli"
|
||||
operands += ",8"
|
||||
elif instr_name == "zip4":
|
||||
instr_name = "shfli"
|
||||
operands += ",12"
|
||||
elif instr_name == "unzip4":
|
||||
instr_name = "unshfli"
|
||||
operands += ",12"
|
||||
elif instr_name == "zip2":
|
||||
instr_name = "shfli"
|
||||
operands += ",14"
|
||||
elif instr_name == "unzip2":
|
||||
instr_name = "unshfli"
|
||||
operands += ",14"
|
||||
elif instr_name == "zip":
|
||||
instr_name = "shfli"
|
||||
operands += ",15"
|
||||
elif instr_name == "unzip":
|
||||
instr_name = "unshfli"
|
||||
operands += ",15"
|
||||
return instr_name, operands
|
||||
|
|
|
@ -27,186 +27,200 @@ from lib import *
|
|||
from riscv_trace_csv import *
|
||||
|
||||
INSTR_RE = re.compile(r"riscvOVPsim.*, 0x(?P<addr>.*?)(?P<section>\(.*\): ?)" \
|
||||
"(?P<mode>[A-Za-z]*?)\s+(?P<bin>[a-f0-9]*?)\s+(?P<instr_str>.*?)$")
|
||||
"(?P<mode>[A-Za-z]*?)\s+(?P<bin>[a-f0-9]*?)\s+(?P<instr_str>.*?)$")
|
||||
RD_RE = re.compile(r" (?P<r>[a-z]*[0-9]{0,2}?) (?P<pre>[a-f0-9]+?)" \
|
||||
" -> (?P<val>[a-f0-9]+?)$")
|
||||
BASE_RE = re.compile(r"(?P<rd>[a-z0-9]+?),(?P<imm>[\-0-9]*?)\((?P<rs1>[a-z0-9]+?)\)")
|
||||
" -> (?P<val>[a-f0-9]+?)$")
|
||||
BASE_RE = re.compile(
|
||||
r"(?P<rd>[a-z0-9]+?),(?P<imm>[\-0-9]*?)\((?P<rs1>[a-z0-9]+?)\)")
|
||||
|
||||
|
||||
def convert_mode(pri, line, stop_on_first_error=False):
|
||||
""" OVPsim uses text string, convert to numeric """
|
||||
if "Machine" in pri: return str(3)
|
||||
if "Supervisor" in pri: return str(1)
|
||||
if "User" in pri: return str(0)
|
||||
logging.error("convert_mode = UNKNOWN PRIV MODE [%s]: %s" % (pri, line))
|
||||
if stop_on_first_error:
|
||||
sys.exit(RET_FATAL)
|
||||
""" OVPsim uses text string, convert to numeric """
|
||||
if "Machine" in pri:
|
||||
return str(3)
|
||||
if "Supervisor" in pri:
|
||||
return str(1)
|
||||
if "User" in pri:
|
||||
return str(0)
|
||||
logging.error("convert_mode = UNKNOWN PRIV MODE [{}]: {}".format(pri, line))
|
||||
if stop_on_first_error:
|
||||
sys.exit(RET_FATAL)
|
||||
|
||||
|
||||
def is_csr(r):
|
||||
""" see if r is a csr """
|
||||
if len(r) > 4:
|
||||
return True
|
||||
elif r[0] in ["m", "u", "d"]:
|
||||
return True
|
||||
elif r in ["frm", "fcsr", "vl", "satp"]:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
""" see if r is a csr """
|
||||
if len(r) > 4:
|
||||
return True
|
||||
elif r[0] in ["m", "u", "d"]:
|
||||
return True
|
||||
elif r in ["frm", "fcsr", "vl", "satp"]:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def process_ovpsim_sim_log(ovpsim_log, csv,
|
||||
stop_on_first_error = 0,
|
||||
dont_truncate_after_first_ecall = 0,
|
||||
full_trace = True):
|
||||
"""Process OVPsim simulation log.
|
||||
stop_on_first_error=0,
|
||||
dont_truncate_after_first_ecall=0,
|
||||
full_trace=True):
|
||||
"""Process OVPsim simulation log.
|
||||
|
||||
Extract instruction and affected register information from ovpsim simulation
|
||||
log and save to a list.
|
||||
"""
|
||||
logging.info("Processing ovpsim log : %s" % ovpsim_log)
|
||||
Extract instruction and affected register information from ovpsim simulation
|
||||
log and save to a list.
|
||||
"""
|
||||
logging.info("Processing ovpsim log : {}".format(ovpsim_log))
|
||||
|
||||
# Remove the header part of ovpsim log
|
||||
cmd = ("sed -i '/Info 1:/,$!d' %s" % ovpsim_log)
|
||||
os.system(cmd)
|
||||
# Remove all instructions after end of trace data (end of program excecution)
|
||||
if dont_truncate_after_first_ecall:
|
||||
cmd = ("sed -i '/^Info --/q' %s" % ovpsim_log)
|
||||
logging.info("Dont truncate logfile after first ecall: %s", ovpsim_log)
|
||||
else:
|
||||
cmd = ("sed -i '/ecall/q' %s" % ovpsim_log)
|
||||
os.system(cmd)
|
||||
# Remove the header part of ovpsim log
|
||||
cmd = ("sed -i '/Info 1:/,$!d' {}".format(ovpsim_log))
|
||||
os.system(cmd)
|
||||
# Remove all instructions after end of trace data (end of program excecution)
|
||||
if dont_truncate_after_first_ecall:
|
||||
cmd = ("sed -i '/^Info --/q' {}".format(ovpsim_log))
|
||||
logging.info("Dont truncate logfile after first ecall: {}".format(ovpsim_log))
|
||||
else:
|
||||
cmd = ("sed -i '/ecall/q' {}".format(ovpsim_log))
|
||||
os.system(cmd)
|
||||
|
||||
instr_cnt = 0
|
||||
with open(ovpsim_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
prev_trace = 0
|
||||
for line in f:
|
||||
# Extract instruction infromation
|
||||
m = INSTR_RE.search(line)
|
||||
if m:
|
||||
if prev_trace: # write out the previous one when find next one
|
||||
trace_csv.write_trace_entry(prev_trace)
|
||||
instr_cnt += 1
|
||||
prev_trace = 0
|
||||
prev_trace = RiscvInstructionTraceEntry()
|
||||
prev_trace.instr_str = m.group("instr_str")
|
||||
prev_trace.pc = m.group("addr")
|
||||
prev_trace.mode = convert_mode(m.group("mode"), line)
|
||||
prev_trace.binary = m.group("bin")
|
||||
if full_trace:
|
||||
prev_trace.instr = prev_trace.instr_str.split(" ")[0]
|
||||
prev_trace.operand = prev_trace.instr_str[len(prev_trace.instr):]
|
||||
prev_trace.operand = prev_trace.operand.replace(" ", "")
|
||||
process_trace(prev_trace)
|
||||
continue
|
||||
# Extract register change value information
|
||||
c = RD_RE.search(line)
|
||||
if c:
|
||||
if is_csr(c.group("r")):
|
||||
prev_trace.csr.append(c.group("r") + ":" + c.group("val"))
|
||||
else:
|
||||
prev_trace.gpr.append(c.group("r") + ":" + c.group("val"))
|
||||
logging.info("Processed instruction count : %d " % instr_cnt)
|
||||
if instr_cnt == 0:
|
||||
logging.error ("No Instructions in logfile: %s" % ovpsim_log)
|
||||
sys.exit(RET_FATAL)
|
||||
logging.info("CSV saved to : %s" % csv)
|
||||
instr_cnt = 0
|
||||
with open(ovpsim_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
prev_trace = 0
|
||||
for line in f:
|
||||
# Extract instruction infromation
|
||||
m = INSTR_RE.search(line)
|
||||
if m:
|
||||
if prev_trace: # write out the previous one when find next one
|
||||
trace_csv.write_trace_entry(prev_trace)
|
||||
instr_cnt += 1
|
||||
prev_trace = 0
|
||||
prev_trace = RiscvInstructionTraceEntry()
|
||||
prev_trace.instr_str = m.group("instr_str")
|
||||
prev_trace.pc = m.group("addr")
|
||||
prev_trace.mode = convert_mode(m.group("mode"), line)
|
||||
prev_trace.binary = m.group("bin")
|
||||
if full_trace:
|
||||
prev_trace.instr = prev_trace.instr_str.split(" ")[0]
|
||||
prev_trace.operand = prev_trace.instr_str[
|
||||
len(prev_trace.instr):]
|
||||
prev_trace.operand = prev_trace.operand.replace(" ", "")
|
||||
process_trace(prev_trace)
|
||||
continue
|
||||
# Extract register change value information
|
||||
c = RD_RE.search(line)
|
||||
if c:
|
||||
if is_csr(c.group("r")):
|
||||
prev_trace.csr.append(c.group("r") + ":" + c.group("val"))
|
||||
else:
|
||||
prev_trace.gpr.append(c.group("r") + ":" + c.group("val"))
|
||||
logging.info("Processed instruction count : {} ".format(instr_cnt))
|
||||
if instr_cnt == 0:
|
||||
logging.error("No Instructions in logfile: {}".format(ovpsim_log))
|
||||
sys.exit(RET_FATAL)
|
||||
logging.info("CSV saved to : {}".format(csv))
|
||||
|
||||
|
||||
def process_trace(trace):
|
||||
""" Process instruction operands """
|
||||
process_compressed_instr(trace)
|
||||
process_imm(trace)
|
||||
if trace.instr == "jalr":
|
||||
process_jalr(trace)
|
||||
trace.instr, trace.operand = convert_pseudo_instr(
|
||||
trace.instr, trace.operand, trace.binary)
|
||||
trace.operand = trace.operand.replace(")", "")
|
||||
trace.operand = trace.operand.replace("(", ",")
|
||||
""" Process instruction operands """
|
||||
process_compressed_instr(trace)
|
||||
process_imm(trace)
|
||||
if trace.instr == "jalr":
|
||||
process_jalr(trace)
|
||||
trace.instr, trace.operand = convert_pseudo_instr(
|
||||
trace.instr, trace.operand, trace.binary)
|
||||
# process any instruction of the form:
|
||||
# <instr> <reg> <imm>(<reg>)
|
||||
m = BASE_RE.search(trace.operand)
|
||||
if m:
|
||||
trace.operand = "{},{},{}".format(
|
||||
m.group("rd"), m.group("rs1"), m.group("imm"))
|
||||
|
||||
|
||||
def process_imm(trace):
|
||||
""" Process imm to follow RISC-V standard convention """
|
||||
if trace.instr in ['beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu', 'c.beqz',
|
||||
'c.bnez', 'beqz', 'bnez', 'bgez', 'bltz', 'blez', 'bgtz'
|
||||
'c.j', "j", "c.jal", "jal"]:
|
||||
# convert from ovpsim logs branch/jump offsets as absolute to relative
|
||||
idx = trace.operand.rfind(",")
|
||||
if idx == -1:
|
||||
imm = trace.operand
|
||||
imm = str(sint_to_hex(int(imm, 16) - int(trace.pc, 16)))
|
||||
trace.operand = imm
|
||||
else:
|
||||
imm = trace.operand[idx+1:]
|
||||
imm = str(sint_to_hex(int(imm, 16) - int(trace.pc, 16)))
|
||||
trace.operand = trace.operand[0:idx+1] + imm
|
||||
""" Process imm to follow RISC-V standard convention """
|
||||
if trace.instr in ['beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu', 'c.beqz',
|
||||
'c.bnez', 'beqz', 'bnez', 'bgez', 'bltz', 'blez', 'bgtz',
|
||||
'c.j','j', 'c.jal', 'jal']:
|
||||
# convert from ovpsim logs branch/jump offsets as absolute to relative
|
||||
idx = trace.operand.rfind(",")
|
||||
if idx == -1:
|
||||
imm = trace.operand
|
||||
imm = str(sint_to_hex(int(imm, 16) - int(trace.pc, 16)))
|
||||
trace.operand = imm
|
||||
else:
|
||||
imm = trace.operand[idx + 1:]
|
||||
imm = str(sint_to_hex(int(imm, 16) - int(trace.pc, 16)))
|
||||
trace.operand = trace.operand[0:idx + 1] + imm
|
||||
|
||||
|
||||
def process_jalr(trace):
|
||||
""" process jalr """
|
||||
## jalr x3
|
||||
## jalr 9(x3)
|
||||
## jalr x2,x3
|
||||
## jalr x2,4(x3)
|
||||
idx = trace.operand.rfind(",")
|
||||
if idx == -1:
|
||||
# Add default destination register : ra
|
||||
trace.operand = "ra," + trace.operand
|
||||
m = BASE_RE.search(trace.operand)
|
||||
if m:
|
||||
# Convert pseudo JALR format to normal format
|
||||
trace.operand = "%s,%s,%s" % (m.group("rd"), m.group("rs1"), m.group("imm"))
|
||||
else:
|
||||
# Add default imm 0
|
||||
trace.operand = trace.operand + ",0"
|
||||
""" process jalr """
|
||||
## jalr x3
|
||||
## jalr 9(x3)
|
||||
## jalr x2,x3
|
||||
## jalr x2,4(x3)
|
||||
idx = trace.operand.rfind(",")
|
||||
if idx == -1:
|
||||
# Add default destination register : ra
|
||||
trace.operand = "ra," + trace.operand
|
||||
m = BASE_RE.search(trace.operand)
|
||||
if m:
|
||||
# Convert pseudo JALR format to normal format
|
||||
trace.operand = "{},{},{}".format(
|
||||
m.group("rd"), m.group("rs1"), m.group("imm"))
|
||||
else:
|
||||
# Add default imm 0
|
||||
trace.operand = trace.operand + ",0"
|
||||
|
||||
|
||||
def process_compressed_instr(trace):
|
||||
""" convert naming for compressed instructions """
|
||||
trace_binary = int(trace.binary, 16)
|
||||
o = trace.operand.split(",")
|
||||
if len(trace.binary) == 4: # compressed are always 4 hex digits
|
||||
trace.instr = "c." + trace.instr
|
||||
if ("sp,sp," in trace.operand) and (trace.instr == "c.addi"):
|
||||
trace.instr = "c.addi16sp"
|
||||
idx = trace.operand.rfind(",")
|
||||
trace.operand = "sp," + trace.operand[idx+1:]
|
||||
elif (",sp," in trace.operand) and (trace.instr == "c.addi"):
|
||||
trace.instr = "c.addi4spn"
|
||||
elif ("(sp)" in trace.operand) and (trace_binary % 4 != 0):
|
||||
trace.instr = trace.instr + "sp"
|
||||
if not ("(" in trace.operand):
|
||||
# OVPSIM use non-compressed instruction format in the trace,
|
||||
# need to remove duplicated rs1/rd
|
||||
if len(o) > 2:
|
||||
trace.operand = ",".join(o[1:])
|
||||
if trace.instr == "c.jal":
|
||||
trace.operand = o[1]
|
||||
""" convert naming for compressed instructions """
|
||||
trace_binary = int(trace.binary, 16)
|
||||
o = trace.operand.split(",")
|
||||
if len(trace.binary) == 4: # compressed are always 4 hex digits
|
||||
trace.instr = "c." + trace.instr
|
||||
if ("sp,sp," in trace.operand) and (trace.instr == "c.addi"):
|
||||
trace.instr = "c.addi16sp"
|
||||
idx = trace.operand.rfind(",")
|
||||
trace.operand = "sp," + trace.operand[idx + 1:]
|
||||
elif (",sp," in trace.operand) and (trace.instr == "c.addi"):
|
||||
trace.instr = "c.addi4spn"
|
||||
elif ("(sp)" in trace.operand) and (trace_binary % 4 != 0):
|
||||
trace.instr = trace.instr + "sp"
|
||||
if not ("(" in trace.operand):
|
||||
# OVPSIM use non-compressed instruction format in the trace,
|
||||
# need to remove duplicated rs1/rd
|
||||
if len(o) > 2:
|
||||
trace.operand = ",".join(o[1:])
|
||||
if trace.instr == "c.jal":
|
||||
trace.operand = o[1]
|
||||
|
||||
|
||||
def main():
|
||||
""" if used standalone set up for testing """
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input ovpsim simulation log")
|
||||
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
parser.add_argument("--verbose", dest="verbose", action="store_true",
|
||||
help="Verbose logging")
|
||||
parser.add_argument("--stop_on_first_error", dest="stop_on_first_error",
|
||||
action="store_true",
|
||||
help="Stop on first error")
|
||||
parser.add_argument("--dont_truncate_after_first_ecall",
|
||||
dest="dont_truncate_after_first_ecall",
|
||||
action="store_true",
|
||||
help="Dont truncate on first ecall")
|
||||
parser.set_defaults(verbose=False)
|
||||
parser.set_defaults(stop_on_first_error=False)
|
||||
parser.set_defaults(dont_truncate_after_first_ecall=False)
|
||||
args = parser.parse_args()
|
||||
# Process ovpsim log
|
||||
process_ovpsim_sim_log(args.log,
|
||||
args.csv,
|
||||
args.stop_on_first_error,
|
||||
args.dont_truncate_after_first_ecall)
|
||||
""" if used standalone set up for testing """
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input ovpsim simulation log")
|
||||
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
parser.add_argument("--verbose", dest="verbose", action="store_true",
|
||||
help="Verbose logging")
|
||||
parser.add_argument("--stop_on_first_error", dest="stop_on_first_error",
|
||||
action="store_true",
|
||||
help="Stop on first error")
|
||||
parser.add_argument("--dont_truncate_after_first_ecall",
|
||||
dest="dont_truncate_after_first_ecall",
|
||||
action="store_true",
|
||||
help="Dont truncate on first ecall")
|
||||
parser.set_defaults(verbose=False)
|
||||
parser.set_defaults(stop_on_first_error=False)
|
||||
parser.set_defaults(dont_truncate_after_first_ecall=False)
|
||||
args = parser.parse_args()
|
||||
# Process ovpsim log
|
||||
process_ovpsim_sim_log(args.log,
|
||||
args.csv,
|
||||
args.stop_on_first_error,
|
||||
args.dont_truncate_after_first_ecall)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
127
vendor/google_riscv-dv/scripts/riscv_trace_csv.py
vendored
127
vendor/google_riscv-dv/scripts/riscv_trace_csv.py
vendored
|
@ -22,77 +22,80 @@ import logging
|
|||
import sys
|
||||
from lib import *
|
||||
|
||||
class RiscvInstructionTraceEntry(object):
|
||||
"""RISC-V instruction trace entry"""
|
||||
def __init__(self):
|
||||
self.gpr = []
|
||||
self.csr = []
|
||||
self.instr = ""
|
||||
self.operand = ""
|
||||
self.pc = ""
|
||||
self.binary = ""
|
||||
self.instr_str = ""
|
||||
self.mode = ""
|
||||
|
||||
def get_trace_string(self):
|
||||
"""Return a short string of the trace entry"""
|
||||
return ("pc[%s] %s: %s %s" %
|
||||
(self.pc, self.instr_str, " ".join(self.gpr), " ".join(self.csr)))
|
||||
class RiscvInstructionTraceEntry(object):
|
||||
"""RISC-V instruction trace entry"""
|
||||
|
||||
def __init__(self):
|
||||
self.gpr = []
|
||||
self.csr = []
|
||||
self.instr = ""
|
||||
self.operand = ""
|
||||
self.pc = ""
|
||||
self.binary = ""
|
||||
self.instr_str = ""
|
||||
self.mode = ""
|
||||
|
||||
def get_trace_string(self):
|
||||
"""Return a short string of the trace entry"""
|
||||
return ("pc[{}] {}: {} {}".format(
|
||||
self.pc, self.instr_str, " ".join(self.gpr), " ".join(self.csr)))
|
||||
|
||||
|
||||
class RiscvInstructionTraceCsv(object):
|
||||
"""RISC-V instruction trace CSV class
|
||||
"""RISC-V instruction trace CSV class
|
||||
|
||||
This class provides functions to read/write trace CSV
|
||||
"""
|
||||
def __init__(self, csv_fd):
|
||||
self.csv_fd = csv_fd
|
||||
This class provides functions to read/write trace CSV
|
||||
"""
|
||||
|
||||
def __init__(self, csv_fd):
|
||||
self.csv_fd = csv_fd
|
||||
|
||||
def start_new_trace(self):
|
||||
"""Create a CSV file handle for a new trace"""
|
||||
fields = [
|
||||
"pc", "instr", "gpr", "csr", "binary", "mode", "instr_str", "operand", "pad"]
|
||||
self.csv_writer = csv.DictWriter(self.csv_fd, fieldnames=fields)
|
||||
self.csv_writer.writeheader()
|
||||
def start_new_trace(self):
|
||||
"""Create a CSV file handle for a new trace"""
|
||||
fields = ["pc", "instr", "gpr", "csr", "binary", "mode", "instr_str",
|
||||
"operand", "pad"]
|
||||
self.csv_writer = csv.DictWriter(self.csv_fd, fieldnames=fields)
|
||||
self.csv_writer.writeheader()
|
||||
|
||||
def read_trace(self, trace):
|
||||
"""Read instruction trace from CSV file"""
|
||||
csv_reader = csv.DictReader(self.csv_fd)
|
||||
for row in csv_reader:
|
||||
new_trace = RiscvInstructionTraceEntry()
|
||||
new_trace.gpr = row['gpr'].split(';')
|
||||
new_trace.csr = row['csr'].split(';')
|
||||
new_trace.pc = row['pc']
|
||||
new_trace.operand = row['operand']
|
||||
new_trace.binary = row['binary']
|
||||
new_trace.instr_str = row['instr_str']
|
||||
new_trace.instr = row['instr']
|
||||
new_trace.mode = row['mode']
|
||||
trace.append(new_trace)
|
||||
|
||||
def read_trace(self, trace):
|
||||
"""Read instruction trace from CSV file"""
|
||||
csv_reader = csv.DictReader(self.csv_fd)
|
||||
for row in csv_reader:
|
||||
new_trace = RiscvInstructionTraceEntry()
|
||||
new_trace.gpr = row['gpr'].split(';')
|
||||
new_trace.csr = row['csr'].split(';')
|
||||
new_trace.pc = row['pc']
|
||||
new_trace.operand = row['operand']
|
||||
new_trace.binary = row['binary']
|
||||
new_trace.instr_str = row['instr_str']
|
||||
new_trace.instr = row['instr']
|
||||
new_trace.mode = row['mode']
|
||||
trace.append(new_trace)
|
||||
# TODO: Convert pseudo instruction to regular instruction
|
||||
|
||||
# TODO: Convert pseudo instruction to regular instruction
|
||||
def write_trace_entry(self, entry):
|
||||
"""Write a new trace entry to CSV"""
|
||||
self.csv_writer.writerow({'instr_str': entry.instr_str,
|
||||
'gpr' : ";".join(entry.gpr),
|
||||
'csr' : ";".join(entry.csr),
|
||||
'operand' : entry.operand,
|
||||
'pc' : entry.pc,
|
||||
'binary' : entry.binary,
|
||||
'instr' : entry.instr,
|
||||
'mode' : entry.mode})
|
||||
|
||||
def write_trace_entry(self, entry):
|
||||
"""Write a new trace entry to CSV"""
|
||||
self.csv_writer.writerow({'instr_str' : entry.instr_str,
|
||||
'gpr' : ";".join(entry.gpr),
|
||||
'csr' : ";".join(entry.csr),
|
||||
'operand' : entry.operand,
|
||||
'pc' : entry.pc,
|
||||
'binary' : entry.binary,
|
||||
'instr' : entry.instr,
|
||||
'mode' : entry.mode})
|
||||
|
||||
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:]
|
||||
"""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:]
|
||||
|
|
|
@ -27,69 +27,72 @@ sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
|||
from riscv_trace_csv import *
|
||||
|
||||
START_RE = re.compile(r"\[4\] \[M\]: 0x.*00001010")
|
||||
END_RE = re.compile(r"ecall")
|
||||
END_RE = re.compile(r"ecall")
|
||||
INSTR_RE = re.compile(r"\[[0-9].*\] \[(?P<pri>.)\]: 0x(?P<addr>[A-F0-9]+?)"
|
||||
" \(0x(?P<bin>[A-F0-9]+?)\) (?P<instr>.+?$)")
|
||||
RD_RE = re.compile(r"x(?P<reg>[0-9]+?) <- 0x(?P<val>[A-F0-9]*)")
|
||||
" \(0x(?P<bin>[A-F0-9]+?)\) (?P<instr>.+?$)")
|
||||
RD_RE = re.compile(r"x(?P<reg>[0-9]+?) <- 0x(?P<val>[A-F0-9]*)")
|
||||
|
||||
|
||||
def process_sail_sim_log(sail_log, csv):
|
||||
"""Process SAIL RISCV simulation log.
|
||||
"""Process SAIL RISCV simulation log.
|
||||
|
||||
Extract instruction and affected register information from sail simulation
|
||||
log and save to a list.
|
||||
"""
|
||||
logging.info("Processing sail log : %s" % sail_log)
|
||||
instr_cnt = 0
|
||||
Extract instruction and affected register information from sail simulation
|
||||
log and save to a list.
|
||||
"""
|
||||
logging.info("Processing sail log : {}".format(sail_log))
|
||||
instr_cnt = 0
|
||||
|
||||
with open(sail_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
search_start = 0
|
||||
instr_start = 0
|
||||
trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
instr = None
|
||||
for line in f:
|
||||
# Extract instruction infromation
|
||||
m = START_RE.search(line)
|
||||
if m:
|
||||
search_start = 1
|
||||
continue
|
||||
m = END_RE.search(line)
|
||||
if m:
|
||||
break
|
||||
if search_start:
|
||||
instr = INSTR_RE.search(line)
|
||||
if instr:
|
||||
instr_start = 1
|
||||
pri = instr.group("pri")
|
||||
addr = instr.group("addr").lower()
|
||||
binary = instr.group("bin").lower()
|
||||
instr_str = instr.group("instr")
|
||||
continue
|
||||
if instr_start:
|
||||
m = RD_RE.search(line)
|
||||
if m:
|
||||
# Write the extracted instruction to a csvcol buffer file
|
||||
instr_cnt += 1
|
||||
rv_instr_trace = RiscvInstructionTraceEntry()
|
||||
rv_instr_trace.gpr.append(
|
||||
gpr_to_abi("x%0s" % m.group("reg")) + ":" + m.group("val").lower())
|
||||
rv_instr_trace.mode = pri
|
||||
rv_instr_trace.pc = addr
|
||||
rv_instr_trace.binary = binary
|
||||
rv_instr_trace.instr_str = instr_str
|
||||
trace_csv.write_trace_entry(rv_instr_trace)
|
||||
instr_start = 0
|
||||
logging.info("Processed instruction count : %d" % instr_cnt)
|
||||
with open(sail_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
search_start = 0
|
||||
instr_start = 0
|
||||
trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
instr = None
|
||||
for line in f:
|
||||
# Extract instruction infromation
|
||||
m = START_RE.search(line)
|
||||
if m:
|
||||
search_start = 1
|
||||
continue
|
||||
m = END_RE.search(line)
|
||||
if m:
|
||||
break
|
||||
if search_start:
|
||||
instr = INSTR_RE.search(line)
|
||||
if instr:
|
||||
instr_start = 1
|
||||
pri = instr.group("pri")
|
||||
addr = instr.group("addr").lower()
|
||||
binary = instr.group("bin").lower()
|
||||
instr_str = instr.group("instr")
|
||||
continue
|
||||
if instr_start:
|
||||
m = RD_RE.search(line)
|
||||
if m:
|
||||
# Write the extracted instruction to a csvcol buffer file
|
||||
instr_cnt += 1
|
||||
rv_instr_trace = RiscvInstructionTraceEntry()
|
||||
rv_instr_trace.gpr.append(
|
||||
gpr_to_abi("x{}".format(m.group("reg"))) + ":" + m.group(
|
||||
"val").lower())
|
||||
rv_instr_trace.mode = pri
|
||||
rv_instr_trace.pc = addr
|
||||
rv_instr_trace.binary = binary
|
||||
rv_instr_trace.instr_str = instr_str
|
||||
trace_csv.write_trace_entry(rv_instr_trace)
|
||||
instr_start = 0
|
||||
logging.info("Processed instruction count : {}".format(instr_cnt))
|
||||
|
||||
|
||||
def main():
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input sail simulation log")
|
||||
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
args = parser.parse_args()
|
||||
# Process sail log
|
||||
process_sail_sim_log(args.log, args.csv)
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input sail simulation log")
|
||||
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
args = parser.parse_args()
|
||||
# Process sail log
|
||||
process_sail_sim_log(args.log, args.csv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
|
@ -27,209 +27,220 @@ sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
|||
from riscv_trace_csv import *
|
||||
from lib import *
|
||||
|
||||
RD_RE = re.compile(r"(?P<pri>\d) 0x(?P<addr>[a-f0-9]+?) " \
|
||||
"\((?P<bin>.*?)\) (?P<reg>[xf]\s*\d*?) 0x(?P<val>[a-f0-9]+)")
|
||||
CORE_RE = re.compile(r"core.*0x(?P<addr>[a-f0-9]+?) \(0x(?P<bin>.*?)\) (?P<instr>.*?)$")
|
||||
ILLE_RE = re.compile(r"trap_illegal_instruction")
|
||||
RD_RE = re.compile(r"(?P<pri>\d) 0x(?P<addr>[a-f0-9]+?) " \
|
||||
"\((?P<bin>.*?)\) (?P<reg>[xf]\s*\d*?) 0x(?P<val>[a-f0-9]+)")
|
||||
CORE_RE = re.compile(
|
||||
r"core.*0x(?P<addr>[a-f0-9]+?) \(0x(?P<bin>.*?)\) (?P<instr>.*?)$")
|
||||
ADDR_RE = re.compile(
|
||||
r"(?P<rd>[a-z0-9]+?),(?P<imm>[\-0-9]+?)\((?P<rs1>[a-z0-9]+)\)")
|
||||
ILLE_RE = re.compile(r"trap_illegal_instruction")
|
||||
|
||||
LOGGER = logging.getLogger()
|
||||
|
||||
|
||||
def process_instr(trace):
|
||||
if trace.instr == "jal":
|
||||
# Spike jal format jal rd, -0xf -> jal rd, -15
|
||||
idx = trace.operand.rfind(",")
|
||||
imm = trace.operand[idx+1:]
|
||||
if imm[0] == "-":
|
||||
imm = "-" + str(int(imm[1:], 16))
|
||||
else:
|
||||
imm = str(int(imm, 16))
|
||||
trace.operand = trace.operand[0:idx+1] + imm
|
||||
trace.operand = trace.operand.replace("(", ",")
|
||||
trace.operand = trace.operand.replace(")", "")
|
||||
if trace.instr == "jal":
|
||||
# Spike jal format jal rd, -0xf -> jal rd, -15
|
||||
idx = trace.operand.rfind(",")
|
||||
imm = trace.operand[idx + 1:]
|
||||
if imm[0] == "-":
|
||||
imm = "-" + str(int(imm[1:], 16))
|
||||
else:
|
||||
imm = str(int(imm, 16))
|
||||
trace.operand = trace.operand[0:idx + 1] + imm
|
||||
# Properly format operands of all instructions of the form:
|
||||
# <instr> <reg1> <imm>(<reg2>)
|
||||
# The operands should be converted into CSV as:
|
||||
# "<reg1>,<reg2>,<imm>"
|
||||
m = ADDR_RE.search(trace.operand)
|
||||
if m:
|
||||
trace.operand = "{},{},{}".format(
|
||||
m.group("rd"), m.group("rs1"), m.group("imm"))
|
||||
|
||||
|
||||
def read_spike_instr(match, full_trace):
|
||||
'''Unpack a regex match for CORE_RE to a RiscvInstructionTraceEntry
|
||||
"""Unpack a regex match for CORE_RE to a RiscvInstructionTraceEntry
|
||||
|
||||
If full_trace is true, extract operand data from the disassembled
|
||||
instruction.
|
||||
If full_trace is true, extract operand data from the disassembled
|
||||
instruction.
|
||||
|
||||
'''
|
||||
"""
|
||||
|
||||
# Extract the disassembled instruction.
|
||||
disasm = match.group('instr')
|
||||
# Extract the disassembled instruction.
|
||||
disasm = match.group('instr')
|
||||
|
||||
# Spike's disassembler shows a relative jump as something like "j pc +
|
||||
# 0x123" or "j pc - 0x123". We just want the relative offset.
|
||||
disasm = disasm.replace('pc + ', '').replace('pc - ', '-')
|
||||
# Spike's disassembler shows a relative jump as something like "j pc +
|
||||
# 0x123" or "j pc - 0x123". We just want the relative offset.
|
||||
disasm = disasm.replace('pc + ', '').replace('pc - ', '-')
|
||||
|
||||
instr = RiscvInstructionTraceEntry()
|
||||
instr.pc = match.group('addr')
|
||||
instr.instr_str = disasm
|
||||
instr.binary = match.group('bin')
|
||||
instr = RiscvInstructionTraceEntry()
|
||||
instr.pc = match.group('addr')
|
||||
instr.instr_str = disasm
|
||||
instr.binary = match.group('bin')
|
||||
|
||||
if full_trace:
|
||||
opcode = disasm.split(' ')[0]
|
||||
operand = disasm[len(opcode):].replace(' ', '')
|
||||
instr.instr, instr.operand = \
|
||||
convert_pseudo_instr(opcode, operand, instr.binary)
|
||||
if full_trace:
|
||||
opcode = disasm.split(' ')[0]
|
||||
operand = disasm[len(opcode):].replace(' ', '')
|
||||
instr.instr, instr.operand = \
|
||||
convert_pseudo_instr(opcode, operand, instr.binary)
|
||||
|
||||
process_instr(instr)
|
||||
process_instr(instr)
|
||||
|
||||
return instr
|
||||
return instr
|
||||
|
||||
|
||||
def read_spike_trace(path, full_trace):
|
||||
'''Read a Spike simulation log at <path>, yielding executed instructions.
|
||||
"""Read a Spike simulation log at <path>, yielding executed instructions.
|
||||
|
||||
This assumes that the log was generated with the -l and --log-commits options
|
||||
to Spike.
|
||||
This assumes that the log was generated with the -l and --log-commits options
|
||||
to Spike.
|
||||
|
||||
If full_trace is true, extract operands from the disassembled instructions.
|
||||
If full_trace is true, extract operands from the disassembled instructions.
|
||||
|
||||
Since Spike has a strange trampoline that always runs at the start, we skip
|
||||
instructions up to and including the one at PC 0x1010 (the end of the
|
||||
trampoline). At the end of a DV program, there's an ECALL instruction, which
|
||||
we take as a signal to stop checking, so we ditch everything that follows
|
||||
that instruction.
|
||||
Since Spike has a strange trampoline that always runs at the start, we skip
|
||||
instructions up to and including the one at PC 0x1010 (the end of the
|
||||
trampoline). At the end of a DV program, there's an ECALL instruction, which
|
||||
we take as a signal to stop checking, so we ditch everything that follows
|
||||
that instruction.
|
||||
|
||||
This function yields instructions as it parses them as tuples of the form
|
||||
(entry, illegal). entry is a RiscvInstructionTraceEntry. illegal is a
|
||||
boolean, which is true if the instruction caused an illegal instruction trap.
|
||||
This function yields instructions as it parses them as tuples of the form
|
||||
(entry, illegal). entry is a RiscvInstructionTraceEntry. illegal is a
|
||||
boolean, which is true if the instruction caused an illegal instruction trap.
|
||||
|
||||
'''
|
||||
"""
|
||||
|
||||
# This loop is a simple FSM with states TRAMPOLINE, INSTR, EFFECT. The idea
|
||||
# is that we're in state TRAMPOLINE until we get to the end of Spike's
|
||||
# trampoline, then we switch between INSTR (where we expect to read an
|
||||
# instruction) and EFFECT (where we expect to read commit information).
|
||||
#
|
||||
# We yield a RiscvInstructionTraceEntry object each time we leave EFFECT
|
||||
# (going back to INSTR), we loop back from INSTR to itself, or we get to the
|
||||
# end of the file and have an instruction in hand.
|
||||
#
|
||||
# On entry to the loop body, we are in state TRAMPOLINE if in_trampoline is
|
||||
# true. Otherwise, we are in state EFFECT if instr is not None, otherwise we
|
||||
# are in state INSTR.
|
||||
# This loop is a simple FSM with states TRAMPOLINE, INSTR, EFFECT. The idea
|
||||
# is that we're in state TRAMPOLINE until we get to the end of Spike's
|
||||
# trampoline, then we switch between INSTR (where we expect to read an
|
||||
# instruction) and EFFECT (where we expect to read commit information).
|
||||
#
|
||||
# We yield a RiscvInstructionTraceEntry object each time we leave EFFECT
|
||||
# (going back to INSTR), we loop back from INSTR to itself, or we get to the
|
||||
# end of the file and have an instruction in hand.
|
||||
#
|
||||
# On entry to the loop body, we are in state TRAMPOLINE if in_trampoline is
|
||||
# true. Otherwise, we are in state EFFECT if instr is not None, otherwise we
|
||||
# are in state INSTR.
|
||||
|
||||
end_trampoline_re = re.compile(r'core.*: 0x0*1010 ')
|
||||
end_trampoline_re = re.compile(r'core.*: 0x0*1010 ')
|
||||
|
||||
in_trampoline = True
|
||||
instr = None
|
||||
in_trampoline = True
|
||||
instr = None
|
||||
|
||||
with open(path, 'r') as handle:
|
||||
for line in handle:
|
||||
if in_trampoline:
|
||||
# The TRAMPOLINE state
|
||||
if end_trampoline_re.match(line):
|
||||
in_trampoline = False
|
||||
continue
|
||||
with open(path, 'r') as handle:
|
||||
for line in handle:
|
||||
if in_trampoline:
|
||||
# The TRAMPOLINE state
|
||||
if end_trampoline_re.match(line):
|
||||
in_trampoline = False
|
||||
continue
|
||||
|
||||
if instr is None:
|
||||
# The INSTR state. We expect to see a line matching CORE_RE. We'll
|
||||
# discard any other lines.
|
||||
instr_match = CORE_RE.match(line)
|
||||
if not instr_match:
|
||||
continue
|
||||
if instr is None:
|
||||
# The INSTR state. We expect to see a line matching CORE_RE.
|
||||
# We'll discard any other lines.
|
||||
instr_match = CORE_RE.match(line)
|
||||
if not instr_match:
|
||||
continue
|
||||
|
||||
instr = read_spike_instr(instr_match, full_trace)
|
||||
instr = read_spike_instr(instr_match, full_trace)
|
||||
|
||||
# If instr.instr_str is 'ecall', we should stop.
|
||||
if instr.instr_str == 'ecall':
|
||||
break
|
||||
# If instr.instr_str is 'ecall', we should stop.
|
||||
if instr.instr_str == 'ecall':
|
||||
break
|
||||
|
||||
continue
|
||||
continue
|
||||
|
||||
# The EFFECT state. If the line matches CORE_RE, we should have been in
|
||||
# state INSTR, so we yield the instruction we had, read the new
|
||||
# instruction and continue. As above, if the new instruction is 'ecall',
|
||||
# we need to stop immediately.
|
||||
instr_match = CORE_RE.match(line)
|
||||
if instr_match:
|
||||
yield (instr, False)
|
||||
instr = read_spike_instr(instr_match, full_trace)
|
||||
if instr.instr_str == 'ecall':
|
||||
break
|
||||
continue
|
||||
# The EFFECT state. If the line matches CORE_RE, we should have been in
|
||||
# state INSTR, so we yield the instruction we had, read the new
|
||||
# instruction and continue. As above, if the new instruction is 'ecall',
|
||||
# we need to stop immediately.
|
||||
instr_match = CORE_RE.match(line)
|
||||
if instr_match:
|
||||
yield instr, False
|
||||
instr = read_spike_instr(instr_match, full_trace)
|
||||
if instr.instr_str == 'ecall':
|
||||
break
|
||||
continue
|
||||
|
||||
# The line doesn't match CORE_RE, so we are definitely on a follow-on
|
||||
# line in the log. First, check for illegal instructions
|
||||
if 'trap_illegal_instruction' in line:
|
||||
yield (instr, True)
|
||||
instr = None
|
||||
continue
|
||||
# The line doesn't match CORE_RE, so we are definitely on a follow-on
|
||||
# line in the log. First, check for illegal instructions
|
||||
if 'trap_illegal_instruction' in line:
|
||||
yield (instr, True)
|
||||
instr = None
|
||||
continue
|
||||
|
||||
# The instruction seems to have been fine. Do we have commit data (from
|
||||
# the --log-commits Spike option)?
|
||||
commit_match = RD_RE.match(line)
|
||||
if commit_match:
|
||||
instr.gpr.append(gpr_to_abi(commit_match.group('reg')
|
||||
.replace(' ', '')) +
|
||||
':' + commit_match.group('val'))
|
||||
instr.mode = commit_match.group('pri')
|
||||
# The instruction seems to have been fine. Do we have commit data (from
|
||||
# the --log-commits Spike option)?
|
||||
commit_match = RD_RE.match(line)
|
||||
if commit_match:
|
||||
instr.gpr.append(gpr_to_abi(commit_match.group('reg')
|
||||
.replace(' ', '')) +
|
||||
':' + commit_match.group('val'))
|
||||
instr.mode = commit_match.group('pri')
|
||||
|
||||
# At EOF, we might have an instruction in hand. Yield it if so.
|
||||
if instr is not None:
|
||||
yield (instr, False)
|
||||
# At EOF, we might have an instruction in hand. Yield it if so.
|
||||
if instr is not None:
|
||||
yield (instr, False)
|
||||
|
||||
|
||||
def process_spike_sim_log(spike_log, csv, full_trace = 0):
|
||||
"""Process SPIKE simulation log.
|
||||
def process_spike_sim_log(spike_log, csv, full_trace=0):
|
||||
"""Process SPIKE simulation log.
|
||||
|
||||
Extract instruction and affected register information from spike simulation
|
||||
log and write the results to a CSV file at csv. Returns the number of
|
||||
instructions written.
|
||||
Extract instruction and affected register information from spike simulation
|
||||
log and write the results to a CSV file at csv. Returns the number of
|
||||
instructions written.
|
||||
|
||||
"""
|
||||
logging.info("Processing spike log : %s" % spike_log)
|
||||
instrs_in = 0
|
||||
instrs_out = 0
|
||||
"""
|
||||
logging.info("Processing spike log : {}".format(spike_log))
|
||||
instrs_in = 0
|
||||
instrs_out = 0
|
||||
|
||||
with open(csv, "w") as csv_fd:
|
||||
trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
with open(csv, "w") as csv_fd:
|
||||
trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
|
||||
for (entry, illegal) in read_spike_trace(spike_log, full_trace):
|
||||
instrs_in += 1
|
||||
for (entry, illegal) in read_spike_trace(spike_log, full_trace):
|
||||
instrs_in += 1
|
||||
|
||||
if illegal and full_trace:
|
||||
logging.debug("Illegal instruction: {}, opcode:{}"
|
||||
.format(entry.instr_str, entry.binary))
|
||||
if illegal and full_trace:
|
||||
logging.debug("Illegal instruction: {}, opcode:{}"
|
||||
.format(entry.instr_str, entry.binary))
|
||||
|
||||
# Instructions that cause no architectural update (which includes illegal
|
||||
# instructions) are ignored if full_trace is false.
|
||||
#
|
||||
# We say that an instruction caused an architectural update if either we
|
||||
# saw a commit line (in which case, entry.gpr will contain a single
|
||||
# entry) or the instruction was 'wfi' or 'ecall'.
|
||||
if not (full_trace or entry.gpr or entry.instr_str in ['wfi', 'ecall']):
|
||||
continue
|
||||
# Instructions that cause no architectural update (which includes illegal
|
||||
# instructions) are ignored if full_trace is false.
|
||||
#
|
||||
# We say that an instruction caused an architectural update if either we
|
||||
# saw a commit line (in which case, entry.gpr will contain a single
|
||||
# entry) or the instruction was 'wfi' or 'ecall'.
|
||||
if not (full_trace or entry.gpr or entry.instr_str in ['wfi',
|
||||
'ecall']):
|
||||
continue
|
||||
|
||||
trace_csv.write_trace_entry(entry)
|
||||
instrs_out += 1
|
||||
trace_csv.write_trace_entry(entry)
|
||||
instrs_out += 1
|
||||
|
||||
logging.info("Processed instruction count : %d" % instrs_in)
|
||||
logging.info("CSV saved to : %s" % csv)
|
||||
return instrs_out
|
||||
logging.info("Processed instruction count : {}".format(instrs_in))
|
||||
logging.info("CSV saved to : {}".format(csv))
|
||||
return instrs_out
|
||||
|
||||
|
||||
def main():
|
||||
# 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, args.full_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, args.full_trace)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
|
@ -27,63 +27,67 @@ sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
|||
from riscv_trace_csv import *
|
||||
from lib import *
|
||||
|
||||
INSTR_RE = re.compile(r"#(?P<n>[0-9]+?)\s+(?P<mode>[0-9]+?)\s+(?P<pc>[0-9a-f]+?)\s+" \
|
||||
"(?P<bin>[0-9a-f]+?)\s+(?P<type>[a-z]+?)\s+" \
|
||||
"(?P<reg>[0-9a-f]+?)\s+(?P<val>[0-9a-f]+?)\s+(?P<instr>.*?)$")
|
||||
INSTR_RE = re.compile(
|
||||
r"#(?P<n>[0-9]+?)\s+(?P<mode>[0-9]+?)\s+(?P<pc>[0-9a-f]+?)\s+" \
|
||||
"(?P<bin>[0-9a-f]+?)\s+(?P<type>[a-z]+?)\s+" \
|
||||
"(?P<reg>[0-9a-f]+?)\s+(?P<val>[0-9a-f]+?)\s+(?P<instr>.*?)$")
|
||||
|
||||
LOGGER = logging.getLogger()
|
||||
|
||||
def process_whisper_sim_log(whisper_log, csv, full_trace = 0):
|
||||
"""Process SPIKE simulation log.
|
||||
|
||||
Extract instruction and affected register information from whisper simulation
|
||||
log and save to a list.
|
||||
"""
|
||||
logging.info("Processing whisper log : %s" % whisper_log)
|
||||
instr_cnt = 0
|
||||
whisper_instr = ""
|
||||
def process_whisper_sim_log(whisper_log, csv, full_trace=0):
|
||||
"""Process SPIKE simulation log.
|
||||
|
||||
with open(whisper_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
for line in f:
|
||||
# Extract instruction infromation
|
||||
m = INSTR_RE.search(line)
|
||||
if m:
|
||||
logging.debug("-> mode: %s, pc:%s, bin:%s, instr:%s" %
|
||||
(m.group('mode'), m.group('pc'), m.group('bin'), m.group('instr')))
|
||||
if re.search('ecall', m.group('instr')):
|
||||
break
|
||||
if m.group('type') == 'r':
|
||||
whisper_instr = m.group("instr").replace("\. + ", "")
|
||||
whisper_instr = whisper_instr.replace("\. - ", "-")
|
||||
rv_instr_trace = RiscvInstructionTraceEntry()
|
||||
rv_instr_trace.instr_str = whisper_instr
|
||||
rv_instr_trace.binary = m.group("bin")
|
||||
reg = "x" + str(int(m.group("reg"), 16))
|
||||
rv_instr_trace.gpr.append(gpr_to_abi(reg) + ":" + m.group("val"))
|
||||
trace_csv.write_trace_entry(rv_instr_trace)
|
||||
instr_cnt += 1
|
||||
logging.info("Processed instruction count : %d" % instr_cnt)
|
||||
logging.info("CSV saved to : %s" % csv)
|
||||
Extract instruction and affected register information from whisper simulation
|
||||
log and save to a list.
|
||||
"""
|
||||
logging.info("Processing whisper log : {}".format(whisper_log))
|
||||
instr_cnt = 0
|
||||
whisper_instr = ""
|
||||
|
||||
with open(whisper_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
for line in f:
|
||||
# Extract instruction infromation
|
||||
m = INSTR_RE.search(line)
|
||||
if m:
|
||||
logging.debug("-> mode: {}, pc:{}, bin:{}, instr:{}".format(
|
||||
m.group('mode'), m.group('pc'), m.group('bin'),m.group('instr')))
|
||||
if re.search('ecall', m.group('instr')):
|
||||
break
|
||||
if m.group('type') == 'r':
|
||||
whisper_instr = m.group("instr").replace("\. + ", "")
|
||||
whisper_instr = whisper_instr.replace("\. - ", "-")
|
||||
rv_instr_trace = RiscvInstructionTraceEntry()
|
||||
rv_instr_trace.instr_str = whisper_instr
|
||||
rv_instr_trace.binary = m.group("bin")
|
||||
reg = "x" + str(int(m.group("reg"), 16))
|
||||
rv_instr_trace.gpr.append(
|
||||
gpr_to_abi(reg) + ":" + m.group("val"))
|
||||
trace_csv.write_trace_entry(rv_instr_trace)
|
||||
instr_cnt += 1
|
||||
logging.info("Processed instruction count : {}".format(instr_cnt))
|
||||
logging.info("CSV saved to : {}".format(csv))
|
||||
|
||||
|
||||
def main():
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input whisper simulation log")
|
||||
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
parser.add_argument("-f", "--full_trace", dest="full_trace", action="store_true",
|
||||
help="Generate the full trace")
|
||||
parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
|
||||
help="Verbose logging")
|
||||
parser.set_defaults(full_trace=False)
|
||||
parser.set_defaults(verbose=False)
|
||||
args = parser.parse_args()
|
||||
setup_logging(args.verbose)
|
||||
# Process whisper log
|
||||
process_whisper_sim_log(args.log, args.csv, args.full_trace)
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input whisper simulation log")
|
||||
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
parser.add_argument("-f", "--full_trace", dest="full_trace",
|
||||
action="store_true",
|
||||
help="Generate the full trace")
|
||||
parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
|
||||
help="Verbose logging")
|
||||
parser.set_defaults(full_trace=False)
|
||||
parser.set_defaults(verbose=False)
|
||||
args = parser.parse_args()
|
||||
setup_logging(args.verbose)
|
||||
# Process whisper log
|
||||
process_whisper_sim_log(args.log, args.csv, args.full_trace)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
|
@ -268,10 +268,10 @@
|
|||
I_FORMAT: begin
|
||||
`DV_CHECK_FATAL(operands.size() == 3, instr_name)
|
||||
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);
|
||||
// load rd, imm(rs1) -> rd,rs1,imm
|
||||
rs1 = get_gpr(operands[1]);
|
||||
rs1_value = get_gpr_state(operands[1]);
|
||||
get_val(operands[2], imm);
|
||||
end else if(category == CSR) begin
|
||||
// csrrwi rd, csr, imm
|
||||
get_val(operands[2], imm);
|
||||
|
@ -290,11 +290,12 @@
|
|||
S_FORMAT, B_FORMAT: begin
|
||||
`DV_CHECK_FATAL(operands.size() == 3)
|
||||
if(category == STORE) begin
|
||||
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);
|
||||
// store rs2, imm(rs1) -> rs1,rs2,imm
|
||||
rs2 = get_gpr(operands[1]);
|
||||
rs2_value = get_gpr_state(operands[1]);
|
||||
rs1 = get_gpr(operands[0]);
|
||||
rs1_value = get_gpr_state(operands[0]);
|
||||
get_val(operands[2], imm);
|
||||
end else begin
|
||||
// bne rs1, rs2, imm
|
||||
rs1 = get_gpr(operands[0]);
|
||||
|
@ -358,18 +359,18 @@
|
|||
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]);
|
||||
// c.lw rd, imm(rs1) -> rd,rs1,imm
|
||||
get_val(operands[2], imm);
|
||||
rs1 = get_gpr(operands[1]);
|
||||
rs1_value = get_gpr_state(operands[1]);
|
||||
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);
|
||||
// c.sw rs2,imm(rs1) -> rs1,rs2,imm
|
||||
rs2 = get_gpr(operands[1]);
|
||||
rs2_value = get_gpr_state(operands[1]);
|
||||
rs1 = get_gpr(operands[0]);
|
||||
rs1_value = get_gpr_state(operands[0]);
|
||||
get_val(operands[2], imm);
|
||||
end
|
||||
CA_FORMAT: begin
|
||||
// c.and rd, rs2 (rs1 == rd)
|
||||
|
|
|
@ -26,6 +26,7 @@ class riscv_vector_instr extends riscv_floating_point_instr;
|
|||
rand va_variant_t va_variant;
|
||||
rand bit vm;
|
||||
rand bit wd;
|
||||
rand bit [10:0] eew;
|
||||
bit has_vd = 1'b1;
|
||||
bit has_vs1 = 1'b1;
|
||||
bit has_vs2 = 1'b1;
|
||||
|
@ -39,6 +40,7 @@ class riscv_vector_instr extends riscv_floating_point_instr;
|
|||
va_variant_t allowed_va_variants[$];
|
||||
string sub_extension;
|
||||
rand bit [2:0] nfields; // Used by segmented load/store
|
||||
rand bit [3:0] emul;
|
||||
|
||||
constraint avoid_reserved_vregs_c {
|
||||
if (m_cfg.vector_cfg.reserved_vregs.size() > 0) {
|
||||
|
@ -56,6 +58,7 @@ class riscv_vector_instr extends riscv_floating_point_instr;
|
|||
// Instructions specifying a vector operand with an odd-numbered vector register will raisean
|
||||
// illegal instruction exception.
|
||||
// TODO: Exclude the instruction that ignore VLMUL
|
||||
// TODO: Update this constraint for fractional LMUL
|
||||
constraint operand_group_c {
|
||||
if (m_cfg.vector_cfg.vtype.vlmul > 0) {
|
||||
vd % m_cfg.vector_cfg.vtype.vlmul == 0;
|
||||
|
@ -268,6 +271,38 @@ class riscv_vector_instr extends riscv_floating_point_instr;
|
|||
}
|
||||
}
|
||||
|
||||
// load/store EEW/EMUL and corresponding register grouping constraints
|
||||
constraint load_store_solve_order_c {
|
||||
solve eew before emul;
|
||||
solve emul before vd;
|
||||
solve emul before vs1;
|
||||
solve emul before vs2;
|
||||
solve emul before vs3;
|
||||
}
|
||||
|
||||
constraint load_store_eew_emul_c {
|
||||
if (category inside {LOAD, STORE, AMO}) {
|
||||
eew inside {m_cfg.vector_cfg.legal_eew};
|
||||
if (eew > m_cfg.vector_cfg.vtype.vsew) {
|
||||
emul == eew / m_cfg.vector_cfg.vtype.vsew;
|
||||
} else {
|
||||
emul == 1;
|
||||
}
|
||||
if (emul > 1) {
|
||||
vd % emul == 0;
|
||||
vs1 % emul == 0;
|
||||
vs2 % emul == 0;
|
||||
vs3 % emul == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Some temporarily constraint to avoid illegal instruction
|
||||
// TODO: Review these constraints
|
||||
constraint temp_c {
|
||||
(vm == 0) -> (vd != 0);
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_vector_instr)
|
||||
`uvm_object_new
|
||||
|
||||
|
@ -303,6 +338,22 @@ class riscv_vector_instr extends riscv_floating_point_instr;
|
|||
return 1'b1;
|
||||
endfunction
|
||||
|
||||
virtual function string get_instr_name();
|
||||
string name = super.get_instr_name();
|
||||
if (category inside {LOAD, STORE}) begin
|
||||
// Add eew before ".v" or "ff.v" suffix
|
||||
if (instr_name inside {VLEFF_V, VLSEGEFF_V}) begin
|
||||
name = name.substr(0, name.len() - 5);
|
||||
name = $sformatf("%0s%0dFF.V", name, eew);
|
||||
end else begin
|
||||
name = name.substr(0, name.len() - 3);
|
||||
name = $sformatf("%0s%0d.V", name, eew);
|
||||
end
|
||||
`uvm_info(`gfn, $sformatf("%0s -> %0s", super.get_instr_name(), name), UVM_LOW)
|
||||
end
|
||||
return name;
|
||||
endfunction
|
||||
|
||||
// Convert the instruction to assembly code
|
||||
virtual function string convert2asm(string prefix = "");
|
||||
string asm_str;
|
||||
|
@ -448,6 +499,9 @@ class riscv_vector_instr extends riscv_floating_point_instr;
|
|||
vs2.rand_mode(has_vs2);
|
||||
vs3.rand_mode(has_vs3);
|
||||
vd.rand_mode(has_vd);
|
||||
if (!(category inside {LOAD, STORE, AMO})) begin
|
||||
load_store_solve_order_c.constraint_mode(0);
|
||||
end
|
||||
endfunction : pre_randomize
|
||||
|
||||
virtual function void set_rand_mode();
|
||||
|
@ -504,9 +558,14 @@ class riscv_vector_instr extends riscv_floating_point_instr;
|
|||
string suffix = instr_name.substr(prefix.len(), instr_name.len() - 1);
|
||||
return $sformatf("%0s%0d%0s", prefix, nfields + 1, suffix);
|
||||
endfunction
|
||||
|
||||
|
||||
function string add_eew(string instr_name, string prefix);
|
||||
string suffix = instr_name.substr(prefix.len(), instr_name.len() - 1);
|
||||
return $sformatf("%0s%0d%0s", prefix, eew, suffix);
|
||||
endfunction
|
||||
|
||||
function bit check_sub_extension(string s, string literal);
|
||||
return s == literal;
|
||||
endfunction
|
||||
|
||||
|
||||
endclass : riscv_vector_instr
|
||||
|
|
96
vendor/google_riscv-dv/src/isa/rv32v_instr.sv
vendored
96
vendor/google_riscv-dv/src/isa/rv32v_instr.sv
vendored
|
@ -205,114 +205,32 @@
|
|||
// Section 7.4 - Vector Unit-Stride Instructions
|
||||
`DEFINE_VA_INSTR(VLE_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VSE_V, VS_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VLB_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VSB_V, VS_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VLH_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VSH_V, VS_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VLW_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VSW_V, VS_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VLBU_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLHU_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLWU_V, VL_FORMAT, LOAD, RVV)
|
||||
// Section 7.5 - Vector Strided Instructions
|
||||
`DEFINE_VA_INSTR(VLSB_V, VLS_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLSH_V, VLS_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLSW_V, VLS_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLSBU_V, VLS_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLSHU_V, VLS_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLSWU_V, VLS_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLSE_V, VLS_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VSSB_V, VSS_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSSH_V, VSS_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSSW_V, VSS_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSSE_V, VSS_FORMAT, STORE, RVV)
|
||||
// Section 7.6 - Vector Indexed Instructions
|
||||
`DEFINE_VA_INSTR(VLXB_V, VLX_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLXH_V, VLX_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLXW_V, VLX_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLXBU_V, VLX_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLXHU_V, VLX_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLXWU_V, VLX_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLXE_V, VLX_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VSXB_V, VSX_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSXH_V, VSX_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSXW_V, VSX_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSXE_V, VSX_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSUXB_V, VSX_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSUXH_V, VSX_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSUXW_V, VSX_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSUXE_V, VSX_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VLXEI_V, VLX_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VSXEI_V, VSX_FORMAT, STORE, RVV)
|
||||
`DEFINE_VA_INSTR(VSUXEI_V, VSX_FORMAT, STORE, RVV)
|
||||
// Section 7.7 - Vector Unit-Stride Fault-Only-First Loads
|
||||
`DEFINE_VA_INSTR(VLBFF_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLHFF_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLWFF_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLBUFF_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLHUFF_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLWUFF_V, VL_FORMAT, LOAD, RVV)
|
||||
`DEFINE_VA_INSTR(VLEFF_V, VL_FORMAT, LOAD, RVV)
|
||||
// Section 7.8 - Vector Load/Store Segment Instructions (Zvlsseg)
|
||||
// 7.8.1. Vector Unit Strided Segment Loads and Stores
|
||||
`DEFINE_VA_INSTR(VLSEGE_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSSEGE_V, VS_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGB_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSSEGB_V, VS_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGH_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSSEGH_V, VS_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGW_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSSEGW_V, VS_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGBU_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGHU_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGWU_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGBFF_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGHFF_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGWFF_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGBUFF_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGHUFF_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGWUFF_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSEGEFF_V, VL_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
// 7.8.2. Vector Strided Segment Loads and Stores
|
||||
`DEFINE_VA_INSTR(VLSSEGB_V, VLS_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSSEGH_V, VLS_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSSEGW_V, VLS_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSSEGBU_V, VLS_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSSEGHU_V, VLS_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSSEGWU_V, VLS_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLSSEGE_V, VLS_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSSSEGB_V, VSS_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSSSEGH_V, VSS_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSSSEGW_V, VSS_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSSSEGE_V, VSS_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
// 7.8.3. Vector Indexed Segment Loads and Stores
|
||||
`DEFINE_VA_INSTR(VLXSEGB_V, VLX_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLXSEGH_V, VLX_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLXSEGW_V, VLX_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLXSEGBU_V, VLX_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLXSEGHU_V, VLX_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLXSEGWU_V, VLX_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLXSEGE_V, VLX_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSXSEGB_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSXSEGH_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSXSEGW_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSXSEGE_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSUXSEGB_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSUXSEGH_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSUXSEGW_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSUXSEGE_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VLXSEGEI_V, VLX_FORMAT, LOAD, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSXSEGEI_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
`DEFINE_VA_INSTR(VSUXSEGEI_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Section 8. Vector AMO Operations (Zvamo)
|
||||
// -------------------------------------------------------------------------
|
||||
// 32-bit vector AMOs
|
||||
`DEFINE_VA_INSTR(VAMOSWAPW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
`DEFINE_VA_INSTR(VAMOADDW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
`DEFINE_VA_INSTR(VAMOXORW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
`DEFINE_VA_INSTR(VAMOANDW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
`DEFINE_VA_INSTR(VAMOORW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
`DEFINE_VA_INSTR(VAMOMINW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
`DEFINE_VA_INSTR(VAMOMAXW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
`DEFINE_VA_INSTR(VAMOMINUW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
`DEFINE_VA_INSTR(VAMOMAXUW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
// SEW-bit vector AMOs
|
||||
// EEW vector AMOs
|
||||
`DEFINE_VA_INSTR(VAMOSWAPE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
`DEFINE_VA_INSTR(VAMOADDE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
`DEFINE_VA_INSTR(VAMOXORE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
|
||||
|
|
|
@ -148,6 +148,27 @@ class riscv_lr_sc_instr_stream extends riscv_amo_base_instr_stream;
|
|||
instr_list.push_back(sc_instr);
|
||||
endfunction
|
||||
|
||||
// section 8.3 Eventual Success of Store-Conditional Instructions
|
||||
// An LR/SC sequence begins with an LR instruction and ends with an SC instruction.
|
||||
// The dynamic code executed between the LR and SC instructions can only contain
|
||||
// instructions from the base “I” instruction set, excluding loads, stores, backward
|
||||
// jumps, taken backward branches, JALR, FENCE, and SYSTEM instructions. If the “C”
|
||||
// extension is supported, then compressed forms of the aforementioned “I” instructions
|
||||
// are also permitted.
|
||||
virtual function void add_mixed_instr(int instr_cnt);
|
||||
riscv_instr instr;
|
||||
int i;
|
||||
setup_allowed_instr(.no_branch(1), .no_load_store(1));
|
||||
while (i < instr_cnt) begin
|
||||
instr = riscv_instr::type_id::create("instr");
|
||||
randomize_instr(instr, .include_group({RV32I, RV32C}));
|
||||
if (!(instr.category inside {SYNCH, SYSTEM})) begin
|
||||
insert_instr(instr);
|
||||
i++;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass : riscv_lr_sc_instr_stream
|
||||
|
||||
class riscv_amo_instr_stream extends riscv_amo_base_instr_stream;
|
||||
|
@ -193,12 +214,8 @@ endclass : riscv_amo_instr_stream
|
|||
class riscv_vector_amo_instr_stream extends riscv_vector_load_store_instr_stream;
|
||||
|
||||
constraint amo_address_mode_c {
|
||||
// AMO operation only supports word alignment or element alignemt
|
||||
alignment inside {W_ALIGNMENT, E_ALIGNMENT};
|
||||
// AMO operation uses indexed address mode
|
||||
address_mode == INDEXED;
|
||||
// For the 32-bit vector AMO operations, SEW must be at least 32 bit
|
||||
(cfg.vector_cfg.vtype.vsew < 32) -> (alignment != W_ALIGNMENT);
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_vector_amo_instr_stream)
|
||||
|
@ -210,10 +227,4 @@ class riscv_vector_amo_instr_stream extends riscv_vector_load_store_instr_stream
|
|||
VAMOMAXE_V, VAMOMINUE_V, VAMOMAXUE_V, allowed_instr};
|
||||
endfunction
|
||||
|
||||
virtual function void add_w_vec_load_stores();
|
||||
allowed_instr = {VAMOSWAPW_V, VAMOADDW_V, VAMOXORW_V,
|
||||
VAMOANDW_V, VAMOORW_V, VAMOMINW_V,
|
||||
VAMOMAXW_V, VAMOMINUW_V, VAMOMAXUW_V, allowed_instr};
|
||||
endfunction
|
||||
|
||||
endclass : riscv_vector_amo_instr_stream
|
||||
|
|
|
@ -89,7 +89,9 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
gen_load_fault_handler(hart);
|
||||
// Store fault handler
|
||||
gen_store_fault_handler(hart);
|
||||
gen_test_done();
|
||||
if (hart == 0) begin
|
||||
gen_test_done();
|
||||
end
|
||||
end
|
||||
// Generate sub program
|
||||
gen_sub_program(hart, sub_program[hart], sub_program_name, cfg.num_of_sub_program);
|
||||
|
@ -117,7 +119,10 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
instr_stream = {instr_stream, main_program[hart].instr_string_list};
|
||||
// If PMP is supported, need to jump from end of main program to test_done section at the end
|
||||
// of main_program, as the test_done will have moved to the beginning of the program
|
||||
instr_stream = {instr_stream, $sformatf("%sj test_done", indent)};
|
||||
instr_stream = {instr_stream,
|
||||
$sformatf("%sla x%0d, test_done", indent, cfg.scratch_reg),
|
||||
$sformatf("%sjalr x0, x%0d, 0", indent, cfg.scratch_reg)
|
||||
};
|
||||
// Test done section
|
||||
// If PMP isn't supported, generate this in the normal location
|
||||
if (hart == 0 & !riscv_instr_pkg::support_pmp) begin
|
||||
|
@ -130,10 +135,6 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Program end
|
||||
gen_program_end(hart);
|
||||
if (!cfg.bare_program_mode) begin
|
||||
if (!riscv_instr_pkg::support_pmp) begin
|
||||
// Privileged mode switch routine
|
||||
gen_privileged_mode_switch_routine(hart);
|
||||
end
|
||||
// Generate debug rom section
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
gen_debug_rom(hart);
|
||||
|
@ -329,7 +330,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
end
|
||||
gen_section("_start", str);
|
||||
for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
|
||||
instr_stream.push_back($sformatf("%0d: j h%0d_start", hart, hart));
|
||||
instr_stream.push_back($sformatf("%0d: la x%0d, h%0d_start", hart, cfg.scratch_reg, hart));
|
||||
instr_stream.push_back($sformatf("jalr x0, x%0d, 0", cfg.scratch_reg));
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -706,19 +708,19 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// TB can check the GPR value for this memory location to compare with expected value generated
|
||||
// by the ISA simulator. If the processor doesn't have a good tracer unit, it might not be
|
||||
// possible to compare the GPR value after each instruction execution.
|
||||
virtual function void gen_register_dump();
|
||||
virtual function void gen_register_dump(ref string instr[$]);
|
||||
string str;
|
||||
// Load base address
|
||||
str = {indent, $sformatf("la x%0d, _start", cfg.gpr[0])};
|
||||
instr_stream.push_back(str);
|
||||
str = $sformatf("la x%0d, _start", cfg.gpr[0]);
|
||||
instr.push_back(str);
|
||||
// Generate sw/sd instructions
|
||||
for(int i = 0; i < 32; i++) begin
|
||||
if(XLEN == 64) begin
|
||||
str = {indent, $sformatf("sd x%0d, %0d(x%0d)", i, i*(XLEN/8), cfg.gpr[0])};
|
||||
str = $sformatf("sd x%0d, %0d(x%0d)", i, i*(XLEN/8), cfg.gpr[0]);
|
||||
end else begin
|
||||
str = {indent, $sformatf("sw x%0d, %0d(x%0d)", i, i*(XLEN/8), cfg.gpr[0])};
|
||||
str = $sformatf("sw x%0d, %0d(x%0d)", i, i*(XLEN/8), cfg.gpr[0]);
|
||||
end
|
||||
instr_stream.push_back(str);
|
||||
instr.push_back(str);
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -749,14 +751,10 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
end
|
||||
// Setup mepc register, jump to init entry
|
||||
setup_epc(hart);
|
||||
// Setup initial privilege mode
|
||||
gen_privileged_mode_switch_routine(hart);
|
||||
// Initialization of any implementation-specific custom CSRs
|
||||
setup_custom_csrs(hart);
|
||||
// Move privileged mode support to the "safe" section of the program
|
||||
// if PMP is supported
|
||||
if (riscv_instr_pkg::support_pmp) begin
|
||||
// Privileged mode switch routine
|
||||
gen_privileged_mode_switch_routine(hart);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void gen_privileged_mode_switch_routine(int hart);
|
||||
|
@ -817,9 +815,6 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
end
|
||||
mode_name = cfg.init_privileged_mode.name();
|
||||
instr.push_back($sformatf("csrw 0x%0x, x%0d", MEPC, cfg.gpr[0]));
|
||||
if (!riscv_instr_pkg::support_pmp) begin
|
||||
instr.push_back($sformatf("j %0sinit_%0s", hart_prefix(hart), mode_name.tolower()));
|
||||
end
|
||||
gen_section(get_label("mepc_setup", hart), instr);
|
||||
endfunction
|
||||
|
||||
|
@ -1092,7 +1087,9 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
// Skip checking tval for illegal instruction as it's implementation specific
|
||||
$sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[1], tval, tval.name()),
|
||||
"1: jal x1, test_done "
|
||||
// use JALR to jump to test_done.
|
||||
$sformatf("1: la x%0d, test_done", cfg.scratch_reg),
|
||||
$sformatf("jalr x1, x%0d, 0", cfg.scratch_reg)
|
||||
};
|
||||
gen_section(get_label($sformatf("%0smode_exception_handler", mode), hart), instr);
|
||||
endfunction
|
||||
|
@ -1138,7 +1135,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Jump to commmon interrupt handling routine
|
||||
intr_handler = {intr_handler,
|
||||
$sformatf("j %0s%0smode_intr_handler", hart_prefix(hart), mode),
|
||||
"1: j test_done"};
|
||||
$sformatf("1: la x%0d, test_done", cfg.scratch_reg),
|
||||
$sformatf("jalr x0, x%0d, 0", cfg.scratch_reg)};
|
||||
gen_section(get_label($sformatf("%0smode_intr_vector_%0d", mode, i), hart), intr_handler);
|
||||
end
|
||||
endfunction
|
||||
|
@ -1147,14 +1145,12 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// It does some clean up like dump GPRs before communicating with host to terminate the test.
|
||||
// User can extend this function if some custom clean up routine is needed.
|
||||
virtual function void gen_ecall_handler(int hart);
|
||||
string str;
|
||||
str = format_string(get_label("ecall_handler:", hart), LABEL_STR_LEN);
|
||||
instr_stream.push_back(str);
|
||||
dump_perf_stats();
|
||||
gen_register_dump();
|
||||
str = format_string(" ", LABEL_STR_LEN);
|
||||
str = {str, "j write_tohost"};
|
||||
instr_stream.push_back(str);
|
||||
string instr[$];
|
||||
dump_perf_stats(instr);
|
||||
gen_register_dump(instr);
|
||||
instr.push_back($sformatf("la x%0d, write_tohost", cfg.scratch_reg));
|
||||
instr.push_back($sformatf("jalr x0, x%0d, 0", cfg.scratch_reg));
|
||||
gen_section(get_label("ecall_handler", hart), instr);
|
||||
endfunction
|
||||
|
||||
// Ebreak trap handler
|
||||
|
@ -1410,17 +1406,14 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
endfunction
|
||||
|
||||
// Dump performance CSRs if applicable
|
||||
virtual function void dump_perf_stats();
|
||||
string perf_stats[$];
|
||||
virtual function void dump_perf_stats(ref string instr[$]);
|
||||
foreach(implemented_csr[i]) begin
|
||||
if (implemented_csr[i] inside {[MCYCLE:MHPMCOUNTER31H]}) begin
|
||||
gen_signature_handshake(.instr(perf_stats),
|
||||
gen_signature_handshake(.instr(instr),
|
||||
.signature_type(WRITE_CSR),
|
||||
.csr(implemented_csr[i]));
|
||||
end
|
||||
end
|
||||
format_section(perf_stats);
|
||||
instr_stream = {instr_stream, perf_stats};
|
||||
endfunction
|
||||
|
||||
// Write the generated program to a file
|
||||
|
@ -1612,19 +1605,23 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
//---------------------------------------------------------------------------------------
|
||||
|
||||
virtual function void randomize_vec_gpr_and_csr();
|
||||
string lmul;
|
||||
if (!(RVV inside {supported_isa})) return;
|
||||
instr_stream.push_back({indent, $sformatf("li x%0d, %0d", cfg.gpr[0], cfg.vector_cfg.vxsat)});
|
||||
instr_stream.push_back({indent, $sformatf("csrw vxsat, x%0d", cfg.gpr[0])});
|
||||
instr_stream.push_back({indent, $sformatf("li x%0d, %0d", cfg.gpr[0], cfg.vector_cfg.vxrm)});
|
||||
instr_stream.push_back({indent, $sformatf("csrw vxrm, x%0d", cfg.gpr[0])});
|
||||
instr_stream.push_back({indent, $sformatf("csrwi vxsat, %0d", cfg.vector_cfg.vxsat)});
|
||||
instr_stream.push_back({indent, $sformatf("csrwi vxrm, %0d", cfg.vector_cfg.vxrm)});
|
||||
init_vec_gpr(); // GPR init uses a temporary SEW/LMUL setting before the final value set below.
|
||||
instr_stream.push_back($sformatf("li x%0d, %0d", cfg.gpr[1], cfg.vector_cfg.vl));
|
||||
instr_stream.push_back($sformatf("%svsetvli x%0d, x%0d, e%0d, m%0d, d%0d",
|
||||
if ((cfg.vector_cfg.vtype.vlmul > 1) && (cfg.vector_cfg.vtype.fractional_lmul)) begin
|
||||
lmul = $sformatf("mf%0d", cfg.vector_cfg.vtype.vlmul);
|
||||
end else begin
|
||||
lmul = $sformatf("m%0d", cfg.vector_cfg.vtype.vlmul);
|
||||
end
|
||||
instr_stream.push_back($sformatf("%svsetvli x%0d, x%0d, e%0d, %0s, d%0d",
|
||||
indent,
|
||||
cfg.gpr[0],
|
||||
cfg.gpr[1],
|
||||
cfg.vector_cfg.vtype.vsew,
|
||||
cfg.vector_cfg.vtype.vlmul,
|
||||
lmul,
|
||||
cfg.vector_cfg.vtype.vediv));
|
||||
endfunction
|
||||
|
||||
|
|
|
@ -93,8 +93,12 @@ class riscv_debug_rom_gen extends riscv_asm_program_gen;
|
|||
cfg.num_debug_sub_program);
|
||||
main_program[hart].post_process_instr();
|
||||
main_program[hart].generate_instr_stream(.no_label(1'b1));
|
||||
debug_main = {debug_main,
|
||||
main_program[hart].instr_string_list,
|
||||
$sformatf("%sla x%0d, debug_end", indent, cfg.scratch_reg),
|
||||
$sformatf("%sjalr x0, x%0d, 0", indent, cfg.scratch_reg)
|
||||
};
|
||||
insert_sub_program(sub_program[hart], debug_main);
|
||||
debug_main = {debug_main, main_program[hart].instr_string_list};
|
||||
gen_section($sformatf("%0sdebug_rom", hart_prefix(hart)), debug_main);
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
gen_ebreak_footer();
|
||||
|
|
|
@ -43,7 +43,7 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// SAME_VALUES_ALL_ELEMS - Using vmv.v.x to fill all the elements of the vreg with the same value as the one in the GPR selected
|
||||
// RANDOM_VALUES_VMV - Using vmv.v.x + vslide1up.vx to randomize the contents of each vector element
|
||||
// RANDOM_VALUES_LOAD - Using vle.v, same approach as RANDOM_VALUES_VMV but more efficient for big VLEN
|
||||
vreg_init_method_t vreg_init_method = RANDOM_VALUES_VMV;
|
||||
vreg_init_method_t vreg_init_method = RANDOM_VALUES_VMV;
|
||||
|
||||
// Associate array for delegation configuration for each exception and interrupt
|
||||
// When the bit is 1, the corresponding delegation is enabled.
|
||||
|
@ -411,16 +411,16 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
!(tp inside {GP, RA, ZERO});
|
||||
}
|
||||
|
||||
// This reg is used in various places throughout the generator,
|
||||
// so need more conservative constraints on it.
|
||||
constraint reserve_scratch_reg_c {
|
||||
scratch_reg != ZERO;
|
||||
scratch_reg != sp;
|
||||
scratch_reg != tp;
|
||||
!(scratch_reg inside {ZERO, sp, tp, ra, GP});
|
||||
}
|
||||
|
||||
// This reg is only used inside PMP exception routine,
|
||||
// so we can be a bit looser with constraints.
|
||||
constraint reserve_pmp_reg_c {
|
||||
pmp_reg != ZERO;
|
||||
pmp_reg != sp;
|
||||
pmp_reg != tp;
|
||||
!(pmp_reg inside {ZERO, sp, tp});
|
||||
}
|
||||
|
||||
constraint gpr_c {
|
||||
|
|
97
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
97
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
|
@ -599,105 +599,23 @@ package riscv_instr_pkg;
|
|||
// Vector load/store instruction
|
||||
VLE_V,
|
||||
VSE_V,
|
||||
VLB_V,
|
||||
VSB_V,
|
||||
VLH_V,
|
||||
VSH_V,
|
||||
VLW_V,
|
||||
VSW_V,
|
||||
VLBU_V,
|
||||
VLHU_V,
|
||||
VLWU_V,
|
||||
VLSB_V,
|
||||
VLSH_V,
|
||||
VLSW_V,
|
||||
VLSBU_V,
|
||||
VLSHU_V,
|
||||
VLSWU_V,
|
||||
VLSE_V,
|
||||
VSSB_V,
|
||||
VSSH_V,
|
||||
VSSW_V,
|
||||
VSSE_V,
|
||||
VLXB_V,
|
||||
VLXH_V,
|
||||
VLXW_V,
|
||||
VLXBU_V,
|
||||
VLXHU_V,
|
||||
VLXWU_V,
|
||||
VLXE_V,
|
||||
VSXB_V,
|
||||
VSXH_V,
|
||||
VSXW_V,
|
||||
VSXE_V,
|
||||
VSUXB_V,
|
||||
VSUXH_V,
|
||||
VSUXW_V,
|
||||
VSUXE_V,
|
||||
VLBFF_V,
|
||||
VLHFF_V,
|
||||
VLWFF_V,
|
||||
VLBUFF_V,
|
||||
VLHUFF_V,
|
||||
VLWUFF_V,
|
||||
VLXEI_V,
|
||||
VSXEI_V,
|
||||
VSUXEI_V,
|
||||
VLEFF_V,
|
||||
// Segmented load/store instruction
|
||||
VLSEGE_V,
|
||||
VSSEGE_V,
|
||||
VLSEGB_V,
|
||||
VSSEGB_V,
|
||||
VLSEGH_V,
|
||||
VSSEGH_V,
|
||||
VLSEGW_V,
|
||||
VSSEGW_V,
|
||||
VLSEGBFF_V,
|
||||
VLSEGHFF_V,
|
||||
VLSEGWFF_V,
|
||||
VLSEGBUFF_V,
|
||||
VLSEGHUFF_V,
|
||||
VLSEGWUFF_V,
|
||||
VLSEGEFF_V,
|
||||
VLSEGBU_V,
|
||||
VLSEGHU_V,
|
||||
VLSEGWU_V,
|
||||
VLSSEGB_V,
|
||||
VLSSEGH_V,
|
||||
VLSSEGW_V,
|
||||
VLSSEGBU_V,
|
||||
VLSSEGHU_V,
|
||||
VLSSEGWU_V,
|
||||
VLSSEGE_V,
|
||||
VSSSEGB_V,
|
||||
VSSSEGH_V,
|
||||
VSSSEGW_V,
|
||||
VSSSEGE_V,
|
||||
VLXSEGB_V,
|
||||
VLXSEGH_V,
|
||||
VLXSEGW_V,
|
||||
VLXSEGBU_V,
|
||||
VLXSEGHU_V,
|
||||
VLXSEGWU_V,
|
||||
VLXSEGE_V,
|
||||
VSXSEGB_V,
|
||||
VSXSEGH_V,
|
||||
VSXSEGW_V,
|
||||
VSXSEGE_V,
|
||||
VSUXSEGB_V,
|
||||
VSUXSEGH_V,
|
||||
VSUXSEGW_V,
|
||||
VSUXSEGE_V,
|
||||
VLXSEGEI_V,
|
||||
VSXSEGEI_V,
|
||||
VSUXSEGEI_V,
|
||||
// Vector AMO instruction
|
||||
// 32-bit vector AMOs
|
||||
VAMOSWAPW_V,
|
||||
VAMOADDW_V,
|
||||
VAMOXORW_V,
|
||||
VAMOANDW_V,
|
||||
VAMOORW_V,
|
||||
VAMOMINW_V,
|
||||
VAMOMAXW_V,
|
||||
VAMOMINUW_V,
|
||||
VAMOMAXUW_V,
|
||||
// SEW-bit vector AMOs
|
||||
// EEW vector AMOs
|
||||
VAMOSWAPE_V,
|
||||
VAMOADDE_V,
|
||||
VAMOXORE_V,
|
||||
|
@ -1218,6 +1136,7 @@ package riscv_instr_pkg;
|
|||
|
||||
typedef struct packed {
|
||||
bit ill;
|
||||
bit fractional_lmul;
|
||||
bit [XLEN-2:7] reserved;
|
||||
int vediv;
|
||||
int vsew;
|
||||
|
|
20
vendor/google_riscv-dv/src/riscv_instr_stream.sv
vendored
20
vendor/google_riscv-dv/src/riscv_instr_stream.sv
vendored
|
@ -52,7 +52,9 @@ class riscv_instr_stream extends uvm_object;
|
|||
// When index is -1, the instruction is injected at a random location
|
||||
function void insert_instr(riscv_instr instr, int idx = -1);
|
||||
int current_instr_cnt = instr_list.size();
|
||||
if(idx == -1) begin
|
||||
if (current_instr_cnt == 0) begin
|
||||
idx = 0;
|
||||
end else if (idx == -1) begin
|
||||
idx = $urandom_range(0, current_instr_cnt-1);
|
||||
while(instr_list[idx].atomic) begin
|
||||
idx += 1;
|
||||
|
@ -228,17 +230,25 @@ class riscv_rand_instr_stream extends riscv_instr_stream;
|
|||
|
||||
function void randomize_instr(output riscv_instr instr,
|
||||
input bit is_in_debug = 1'b0,
|
||||
input bit disable_dist = 1'b0);
|
||||
input bit disable_dist = 1'b0,
|
||||
input riscv_instr_group_t include_group[$] = {});
|
||||
riscv_instr_name_t exclude_instr[];
|
||||
if ((SP inside {reserved_rd, cfg.reserved_regs}) ||
|
||||
((avail_regs.size() > 0) && !(SP inside {avail_regs}))) begin
|
||||
exclude_instr = {C_ADDI4SPN, C_ADDI16SP, C_LWSP, C_LDSP};
|
||||
end
|
||||
if (is_in_debug && !cfg.enable_ebreak_in_debug_rom) begin
|
||||
exclude_instr = {exclude_instr, EBREAK, C_EBREAK};
|
||||
// Post-process the allowed_instr and exclude_instr lists to handle
|
||||
// adding ebreak instructions to the debug rom.
|
||||
if (is_in_debug) begin
|
||||
if (cfg.no_ebreak && cfg.enable_ebreak_in_debug_rom) begin
|
||||
allowed_instr = {allowed_instr, EBREAK, C_EBREAK};
|
||||
end else if (!cfg.no_ebreak && !cfg.enable_ebreak_in_debug_rom) begin
|
||||
exclude_instr = {exclude_instr, EBREAK, C_EBREAK};
|
||||
end
|
||||
end
|
||||
instr = riscv_instr::get_rand_instr(.include_instr(allowed_instr),
|
||||
.exclude_instr(exclude_instr));
|
||||
.exclude_instr(exclude_instr),
|
||||
.include_group(include_group));
|
||||
instr.m_cfg = cfg;
|
||||
randomize_gpr(instr);
|
||||
endfunction
|
||||
|
|
|
@ -521,10 +521,9 @@ endclass
|
|||
|
||||
class riscv_vector_load_store_instr_stream extends riscv_mem_access_stream;
|
||||
|
||||
typedef enum {B_ALIGNMENT, H_ALIGNMENT, W_ALIGNMENT, E_ALIGNMENT} alignment_e;
|
||||
typedef enum {UNIT_STRIDED, STRIDED, INDEXED} address_mode_e;
|
||||
|
||||
rand alignment_e alignment;
|
||||
rand bit [10:0] eew;
|
||||
rand int unsigned data_page_id;
|
||||
rand int unsigned num_mixed_instr;
|
||||
rand int unsigned stride_byte_offset;
|
||||
|
@ -538,20 +537,22 @@ class riscv_vector_load_store_instr_stream extends riscv_mem_access_stream;
|
|||
num_mixed_instr inside {[0:10]};
|
||||
}
|
||||
|
||||
constraint eew_c {
|
||||
eew inside {cfg.vector_cfg.legal_eew};
|
||||
}
|
||||
|
||||
constraint stride_byte_offset_c {
|
||||
solve eew before stride_byte_offset;
|
||||
// Keep a reasonable byte offset range to avoid vector memory address overflow
|
||||
stride_byte_offset inside {[1 : 32]};
|
||||
(alignment == H_ALIGNMENT) -> (stride_byte_offset % 2 == 0);
|
||||
(alignment == W_ALIGNMENT) -> (stride_byte_offset % 4 == 0);
|
||||
(alignment == E_ALIGNMENT) -> (stride_byte_offset % cfg.vector_cfg.vtype.vsew == 0);
|
||||
stride_byte_offset inside {[1 : 128]};
|
||||
stride_byte_offset % (eew / 8) == 1;
|
||||
}
|
||||
|
||||
constraint index_addr_c {
|
||||
solve eew before index_addr;
|
||||
// Keep a reasonable index address range to avoid vector memory address overflow
|
||||
index_addr inside {[1 : 128]};
|
||||
(alignment == H_ALIGNMENT) -> (index_addr % 2 == 0);
|
||||
(alignment == W_ALIGNMENT) -> (index_addr % 4 == 0);
|
||||
(alignment == E_ALIGNMENT) -> (index_addr % cfg.vector_cfg.vtype.vsew == 0);
|
||||
index_addr inside {[0 : 128]};
|
||||
index_addr % (eew / 8) == 1;
|
||||
}
|
||||
|
||||
constraint vec_rs_c {
|
||||
|
@ -564,11 +565,6 @@ class riscv_vector_load_store_instr_stream extends riscv_mem_access_stream;
|
|||
data_page_id < max_data_page_id;
|
||||
}
|
||||
|
||||
constraint alignment_sew_c {
|
||||
if (cfg.vector_cfg.vtype.vsew <= 16) {alignment != W_ALIGNMENT;}
|
||||
if (cfg.vector_cfg.vtype.vsew <= 8) {alignment != H_ALIGNMENT;}
|
||||
}
|
||||
|
||||
int base;
|
||||
int max_load_store_addr;
|
||||
riscv_vector_instr load_store_instr;
|
||||
|
@ -576,10 +572,6 @@ class riscv_vector_load_store_instr_stream extends riscv_mem_access_stream;
|
|||
`uvm_object_utils(riscv_vector_load_store_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
virtual function int get_addr_alignment_mask(int alignment_bytes);
|
||||
return alignment_bytes - 1;
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
reserved_rd = {reserved_rd, rs1_reg, rs2_reg};
|
||||
randomize_avail_regs();
|
||||
|
@ -613,17 +605,13 @@ class riscv_vector_load_store_instr_stream extends riscv_mem_access_stream;
|
|||
`uvm_fatal(`gfn, $sformatf({"Expected positive value for max_load_store_addr, got %0d.",
|
||||
" Perhaps more memory needs to be allocated in the data pages for vector loads and stores.",
|
||||
"\ndata_page_id:%0d\ndata_page[data_page_id].size_in_bytes:%0d\naddress_span:%0d",
|
||||
"\nalignment:%s\nstride_bytes:%0d\nVLEN:%0d\nLMUL:%0d\ncfg.vector_cfg.vtype.vsew:%0d\n\n"},
|
||||
"\nstride_bytes:%0d\nVLEN:%0d\nLMUL:%0d\ncfg.vector_cfg.vtype.vsew:%0d\n\n"},
|
||||
max_load_store_addr, data_page_id, data_page[data_page_id].size_in_bytes, ss,
|
||||
alignment.name(), stride_bytes(), VLEN,
|
||||
cfg.vector_cfg.vtype.vlmul, cfg.vector_cfg.vtype.vsew))
|
||||
stride_bytes(), VLEN, cfg.vector_cfg.vtype.vlmul, cfg.vector_cfg.vtype.vsew))
|
||||
end
|
||||
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(base, base >= 0; base <= max_load_store_addr;)
|
||||
|
||||
if (!cfg.enable_unaligned_load_store) begin
|
||||
base &= ~get_addr_alignment_mask(stride_bytes());
|
||||
end
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(base, base inside {[0 : max_load_store_addr]};
|
||||
base % eew == 0;)
|
||||
endfunction
|
||||
|
||||
virtual function int address_span();
|
||||
|
@ -636,11 +624,7 @@ class riscv_vector_load_store_instr_stream extends riscv_mem_access_stream;
|
|||
endfunction
|
||||
|
||||
virtual function int stride_bytes();
|
||||
stride_bytes = 0;
|
||||
if (alignment == B_ALIGNMENT) stride_bytes = 1;
|
||||
else if (alignment == H_ALIGNMENT) stride_bytes = 2;
|
||||
else if (alignment == W_ALIGNMENT) stride_bytes = 4;
|
||||
else if (alignment == E_ALIGNMENT) stride_bytes = cfg.vector_cfg.vtype.vsew;
|
||||
stride_bytes = eew / 8;
|
||||
endfunction
|
||||
|
||||
// Generate each load/store instruction
|
||||
|
@ -651,13 +635,6 @@ class riscv_vector_load_store_instr_stream extends riscv_mem_access_stream;
|
|||
endfunction
|
||||
|
||||
virtual function void build_allowed_instr();
|
||||
if (alignment == B_ALIGNMENT) add_byte_aligned_vec_load_stores();
|
||||
else if (alignment == H_ALIGNMENT) add_h_aligned_vec_load_stores();
|
||||
else if (alignment == W_ALIGNMENT) add_w_aligned_vec_load_stores();
|
||||
else if (alignment == E_ALIGNMENT) add_element_vec_load_stores();
|
||||
endfunction
|
||||
|
||||
virtual function void add_element_vec_load_stores();
|
||||
case (address_mode)
|
||||
UNIT_STRIDED : begin
|
||||
allowed_instr = {VLE_V, VSE_V, allowed_instr};
|
||||
|
@ -678,96 +655,9 @@ class riscv_vector_load_store_instr_stream extends riscv_mem_access_stream;
|
|||
end
|
||||
end
|
||||
INDEXED : begin
|
||||
allowed_instr = {VLXE_V, VSXE_V, allowed_instr};
|
||||
allowed_instr = {VLXEI_V, VSXEI_V, VSUXEI_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_zvlsseg) begin
|
||||
allowed_instr = {VLXSEGE_V, VSXSEGE_V, allowed_instr};
|
||||
end
|
||||
end
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
virtual function void add_byte_aligned_vec_load_stores();
|
||||
case (address_mode)
|
||||
UNIT_STRIDED : begin
|
||||
allowed_instr = {VLB_V, VSB_V, VLBU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_fault_only_first_load) begin
|
||||
allowed_instr = {VLBFF_V, VLBUFF_V, allowed_instr};
|
||||
end
|
||||
if (cfg.vector_cfg.enable_zvlsseg) begin
|
||||
allowed_instr = {VLSEGB_V, VSSEGB_V, VLSEGBU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_fault_only_first_load) begin
|
||||
allowed_instr = {VLSEGBFF_V, VLSEGBUFF_V, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
STRIDED : begin
|
||||
allowed_instr = {VLSB_V, VSSB_V, VLSBU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_zvlsseg) begin
|
||||
allowed_instr = {VLSSEGB_V, VSSSEGB_V, VLSSEGBU_V, allowed_instr};
|
||||
end
|
||||
end
|
||||
INDEXED : begin
|
||||
allowed_instr = {VLXB_V, VSXB_V, VLXBU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_zvlsseg) begin
|
||||
allowed_instr = {VLXSEGB_V, VSXSEGB_V, VLXSEGBU_V, allowed_instr};
|
||||
end
|
||||
end
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
virtual function void add_h_aligned_vec_load_stores();
|
||||
case (address_mode)
|
||||
UNIT_STRIDED : begin
|
||||
allowed_instr = {VLH_V, VSH_V, VLHU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_fault_only_first_load) begin
|
||||
allowed_instr = {VLHFF_V, VLHUFF_V, allowed_instr};
|
||||
end
|
||||
if (cfg.vector_cfg.enable_zvlsseg) begin
|
||||
allowed_instr = {VLSEGH_V, VSSEGH_V, VLSEGHU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_fault_only_first_load) begin
|
||||
allowed_instr = {VLSEGHFF_V, VLSEGHUFF_V, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
STRIDED : begin
|
||||
allowed_instr = {VLSH_V, VSSH_V, VLSHU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_zvlsseg) begin
|
||||
allowed_instr = {VLSSEGH_V, VSSSEGH_V, VLSSEGHU_V, allowed_instr};
|
||||
end
|
||||
end
|
||||
INDEXED : begin
|
||||
allowed_instr = {VLXH_V, VSXH_V, VLXHU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_zvlsseg) begin
|
||||
allowed_instr = {VLXSEGH_V, VSXSEGH_V, VLXSEGHU_V, allowed_instr};
|
||||
end
|
||||
end
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
virtual function void add_w_aligned_vec_load_stores();
|
||||
case (address_mode)
|
||||
UNIT_STRIDED : begin
|
||||
allowed_instr = {VLW_V, VSW_V, VLWU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_fault_only_first_load) begin
|
||||
allowed_instr = {VLWFF_V, VLWUFF_V, allowed_instr};
|
||||
end
|
||||
if (cfg.vector_cfg.enable_zvlsseg) begin
|
||||
allowed_instr = {VLSEGW_V, VSSEGW_V, VLSEGWU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_fault_only_first_load) begin
|
||||
allowed_instr = {VLSEGWFF_V, VLSEGWUFF_V, allowed_instr};
|
||||
end
|
||||
end
|
||||
end
|
||||
STRIDED : begin
|
||||
allowed_instr = {VLSW_V, VSSW_V, VLSWU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_zvlsseg) begin
|
||||
allowed_instr = {VLSSEGW_V, VSSSEGW_V, VLSSEGWU_V, allowed_instr};
|
||||
end
|
||||
end
|
||||
INDEXED : begin
|
||||
allowed_instr = {VLXW_V, VSXW_V, VLXWU_V, allowed_instr};
|
||||
if (cfg.vector_cfg.enable_zvlsseg) begin
|
||||
allowed_instr = {VLXSEGW_V, VSXSEGW_V, VLXSEGWU_V, allowed_instr};
|
||||
allowed_instr = {VLXSEGEI_V, VSXSEGEI_V, VSUXSEGEI_V, allowed_instr};
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
|
|
@ -371,6 +371,8 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
|
|||
|
||||
// End of page table fault handling
|
||||
instr.push_back("fix_pte_done:");
|
||||
// Make sure all outstanding memory access is completed
|
||||
instr.push_back("sfence.vma");
|
||||
// Randomly decide if run some kernel program before exiting from exception handling
|
||||
// Use the low 2 bits of x30 to determine whether to skip it or not.
|
||||
instr.push_back($sformatf("slli x30, x30, %0d", XLEN - 2));
|
||||
|
@ -526,6 +528,7 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
|
|||
// If not the end of the kernel space, process the next PTE
|
||||
$sformatf("ble x%0d, x%0d, 2b", cfg.gpr[0], cfg.gpr[1])};
|
||||
end
|
||||
instr = {instr, "sfence.vma"};
|
||||
endfunction
|
||||
|
||||
// If you want to create custom page table topology, override the below tasks to specify the
|
||||
|
|
20
vendor/google_riscv-dv/src/riscv_pmp_cfg.sv
vendored
20
vendor/google_riscv-dv/src/riscv_pmp_cfg.sv
vendored
|
@ -77,8 +77,6 @@ class riscv_pmp_cfg extends uvm_object;
|
|||
pmp_granularity inside {[0 : XLEN + 3]};
|
||||
}
|
||||
|
||||
// TODO(udinator) more address constraints?
|
||||
// TODO(udinator) move to posts_randomize() if lower performance
|
||||
constraint xwr_c {
|
||||
foreach (pmp_cfg[i]) {
|
||||
!(pmp_cfg[i].w && !pmp_cfg[i].r);
|
||||
|
@ -438,7 +436,8 @@ class riscv_pmp_cfg extends uvm_object;
|
|||
$sformatf("li x%0d, 3", scratch_reg[0]),
|
||||
$sformatf("beq x%0d, x%0d, 27f", scratch_reg[4], scratch_reg[0]),
|
||||
// Error check, if no address modes match, something has gone wrong
|
||||
$sformatf("j test_done"),
|
||||
$sformatf("la x%0d, test_done", scratch_reg[0]),
|
||||
$sformatf("jalr x0, x%0d, 0", scratch_reg[0]),
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// increment loop counter and branch back to beginning of loop //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -459,7 +458,8 @@ class riscv_pmp_cfg extends uvm_object;
|
|||
// We must immediately jump to <test_done> since the CPU is taking a PMP exception,
|
||||
// but this routine is unable to find a matching PMP region for the faulting access -
|
||||
// there is a bug somewhere.
|
||||
$sformatf("19: j test_done")
|
||||
$sformatf("19: la x%0d, test_done", scratch_reg[0]),
|
||||
$sformatf("jalr x0, x%0d, 0", scratch_reg[0])
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
@ -495,8 +495,8 @@ class riscv_pmp_cfg extends uvm_object;
|
|||
// <test_done>, otherwise modify access bits and return
|
||||
$sformatf("andi x%0d, x%0d, 128", scratch_reg[4], scratch_reg[3]),
|
||||
$sformatf("beqz x%0d, 24f", scratch_reg[4]),
|
||||
$sformatf("j test_done"),
|
||||
// TODO : update with correct label
|
||||
$sformatf("la x%0d, test_done", scratch_reg[0]),
|
||||
$sformatf("jalr x0, x%0d, 0", scratch_reg[0]),
|
||||
$sformatf("24: j 29f")
|
||||
};
|
||||
|
||||
|
@ -515,8 +515,8 @@ class riscv_pmp_cfg extends uvm_object;
|
|||
// entry is locked, otherwise modify access bits
|
||||
$sformatf("andi x%0d, x%0d, 128", scratch_reg[4], scratch_reg[3]),
|
||||
$sformatf("beqz x%0d, 26f", scratch_reg[4]),
|
||||
$sformatf("j test_done"),
|
||||
// TODO : update with correct label
|
||||
$sformatf("la x%0d, test_done", scratch_reg[0]),
|
||||
$sformatf("jalr x0, x%0d, 0", scratch_reg[0]),
|
||||
$sformatf("26: j 29f")
|
||||
};
|
||||
|
||||
|
@ -540,8 +540,8 @@ class riscv_pmp_cfg extends uvm_object;
|
|||
// the entry is locked, otherwise modify access bits
|
||||
$sformatf("andi x%0d, x%0d, 128", scratch_reg[4], scratch_reg[3]),
|
||||
$sformatf("beqz x%0d, 29f", scratch_reg[4]),
|
||||
$sformatf("j test_done"),
|
||||
// TODO : update with correct label
|
||||
$sformatf("la x%0d, test_done", scratch_reg[0]),
|
||||
$sformatf("jalr x0, x%0d, 0", scratch_reg[0]),
|
||||
$sformatf("28: j 29f")
|
||||
};
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
|
|||
add_field("WPRI1", 1, WPRI);
|
||||
add_field("MPIE", 1, WARL);
|
||||
add_field("SPP", 1, WLRL);
|
||||
add_field("WPRI2", 2, WPRI);
|
||||
add_field("VS", 2, WARL);
|
||||
add_field("MPP", 2, WLRL);
|
||||
add_field("FS", 2, WARL);
|
||||
add_field("XS", 2, WARL);
|
||||
|
@ -77,11 +77,10 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
|
|||
add_field("TVM", 1, WARL);
|
||||
add_field("TW", 1, WARL);
|
||||
add_field("TSR", 1, WARL);
|
||||
add_field("VS", 2, WARL);
|
||||
if(XLEN == 32) begin
|
||||
add_field("WPRI3", 6, WPRI);
|
||||
add_field("WPRI3", 8, WPRI);
|
||||
end else begin
|
||||
add_field("WPRI3", 7, WPRI);
|
||||
add_field("WPRI3", 9, WPRI);
|
||||
add_field("UXL", 2, WARL);
|
||||
add_field("SXL", 2, WARL);
|
||||
add_field("WPRI4", XLEN - 37, WPRI);
|
||||
|
|
29
vendor/google_riscv-dv/src/riscv_vector_cfg.sv
vendored
29
vendor/google_riscv-dv/src/riscv_vector_cfg.sv
vendored
|
@ -24,6 +24,9 @@ class riscv_vector_cfg extends uvm_object;
|
|||
rand bit vxsat;
|
||||
riscv_vreg_t reserved_vregs[$];
|
||||
|
||||
// Allowed effective element width based on the LMUL setting
|
||||
int unsigned legal_eew[$];
|
||||
|
||||
// Allow only vector instructions from the random sequences
|
||||
rand bit only_vec_instr;
|
||||
constraint only_vec_instr_c {soft only_vec_instr == 0;}
|
||||
|
@ -80,10 +83,10 @@ class riscv_vector_cfg extends uvm_object;
|
|||
vtype.vlmul inside {1, 2, 4, 8};
|
||||
vtype.vlmul <= MAX_LMUL;
|
||||
if (vec_narrowing_widening) {
|
||||
vtype.vlmul < 8;
|
||||
(vtype.vlmul < 8) || (vtype.fractional_lmul == 1'b1);
|
||||
}
|
||||
if (vec_quad_widening) {
|
||||
vtype.vlmul < 4;
|
||||
(vtype.vlmul < 4) || (vtype.fractional_lmul == 1'b1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,6 +113,8 @@ class riscv_vector_cfg extends uvm_object;
|
|||
`uvm_field_int(vtype.vediv, UVM_DEFAULT)
|
||||
`uvm_field_int(vtype.vsew, UVM_DEFAULT)
|
||||
`uvm_field_int(vtype.vlmul, UVM_DEFAULT)
|
||||
`uvm_field_int(vtype.fractional_lmul, UVM_DEFAULT)
|
||||
`uvm_field_queue_int(legal_eew, UVM_DEFAULT)
|
||||
`uvm_field_int(vl, UVM_DEFAULT)
|
||||
`uvm_field_int(vstart, UVM_DEFAULT)
|
||||
`uvm_field_enum(vxrm_t,vxrm, UVM_DEFAULT)
|
||||
|
@ -128,4 +133,24 @@ class riscv_vector_cfg extends uvm_object;
|
|||
end
|
||||
endfunction : new
|
||||
|
||||
function void post_randomize();
|
||||
real temp_eew;
|
||||
legal_eew = {};
|
||||
// Section 7.3 Vector loads and stores have the EEW encoded directly in the instruction.
|
||||
// EMUL is calculated as EMUL =(EEW/SEW)*LMUL. If the EMUL would be out of range
|
||||
// (EMUL>8 or EMUL<1/8), an illegal instruction exceptionis raised.
|
||||
// EEW = SEW * EMUL / LMUL
|
||||
for (real emul = 0.125; emul <= 8; emul = emul * 2) begin
|
||||
if (vtype.fractional_lmul == 0) begin
|
||||
temp_eew = real'(vtype.vsew) * emul / real'(vtype.vlmul);
|
||||
end else begin
|
||||
temp_eew = real'(vtype.vsew) * emul * real'(vtype.vlmul);
|
||||
end
|
||||
if (temp_eew inside {[8:1024]}) begin
|
||||
legal_eew.push_back(int'(temp_eew));
|
||||
end
|
||||
`uvm_info(`gfn, $sformatf("Checking emul: %.2f", emul), UVM_LOW)
|
||||
end
|
||||
endfunction : post_randomize
|
||||
|
||||
endclass : riscv_vector_cfg
|
||||
|
|
|
@ -115,11 +115,7 @@ const privileged_reg_t implemented_csr[] = {
|
|||
};
|
||||
|
||||
// Implementation-specific custom CSRs
|
||||
`ifdef DSIM
|
||||
bit [11:0] custom_csr[] = {
|
||||
`else
|
||||
const bit [11:0] custom_csr[] = {
|
||||
`endif
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -115,11 +115,7 @@ const privileged_reg_t implemented_csr[] = {
|
|||
};
|
||||
|
||||
// Implementation-specific custom CSRs
|
||||
`ifdef DSIM
|
||||
bit [11:0] custom_csr[] = {
|
||||
`else
|
||||
const bit [11:0] custom_csr[] = {
|
||||
`endif
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -115,11 +115,7 @@ const privileged_reg_t implemented_csr[] = {
|
|||
};
|
||||
|
||||
// Implementation-specific custom CSRs
|
||||
`ifdef DSIM
|
||||
bit [11:0] custom_csr[] = {
|
||||
`else
|
||||
const bit [11:0] custom_csr[] = {
|
||||
`endif
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -115,11 +115,7 @@ const privileged_reg_t implemented_csr[] = {
|
|||
};
|
||||
|
||||
// Implementation-specific custom CSRs
|
||||
`ifdef DSIM
|
||||
bit [11:0] custom_csr[] = {
|
||||
`else
|
||||
const bit [11:0] custom_csr[] = {
|
||||
`endif
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
22
vendor/google_riscv-dv/target/rv32imc_sv32/riscvOVPsim.ic
vendored
Normal file
22
vendor/google_riscv-dv/target/rv32imc_sv32/riscvOVPsim.ic
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
# riscOVPsim configuration file converted from YAML
|
||||
--variant RV32I
|
||||
--override riscvOVPsim/cpu/add_Extensions=MC
|
||||
--override riscvOVPsim/cpu/misa_MXL=1
|
||||
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/unaligned=T
|
||||
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/user_version=2.3
|
||||
--override riscvOVPsim/cpu/priv_version=1.11
|
||||
--override riscvOVPsim/cpu/mvendorid=0
|
||||
--override riscvOVPsim/cpu/marchid=0
|
||||
--override riscvOVPsim/cpu/mimpid=0
|
||||
--override riscvOVPsim/cpu/mhartid=0
|
||||
--override riscvOVPsim/cpu/cycle_undefined=F
|
||||
--override riscvOVPsim/cpu/instret_undefined=F
|
||||
--override riscvOVPsim/cpu/time_undefined=T
|
||||
--override riscvOVPsim/cpu/reset_address=0x80000000
|
||||
--override riscvOVPsim/cpu/simulateexceptions=T
|
||||
--override riscvOVPsim/cpu/defaultsemihost=F
|
||||
--override riscvOVPsim/cpu/wfi_is_nop=T
|
||||
--exitonsymbol _exit
|
146
vendor/google_riscv-dv/target/rv32imc_sv32/riscv_core_setting.sv
vendored
Normal file
146
vendor/google_riscv-dv/target/rv32imc_sv32/riscv_core_setting.sv
vendored
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Processor feature configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
// XLEN
|
||||
parameter int XLEN = 32;
|
||||
|
||||
// Parameter for SATP mode, set to BARE if address translation is not supported
|
||||
parameter satp_mode_t SATP_MODE = SV32;
|
||||
|
||||
// Supported Privileged mode
|
||||
privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE, USER_MODE};
|
||||
|
||||
// Unsupported instructions
|
||||
riscv_instr_name_t unsupported_instr[];
|
||||
|
||||
// ISA supported by the processor
|
||||
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C};
|
||||
|
||||
// Interrupt mode support
|
||||
mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};
|
||||
|
||||
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
|
||||
// supported
|
||||
int max_interrupt_vector_num = 16;
|
||||
|
||||
// Physical memory protection support
|
||||
bit support_pmp = 0;
|
||||
|
||||
// Debug mode support
|
||||
bit support_debug_mode = 0;
|
||||
|
||||
// Support delegate trap to user mode
|
||||
bit support_umode_trap = 0;
|
||||
|
||||
// Support sfence.vma instruction
|
||||
bit support_sfence = 0;
|
||||
|
||||
// Support unaligned load/store
|
||||
bit support_unaligned_load_store = 1'b1;
|
||||
|
||||
// GPR setting
|
||||
parameter int NUM_FLOAT_GPR = 32;
|
||||
parameter int NUM_GPR = 32;
|
||||
parameter int NUM_VEC_GPR = 32;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Vector extension configuration
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Parameter for vector extension
|
||||
parameter int VECTOR_EXTENSION_ENABLE = 0;
|
||||
|
||||
parameter int VLEN = 512;
|
||||
|
||||
// Maximum size of a single vector element
|
||||
parameter int ELEN = 32;
|
||||
|
||||
// Minimum size of a sub-element, which must be at most 8-bits.
|
||||
parameter int SELEN = 8;
|
||||
|
||||
// Maximum size of a single vector element (encoded in vsew format)
|
||||
parameter int VELEN = int'($ln(ELEN)/$ln(2)) - 3;
|
||||
|
||||
// Maxium LMUL supported by the core
|
||||
parameter int MAX_LMUL = 8;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Multi-harts configuration
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Number of harts
|
||||
parameter int NUM_HARTS = 1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Implemented previlieged CSR list
|
||||
`ifdef DSIM
|
||||
privileged_reg_t implemented_csr[] = {
|
||||
`else
|
||||
const privileged_reg_t implemented_csr[] = {
|
||||
`endif
|
||||
// Machine mode mode CSR
|
||||
MVENDORID, // Vendor ID
|
||||
MARCHID, // Architecture ID
|
||||
MIMPID, // Implementation ID
|
||||
MHARTID, // Hardware thread ID
|
||||
MSTATUS, // Machine status
|
||||
MISA, // ISA and extensions
|
||||
MIE, // Machine interrupt-enable register
|
||||
MTVEC, // Machine trap-handler base address
|
||||
MCOUNTEREN, // Machine counter enable
|
||||
MSCRATCH, // Scratch register for machine trap handlers
|
||||
MEPC, // Machine exception program counter
|
||||
MCAUSE, // Machine trap cause
|
||||
MTVAL, // Machine bad address or instruction
|
||||
MIP // Machine interrupt pending
|
||||
};
|
||||
|
||||
// Implementation-specific custom CSRs
|
||||
bit [11:0] custom_csr[] = {
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Supported interrupt/exception setting, used for functional coverage
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
`ifdef DSIM
|
||||
interrupt_cause_t implemented_interrupt[] = {
|
||||
`else
|
||||
const interrupt_cause_t implemented_interrupt[] = {
|
||||
`endif
|
||||
M_SOFTWARE_INTR,
|
||||
M_TIMER_INTR,
|
||||
M_EXTERNAL_INTR
|
||||
};
|
||||
|
||||
`ifdef DSIM
|
||||
exception_cause_t implemented_exception[] = {
|
||||
`else
|
||||
const exception_cause_t implemented_exception[] = {
|
||||
`endif
|
||||
INSTRUCTION_ACCESS_FAULT,
|
||||
ILLEGAL_INSTRUCTION,
|
||||
BREAKPOINT,
|
||||
LOAD_ADDRESS_MISALIGNED,
|
||||
LOAD_ACCESS_FAULT,
|
||||
ECALL_MMODE
|
||||
};
|
44
vendor/google_riscv-dv/target/rv32imc_sv32/testlist.yaml
vendored
Normal file
44
vendor/google_riscv-dv/target/rv32imc_sv32/testlist.yaml
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Copyright 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 test list format
|
||||
# --------------------------------------------------------------------------------
|
||||
# test : Assembly test name
|
||||
# description : Description of this test
|
||||
# gen_opts : Instruction generator options
|
||||
# iterations : Number of iterations of this test
|
||||
# no_iss : Enable/disable ISS simulator (Optional)
|
||||
# gen_test : Test name used by the instruction generator
|
||||
# asm_tests : Path to directed, hand-coded assembly test file or directory
|
||||
# rtl_test : RTL simulation test name
|
||||
# cmp_opts : Compile options passed to the instruction generator
|
||||
# sim_opts : Simulation options passed to the instruction generator
|
||||
# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional)
|
||||
# compare_opts : Options for the RTL & ISS trace comparison
|
||||
# gcc_opts : gcc compile options
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
- import: <riscv_dv_root>/target/rv32imc/testlist.yaml
|
||||
|
||||
- test: riscv_u_mode_rand_test
|
||||
description: >
|
||||
Random previliged mode test
|
||||
iterations: 2
|
||||
gen_test: riscv_instr_base_test
|
||||
gen_opts: >
|
||||
+instr_cnt=10000
|
||||
+num_of_sub_program=5
|
||||
+boot_mode=u
|
||||
rtl_test: core_base_test
|
|
@ -115,11 +115,7 @@ const privileged_reg_t implemented_csr[] = {
|
|||
};
|
||||
|
||||
// Implementation-specific custom CSRs
|
||||
`ifdef DSIM
|
||||
bit [11:0] custom_csr[] = {
|
||||
`else
|
||||
const bit [11:0] custom_csr[] = {
|
||||
`endif
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -141,11 +141,7 @@ const privileged_reg_t implemented_csr[] = {
|
|||
};
|
||||
|
||||
// Implementation-specific custom CSRs
|
||||
`ifdef DSIM
|
||||
bit [11:0] custom_csr[] = {
|
||||
`else
|
||||
const bit [11:0] custom_csr[] = {
|
||||
`endif
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/user_version=2.3
|
||||
--override riscvOVPsim/cpu/priv_version=1.11
|
||||
--override riscvOVPsim/cpu/vector_version=0.8
|
||||
--override riscvOVPsim/cpu/vector_version=0.9
|
||||
--override riscvOVPsim/cpu/mvendorid=0
|
||||
--override riscvOVPsim/cpu/marchid=0
|
||||
--override riscvOVPsim/cpu/mimpid=0
|
||||
|
|
|
@ -140,11 +140,7 @@ const privileged_reg_t implemented_csr[] = {
|
|||
};
|
||||
|
||||
// Implementation-specific custom CSRs
|
||||
`ifdef DSIM
|
||||
bit [11:0] custom_csr[] = {
|
||||
`else
|
||||
const bit [11:0] custom_csr[] = {
|
||||
`endif
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -29,7 +29,80 @@
|
|||
# gcc_opts : gcc compile options
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
- import: <riscv_dv_root>/target/rv64gc/testlist.yaml
|
||||
- import: <riscv_dv_root>/target/rv64imc/testlist.yaml
|
||||
|
||||
- test: riscv_invalid_csr_test
|
||||
description: >
|
||||
Boot core into random privileged mode and generate csr accesses to invalid CSRs (at a higher priv mode)
|
||||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+instr_cnt=6000
|
||||
+num_of_sub_program=0
|
||||
+enable_access_invalid_csr_level=1
|
||||
rtl_test: core_invalid_csr_test
|
||||
sim_opts: >
|
||||
+require_signature_addr=1
|
||||
|
||||
- test: riscv_amo_test
|
||||
description: >
|
||||
RISC-V atomic instruction extension test
|
||||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+instr_cnt=5000
|
||||
+num_of_sub_program=5
|
||||
+directed_instr_0=riscv_lr_sc_instr_stream,10
|
||||
+directed_instr_1=riscv_amo_instr_stream,10
|
||||
rtl_test: core_base_test
|
||||
|
||||
- test: riscv_floating_point_arithmetic_test
|
||||
description: >
|
||||
Enable floating point instructions
|
||||
gen_opts: >
|
||||
+instr_cnt=10000
|
||||
+num_of_sub_program=0
|
||||
+no_fence=1
|
||||
+no_data_page=1
|
||||
+no_branch_jump=1
|
||||
+enable_floating_point=1
|
||||
+boot_mode=m
|
||||
iterations: 1
|
||||
gen_test: riscv_instr_base_test
|
||||
rtl_test: core_base_test
|
||||
|
||||
- test: riscv_floating_point_rand_test
|
||||
description: >
|
||||
Enable floating point instructions
|
||||
gen_opts: >
|
||||
+enable_floating_point=1
|
||||
+instr_cnt=10000
|
||||
+num_of_sub_program=5
|
||||
+directed_instr_0=riscv_load_store_rand_instr_stream,4
|
||||
+directed_instr_1=riscv_loop_instr,4
|
||||
+directed_instr_2=riscv_multi_page_load_store_instr_stream,4
|
||||
+directed_instr_3=riscv_mem_region_stress_test,4
|
||||
+directed_instr_4=riscv_jal_instr,4
|
||||
iterations: 1
|
||||
gen_test: riscv_instr_base_test
|
||||
rtl_test: core_base_test
|
||||
|
||||
- test: riscv_floating_point_mmu_stress_test
|
||||
description: >
|
||||
Test with different patterns of load/store instructions, stress test MMU
|
||||
operations.
|
||||
iterations: 2
|
||||
gen_test: riscv_instr_base_test
|
||||
gen_opts: >
|
||||
+instr_cnt=5000
|
||||
+num_of_sub_program=5
|
||||
+enable_floating_point=1
|
||||
+directed_instr_0=riscv_load_store_rand_instr_stream,40
|
||||
+directed_instr_1=riscv_load_store_hazard_instr_stream,40
|
||||
+directed_instr_2=riscv_multi_page_load_store_instr_stream,10
|
||||
+directed_instr_3=riscv_mem_region_stress_test,10
|
||||
rtl_test: core_base_test
|
||||
|
||||
|
||||
- test: riscv_vector_arithmetic_test
|
||||
description: >
|
||||
|
|
|
@ -114,11 +114,7 @@ const privileged_reg_t implemented_csr[] = {
|
|||
};
|
||||
|
||||
// Implementation-specific custom CSRs
|
||||
`ifdef DSIM
|
||||
bit [11:0] custom_csr[] = {
|
||||
`else
|
||||
const bit [11:0] custom_csr[] = {
|
||||
`endif
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -115,11 +115,7 @@ const privileged_reg_t implemented_csr[] = {
|
|||
};
|
||||
|
||||
// Implementation-specific custom CSRs
|
||||
`ifdef DSIM
|
||||
bit [11:0] custom_csr[] = {
|
||||
`else
|
||||
const bit [11:0] custom_csr[] = {
|
||||
`endif
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -42,7 +42,7 @@ class riscv_instr_cov_test extends uvm_test;
|
|||
bit expect_illegal_instr;
|
||||
entry_cnt = 0;
|
||||
instr_cg.reset();
|
||||
if (uvm_is_match("*illegal*", trace_csv[i])) begin
|
||||
if (uvm_is_match("*illegal*", trace_csv[i]) || uvm_is_match("*unknown*", trace_csv[i]) ) begin
|
||||
expect_illegal_instr = 1;
|
||||
end
|
||||
`uvm_info(`gfn, $sformatf("Processing CSV trace[%0d]: %s", i, trace_csv[i]), UVM_LOW)
|
||||
|
|
5
vendor/google_riscv-dv/yaml/simulator.yaml
vendored
5
vendor/google_riscv-dv/yaml/simulator.yaml
vendored
|
@ -135,3 +135,8 @@
|
|||
sim:
|
||||
cmd: >
|
||||
xrun -R -xmlibdirpath <out> <sim_opts> -svseed <seed> -svrnc rand_struct -nokey
|
||||
|
||||
- tool: pyflow
|
||||
sim:
|
||||
cmd: >
|
||||
python3 <cwd>/pygen/pygen_src/test/<test_name>.py <sim_opts>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue