blob: 2f8fdd9b838d3e544b3b4bbf692a20f5b09f3bd8 [file] [log] [blame]
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Modified from bazel_rules_hdl to use SystemC
"""Functions for verilator."""
load("@rules_hdl//verilog:providers.bzl", "VerilogInfo")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
def cc_compile_and_link_static_library(ctx, srcs, hdrs, deps, runfiles, includes = [], defines = []):
"""Compile and link C++ source into a static library
Args:
ctx: Context for rule
srcs: The cpp sources generated by verilator.
hdrs: The headers generated by verilator.
deps: Library dependencies to build with.
runfiles: Data dependencies that are read at runtime.
includes: The includes for the verilator module to build.
defines: Cpp defines to build with.
Returns:
CCInfo with the compiled library.
"""
cc_toolchain = find_cpp_toolchain(ctx)
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
compilation_contexts = [dep[CcInfo].compilation_context for dep in deps]
compilation_context, compilation_outputs = cc_common.compile(
name = ctx.label.name,
actions = ctx.actions,
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
srcs = srcs,
includes = includes,
defines = defines,
public_hdrs = hdrs,
compilation_contexts = compilation_contexts,
)
linking_contexts = [dep[CcInfo].linking_context for dep in deps]
linking_context, linking_output = cc_common.create_linking_context_from_compilation_outputs(
actions = ctx.actions,
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
compilation_outputs = compilation_outputs,
linking_contexts = linking_contexts,
name = ctx.label.name,
disallow_dynamic_library = True,
)
output_files = []
if linking_output.library_to_link.static_library != None:
output_files.append(linking_output.library_to_link.static_library)
if linking_output.library_to_link.dynamic_library != None:
output_files.append(linking_output.library_to_link.dynamic_library)
return [
DefaultInfo(files = depset(output_files), runfiles = ctx.runfiles(files = runfiles)),
CcInfo(
compilation_context = compilation_context,
linking_context = linking_context,
),
]
_CPP_SRC = ["cc", "cpp", "cxx", "c++"]
_HPP_SRC = ["h", "hh", "hpp"]
_RUNFILES = ["dat", "mem"]
def _only_cpp(f):
"""Filter for just C++ source/headers"""
if f.extension in _CPP_SRC + _HPP_SRC:
return f.path
return None
def _only_hpp(f):
"""Filter for just C++ headers"""
if f.extension in _HPP_SRC:
return f.path
return None
_COPY_TREE_SH = """
OUT=$1; shift && mkdir -p "$OUT" && cp $* "$OUT"
"""
def _copy_tree(ctx, idir, odir, map_each = None, progress_message = None):
"""Copy files from a TreeArtifact to a new directory"""
args = ctx.actions.args()
args.add(odir.path)
args.add_all([idir], map_each = map_each)
ctx.actions.run_shell(
arguments = [args],
command = _COPY_TREE_SH,
inputs = [idir],
outputs = [odir],
progress_message = progress_message,
)
return odir
def _verilator_cc_library(ctx):
transitive_srcs = depset([], transitive = [ctx.attr.module[VerilogInfo].dag])
all_srcs = [verilog_info_struct.srcs for verilog_info_struct in transitive_srcs.to_list()]
all_files = [src for sub_tuple in all_srcs for src in sub_tuple]
# Filter out .dat files.
runfiles = []
verilog_files = []
for file in all_files:
if file.extension in _RUNFILES:
runfiles.append(file)
else:
verilog_files.append(file)
verilator_output = ctx.actions.declare_directory(ctx.label.name + "-gen")
verilator_output_cpp = ctx.actions.declare_directory(ctx.label.name + ".cpp")
verilator_output_hpp = ctx.actions.declare_directory(ctx.label.name + ".h")
prefix = "V" + ctx.attr.module_top
args = ctx.actions.args()
args.add("--sc")
args.add("--pins-bv", "2")
args.add("--Mdir", verilator_output.path)
args.add("--top-module", ctx.attr.module_top)
args.add("--prefix", prefix)
verilog_dirs = dict()
for file in verilog_files:
verilog_dirs[file.dirname] = None
for vdir in verilog_dirs:
args.add("-I" + vdir)
if ctx.attr.trace:
args.add("--trace")
for verilog_file in verilog_files:
args.add(verilog_file.path)
args.add("-Wno-UNOPTFLAT")
args.add_all(ctx.attr.vopts, expand_directories = False)
ctx.actions.run(
arguments = [args],
executable = ctx.executable._verilator,
inputs = verilog_files,
outputs = [verilator_output],
progress_message = "[Verilator] Compiling {}".format(ctx.label),
)
_copy_tree(
ctx,
verilator_output,
verilator_output_cpp,
map_each = _only_cpp,
progress_message = "[Verilator] Extracting C++ source files",
)
_copy_tree(
ctx,
verilator_output,
verilator_output_hpp,
map_each = _only_hpp,
progress_message = "[Verilator] Extracting C++ header files",
)
# Do actual compile
defines = ["VM_TRACE"] if ctx.attr.trace else []
deps = [ctx.attr._verilator_lib, ctx.attr._zlib, ctx.attr._verilator_svdpi]
return cc_compile_and_link_static_library(
ctx,
srcs = [verilator_output_cpp],
hdrs = [verilator_output_hpp],
defines = defines,
runfiles = runfiles,
includes = [verilator_output_hpp.path],
deps = deps,
)
verilator_cc_library = rule(
_verilator_cc_library,
attrs = {
"module": attr.label(
doc = "The top level module target to verilate.",
providers = [VerilogInfo],
mandatory = True,
),
"module_top": attr.string(
doc = "The name of the verilog module to verilate.",
mandatory = True,
),
"trace": attr.bool(
doc = "Enable tracing for Verilator",
default = True,
),
"vopts": attr.string_list(
doc = "Additional command line options to pass to Verilator",
default = ["-Wall"],
),
"_cc_toolchain": attr.label(
doc = "CC compiler.",
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
),
"_verilator": attr.label(
doc = "Verilator binary.",
executable = True,
cfg = "exec",
default = Label("@verilator//:verilator_executable"),
),
"_verilator_lib": attr.label(
doc = "Verilator library",
default = Label("@verilator//:libverilator"),
),
"_verilator_svdpi": attr.label(
doc = "Verilator svdpi lib",
default = Label("@verilator//:svdpi"),
),
"_zlib": attr.label(
doc = "zlib dependency",
default = Label("@net_zlib//:zlib"),
),
},
provides = [
CcInfo,
DefaultInfo,
],
toolchains = [
"@bazel_tools//tools/cpp:toolchain_type",
],
fragments = ["cpp"],
)