blob: cc993159345a41626fbcded182fcdb0c3f34c587 [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
load("@lowrisc_opentitan//rules:opentitan.bzl", "opentitan_flash_binary", "opentitan_rom_binary")
load("@bazel_skylib//lib:shell.bzl", "shell")
_EXIT_SUCCESS = r"PASS.*\n"
_EXIT_FAILURE = r"(FAIL|FAULT).*\n"
_BASE_PARAMS = {
"args": [],
"data": [],
"local": True,
"otp": "@//hw/ip/otp_ctrl/data:img_rma",
"rom": "@//sw/device/lib/testing/test_rom:test_rom_{}_scr_vmem",
"tags": [],
"test_runner": "@//util:opentitan_functest_runner.sh",
"timeout": "moderate", # 5 minutes
"exit_success": _EXIT_SUCCESS,
"exit_failure": _EXIT_FAILURE,
}
def dv_params(
# Base Parameters
args = _BASE_PARAMS["args"] + [
"$(location {dvsim_config})",
],
data = _BASE_PARAMS["data"],
local = _BASE_PARAMS["local"],
otp = _BASE_PARAMS["otp"],
rom = _BASE_PARAMS["rom"].format("sim_dv"),
tags = _BASE_PARAMS["tags"],
timeout = _BASE_PARAMS["timeout"],
test_runner = "@//util:dvsim_test_runner.sh",
# DV-specific Parameters
bootstrap_sw = False, # Default to backdoor loading.
dvsim_config = "@//hw/top_earlgrey/dv:chip_sim_cfg.hjson",
**kwargs):
"""A macro to create DV sim parameters for OpenTitan functional tests.
This macro emits a dictionary of parameters which are pasted into the DV
simulation specific test rule.
Args:
@param args: Extra arguments to pass to the test runner (`dvsim.py`).
@param data: Data dependencies of the test.
@param local: Whether the test should be run locally without sandboxing.
@param otp: The OTP image to use.
@param rom: The ROM image to use.
@param tags: The test tags to apply to the test rule.
@param timeout: The timeout to apply to the test rule.
@param bootstrap_sw: Whether to load flash via bootstrap.
@param dvsim_config: The dvsim.py Hjson config file for the toplevel.
"""
required_args = [
"-i",
"chip_sw_{name}",
"--",
]
required_data = [
dvsim_config,
"@//util/dvsim",
"@//hw:all_files",
"@//hw:fusesoc_ignore",
]
required_tags = ["dv"]
kwargs.update(
args = args + required_args,
data = required_data + data,
local = local,
otp = otp,
rom = rom,
tags = required_tags + tags,
test_runner = test_runner,
timeout = timeout,
bootstrap_sw = bootstrap_sw,
dvsim_config = dvsim_config,
)
return kwargs
def verilator_params(
# Base Parameters
args = _BASE_PARAMS["args"] + [
"console",
"--exit-success={exit_success}",
"--exit-failure={exit_failure}",
"--timeout=3600s",
],
data = _BASE_PARAMS["data"],
exit_success = _BASE_PARAMS["exit_success"],
exit_failure = _BASE_PARAMS["exit_failure"],
local = _BASE_PARAMS["local"],
otp = _BASE_PARAMS["otp"],
rom = _BASE_PARAMS["rom"].format("sim_verilator"),
tags = _BASE_PARAMS["tags"] + ["cpu:4"],
timeout = _BASE_PARAMS["timeout"],
test_runner = _BASE_PARAMS["test_runner"],
# Verilator-specific Parameters
# None
**kwargs):
"""A macro to create Verilator sim parameters for OpenTitan functional tests.
This macro emits a dictionary of parameters which are pasted into the
Verilator simulation specific test rule.
Args:
@param args: Extra arguments to pass to the test runner (`opentitantool`).
@param data: Data dependencies of the test.
@param local: Whether the test should be run locally without sandboxing.
@param otp: The OTP image to use.
@param rom: The ROM image to use.
@param tags: The test tags to apply to the test rule.
@param timeout: The timeout to apply to the test rule.
"""
required_args = [
"--rcfile=",
"--logging=info",
"--interface=verilator",
"--conf=sw/host/opentitantool/config/opentitan_verilator.json",
"--verilator-bin=$(location @//hw:verilator)/sim-verilator/Vchip_sim_tb",
"--verilator-rom=$(location {rom})",
"--verilator-flash=$(location {flash})",
"--verilator-otp=$(location {otp})",
]
required_data = [
"@//sw/host/opentitantool:test_resources",
"@//hw:verilator",
"@//hw:fusesoc_ignore",
]
required_tags = ["verilator"]
kwargs.update(
args = required_args + args,
data = required_data + data,
exit_success = exit_success,
exit_failure = exit_failure,
local = local,
otp = otp,
rom = rom,
tags = required_tags + tags,
test_runner = test_runner,
timeout = timeout,
)
return kwargs
def cw310_params(
# Base Parameters
args = _BASE_PARAMS["args"] + [
"--exec=\"load-bitstream --rom-kind={rom_kind} $(location {bitstream})\"",
"--exec=\"bootstrap --clear-uart=true $(location {flash})\"",
"console",
"--exit-success={exit_success}",
"--exit-failure={exit_failure}",
"--timeout=3600s",
],
data = _BASE_PARAMS["data"] + ["{bitstream}"],
exit_success = _BASE_PARAMS["exit_success"],
exit_failure = _BASE_PARAMS["exit_failure"],
local = _BASE_PARAMS["local"],
otp = _BASE_PARAMS["otp"],
rom = _BASE_PARAMS["rom"].format("fpga_cw310"),
tags = _BASE_PARAMS["tags"],
test_runner = _BASE_PARAMS["test_runner"],
# CW310-specific Parameters
bitstream = "@//hw/bitstream:test_rom",
rom_kind = None,
# None
timeout = "short",
**kwargs):
"""A macro to create CW310 parameters for OpenTitan functional tests.
This macro emits a dictionary of parameters which are pasted into the
ChipWhisperer-310 FPGA specific test rule.
Args:
@param args: Extra arguments to pass the test runner `opentitantool`.
@param data: Data dependencies of the test.
@param local: Whether the test should be run locally without sandboxing.
@param otp: The OTP image to use.
@param rom: The ROM image to use.
@param tags: The test tags to apply to the test rule.
@param timeout: The timeout to apply to the test rule.
"""
required_args = [
"--rcfile=",
"--logging=info",
"--interface=cw310",
"--conf=sw/host/opentitantool/config/opentitan_cw310.json",
]
required_data = [
"@//sw/host/opentitantool:test_resources",
]
required_tags = [
"cw310",
"exclusive",
]
kwargs.update(
args = required_args + args,
data = required_data + data,
exit_success = exit_success,
exit_failure = exit_failure,
local = local,
otp = otp,
rom = rom,
tags = required_tags + tags,
test_runner = test_runner,
timeout = timeout,
bitstream = bitstream,
rom_kind = rom_kind,
)
return kwargs
def _format_list(param_name, list1, datadict, **kwargs):
"""Concatenate and format list items.
This is used to prepare substitutions in user-supplied args to the
various test invocations (ie: the location of flash).
Args:
@param param_name: The name of the item in `datadict`.
@param list1: A list of items to prepend to the list item from datadict.
@param datadict: A dictionary of per-test parameters.
@param **kwargs: Values to pass to the format function.
Returns:
list[str]
"""
return [x.format(**kwargs) for x in list1 + datadict.pop(param_name, [])]
def opentitan_functest(
name,
targets = ["dv", "verilator", "cw310"],
args = [],
data = [],
test_in_rom = False,
signed = False,
test_harness = "//sw/host/opentitantool",
key = "test_key_0",
dv = None,
verilator = None,
cw310 = None,
test_binary = None,
**kwargs):
"""A helper macro for generating OpenTitan functional tests.
This macro is mostly a wrapper around opentitan_flash_binary, but creates
testing artifacts for each of the hardware targets in `targets`. The testing
artifacts are then given to an `sh_test` rule which dispatches the test to
the corresponding hardware target via opentitantool.
Args:
@param name: The name of this rule.
@param targets: A list of hardware targets on which to dispatch tests.
@param args: Extra arguments (in addition to those defined in the target-
specific parameter dictionary) to pass to the test runner
(`opentitantool` or `dvsim.py`).
@param data: Extra data dependencies (in addition to those defined in the
target-specific parameter dictionary) needed while executing
the test.
@param ottf: Default dependencies for OTTF tests. Set to empty list if
your test doesn't use the OTTF.
@param test_in_rom: Whether to run the test from ROM, runs from flash by
default.
@param signed: Whether to sign the test image. Unsigned by default.
@param test_harness: The binary on the host side that runs the test.
@param key: Which signed test image (by key) to use.
@param dv: DV test parameters.
@param verilator: Verilator test parameters.
@param cw310: CW310 test parameters.
@param test_binary: Use the named binary as the test program rather than building one from srcs/deps.
@param **kwargs: Arguments to forward to `opentitan_flash_binary`.
This macro emits the following rules:
opentitan_flash_binary named: {name}_prog (and all emitted rules).
sh_test named: dv_{name}
sh_test named: verilator_{name}
sh_test named: cw310_{name}
test_suite named: {name}
"""
# Generate flash artifacts for test.
deps = kwargs.pop("deps", [])
if test_in_rom:
opentitan_rom_binary(
name = name + "_rom_prog",
deps = deps,
**kwargs
)
if not test_binary:
test_binary = name + "_prog"
opentitan_flash_binary(
name = test_binary,
output_signed = signed,
deps = deps,
**kwargs
)
all_tests = []
target_params = {
"sim_dv": dv_params() if not dv else dv,
"sim_verilator": verilator_params() if not verilator else verilator,
"fpga_cw310": cw310_params() if not cw310 else cw310,
}
for target, params in target_params.items():
if target.split("_")[-1] not in targets:
continue
# Set test name.
test_name = "{}_{}".format(name, target)
if "manual" not in params.get("tags"):
all_tests.append(test_name)
sw_logs_db = []
# Set flash image.
if target in ["sim_dv", "sim_verilator"]:
flash = "{}_{}_scr_vmem64".format(test_binary, target)
sw_logs_db.append("{}_{}_logs_db".format(test_binary, target))
else:
flash = "{}_{}_bin".format(test_binary, target)
if signed:
flash += "_signed_{}".format(key)
# If the (flash) test image is to be loaded via bootstrap in the DV
# simulation environment, then we need to use a special VMEM image
# that has been split into SPI flash frames. Currently, signed
# images loaded via bootstrap in DV sim are not supported.
# TODO: support signed bootstap images in DV sim.
if target == "sim_dv" and params.pop("bootstrap_sw"):
if test_in_rom:
fail("Tests that run in ROM cannot be bootstrapped.")
if signed:
fail("A signed test cannot be bootstrapped in DV sim.")
flash = "{}_{target}_frames_vmem".format(test_binary, target)
# Set ROM image.
rom = params.pop("rom")
if test_in_rom:
rom = "{}_rom_prog_{}_scr_vmem".format(name, target)
if target in ["sim_dv", "sim_verilator"]:
sw_logs_db.append(rom.replace("_scr_vmem", "_logs_db"))
bitstream = params.pop("bitstream", None)
rom_kind = params.pop("rom_kind", None)
if bitstream and not rom_kind:
if "test_rom" in bitstream:
rom_kind = "testrom"
elif "mask_rom" in bitstream:
rom_kind = "maskrom"
else:
fail("Unknown bitstream type. Expected the bitstream label to contain the string 'test_rom' or 'mask_rom'.")
# Set OTP image.
otp = params.pop("otp")
# Success and failure strings.
exit_strings_kwargs = {}
if target in ["fpga_cw310", "sim_verilator"]:
exit_strings_kwargs = {
"exit_success": shell.quote(params.pop("exit_success")),
"exit_failure": shell.quote(params.pop("exit_failure")),
}
# Retrieve remaining device-agnostic params.
test_runner = params.pop("test_runner")
# Retrieve device-specific params.
dvsim_config = None
if target == "sim_dv":
dvsim_config = params.pop("dvsim_config")
# Concatenate args / data passed into the opentitan_functest macro
# with args / data from device-specific params.
# TODO(lowRISC/opentitan:#11779): remove this concatenation action
concat_args = _format_list(
"args",
args,
params,
dvsim_config = dvsim_config,
flash = flash,
name = name,
otp = otp,
rom = rom,
rom_kind = rom_kind,
bitstream = bitstream,
**exit_strings_kwargs
)
if target == "fpga_cw310":
# We attach the uarts configuration to the front of the command
# line so that they'll be parsed as global options rather than
# command-specific options.
concat_args = select({
"@//ci:lowrisc_fpga_cw310": ["--cw310-uarts=/dev/ttyACM_CW310_1,/dev/ttyACM_CW310_0"],
"//conditions:default": [],
}) + concat_args
concat_data = _format_list(
"data",
data,
params,
flash = flash,
bitstream = bitstream,
)
# Environment variables to pass into sh_test
env = {}
# Specify the test harness
env["TEST_HARNESS"] = "$(location {})".format(test_harness)
concat_data += [test_harness]
native.sh_test(
name = test_name,
srcs = [test_runner],
args = concat_args,
data = [
flash,
rom,
otp,
] + concat_data + sw_logs_db,
env = env,
**params
)
native.test_suite(
name = name,
tests = all_tests,
# In test_suites, tags perform a filtering function and will select
# matching tags internally instead of allowing filters to select
# test_suites.
# There are exceptions: "small", "medium", "large", "enourmous", "manual"
tags = [
# The manual tag is a special case and is applied to the test suite
# it prevents it from being included in wildcards so that
# --build_tag_filters=-verilator works as expected and excludes
# building verilator tests so the verilator build wont be invoked.
"manual",
# For more see https://bazel.build/reference/be/general#test_suite.tags
],
)