blob: f2c43166a47ed787ec4d54caee9391653b43f970 [file] [log] [blame]
Chris Frantz9b34e4a2021-11-24 17:03:12 -08001# Copyright lowRISC contributors.
2# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3# SPDX-License-Identifier: Apache-2.0
4
5load("//rules:opentitan.bzl", "OPENTITAN_PLATFORM", "opentitan_transition")
6load("//rules:bugfix.bzl", "find_cc_toolchain")
7
8def _otbn_binary(ctx):
9 """The build process for otbn resources currently invokes
10 `//hw/ip/otbn/util/otbn-{as,ld,...}` to build the otbn resource.
11 These programs are python scripts which translate otbn special
12 instructions into the proper opcode sequences and _then_ invoke the normal
13 `rv32-{as,ld,...}` programs to produce the resource. These "native"
14 otbn resources are the `otbn_objs` and `elf` output groups.
15
16 In order to make the otbn resource useful to the the main CPU, the
17 otbn resource needs to be included as a blob of data that the main
18 CPU can dump into the otbn `imem` area and ask otbn to execute it.
19 `util/otbn-build.py` does this with some objcopy-fu, emitting
20 `foo.rv32embed.o`. Bazel's `cc_*` rules really want dependency objects
21 expressed as archives rather than raw object files, so I've modified
22 `otbn-build` to also emit an archive file.
23
24 _Morally_, the otbn resource is a data dependency. However the
25 practical meaning of a `data` dependency in bazel is a file made
26 available at runtime, which is not how we're using the otbn resource.
27 The closest analog is something like `cc_embed_data`, which is like
28 a data dependency that needs to be linked into the main program.
29 We achieve by having `otbn-build` emit a conventional RV32I library
30 that other rules can depend on in their `deps`.
31 """
32 cc_toolchain = find_cc_toolchain(ctx)
33 objs = [
34 ctx.actions.declare_file(src.basename.replace("." + src.extension, ".o"))
35 for src in ctx.files.srcs
36 ]
37 elf = ctx.actions.declare_file(ctx.attr.name + ".elf")
38 rv32embed = ctx.actions.declare_file(ctx.attr.name + ".rv32embed.o")
39 archive = ctx.actions.declare_file(ctx.attr.name + ".rv32embed.a")
40 outputs = objs + [elf, rv32embed, archive]
41
42 # Note: the toolchain config doesn"t appear to have a good way to get
43 # access to the assembler. We should be able to access it via the
44 # the compiler, but I had trouble with //hw/ip/otbn/util/otbn-as invoking
45 # the compiler as assembler.
46 assembler = [f for f in cc_toolchain.all_files.to_list() if f.basename.endswith("as")][0]
47
48 ctx.actions.run(
49 outputs = outputs,
50 inputs = (ctx.files.srcs +
51 cc_toolchain.all_files.to_list() +
52 ctx.files._otbn_as +
53 ctx.files._otbn_ld +
54 ctx.files._otbn_data +
55 ctx.files._wrapper),
56 env = {
57 "OTBN_AS": ctx.file._otbn_as.path,
58 "OTBN_LD": ctx.file._otbn_ld.path,
59 "RV32_TOOL_AS": assembler.path,
60 "RV32_TOOL_AR": cc_toolchain.ar_executable,
61 "RV32_TOOL_LD": cc_toolchain.ld_executable,
62 "RV32_TOOL_OBJCOPY": cc_toolchain.objcopy_executable,
63 },
64 arguments = [
65 "--app-name={}".format(ctx.attr.name),
66 "--archive",
67 "--out-dir={}".format(elf.dirname),
68 ] + [src.path for src in ctx.files.srcs],
69 executable = ctx.file._wrapper,
70 )
71
72 feature_configuration = cc_common.configure_features(
73 ctx = ctx,
74 cc_toolchain = cc_toolchain,
75 requested_features = ctx.features,
76 unsupported_features = ctx.disabled_features,
77 )
78
79 return [
80 DefaultInfo(files = depset(outputs), data_runfiles = ctx.runfiles(files = outputs)),
81 OutputGroupInfo(
82 otbn_objs = depset(objs),
83 elf = depset([elf]),
84 rv32embed = depset([rv32embed]),
85 archive = depset([archive]),
86 ),
87 # Emit a CcInfo provider so that this rule can be a dependency in other
88 # cc_* rules.
89 CcInfo(
90 linking_context = cc_common.create_linking_context(
91 linker_inputs = depset([cc_common.create_linker_input(
92 owner = ctx.label,
93 libraries = depset([cc_common.create_library_to_link(
94 actions = ctx.actions,
95 feature_configuration = feature_configuration,
96 cc_toolchain = cc_toolchain,
97 static_library = archive,
98 )]),
99 )]),
100 ),
101 ),
102 ]
103
104otbn_binary = rule(
105 implementation = _otbn_binary,
106 cfg = opentitan_transition,
107 attrs = {
108 "srcs": attr.label_list(allow_files = True),
109 "platform": attr.string(default = OPENTITAN_PLATFORM),
110 "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
111 "_otbn_as": attr.label(default = "//hw/ip/otbn/util:otbn-as", allow_single_file = True),
112 "_otbn_ld": attr.label(default = "//hw/ip/otbn/util:otbn-ld", allow_single_file = True),
113 "_otbn_data": attr.label(default = "//hw/ip/otbn/data:all_files", allow_files = True),
114 "_wrapper": attr.label(default = "//util:otbn_build.py", allow_single_file = True),
115 "_allowlist_function_transition": attr.label(
116 default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
117 ),
118 },
119 fragments = ["cpp"],
120 toolchains = ["@rules_cc//cc:toolchain_type"],
121 incompatible_use_toolchain_transition = True,
122)