Add a wrapper script for building the core_ibex UVM testbench

This kind of existed already, but this tweaks things so that it's the
same shape as the other scripts we're adding and (hopefully) the
Python gets a bit cleaner.
This commit is contained in:
Rupert Swarbrick 2022-04-13 20:48:14 +01:00 committed by hcallahan-lowrisc
parent 014b5443b8
commit 8fd1a0df50
4 changed files with 92 additions and 59 deletions

View file

@ -396,14 +396,13 @@ cosim-arg := $(if $(call equal,$(COSIM),1),--en_cosim,)
$(OUT-DIR)rtl_sim/.rtl.tb_compile.stamp: \
$(tb-compile-vars-prereq) $(all-verilog) $(risc-dv-files) \
sim.py yaml/rtl_simulation.yaml \
scripts/compile-tb.py yaml/rtl_simulation.yaml \
| $(OUT-DIR)rtl_sim
$(verb)./sim.py \
--o=$(OUT-DIR) \
--steps=compile \
${COMMON_OPTS} \
--simulator="${SIMULATOR}" \
$(cov-arg) $(wave-arg) $(cosim-arg)
$(verb)scripts/compile-tb.py \
$(verb-arg) \
--output=$(OUT-DIR) \
--simulator=$(SIMULATOR) \
$(cov-arg) $(wave-arg) $(cosim-arg)
$(call dump-vars,$(OUT-DIR)rtl_sim/.rtl.tb_compile.vars.mk,comp,$(tb-compile-var-deps))
@touch $@

View file

@ -0,0 +1,58 @@
#!/usr/bin/env python3
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
import argparse
import os
import sys
from scripts_lib import run_one
from sim_cmd import get_simulator_cmd
def subst_vars(string, var_dict):
'''Apply substitutions in var_dict to string
If var_dict[K] = V, then <K> will be replaced with V in string.'''
for key, value in var_dict.items():
string = string.replace('<{}>'.format(key), value)
return string
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', action='store_true')
parser.add_argument('--output', required=True)
parser.add_argument('--simulator', required=True)
parser.add_argument('--en_cov', action='store_true')
parser.add_argument('--en_wave', action='store_true')
parser.add_argument('--en_cosim', action='store_true')
args = parser.parse_args()
output_dir = os.path.join(args.output, 'rtl_sim')
os.makedirs(output_dir, exist_ok=True)
enables = {
'cov_opts': args.en_cov,
'wave_opts': args.en_wave,
'cosim_opts': args.en_cosim
}
compile_cmds, _ = get_simulator_cmd(args.simulator, enables)
for pre_cmd in compile_cmds:
cmd = subst_vars(pre_cmd, {'out': output_dir})
retcode = run_one(args.verbose, ['sh', '-c', cmd],
discard_stdstreams=True)
if retcode:
return retcode
return 0
if __name__ == '__main__':
sys.exit(main())

View file

@ -15,16 +15,37 @@ RISCV_DV_ROOT = os.path.normpath(os.path.join(IBEX_ROOT,
'vendor/google_riscv-dv'))
def run_one(verbose: bool, cmd: List[str]) -> int:
def run_one(verbose: bool,
cmd: List[str],
discard_stdstreams: bool = False) -> int:
'''Run a command, returning its return code
If verbose is true, print the command to stderr first (a bit like bash -x).
If discard_stdstreams is true, redirect stdout and stderr in the subprocess
to /dev/null. This seems a bit crazy, but makes sense for EDA tools that
have a '-l' argument that takes a path to which they write a copy of
everything that was going out on stdout/stderr.
'''
stdstream_dest = None
shell_redirection = ''
if discard_stdstreams:
stdstream_dest = subprocess.DEVNULL
shell_redirection = ' >/dev/null 2>&1'
if verbose:
# The equivalent of bash -x
print('+ ' + ' '.join(shlex.quote(w) for w in cmd),
file=sys.stderr)
cmd_str = ' '.join(shlex.quote(w) for w in cmd) + shell_redirection
print('+ ' + cmd_str, file=sys.stderr)
# Passing close_fds=False ensures that if cmd is a call to Make then we'll
# pass through the jobserver fds. If you don't do this, you get a warning
# starting "warning: jobserver unavailable".
return subprocess.run(cmd, close_fds=False).returncode
return subprocess.run(cmd,
stdout=stdstream_dest,
stderr=stdstream_dest,
close_fds=False).returncode
def start_riscv_dv_run_cmd(verbose: bool):

View file

@ -22,8 +22,6 @@ import os
import subprocess
import sys
from scripts.sim_cmd import get_simulator_cmd
_CORE_IBEX = os.path.normpath(os.path.join(os.path.dirname(__file__)))
_IBEX_ROOT = os.path.normpath(os.path.join(_CORE_IBEX, '../../..'))
_RISCV_DV_ROOT = os.path.join(_IBEX_ROOT, 'vendor/google_riscv-dv')
@ -45,44 +43,6 @@ finally:
sys.path = _OLD_SYS_PATH
def subst_vars(string, var_dict):
'''Apply substitutions in var_dict to string
If var_dict[K] = V, then <K> will be replaced with V in string.'''
for key, value in var_dict.items():
string = string.replace('<{}>'.format(key), value)
return string
def rtl_compile(compile_cmds, output_dir, lsf_cmd):
"""Compile the testbench RTL
compile_cmds is a list of commands (each a string), which will have <out>
substituted. Running them in sequence should compile the testbench.
output_dir is the directory in which to generate the testbench (usually
something like 'out/rtl_sim'). This will be substituted for <out> in the
commands.
If lsf_cmd is not None, it should be a string to prefix onto commands to
run them through LSF. Here, this is not used for parallelism, but might
still be needed for licence servers.
"""
logging.info("Compiling TB")
for cmd in compile_cmds:
cmd = subst_vars(cmd, {'out': output_dir})
if lsf_cmd is not None:
cmd = lsf_cmd + ' ' + cmd
logging.debug("Compile command: %s" % cmd)
# Note that we don't use run_parallel_cmd here: the commands in
# compile_cmds need to be run serially.
run_cmd(cmd)
#TODO(udinator) - support DSim, and Riviera
def gen_cov(base_dir, simulator, lsf_cmd):
"""Generate a merged coverage directory.
@ -203,14 +163,9 @@ def main():
# Compile TB
if steps['compile']:
enables = {
'cov_opts': args.en_cov,
'wave_opts': args.en_wave,
'cosim_opts': args.en_cosim
}
compile_cmds, sim_cmd = get_simulator_cmd(args.simulator, enables)
rtl_compile(compile_cmds, output_dir, args.lsf_cmd)
raise RuntimeError('TB compilation is no longer supported by this '
'script: use compile-tb.py.')
exit(1)
# Generate merged coverage directory and load it into appropriate GUI
if steps['cov']: