blob: 752cb4d1bf734c1206ee044c5a161c58fd9210ef [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
"""Rules for generating OTP images.
OTP image generation begins with producing one or more (H)JSON files that
describe the OTP configuration. These files are then consumed by the OTP image
generation tool to produce the OTP VMEM image file used to preload the OTP in
FPGA synthesis or simulation.
The JSON file generation is handled by the otp_json rule, which accepts a list
of partitions. Due to Bazel's limited datatypes for rule attributes, a helper
function (otp_partition) is used to serialize the representation of each
partition to pass it into otp_json as a string.
Usage example:
otp_json(
name = "example_otp_json",
partitions = [
otp_partition(
name = "Partition0",
lock = True,
items = {
"ITEM_1": "abc",
"ITEM_2": "<random>",
}
),
otp_partition(...),
],
)
Note that the "items" dictionary for each partition should be expressed as
{"key": "value"} mappings. This will be expanded by the otp_json rule into a
list of dicts, each of the form {"name": key, "value": value}, which is the
format expected by the image generation tool.
"""
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("//rules:host.bzl", "host_tools_transition")
def get_otp_images():
"""Returns a list of (otp_name, img_target) tuples.
Each tuple corresponds to an OTP image defined in //hw/ip/otp_ctrl/data. The
otp_name is a short, unique suffix of the image target, e.g. "rma". The
img_target is the full path of the OTP image target.
"""
img_targets = [
"//hw/ip/otp_ctrl/data:img_dev",
"//hw/ip/otp_ctrl/data:img_rma",
"//hw/ip/otp_ctrl/data:img_test_unlocked0",
"//hw/ip/otp_ctrl/data:img_prod",
"//hw/ip/otp_ctrl/data:img_prod_end",
"//hw/ip/otp_ctrl/data:img_exec_disabled",
"//hw/ip/otp_ctrl/data:img_bootstrap_disabled",
]
out = []
for img_target in img_targets:
[_, img_target_name] = img_target.rsplit(":")
otp_name = img_target_name.removeprefix("img_")
out.append((
otp_name,
img_target,
))
return out
def otp_partition(name, **kwargs):
partition = {
"name": name,
}
partition.update(kwargs)
return json.encode(partition)
def _otp_json_impl(ctx):
otp = {}
if ctx.attr.seed != "":
otp["seed"] = ctx.attr.seed
otp["partitions"] = [json.decode(p) for p in ctx.attr.partitions]
# For every partition with an "items" dictionary, expand the dictionary of
# key:value pairs into a list of dicts, each of the form
# {
# "name": key,
# "value": value
# }
# This format is expected by the OTP image generation tool
for partition in otp["partitions"]:
if "items" in partition.keys():
items = partition["items"]
partition["items"] = [{"name": k, "value": v} for k, v in items.items()]
file = ctx.actions.declare_file("{}.json".format(ctx.attr.name))
ctx.actions.write(file, json.encode_indent(otp))
return [DefaultInfo(files = depset([file]))]
otp_json = rule(
implementation = _otp_json_impl,
attrs = {
"seed": attr.string(
doc = "Seed to be used for generation of partition randomized values. Can be overridden by the OTP image generation tool.",
),
"partitions": attr.string_list(doc = "A list of serialized partitions from otp_partition."),
},
)
def _otp_alert_digest_impl(ctx):
file = ctx.actions.declare_file("{}.json".format(ctx.attr.name))
outputs = [file]
inputs = [
ctx.file._opentitantool,
ctx.file.otp_img,
]
args = ctx.actions.args()
args.add_all(("--rcfile=", "otp", "alert-digest", ctx.file.otp_img))
args.add("--output", file)
ctx.actions.run(
outputs = outputs,
inputs = inputs,
arguments = [args],
executable = ctx.file._opentitantool.path,
)
return [DefaultInfo(files = depset([file]))]
otp_alert_digest = rule(
implementation = _otp_alert_digest_impl,
attrs = {
"otp_img": attr.label(
allow_single_file = [".json", ".hjson"],
doc = "The OTP image file containing alert_handler values.",
),
"_opentitantool": attr.label(
default = "//sw/host/opentitantool:opentitantool",
allow_single_file = True,
executable = True,
cfg = host_tools_transition,
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
)
def _otp_image(ctx):
output = ctx.actions.declare_file(ctx.attr.name + ".24.vmem")
args = ctx.actions.args()
if not ctx.attr.verbose:
args.add("--quiet")
args.add("--lc-state-def", ctx.file.lc_state_def)
args.add("--mmap-def", ctx.file.mmap_def)
if ctx.attr.img_seed:
args.add("--img-seed", ctx.attr.img_seed[BuildSettingInfo].value)
if ctx.attr.lc_seed:
args.add("--lc-seed", ctx.attr.lc_seed[BuildSettingInfo].value)
if ctx.attr.otp_seed:
args.add("--otp-seed", ctx.attr.otp_seed[BuildSettingInfo].value)
if ctx.attr.data_perm:
args.add("--data-perm", ctx.attr.data_perm[BuildSettingInfo].value)
args.add("--img-cfg", ctx.file.src)
args.add_all(ctx.files.overlays, before_each = "--add-cfg")
args.add("--out", "{}/{}.BITWIDTH.vmem".format(output.dirname, ctx.attr.name))
ctx.actions.run(
outputs = [output],
inputs = [
ctx.file.src,
ctx.file.lc_state_def,
ctx.file.mmap_def,
] + ctx.files.overlays,
arguments = [args],
executable = ctx.executable._tool,
)
return [DefaultInfo(files = depset([output]), runfiles = ctx.runfiles(files = [output]))]
otp_image = rule(
implementation = _otp_image,
attrs = {
"src": attr.label(
allow_single_file = [".json", ".hjson"],
doc = "Image configuration file in Hjson format.",
),
"overlays": attr.label_list(
allow_files = [".json", ".hjson"],
doc = "Additional image configuration file(s) in Hjson format to override src. Overlays are applied in the order provided.",
),
"lc_state_def": attr.label(
allow_single_file = True,
default = "//hw/ip/lc_ctrl/data:lc_ctrl_state.hjson",
doc = "Life-cycle state definition file in Hjson format.",
),
"mmap_def": attr.label(
allow_single_file = True,
default = "//hw/ip/otp_ctrl/data:otp_ctrl_mmap.hjson",
doc = "OTP Controller memory map file in Hjson format.",
),
"img_seed": attr.label(
default = "//hw/ip/otp_ctrl/data:img_seed",
doc = "Configuration override seed used to randomize field values in an OTP image.",
),
"lc_seed": attr.label(
default = "//hw/ip/otp_ctrl/data:lc_seed",
doc = "Configuration override seed used to randomize LC netlist constants.",
),
"otp_seed": attr.label(
default = "//hw/ip/otp_ctrl/data:otp_seed",
doc = "Configuration override seed used to randomize OTP netlist constants.",
),
"data_perm": attr.label(
default = "//hw/ip/otp_ctrl/data:data_perm",
doc = "Post-processing option to trigger permuting bit positions in memfile.",
),
"verbose": attr.bool(
default = False,
doc = "Display progress messages from image-generation tool.",
),
"_tool": attr.label(
default = "//util/design:gen-otp-img",
executable = True,
cfg = "exec",
),
},
)
# This is a set of overlays to generate a generic, standard OTP image.
# Additional overlays can be applied on top to further customize the OTP.
STD_OTP_OVERLAYS = [
"//hw/ip/otp_ctrl/data:otp_json_creator_sw_cfg",
"//hw/ip/otp_ctrl/data:otp_json_owner_sw_cfg",
"//hw/ip/otp_ctrl/data:otp_json_alert_digest_cfg",
"//hw/ip/otp_ctrl/data:otp_json_hw_cfg",
]