[bazel,dvsim] remove gen-binaries.py's reliance on meson_init.sh
Meson will soon be removed from our project and replaced entirely with
bazel (#12449). This updates the the OTBN `gen-binaries.py` script to
not rely on the presence of the `.env` file that was produced by the
`meson_init.sh` script to provide locations to the RV32 toolchain.
Instead, the `gen-binaries.py` script now uses environment variables to
get the locations of the RV32 toolchain tools, which are populated via
queries to bazel.
This fixes #12447.
Signed-off-by: Timothy Trippel <ttrippel@google.com>
diff --git a/hw/ip/otbn/dv/uvm/gen-binaries.py b/hw/ip/otbn/dv/uvm/gen-binaries.py
index 7960fa4..47eb8ec 100755
--- a/hw/ip/otbn/dv/uvm/gen-binaries.py
+++ b/hw/ip/otbn/dv/uvm/gen-binaries.py
@@ -38,6 +38,10 @@
return read_positive(val)
+def is_exe(path: str) -> bool:
+ return os.path.isfile(path) and os.access(path, os.X_OK)
+
+
class Toolchain:
def __init__(self, env_data: Dict[str, str]) -> None:
@@ -50,7 +54,7 @@
def get_tool(env_data: Dict[str, str], tool: str) -> str:
path = env_data.get(tool)
if path is None:
- raise RuntimeError('No entry for {} in .env file'.format(tool))
+ raise RuntimeError('Unable to find tool: {}.'.format(tool))
return path
def run(self, cmd: List[str]) -> None:
@@ -61,60 +65,29 @@
subprocess.run(cmd, env=env)
-def take_env_line(dst: Dict[str, str], path: str, line_number: int,
- line: str) -> None:
- '''Read one line from a .env file, updating dst.'''
- line = line.split('#', 1)[0].strip()
- if not line:
- return
+def get_toolchain(otbn_dir: str) -> Toolchain:
+ '''Reads environment variables to get toolchain info.'''
+ env_dict = {} # type: Dict[str, str]
- parts = line.split('=', 1)
- if len(parts) != 2:
- raise RuntimeError('{}:{}: No equals sign in line {!r}.'.format(
- path, line_number, line))
+ # OTBN assembler and linker
+ env_dict['OTBN_AS'] = f"{otbn_dir}/util/otbn_as.py"
+ env_dict['OTBN_LD'] = f"{otbn_dir}/util/otbn_ld.py"
- dst[parts[0]] = parts[1]
+ # RV32 assembler and linker
+ env_dict['RV32_TOOL_AS'] = os.getenv('RV32_TOOL_AS')
+ rv32_tool_as_default = "tools/riscv/bin/riscv32-unknown-elf-as"
+ if env_dict['RV32_TOOL_AS'] is None and is_exe(rv32_tool_as_default):
+ env_dict['RV32_TOOL_AS'] = rv32_tool_as_default
+ env_dict['RV32_TOOL_LD'] = os.getenv('RV32_TOOL_LD')
+ rv32_tool_ld_default = "tools/riscv/bin/riscv32-unknown-elf-ld"
+ if env_dict['RV32_TOOL_LD'] is None and is_exe(rv32_tool_ld_default):
+ env_dict['RV32_TOOL_LD'] = rv32_tool_ld_default
-
-def read_toolchain(obj_dir_arg: Optional[str], otbn_dir: str) -> Toolchain:
- '''Read Meson's dumped .env file to get toolchain info'''
- if obj_dir_arg is not None:
- obj_dir = obj_dir_arg
- source = 'specified by an --obj-dir argument'
- else:
- obj_dir_env = os.getenv('OBJ_DIR')
- if obj_dir_env is not None:
- obj_dir = obj_dir_env
- source = ('inferred from OBJ_DIR environment variable; '
- 'have you run meson_init.sh?')
- else:
- git_dir = os.path.normpath(os.path.join(otbn_dir, '../' * 3))
- obj_dir = os.path.normpath(os.path.join(git_dir, 'build-out'))
- source = ('inferred from script location; '
- 'have you run meson_init.sh?')
-
- env_path = os.path.join(obj_dir, '.env')
- try:
- with open(env_path) as env_file:
- env_dict = {} # type: Dict[str, str]
- for idx, line in enumerate(env_file):
- take_env_line(env_dict, env_path, idx + 1, line)
-
- return Toolchain(env_dict)
- except OSError as ose:
- raise RuntimeError('Failed to read .env file at {!r} '
- '(at a path {}): {}.'.format(env_path, source,
- ose)) from None
+ return Toolchain(env_dict)
def main() -> int:
parser = argparse.ArgumentParser()
- parser.add_argument('--obj-dir',
- help=('Object directory configured with Meson (used '
- 'to find tool configuration). If not supplied, '
- 'defaults to the OBJ_DIR environment variable '
- 'if set, or build-out at the top of the '
- 'repository if not.'))
parser.add_argument('--count',
type=read_positive,
help='Number of binaries to generate (default: 10)')
@@ -164,7 +137,7 @@
otbn_dir = os.path.normpath(os.path.join(script_dir, '../' * 2))
try:
- toolchain = read_toolchain(args.obj_dir, otbn_dir)
+ toolchain = get_toolchain(otbn_dir)
except RuntimeError as err:
print(err, file=sys.stderr)
return 1
@@ -204,7 +177,7 @@
def write_ninja_rnd(handle: TextIO, toolchain: Toolchain, otbn_dir: str,
count: int, start_seed: int, size: int) -> None:
- '''Write a build.ninja to build random binaries
+ '''Write a build.ninja to build random binaries.
The rules build everything in the same directory as the build.ninja file.
OTBN tooling is found through the toolchain argument.
diff --git a/hw/ip/otbn/dv/uvm/get-toolchain-paths.sh b/hw/ip/otbn/dv/uvm/get-toolchain-paths.sh
new file mode 100755
index 0000000..00b941c
--- /dev/null
+++ b/hw/ip/otbn/dv/uvm/get-toolchain-paths.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+set -o errexit
+set -o pipefail
+
+# If we are on an air-gapped machine, we need to first ensure the toolchain has
+# been unpacked from the repository cache.
+if [[ -n ${BAZEL_CACHE} ]]; then
+ BAZEL_CMD="bazel"
+ ${BAZEL_CMD} fetch \
+ --distdir=${BAZEL_DISTDIR} \
+ --repository_cache=${BAZEL_CACHE} \
+ @com_lowrisc_toolchain_rv32imc_compiler//...
+else
+ BAZEL_CMD="./bazelisk.sh"
+ ${BAZEL_CMD} fetch @com_lowrisc_toolchain_rv32imc_compiler//...
+fi
+
+# Set environment variables for the RV32 linker and assembler.
+export RV32_TOOL_LD=$(${BAZEL_CMD} query \
+ 'deps(@com_lowrisc_toolchain_rv32imc_compiler//:bin/riscv32-unknown-elf-ld)' \
+ --output location | cut -f1 -d:)
+export RV32_TOOL_AS=$(${BAZEL_CMD} query \
+ 'deps(@com_lowrisc_toolchain_rv32imc_compiler//:bin/riscv32-unknown-elf-as)' \
+ --output location | cut -f1 -d:)
diff --git a/hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson b/hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson
index bf2cfc6..01d5378 100644
--- a/hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson
+++ b/hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson
@@ -70,18 +70,12 @@
run_opts: ["+otbn_elf_dir={otbn_elf_dir}"]
- // A default build mode, used for the tests explicitly listed below. This
- // runs meson to set up a .env file, needed by gen-binaries.py to find a
- // toolchain. This isn't needed for things like the automated CSR tests, and
- // they won't use it because they build in a different mode anyway.
- //
- // This step could run either as a pre-build command or a post-build command.
- // Since it's much quicker than the SV build, we do it first so that you get
- // a quick result if something has gone wrong.
+ // The default build mode, used for the tests explicitly listed below does not
+ // require any pre-build steps.
build_modes: [
{
name: default
- pre_build_cmds: ["cd {proj_root} && BUILD_ROOT={build_dir} ./meson_init.sh"]
+ pre_build_cmds: []
}
]
@@ -89,12 +83,13 @@
// controls the number of instructions that are run before ECALL or error.
binary_size: 2000
- otbn_obj_dir: "{build_dir}/build-out"
- gen_binaries_py: "{otbn_dir}/dv/uvm/gen-binaries.py"
+ // This runs bazel to locate the RV32 toolchain, needed by gen-binaries.py.
+ setup_env: "pushd {proj_root}; source hw/ip/otbn/dv/uvm/get-toolchain-paths.sh; popd;"
+ gen_binaries_py: "{setup_env} {otbn_dir}/dv/uvm/gen-binaries.py"
rnd_args: "--seed {seed} --size {binary_size}"
- gen_fixed: "{gen_binaries_py} --obj-dir {otbn_obj_dir}"
- gen_rnd: "{gen_binaries_py} --obj-dir {otbn_obj_dir} {rnd_args}"
+ gen_fixed: "{gen_binaries_py}"
+ gen_rnd: "{gen_binaries_py} {rnd_args}"
smoke_dir: "{otbn_dir}/dv/smoke"
multi_err_dir: "{otbn_dir}/dv/otbnsim/test/simple/multi"