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