blob: 1a6de2d251bd63de678d6004d9bde3e9f561325d [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
# TODO(drewmacrae) this should be in rules_cc
# pending resolution of https://github.com/bazelbuild/rules_cc/issues/75
load("//rules:bugfix.bzl", "find_cc_toolchain")
"""Rules to build OpenTitan for the RiscV target"""
OPENTITAN_CPU = "@bazel_embedded//constraints/cpu:riscv32"
OPENTITAN_PLATFORM = "@bazel_embedded//platforms:opentitan_rv32imc"
_targets_compatible_with = {
OPENTITAN_PLATFORM: [OPENTITAN_CPU],
}
def _platforms_transition_impl(settings, attr):
return {"//command_line_option:platforms": attr.platform}
_platforms_transition = transition(
implementation = _platforms_transition_impl,
inputs = [],
outputs = ["//command_line_option:platforms"],
)
def _obj_transform(ctx):
cc_toolchain = find_cc_toolchain(ctx)
outputs = []
for src in ctx.files.srcs:
binary = ctx.actions.declare_file("{}.{}".format(src.basename, ctx.attr.suffix))
outputs.append(binary)
ctx.actions.run(
outputs = [binary],
inputs = [src] + cc_toolchain.all_files.to_list(),
arguments = [
"--output-target",
ctx.attr.format,
src.path,
binary.path,
],
executable = cc_toolchain.objcopy_executable,
)
return [DefaultInfo(files = depset(outputs), data_runfiles = ctx.runfiles(files = outputs))]
obj_transform = rule(
implementation = _obj_transform,
cfg = _platforms_transition,
attrs = {
"srcs": attr.label_list(allow_files = True),
"suffix": attr.string(default = "bin"),
"format": attr.string(default = "binary"),
"platform": attr.string(default = OPENTITAN_PLATFORM),
"_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
toolchains = ["@rules_cc//cc:toolchain_type"],
)
def _elf_to_disassembly(ctx):
cc_toolchain = find_cc_toolchain(ctx)
outputs = []
for src in ctx.files.srcs:
disassembly = ctx.actions.declare_file("{}.dis".format(src.basename))
outputs.append(disassembly)
ctx.actions.run_shell(
outputs = [disassembly],
inputs = [src] + cc_toolchain.all_files.to_list(),
arguments = [
cc_toolchain.objdump_executable,
src.path,
disassembly.path,
],
command = "$1 --disassemble --headers --line-numbers --source $2 > $3",
)
return [DefaultInfo(files = depset(outputs), data_runfiles = ctx.runfiles(files = outputs))]
elf_to_disassembly = rule(
implementation = _elf_to_disassembly,
cfg = _platforms_transition,
attrs = {
"srcs": attr.label_list(allow_files = True),
"platform": attr.string(default = OPENTITAN_PLATFORM),
"_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
toolchains = ["@rules_cc//cc:toolchain_type"],
incompatible_use_toolchain_transition = True,
)
def _elf_to_scrambled(ctx):
outputs = []
for src in ctx.files.srcs:
scrambled = ctx.actions.declare_file("{}.scr.40.vmem".format(src.basename))
outputs.append(scrambled)
ctx.actions.run(
outputs = [scrambled],
inputs = [
src,
ctx.files._tool[0],
ctx.files._config[0],
],
arguments = [
ctx.files._config[0].path,
src.path,
scrambled.path,
],
executable = ctx.files._tool[0].path,
)
return [DefaultInfo(files = depset(outputs), data_runfiles = ctx.runfiles(files = outputs))]
elf_to_scrambled = rule(
implementation = _elf_to_scrambled,
cfg = _platforms_transition,
attrs = {
"srcs": attr.label_list(allow_files = True),
"platform": attr.string(default = OPENTITAN_PLATFORM),
"_tool": attr.label(default = "//hw/ip/rom_ctrl/util:scramble_image.py", allow_files = True),
"_config": attr.label(default = "//hw/top_earlgrey:data/autogen/top_earlgrey.gen.hjson", allow_files = True),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
)
def opentitan_binary(
name,
platform = OPENTITAN_PLATFORM,
per_device_deps = {
"verilator": ["//sw/device/lib/arch:sim_verilator"],
"dv": ["//sw/device/lib/arch:sim_dv"],
"fpga_nexysvideo": ["//sw/device/lib/arch:fpga_nexysvideo"],
"cw310": ["//sw/device/lib/arch:fpga_cw310"],
},
output_bin = True,
output_disassembly = True,
output_scrambled = False,
**kwargs):
"""A helper macro for generating OpenTitan binary artifacts.
This macro is mostly a wrapper around cc_binary, but creates artifacts
for each of the keys in `per_device_deps`. The actual artifacts
created are an ELF file, a BIN file, the disassembly and the scrambled
ROM image. Each of these output targets performs a bazel transition to
the RV32I toolchain to build the target under the correct compiler.
Args:
@param name: The name of this rule.
@param platform: The target platform for the artifacts.
@param per_device_deps: The deps for each of the execution environments.
@param output_bin: Whether or not to emit a BIN file.
@param output_disassembly: Whether or not to emit a disassembly file.
@param output_scrambled: Whether or not to emit a SCR file.
@param **kwargs: Arguments to forward to `cc_binary`.
Emits rules:
For each device in per_device_deps entry:
cc_binary named: name_device
obj_transform named: name_device_elf
optionally:
obj_transform named: name_device_bin
elf_to_dissassembly named: name_device_dis
elf_to_scrambled named: name_device_scr
filegroup named: name
with all the generated rules
"""
copts = kwargs.pop("copts", []) + [
"-nostdlib",
"-ffreestanding",
]
linkopts = kwargs.pop("linkopts", []) + [
"-nostartfiles",
"-nostdlib",
]
deps = kwargs.pop("deps", [])
targets = []
for (device, dev_deps) in per_device_deps.items():
devname = "{}_{}".format(name, device)
native.cc_binary(
name = devname,
deps = deps + dev_deps,
target_compatible_with = _targets_compatible_with[platform],
copts = copts,
linkopts = linkopts,
**kwargs
)
targets.append(":" + devname + "_elf")
obj_transform(
name = devname + "_elf",
srcs = [devname],
format = "elf32-little",
suffix = "elf",
platform = platform,
)
if output_bin:
targets.append(":" + devname + "_bin")
obj_transform(
name = devname + "_bin",
srcs = [devname],
platform = platform,
)
if output_disassembly:
targets.append(":" + devname + "_dis")
elf_to_disassembly(
name = devname + "_dis",
srcs = [devname],
platform = platform,
)
if output_scrambled:
targets.append(":" + devname + "_scr")
elf_to_scrambled(
name = devname + "_scr",
srcs = [devname],
platform = platform,
)
native.filegroup(
name = name,
srcs = targets,
)