| # Copyright 2024 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. | 
 |  | 
 | """Bazel functions for VCS.""" | 
 |  | 
 | load("@rules_hdl//verilog:providers.bzl", "VerilogInfo") | 
 |  | 
 | def _collect_verilog_files(dep): | 
 |     transitive_srcs = depset([], transitive = [dep[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] | 
 |     return all_files | 
 |  | 
 | def _vcs_testbench_test_impl(ctx): | 
 |     all_files = _collect_verilog_files(ctx.attr.deps) | 
 |  | 
 |     vcs_binary_output = ctx.actions.declare_file(ctx.attr.module) | 
 |     vcs_daidir_output = ctx.actions.declare_directory( | 
 |         ctx.attr.module + ".daidir") | 
 |  | 
 |     verilog_files = [] | 
 |     for file in all_files: | 
 |         if file.extension in ["dat", "mem"]: | 
 |             continue | 
 |         verilog_files.append(file) | 
 |  | 
 |     command = [ | 
 |         "vcs", | 
 |         "-full64", | 
 |         "-sverilog", | 
 |     ] | 
 |     verilog_dirs = dict() | 
 |     for file in verilog_files: | 
 |         verilog_dirs[file.dirname] = None | 
 |     for verilog_file in verilog_files: | 
 |         command.append(verilog_file.path) | 
 |     command.append("-o") | 
 |     command.append(vcs_binary_output.path) | 
 |  | 
 |     ctx.actions.run_shell( | 
 |         outputs=[vcs_binary_output, vcs_daidir_output], | 
 |         inputs=verilog_files, | 
 |         command = " ".join(command), | 
 |         use_default_shell_env = True, | 
 |     ) | 
 |  | 
 |     return [DefaultInfo(runfiles=ctx.runfiles(files=[vcs_daidir_output]), | 
 |                         executable=vcs_binary_output)] | 
 |  | 
 | _vcs_testbench_test = rule( | 
 |     _vcs_testbench_test_impl, | 
 |     attrs = { | 
 |         "srcs": attr.label_list(allow_files = True), | 
 |         "deps": attr.label( | 
 |             doc = "The verilog target to create a test bench for.", | 
 |             providers = [VerilogInfo], | 
 |             mandatory = True, | 
 |         ), | 
 |         "module": attr.string( | 
 |             doc = "The name of the verilog module to verilate.", | 
 |             mandatory = True, | 
 |         ), | 
 |     }, | 
 |     test = True, | 
 | ) | 
 |  | 
 | def vcs_testbench_test(name, tags=[], **kwargs): | 
 |     _vcs_testbench_test(name = name, tags = ["vcs"] + tags, **kwargs) | 
 |  | 
 | def _vcs_systemc_binary_impl(ctx): | 
 |     verilog_files = [] | 
 |     for dep in ctx.attr.verilog_deps: | 
 |         verilog_files += _collect_verilog_files(dep) | 
 |     systemc_include_paths = [] | 
 |     systemc_link_args = [] | 
 |     libs = [] | 
 |  | 
 |     for dep in ctx.attr.systemc_deps: | 
 |         transitive_quote_includes = depset([], transitive = [dep[CcInfo].compilation_context.quote_includes]) | 
 |         transitive_system_includes = depset([], transitive = [dep[CcInfo].compilation_context.system_includes]) | 
 |         for include in transitive_quote_includes.to_list(): | 
 |             if include.find('accellera_systemc') == -1: | 
 |                 systemc_include_paths += ["-cflags", "-I" + include] | 
 |         for include in transitive_system_includes.to_list(): | 
 |             if include.find('accellera_systemc') == -1: | 
 |                 systemc_include_paths += ["-cflags", "-I" + include] | 
 |         transitive_linker_inputs = depset([], transitive = [dep[CcInfo].linking_context.linker_inputs]) | 
 |         for link in transitive_linker_inputs.to_list(): | 
 |             for library in link.libraries: | 
 |                 if library.pic_static_library: | 
 |                     if library.pic_static_library.path.find('accellera_systemc') == -1: | 
 |                         libs.append(library.pic_static_library) | 
 |                 elif library.static_library: | 
 |                     if library.static_library.path.find('accellera_systemc') == -1: | 
 |                         libs.append(library.static_library) | 
 |                 if library.pic_objects: | 
 |                     for object in library.pic_objects: | 
 |                         systemc_link_args.append(object.path) | 
 |  | 
 |     vcs_binary_output = ctx.actions.declare_file(ctx.attr.name) | 
 |     vlogan_command = [ | 
 |         "vlogan", | 
 |         "-kdb", | 
 |         "-full64", | 
 |         "-sverilog", | 
 |         "-sysc", | 
 |         "-q", | 
 |         "-incr_vlogan", | 
 |         "+define+SIMULATION", | 
 |     ] + ctx.attr.build_args | 
 |     vlogan_outputs = [] | 
 |     verilog_files += ctx.files.verilog_srcs | 
 |     verilog_include_paths = [] | 
 |     for f in verilog_files: | 
 |         verilog_include_paths  += ["-cflags", "-I" + f.dirname] | 
 |     for (i, file) in enumerate(verilog_files): | 
 |         vlogan_output = ctx.actions.declare_file(file.path + ".stamp") | 
 |         vlogan_outputs.append(vlogan_output) | 
 |         main_module_args = [] | 
 |         if file.basename.startswith(ctx.attr.module): | 
 |             main_module_args += ["-sc_model", ctx.attr.module] | 
 |         if file.basename.startswith(ctx.attr.module) and ctx.attr.portmap: | 
 |             main_module_args += ["-sc_portmap", ctx.file.portmap.path] | 
 |         prev_input = [vlogan_outputs[i-1]] if i > 0 else [] | 
 |         ctx.actions.run_shell( | 
 |             command = " ".join( | 
 |                 vlogan_command + | 
 |                 main_module_args + | 
 |                 [file.path, "&&", "touch", vlogan_output.path] | 
 |             ), | 
 |             outputs = [vlogan_output], | 
 |             inputs = [file] + prev_input, | 
 |             use_default_shell_env = True, | 
 |             progress_message = "[VLOGAN] %{input}", | 
 |         ) | 
 |  | 
 |     syscan_command = [ | 
 |         "syscan", | 
 |         "-cflags", | 
 |         "-g", | 
 |         "-full64", | 
 |         "-q", | 
 |     ] + verilog_include_paths + systemc_include_paths | 
 |     syscan_outputs = [] | 
 |     for (i, file) in enumerate(ctx.files.systemc_srcs): | 
 |         syscan_output = ctx.actions.declare_file(file.path + ".stamp") | 
 |         syscan_outputs.append(syscan_output) | 
 |         prev_input = [syscan_outputs[i-1]] if i > 0 else [vlogan_outputs[-1]] | 
 |         ctx.actions.run_shell( | 
 |             command = " ".join( | 
 |                 syscan_command + [file.path, "&&", "touch", syscan_output.path] | 
 |             ), | 
 |             inputs = vlogan_outputs + prev_input + [file], | 
 |             outputs = [syscan_output], | 
 |             use_default_shell_env = True, | 
 |             progress_message = "[SYSCAN] %{input}", | 
 |         ) | 
 |  | 
 |     vcs_daidir_output = ctx.actions.declare_directory( | 
 |         ctx.attr.name + ".daidir") | 
 |     vcs_vdb_output = ctx.actions.declare_directory( | 
 |         ctx.attr.name + ".vdb") | 
 |     vcs_command = [ | 
 |         "vcs", | 
 |         "-full64", | 
 |         "-sverilog", | 
 |         "-q", | 
 |         "-cflags", "-g", | 
 |         "-sysc=incr", | 
 |         "-kdb", | 
 |         "+vcs+fsdbon", | 
 |         "-debug_access+all", | 
 |         "+notimingcheck", | 
 |         "-timescale=1ns/1ps", | 
 |         "-cm", "line+tgl+fsm+cond+branch+assert", | 
 |         "sc_main", | 
 |         "-o", | 
 |         vcs_binary_output.path, | 
 |     ] + systemc_link_args | 
 |     ctx.actions.run_shell( | 
 |         command = " ".join(vcs_command), | 
 |         inputs = libs + vlogan_outputs + syscan_outputs, | 
 |         outputs = [vcs_binary_output, vcs_daidir_output, vcs_vdb_output], | 
 |         use_default_shell_env = True, | 
 |     ) | 
 |  | 
 |     return [DefaultInfo( | 
 |         files=depset([vcs_binary_output]), | 
 |         runfiles=ctx.runfiles(files=[vcs_daidir_output, vcs_vdb_output]), | 
 |         executable=vcs_binary_output, | 
 |     )] | 
 |  | 
 | _vcs_systemc_binary = rule( | 
 |     _vcs_systemc_binary_impl, | 
 |     attrs = { | 
 |         "verilog_srcs": attr.label_list(allow_files = True), | 
 |         "systemc_srcs": attr.label_list(allow_files = True), | 
 |         "verilog_deps": attr.label_list( | 
 |             doc = "Verilog library dependencies", | 
 |             providers = [VerilogInfo], | 
 |         ), | 
 |         "build_args": attr.string_list(allow_empty = True), | 
 |         "systemc_deps": attr.label_list( | 
 |             doc = "SystemC library dependencies", | 
 |             providers = [CcInfo], | 
 |         ), | 
 |         "portmap": attr.label(allow_single_file = True), | 
 |         "module": attr.string( | 
 |             doc = "The name of the main verilog module.", | 
 |             mandatory = True, | 
 |         ), | 
 |         "_cc_toolchain": attr.label( | 
 |             doc = "CC compiler.", | 
 |             default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), | 
 |         ), | 
 |     }, | 
 |     toolchains = [ | 
 |         "@bazel_tools//tools/cpp:toolchain_type", | 
 |     ], | 
 |     executable = True, | 
 | ) | 
 |  | 
 | def vcs_systemc_binary(name, tags=[], **kwargs): | 
 |     _vcs_systemc_binary(name = name, tags = ["vcs"] + tags, **kwargs) |