blob: 57a9a82087ec5a4bd0d154ee64895fe0b17e153a [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("@nonhermetic//:env.bzl", "ENV")
"""Rules for memory splicing with Vivado.
"""
def _bitstream_splice_impl(ctx):
update = ctx.actions.declare_file("{}.update.mem".format(ctx.label.name))
spliced = ctx.actions.declare_file("{}.spliced.bit".format(ctx.label.name))
output = ctx.actions.declare_file("{}.bit".format(ctx.label.name))
gen_mem_img_args = ctx.actions.args()
gen_mem_img_args.add_all([ctx.file.data, update])
if ctx.attr.swap_nybbles:
gen_mem_img_args.add("--swap-nibbles")
ctx.actions.run(
mnemonic = "GenVivadoImage",
outputs = [update],
inputs = [ctx.executable._gen_mem_img, ctx.file.data],
arguments = [gen_mem_img_args],
executable = ctx.executable._gen_mem_img,
use_default_shell_env = True,
execution_requirements = {
"no-sandbox": "",
},
)
# Vivado's `updatemem` only accepts bitstream filenames that end with
# ".bit". If the `src` bitstream came from the GCP bucket, its filename will
# end with ".bit.splice" or ".bit.orig" and `updatemem` would reject it.
#
# TODO(#13807) Eliminate this symlink step once the names of cached
# bitstream files are guaranteed to end with ".bit".
tmpsrc = ctx.actions.declare_file("{}.tmpsrc.bit".format(ctx.label.name))
ctx.actions.symlink(output = tmpsrc, target_file = ctx.file.src)
updatemem_args = ctx.actions.args()
updatemem_args.add("--force")
updatemem_args.add("--meminfo", ctx.file.meminfo)
updatemem_args.add("--data", update)
updatemem_args.add("--bit", tmpsrc)
updatemem_args.add("--proc", "dummy")
updatemem_args.add("--out", spliced)
if ctx.attr.debug:
updatemem_args.add("--debug")
ctx.actions.run(
mnemonic = "SpliceBitstream",
outputs = [spliced],
inputs = [tmpsrc, ctx.file.meminfo, update],
arguments = [updatemem_args],
executable = "updatemem",
use_default_shell_env = False,
execution_requirements = {
"no-sandbox": "",
},
env = ENV,
)
if ctx.attr.update_usr_access:
ott_args = ctx.actions.args()
ott_args.add_all(
[
"--rcfile=",
"--logging=info",
"fpga",
"update-usr-access",
spliced.path,
output.path,
],
)
ctx.actions.run(
mnemonic = "UpdateUsrAccessValue",
outputs = [output],
inputs = [spliced],
arguments = [ott_args],
executable = ctx.executable._opentitantool,
)
else:
ctx.actions.symlink(
output = output,
target_file = spliced,
)
return [
DefaultInfo(
files = depset([output]),
data_runfiles = ctx.runfiles(files = [output]),
),
OutputGroupInfo(
bitstream = depset([output]),
update = depset([update]),
),
]
bitstream_splice_ = rule(
implementation = _bitstream_splice_impl,
attrs = {
"meminfo": attr.label(allow_single_file = True, doc = "Memory layout info file (an .mmi file)"),
"src": attr.label(allow_single_file = True, doc = "The bitstream to splice"),
"data": attr.label(allow_single_file = True, doc = "The memory image to splice into the bitstream"),
"swap_nybbles": attr.bool(default = True, doc = "Swap nybbles while preparing the memory image"),
"debug": attr.bool(default = False, doc = "Emit debug info while updating"),
"update_usr_access": attr.bool(default = False, doc = "Update the USR_ACCESS value of the bitstream, breaks hermeticity"),
"_gen_mem_img": attr.label(
default = "//hw/ip/rom_ctrl/util:gen_vivado_mem_image",
executable = True,
cfg = "exec",
),
"_opentitantool": attr.label(
default = "//sw/host/opentitantool:opentitantool",
executable = True,
cfg = "exec",
),
},
)
def bitstream_splice(testonly = True, **kwargs):
bitstream_splice_(testonly = testonly, **kwargs)