Skip to content

Commit

Permalink
[bazel,dvsim] remove gen-binaries.py's reliance on meson_init.sh
Browse files Browse the repository at this point in the history
Meson will soon be removed from our project and replaced entirely with
bazel (lowRISC#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 lowRISC#12447.

Signed-off-by: Timothy Trippel <[email protected]>
  • Loading branch information
timothytrippel committed May 13, 2022
1 parent 46cd727 commit ea9b55b
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 63 deletions.
73 changes: 23 additions & 50 deletions hw/ip/otbn/dv/uvm/gen-binaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def read_jobs(val: Optional[str]) -> Optional[Union[str, int]]:
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:
Expand All @@ -50,7 +54,7 @@ def __init__(self, env_data: Dict[str, str]) -> None:
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:
Expand All @@ -61,60 +65,29 @@ def run(self, cmd: List[str]) -> None:
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

parts = line.split('=', 1)
if len(parts) != 2:
raise RuntimeError('{}:{}: No equals sign in line {!r}.'.format(
path, line_number, line))

dst[parts[0]] = parts[1]
def get_toolchain(otbn_dir: str) -> Toolchain:
'''Reads environment variables to get toolchain info.'''
env_dict = {} # type: Dict[str, str]

# 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"

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)
# 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

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)')
Expand Down Expand Up @@ -164,7 +137,7 @@ def main() -> int:
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
Expand Down Expand Up @@ -204,7 +177,7 @@ def main() -> int:

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.
Expand Down
28 changes: 28 additions & 0 deletions hw/ip/otbn/dv/uvm/get-toolchain-paths.sh
Original file line number Diff line number Diff line change
@@ -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:)
21 changes: 8 additions & 13 deletions hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -70,31 +70,26 @@ name:

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: []
}
]

// The value to pass to the --size parameter for gen-binaries.py. This
// 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"
Expand Down

0 comments on commit ea9b55b

Please sign in to comment.