Skip to content

Commit

Permalink
[bazel] Add rule to autogenerate the top-specific DT code
Browse files Browse the repository at this point in the history
This rule can generate both `dt_api.h` and the `devicetables.{c,h}`
library.

Signed-off-by: Amaury Pouly <[email protected]>
  • Loading branch information
pamaury committed Nov 13, 2024
1 parent b94ac54 commit d9b76f0
Showing 1 changed file with 147 additions and 22 deletions.
169 changes: 147 additions & 22 deletions rules/autogen.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -181,47 +181,66 @@ opentitan_ip_rust_header = rule(
} | stamp_attr(-1, "//rules:stamp_flag"),
)

def _opentitan_ip_dt_header_impl(ctx):
header = ctx.actions.declare_file("dt_{}.h".format(ctx.attr.ip))
def _opentitan_top_dt_gen(ctx):
outputs = []
outdir = "{}/{}".format(ctx.bin_dir.path, ctx.label.package)

groups = {}
for group, files in ctx.attr.output_groups.items():
deps = []
for file in files:
deps.append(ctx.actions.declare_file(file))
outputs.extend(deps)
groups[group] = depset(deps)

top = ctx.attr.top[OpenTitanTopInfo]
if ctx.attr.ip not in top.ip_hjson:
fail("Cannot generate headers: top {} does not contain IP {}".format(top.name, ctx.attr.ip))
hjson = top.ip_hjson[ctx.attr.ip]

inputs = [top.hjson]
ips = []
for (ipname, hjson) in top.ip_hjson.items():
if hjson != None and (ctx.attr.gen_top or ipname in ctx.attr.gen_ips):
inputs.append(hjson)
ips.extend(["-i", hjson.path])

arguments = [
"--gen-ip",
"-i",
hjson.path,
"--topgencfg",
top.hjson.path,
"--outdir",
header.dirname,
outdir,
]
arguments.append("--gen-top" if ctx.attr.gen_top else "--gen-ip")
for ipname in ctx.attr.gen_ips:
if ipname not in top.ip_hjson:
fail("Cannot generate IP headers: top {} does not contain IP {}".format(top.name, ipname))

arguments.extend(ips)

ctx.actions.run(
outputs = [header],
inputs = [hjson, top.hjson],
outputs = outputs,
inputs = inputs,
arguments = arguments,
executable = ctx.executable._dttool,
)

return [
CcInfo(compilation_context = cc_common.create_compilation_context(
includes = depset([header.dirname]),
headers = depset([header]),
)),
DefaultInfo(files = depset([header])),
OutputGroupInfo(
header = depset([header]),
),
DefaultInfo(files = depset(outputs)),
OutputGroupInfo(**groups),
]

opentitan_ip_dt_header = rule(
implementation = _opentitan_ip_dt_header_impl,
opentitan_top_dt_gen = rule(
implementation = _opentitan_top_dt_gen,
doc = "Generate the C headers for an IP block as used in a top",
attrs = {
"top": attr.label(providers = [OpenTitanTopInfo], doc = "Opentitan top description"),
"ip": attr.string(doc = "Name of the IP block"),
"gen_top": attr.bool(default = False, doc = "If true, generate the toplevel files"),
"gen_ips": attr.string_list(doc = "List of IPs for which to generate header files"),
"output_groups": attr.string_list_dict(
allow_empty = True,
doc = """
Mappings from output group names to lists of paths contained in
that group.
""",
),
"_dttool": attr.label(
default = "//util:dttool",
executable = True,
Expand All @@ -230,6 +249,112 @@ opentitan_ip_dt_header = rule(
},
)

def opentitan_ip_dt_header(name, top, ip, deps = None):
"""
Generate the C header for an IP block as used in a top. This library is created to the
provided top and can have additional dependencies. The top target must export an
OpenTitanTopInfo provider, e.g. by created by opentitan_top. If this IP is not included
in the top, an error will be thrown.
"""
if deps == None:
deps = []

opentitan_top_dt_gen(
name = "{}_gen".format(name),
top = top,
gen_ips = [ip],
output_groups = {
"hdr": ["dt_{}.h".format(ip)],
},
)

native.filegroup(
name = "{}_hdr".format(name),
srcs = [":{}_gen".format(name)],
output_group = "hdr",
)

native.cc_library(
name = name,
srcs = [],
hdrs = [":{}_hdr".format(name)],
deps = deps,
# Make the header accessible as "dt_<ip>.h".
includes = ["."],
)

def opentitan_top_dt_api(name, top, deps = None):
"""
Create a library that exports the "dt_api.h" header. This library is created to the
provided top and can have additional dependencies. The top target must export an
OpenTitanTopInfo provider, e.g. by created by opentitan_top.
"""
if deps == None:
deps = []

opentitan_top_dt_gen(
name = "{}_gen".format(name),
top = top,
gen_top = True,
output_groups = {
"hdr": ["dt_api.h"],
},
)

native.filegroup(
name = "{}_hdr".format(name),
srcs = [":{}_gen".format(name)],
output_group = "hdr",
)

native.cc_library(
name = name,
srcs = [],
hdrs = [":{}_hdr".format(name)],
deps = deps,
# Make the dt_api.h header accessible as "dt_api.h".
includes = ["."],
)

def opentitan_top_devicetables(name, top, deps = None):
"""
Create a library that exports the "devicetables.h" header and contains the device tables.
This library is created to the provided top and can have additional dependencies.
The top target must export an OpenTitanTopInfo provider, e.g. by created by opentitan_top.
"""
if deps == None:
deps = []

opentitan_top_dt_gen(
name = "{}_gen".format(name),
top = top,
gen_top = True,
output_groups = {
"hdr": ["devicetables.h"],
"src": ["devicetables.c"],
},
)

native.filegroup(
name = "{}_hdr".format(name),
srcs = [":{}_gen".format(name)],
output_group = "hdr",
)
native.filegroup(
name = "{}_src".format(name),
srcs = [":{}_gen".format(name)],
output_group = "src",
)

native.cc_library(
name = name,
srcs = [":{}_src".format(name)],
hdrs = [":{}_hdr".format(name)],
deps = deps,
# Make the dt_api.h header accessible as "dt_api.h".
includes = ["."],
)

def _hjson_rust_header(ctx):
node = []
if ctx.attr.node:
Expand Down

0 comments on commit d9b76f0

Please sign in to comment.