diff --git a/BUILD b/BUILD new file mode 100644 index 000000000..7e55b5d96 --- /dev/null +++ b/BUILD @@ -0,0 +1,734 @@ +# Copyright 2020 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. + +# Description: +# Icarus Verilog is a Verilog simulation and synthesis tool. +# Use :iverilog and :vvp targets in your genrules. +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_binary") + +load("//bazel:yacclex_helpers.bzl", "genyacc", "genlex") +load("//bazel:build_plugins.bzl", "vpi_binary") +load("//bazel:pseudo_configure.bzl", "pseudo_configure") +load("//bazel:system.bzl", "cc_system_headers") + +# The only two exported labels are iverilog and vvp. They are enough +# to run simple simulations. +package( + default_visibility = ["//visibility:private"], + features = [ + "-layering_check", # vpi/fastlz.c including itself + "-parse_headers", # missing: `size_t` definition in stab.h, `using string` in parse_api.h + ], +) + +licenses(["restricted"]) # GPLv2 + +exports_files([ + "LICENSE", + "build-plugins", +]) + +filegroup( + name = "system_vpis", + srcs = [ + ":system_vpi", + ":v2005_math_vpi", + ":v2009_vpi", + ":va_math_vpi", + ":vhdl_sys_vpi", + ":vhdl_textio_vpi", + ":vpi_debug_vpi", + ], +) + +# This wrapper around iverilog compiler is to be used by +# simulations. A typical genrule will look similar to gen_hello.vvp +# below. +sh_binary( + name = "iverilog", + srcs = ["iverilog.sh"], + data = [ + "vvp.conf", + ":iverilog-bin", + ":ivl", + ":ivlpp", + ":vvp_tgt", + ], + deps = ["@bazel_tools//tools/bash/runfiles"], + output_licenses = ["unencumbered"], + visibility = ["//visibility:public"], +) + +genrule( + name = "vvp_conf", + srcs = ["tgt-vvp/vvp.conf.in"], + outs = ["vvp.conf"], + cmd = "echo 'flag:VVP_EXECUTABLE=/unused' | cat $(location :tgt-vvp/vvp.conf.in) - > $@", +) + +# This wrapper around vvp simulator is to be used by simulations. A +# typical genrule will look similar to run_hello below. +sh_binary( + name = "vvp", + srcs = ["vvp.sh"], + data = [ + ":vvp-bin", + ":system_vpis", + ], + output_licenses = ["unencumbered"], + deps = ["@bazel_tools//tools/bash/runfiles"], + visibility = ["//visibility:public"], +) + +cc_system_headers( + name = "tgt_vvp_config_header", + hdrs = [ + "tgt-vvp/vvp_config.h", + ], +) + +cc_system_headers( + name = "vpi_user_header", + hdrs = [ + "vpi_user.h", + "_pli_types.h", + ], +) + +cc_system_headers( + name = "config_header", + hdrs = [ + "config.h", + ], +) + +cc_library( + name = "ivl-misc", + srcs = [ + "libmisc/LineInfo.cc", + "libmisc/StringHeap.cc", + ], + hdrs = [ + "libmisc/LineInfo.h", + "libmisc/StringHeap.h", + ], + copts = ["-Wno-unused-variable"], +) + +cc_binary( + name = "ivl", + srcs = glob( + [ + "*.cc", + "*.h", + ], + exclude = ["elab_anet.cc"], + ) + [ + ":config_h", + "vvp/ivl_dlfcn.h", + "_pli_types.h", + ":lexor", + ":lexor_keyword_cc", + ":parse_y", + ":syn-rules_y", + ":version_tag_h", + ], + # Really poor code hygiene. Produces mounds of warnings. + copts = ["-w"], + includes = [ + "libmisc", + ], + linkopts = [ + "-ldl", + "-Wl,--export-dynamic", + "-Wl,-no-pie", + ], + deps = [ + ":ivl-misc", + ], +) + +genlex( + name = "lexor", + src = "lexor.lex", + out = "lexor.cc", +) + +genyacc( + name = "parse_y", + src = "parse.y", + header_out = "parse.h", + prefix = "VL", + source_out = "parse.cc", +) + +genyacc( + name = "syn-rules_y", + src = "syn-rules.y", + header_out = "syn-rules.h", + prefix = "syn_", + source_out = "syn-rules.cc", +) + +cc_binary( + name = "iverilog-bin", + srcs = glob([ + "driver/*.c", + "driver/*.h", + ]) + [ + ":config_h", + "ivl_alloc.h", + "version_base.h", + ":version_tag_h", + ":cflexor", + ":cfparse_y", + ], + copts = [ + "-D_GNU_SOURCE", + "-std=c11", + "-fcommon", + "-DIVL_LIB='\"\"'", + "-DIVL_SUFFIX='\"\"'", + "-DIVL_INCLUDE_INSTALL_DIR='\"\"'", + ], + includes = [ + "driver", + "libmisc", + ], +) + +genlex( + name = "cflexor", + src = "driver/cflexor.lex", + out = "driver/cflexor.c", +) + +genyacc( + name = "cfparse_y", + src = "driver/cfparse.y", + header_out = "driver/cfparse.h", + prefix = "cf", + source_out = "driver/cfparse.c", +) + +cc_binary( + name = "vvp-bin", + srcs = glob([ + "vvp/*.cc", + "vvp/*.h", + ]) + [ + "ivl_alloc.h", + "sv_vpi_user.h", + "version_base.h", + ":version_tag_h", + ":gen_tables", + ":vvp_flexor", + ":vvp_parse_y", + ":vvp_gen__vvp_config_h", + ], + copts = [ + "-O2", # Optimized binary regardless of configuration. + "-Wno-implicit-fallthrough", + ], + # Do not sort: dot last. + includes = [ + "vvp_gen", + "vvp", + ], + linkopts = [ + "-ldl", + "-Wl,--export-dynamic", + ], + deps = [ + ":vpi_user_header", + "@readline//:readline", + ], +) + +genyacc( + name = "vvp_parse_y", + src = "vvp/parse.y", + header_out = "vvp_gen/parse.h", + source_out = "vvp_gen/parse.cc", +) + +genlex( + name = "vvp_flexor", + src = "vvp/lexor.lex", + out = "vvp_gen/lexor.cc", +) + +cc_binary( + name = "draw_tt", + srcs = ["vvp/draw_tt.c"], +) + +genrule( + name = "gen_tables", + outs = ["vvp_gen/tables.cc"], + cmd = "$(location :draw_tt) > $@", + tools = [":draw_tt"], +) + +cc_binary( + name = "ivlpp", + srcs = glob([ + "ivlpp/*.c", + "ivlpp/*.h", + ]) + [ + ":config_h", + "ivl_alloc.h", + "version_base.h", + ":version_tag_h", + ":ivlpp_lexor", + ], + copts = ["-Wno-unused-variable"], + # Do not sort: dot last. + includes = [ + "ivlpp", + ], +) + +genlex( + name = "ivlpp_lexor", + src = "ivlpp/lexor.lex", + out = "ivlpp_gen/lexor.c", +) + +vpi_binary( + name = "system_vpi", + srcs = [ + ":config_h", + "ivl_alloc.h", + "sv_vpi_user.h", + "version_base.h", + "vpi/fastlz.c", + "vpi/fastlz.h", + "vpi/fstapi.c", + "vpi/fstapi.h", + "vpi/lxt_write.c", + "vpi/lxt_write.h", + "vpi/lxt2_write.c", + "vpi/lxt2_write.h", + "vpi/lz4.c", + "vpi/lz4.h", + "vpi/mt19937int.c", + "vpi/sdf_parse_priv.h", + "vpi/sdf_priv.h", + "vpi/stringheap.c", + "vpi/stringheap.h", + "vpi/sys_convert.c", + "vpi/sys_countdrivers.c", + "vpi/sys_darray.c", + "vpi/sys_deposit.c", + "vpi/sys_display.c", + "vpi/sys_fileio.c", + "vpi/sys_finish.c", + "vpi/sys_fst.c", + "vpi/sys_icarus.c", + "vpi/sys_lxt.c", + "vpi/sys_lxt2.c", + "vpi/sys_plusargs.c", + "vpi/sys_priv.c", + "vpi/sys_priv.h", + "vpi/sys_queue.c", + "vpi/sys_random.c", + "vpi/sys_random.h", + "vpi/sys_random_mti.c", + "vpi/sys_readmem.c", + "vpi/sys_readmem_lex.h", + "vpi/sys_scanf.c", + "vpi/sys_sdf.c", + "vpi/sys_table.c", + "vpi/sys_time.c", + "vpi/sys_vcd.c", + "vpi/sys_vcdoff.c", + "vpi/table_mod.c", + "vpi/table_mod.h", + "vpi/vams_simparam.c", + "vpi/vcd_priv.c", + "vpi/vcd_priv.h", + "vpi/vcd_priv2.cc", + "vpi/vpi_config.h", + "vpi/wavealloca.h", + ":table_mod_lexor_lex", + ":table_mod_parse_y", + ":vpi_sdf_lexor", + ":vpi_sdfparse_y", + ":vpi_sys_readmem_lex", + ], + out = "system.vpi", + # Optimized binary regardless of configuration. + copts = [ + "$(STACK_FRAME_UNLIMITED)", + "-O2", + # "-std=c11", + # was for for-loop-indices, removed to allow vcd_priv2.cc to compile + ], + includes = [ + "vpi", + ], + # The code has atrocious const hygiene. Produces mounds of warnings. + deps = [ + ":vpi_user_header", + ":config_header", + "@bzip2//:bz2", + "@zlib//:zlib", + ], +) + +genyacc( + name = "table_mod_parse_y", + src = "vpi/table_mod_parse.y", + header_out = "vpi/table_mod_parse.h", + prefix = "tblmod", + source_out = "vpi/table_mod_parse.c", +) + +genlex( + name = "table_mod_lexor_lex", + src = "vpi/table_mod_lexor.lex", + out = "vpi/table_mod_lexor.c", +) + +genyacc( + name = "vpi_sdfparse_y", + src = "vpi/sdf_parse.y", + header_out = "vpi/sdf_parse.h", + prefix = "sdf", + source_out = "vpi/sdf_parse.c", +) + +genlex( + name = "vpi_sdf_lexor", + src = "vpi/sdf_lexor.lex", + out = "vpi/sdf_lexor.c", +) + +genlex( + name = "vpi_sys_readmem_lex", + src = "vpi/sys_readmem_lex.lex", + out = "vpi/sys_readmem_lex.c", +) + +vpi_binary( + name = "vhdl_sys_vpi", + srcs = [ + "ivl_alloc.h", + "sv_vpi_user.h", + "vpi/sys_priv.c", + "vpi/sys_priv.h", + "vpi/vhdl_table.c", + "vpi/vpi_config.h", + ], + out = "vhdl_sys.vpi", + copts = ["-O2"], + includes = [ + "vpi", + ], + deps = [ + ":vpi_user_header", + ], +) + +vpi_binary( + name = "vhdl_textio_vpi", + srcs = [ + "ivl_alloc.h", + "sv_vpi_user.h", + "vpi/sys_priv.c", + "vpi/sys_priv.h", + "vpi/vhdl_textio.c", + "vpi/vpi_config.h", + ], + out = "vhdl_textio.vpi", + copts = ["-O2"], + includes = [ + "vpi", + ], + deps = [ + ":vpi_user_header", + ], +) + +vpi_binary( + name = "va_math_vpi", + srcs = [ + "ivl_alloc.h", + "vpi/va_math.c", + "vpi/vpi_config.h", + ], + out = "va_math.vpi", + copts = ["-O2"], # Optimized binary regardless of configuration. + includes = [ + "vpi", + ], + # The code has atrocious const hygiene. Produces mounds of warnings. + deps = [ + ":vpi_user_header", + ], +) + +vpi_binary( + name = "v2005_math_vpi", + srcs = [ + "ivl_alloc.h", + "sv_vpi_user.h", + "vpi/sys_clog2.c", + "vpi/v2005_math.c", + "vpi/vpi_config.h", + ], + out = "v2005_math.vpi", + copts = ["-O2"], # Optimized binary regardless of configuration. + includes = [ + "vpi", + ], + # The code has atrocious const hygiene. Produces mounds of warnings. + deps = [ + ":vpi_user_header", + ], +) + +vpi_binary( + name = "vpi_debug_vpi", + srcs = ["vpi/vpi_debug.c"], + out = "vpi_debug.vpi", + copts = ["-O2"], + includes = [ + "vpi", + ], + deps = [ + ":vpi_user_header", + ], +) + +vpi_binary( + name = "v2009_vpi", + srcs = [ + "ivl_alloc.h", + "sv_vpi_user.h", + "vpi/sys_priv.c", + "vpi/sys_priv.h", + "vpi/v2009_array.c", + "vpi/v2009_bitvec.c", + "vpi/v2009_enum.c", + "vpi/v2009_string.c", + "vpi/v2009_table.c", + "vpi/vpi_config.h", + ], + out = "v2009.vpi", + copts = [ + "-O2", # Optimized binary regardless of configuration. + ], + includes = [ + "vpi", + ], + deps = [ + ":vpi_user_header", + ], +) + +vpi_binary( + name = "vvp_tgt", + srcs = glob([ + "tgt-vvp/*.c", + "tgt-vvp/*.h", + ]) + [ + "ivl_alloc.h", + "ivl_target.h", + "version_base.h", + ":version_tag_h", + ":tgt_vvp__vvp_config_h", + ], + out = "vvp.tgt", + copts = [ + "-std=c11", + "-Wno-implicit-function-declaration", + "-Wno-int-conversion", + ], + includes = [ + "tgt-vvp", + ], + # The code has atrocious const hygiene. Produces mounds of warnings. +) + +genrule( + name = "_pli_types_h", + srcs = ["_pli_types.h.in"], + outs = ["_pli_types.h"], + cmd = "cat $(location :_pli_types.h.in) | sed 's/# undef HAVE_INTTYPES_H/# define HAVE_INTTYPES_H 1/' > $@", +) + +genrule( + name = "lexor_keyword_cc", + srcs = ["lexor_keyword.gperf"], + tools = ["@gperf//:gperf"], + outs = ["lexor_keyword.cc"], + cmd = "$(location @gperf//:gperf) -o -i 7 -C -k 1-4,6,9,$$ -H keyword_hash -N check_identifier -t $(location :lexor_keyword.gperf) > $@", + message = "Generating perfect hash function from $(SRCS)", +) + +# In the following genrules we do an extremely crude approximation of a +# configuration step -- workable now given the limited set of +# platforms/environments we intend to target. + +HAVE_CONFIG_SUFFIXES = "TIMES|IOSFWD|GETOPT_H|INTTYPES_H|DLFCN_H|LIBREADLINE|LIBZ|LIBBZ2|LROUND|SYS_WAIT_H|ALLOCA_H|FSEEKO|LIBPTHREAD|REALPATH" +HAVE_CONFIG_RE = "HAVE_(%s)" % HAVE_CONFIG_SUFFIXES + +DEFS = [ + "HAVE_IOSFWD", + "HAVE_DLFCN_H", + "HAVE_GETOPT_H", + "HAVE_LIBREADLINE", + "HAVE_READLINE_READLINE_H", + "HAVE_LIBHISTORY", + "HAVE_READLINE_HISTORY_H", + "HAVE_INTTYPES_H", + "HAVE_LROUND", + "HAVE_LLROUND", + "HAVE_NAN", + "UINT64_T_AND_ULONG_SAME", + "HAVE_SYS_RESOURCE_H", + "LINUX" +] + +pseudo_configure( + name = "tgt_vvp__vvp_config_h", + src = "tgt-vvp/vvp_config.h.in", + out = "tgt-vvp/vvp_config.h", + defs = [ + "HAVE_STDINT_H", + "HAVE_INTTYPES_H", + "_LARGEFILE_SOURCE" + ], + mappings = {}, +) + +pseudo_configure( + name = "config_h", + src = "config.h.in", + out = "config.h", + defs = [ + "HAVE_TIMES", + "HAVE_IOSFWD", + "HAVE_GETOPT_H", + "HAVE_INTTYPES_H", + "HAVE_DLFCN_H", + "HAVE_LIBREADLINE", + "HAVE_LIBZ", + "HAVE_LIBBZ2", + "HAVE_LROUND", + "HAVE_SYS_WAIT_H", + "HAVE_ALLOCA_H", + "HAVE_FSEEKO", + "HAVE_LIBPTHREAD", + "HAVE_REALPATH" + ], + mappings = {}, +) + +genrule( + name = "vpi__vpi_config_h", + srcs = ["vpi/vpi_config.h.in"], + outs = ["vpi/vpi_config.h"], + cmd = "perl -p -e 's/# undef (\\w+)/#define $$1 1/' $< > $@", + message = "Configuring vpi/vpi_config.h.in", +) + +pseudo_configure( + name = "vvp_gen__vvp_config_h", + src = "vvp/config.h.in", + out = "vvp_gen/config.h", + defs = DEFS, + mappings = { + "SIZEOF_UNSIGNED_LONG_LONG": "8", + "SIZEOF_UNSIGNED_LONG": "8", + "SIZEOF_UNSIGNED": "4", + "SIZEOF_VOID_P": "8", + "USE_READLINE": "", + "USE_HISTORY": "", + "MODULE_DIR": '"."', + "__STDC_FORMAT_MACROS": "", + "TIME_FMT_O": '"lo"', + "TIME_FMT_U": '"lu"', + "TIME_FMT_X": '"lx"', + "UL_AND_TIME64_SAME": "", + "i64round": "lround", + "nan(x)": "(NAN)", + "INFINITY": "HUGE_VAL", + "LU": '""', + "TU": '""' + }, +) + +genrule( + name = "version_tag_h", + outs = ["version_tag.h"], + cmd = "\n".join([ + "cat <<'EOF' >$@", + '#ifndef __VERSION_TAG_H_', + '#define __VERSION_TAG_H_', + '#define VERSION_TAG "v12_0"', + '#endif // __VERSION_TAG_H_', + "EOF", + ]), +) + +# Trivial integration tests to confirm iverilog is minimally functional. + +genrule( + name = "hello_vvp", + srcs = ["hello.v"], + outs = ["hello.vvp"], + cmd = ( + "$(location :iverilog) " + + "-o $@ " + + "$<" + ), + tools = [ + ":iverilog", + ":vvp", # to resolve module include + ], +) + +vpi_binary( + name = "hello_vpi", + srcs = ["hello_vpi.c"], + out = "hello.vpi", + deps = [ + ":vpi_user_header", + ], +) + +genrule( + name = "run_hello", + srcs = ["hello.vvp"], + outs = ["hello.out"], + cmd = ( + "$(location :vvp) " + + "-M$$(dirname $(location :hello_vpi)) " + + "-mhello $< > $@ " + ), + tools = [ + ":hello_vpi", + ":vvp", + ], +) + +sh_test( + name = "hello_verilog_test", + srcs = [":hello_verilog_test.sh"], + args = ["$(location :run_hello)"], + data = [":run_hello"], +) diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 000000000..260927b0a --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,15 @@ +module( + name = "iverilog", + version = "12.0.0", +) + +bazel_dep(name = "gperf", version = "3.1") +bazel_dep(name = "bzip2", version = "1.0.8.bcr.2") +bazel_dep(name = "rules_flex", version = "0.4") +bazel_dep(name = "rules_bison", version = "0.4") +bazel_dep(name = "sed", version = "4.9.bcr.1") +bazel_dep(name = "rules_m4", version = "0.3") +bazel_dep(name = "readline", version = "8.2.bcr.1") +bazel_dep(name = "zlib", version = "1.3.1.bcr.5") +bazel_dep(name = "rules_cc", version = "0.1.1") +bazel_dep(name = "bazel_skylib", version = "1.7.1") diff --git a/bazel/BUILD b/bazel/BUILD new file mode 100644 index 000000000..e69de29bb diff --git a/bazel/build_plugins.bzl b/bazel/build_plugins.bzl new file mode 100644 index 000000000..aea45c4e8 --- /dev/null +++ b/bazel/build_plugins.bzl @@ -0,0 +1,40 @@ +# Copyright 2020 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. + +"""BUILD helpers for using iverilog. +""" + +load("@rules_cc//cc:defs.bzl", "cc_binary") + +def vpi_binary(name, out, srcs, **kwargs): + """Creates a .vpi file with the given name from the given sources. + + All the extra arguments are passed directly to cc_binary. + """ + cc_target = name + "_shared" + cc_binary( + name = cc_target, + srcs = srcs, + linkshared = 1, + **kwargs + ) + + native.genrule( + name = name, + srcs = [":" + cc_target], + outs = [out], + cmd = "cp $< $@", + output_to_bindir = 1, + executable = 1, + ) diff --git a/bazel/pseudo_configure.bzl b/bazel/pseudo_configure.bzl new file mode 100644 index 000000000..dcf60e2dc --- /dev/null +++ b/bazel/pseudo_configure.bzl @@ -0,0 +1,107 @@ +# Copyright 2020 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. + +"""Fake configuration step for hacky substitutions in ".in" files.""" + +_UNIX_TEMPLATE = """\ +#!/usr/bin/env bash +# Generated by `@iverilog//bazel:pseudo_configure.bzl` +set -euo pipefail +{} +""" + +def _pseudo_configure_impl(ctx): + additional = ctx.attr.additional + mappings = ctx.attr.mappings + defs = ctx.attr.defs + out = ctx.outputs.out + src = ctx.file.src if ctx.attr.src else None + sed = ctx.executable._sed + + cmd = [] + + if src == None: + cmd.append("echo '#pragma once' >> %s" % (out.path)) + + for k, v in additional.items(): + cmd.append("echo '#define %s %s' >> %s" % (k, v, out.path)) + + if src != None: + cmd.append("cat %s \\" % (src.path)) + else: + cmd.append("echo '' \\") + all_defs = "" + for def_ in defs: + cmd.append(r"| " + sed.path + r" 's/#\s*undef \b\(" + def_ + r"\)\b/#define \1 1/'" + "\\") + all_defs += ("#define " + def_ + " 1\\n") + for key, value in mappings.items(): + cmd.append(r"| " + sed.path + r" 's/#\s*undef \b" + key + r"\b/#define " + str(key) + " " + str(value) + "/' \\") + cmd.append(r"| " + sed.path + r" 's/#\s*define \b\(" + key + r"\)\b 0/#define \1 " + str(value) + "/' \\") + all_defs += "#define " + key + " " + value + "\\n" + cmd.append(r"| " + sed.path + r" 's/\@DEFS\@/" + all_defs + "/' \\") + cmd.append(" >> " + out.path) + + executable = ctx.actions.declare_file("{}.sh".format(ctx.label.name)) + ctx.actions.write( + output = executable, + content = _UNIX_TEMPLATE.format( + "\n".join(cmd), + ), + is_executable = True, + ) + + ctx.actions.run( + mnemonic = "NCursesPseudoConfigure", + inputs = [src] if src != None else [], + outputs = [out], + executable = executable, + tools = [sed], + use_default_shell_env = True, + ) + + return [DefaultInfo( + files = depset([out]), + )] + +pseudo_configure = rule( + doc = "Perform a fake 'configure' step on a file.", + implementation = _pseudo_configure_impl, + attrs = { + "additional": attr.string_dict( + doc = "Optional mapping of definitions to prepend to the file.", + default = {}, + ), + "defs": attr.string_list( + doc = "List of definitions to #define as `1`.", + default = [], + ), + "mappings": attr.string_dict( + doc = "Mapping of definitions with non-trivial values.", + default = {}, + ), + "out": attr.output( + doc = "Path to place the output file contents.", + mandatory = True, + ), + "src": attr.label( + doc = "`.in` file to transform.", + allow_single_file = True, + ), + "_sed": attr.label( + cfg = "exec", + executable = True, + default = Label("@sed"), + ), + }, +) diff --git a/bazel/system.bzl b/bazel/system.bzl new file mode 100644 index 000000000..e44b42129 --- /dev/null +++ b/bazel/system.bzl @@ -0,0 +1,33 @@ +load("@bazel_skylib//rules:copy_file.bzl", "copy_file") + +SYSTEM_HEADERS_BASE = "_system" + +def cc_system_headers(name, hdrs, strip_include_prefix='', **kwargs): + """Copy headers in a folder and create a cc_library with system includes. + + This rule relies on strip_include_prefix behavior that adds a folder with virtual_includes + and includes both iquote and isystem compiler options. + + The SYSTEM_HEADERS_BASE is just used to hide in the gendir the files. + """ + outs = [ + '{}/{}'.format(SYSTEM_HEADERS_BASE, hdr) + for hdr in hdrs + ] + [copy_file( + name = "{}_{}".format(SYSTEM_HEADERS_BASE, hdr).replace('/', '_').replace('.', '_').replace('-', '_'), + src = hdr, + out = out, + ) for hdr, out in zip(hdrs, outs)] + includes = kwargs.pop('includes', default=[]) + includes = [ + '{}/{}'.format(SYSTEM_HEADERS_BASE, k) + for k in includes + ] + native.cc_library( + name = name, + hdrs = outs, + includes = includes, + strip_include_prefix = '{}/{}'.format(SYSTEM_HEADERS_BASE, strip_include_prefix), + **kwargs + ) diff --git a/bazel/yacclex_helpers.bzl b/bazel/yacclex_helpers.bzl new file mode 100644 index 000000000..0472c68a1 --- /dev/null +++ b/bazel/yacclex_helpers.bzl @@ -0,0 +1,34 @@ +"""Port of the original rules to bzlmod bison and lex.""" + +def genlex(name, src, out, prefix = "yy"): + native.genrule( + name = name, + srcs = [src], + outs = [out], + cmd = "M4=$(M4) $(FLEX) -P {} --outfile=$@ $<".format(prefix), + toolchains = [ + "@rules_flex//flex:current_flex_toolchain", + "@rules_m4//m4:current_m4_toolchain", + ], + ) + + +def genyacc(name, src, header_out, source_out, prefix = "yy", extra_outs = []): + native.genrule( + name = name, + srcs = [src], + outs = [ + header_out, + source_out, + ] + extra_outs, + cmd = """ + M4=$(M4) $(BISON) \ + --defines=$(@D)/{} \ + --output-file=$(@D)/{} \ + --name-prefix={} $< + """.format(header_out, source_out, prefix), + toolchains = [ + "@rules_bison//bison:current_bison_toolchain", + "@rules_m4//m4:current_m4_toolchain", + ], + ) diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..376925ffe --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1743583204, + "narHash": "sha256-F7n4+KOIfWrwoQjXrL2wD9RhFYLs2/GGe/MQY1sSdlE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2c8d3f48d33929642c1c12cd243df4cc7d2ce434", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2c8d3f48d33929642c1c12cd243df4cc7d2ce434", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/hello.v b/hello.v new file mode 100644 index 000000000..293fc4945 --- /dev/null +++ b/hello.v @@ -0,0 +1,29 @@ +// Copyright 2020 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. + + +// Verilog test helper file. + +module hello; + +integer val; + +initial begin + val = 41; + $increment(val); + $display("$increment returns val=%d", val); + $finish(); +end + +endmodule diff --git a/hello_verilog_test.sh b/hello_verilog_test.sh new file mode 100755 index 000000000..bc0688a29 --- /dev/null +++ b/hello_verilog_test.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# +# Copyright 2020 The XLS Authors +# +# 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. + +set -eu + +exec grep 42 $1 diff --git a/hello_vpi.c b/hello_vpi.c new file mode 100644 index 000000000..5ac3765b5 --- /dev/null +++ b/hello_vpi.c @@ -0,0 +1,60 @@ +// Copyright 2020 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. + +// Based on http://en.wikipedia.org/wiki/Verilog_Procedural_Interface. +// +// Simple VPI plug-in to test the toolchain. + +#include "vpi_user.h" + +// Implements the increment system task +static PLI_INT32 increment(PLI_BYTE8 *userdata) { + // Obtains a handle to the argument list + vpiHandle systfref = vpi_handle(vpiSysTfCall, NULL); + vpiHandle args_iter = vpi_iterate(vpiArgument, systfref); + + // Grabs the value of the first argument + vpiHandle argh = vpi_scan(args_iter); + struct t_vpi_value argval; + argval.format = vpiIntVal; + vpi_get_value(argh, &argval); + + int value = argval.value.integer; + vpi_printf("Input %d\n", value); + + // Increments the value and puts it back as first argument + argval.value.integer = value + 1; + vpi_put_value(argh, &argval, NULL, vpiNoDelay); + + // Cleans up and returns. + vpi_free_object(args_iter); + return 0; +} + +// Registers the $increment task with the system. +static void registerIncrementTask() { + s_vpi_systf_data task; + task.type = vpiSysTask; + task.tfname = "$increment"; + task.calltf = increment; + task.compiletf = 0; + + vpi_register_systf(&task); +} + +// Registers the new system task here. +void (*vlog_startup_routines[]) () = { + registerIncrementTask, + 0 +}; diff --git a/iverilog.sh b/iverilog.sh new file mode 100755 index 000000000..a5e822ca2 --- /dev/null +++ b/iverilog.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# Copyright 2020 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. + +# Wrapper around iverilog binary. Adds the path to the dependencies to +# the command line of iverilog. +set -eu + +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +# shellcheck disable=SC1090 +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e + +repo_name=$(runfiles_current_repository) +repo_name=${repo_name:-_main} +dir="$0.runfiles/$repo_name" +vvp_dir="${0/%iverilog/vvp}.runfiles/$repo_name" + +if [[ ! -d "$dir" ]]; then + dir=$(dirname $0) # use current directory it not launched directly from the :iverilog target. +fi +if [[ ! -d "$vvp_dir" ]]; then + vvp_dir=$(dirname $0) # use current directory it not launched directly from the :iverilog target. +fi + +exec "$dir/iverilog-bin" -B"$dir" -BM"$vvp_dir" -DIVERILOG "$@" diff --git a/vvp.sh b/vvp.sh new file mode 100755 index 000000000..858479014 --- /dev/null +++ b/vvp.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Copyright 2020 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. + +# Wrapper around vvp binary. Adds the path to the dependencies to +# the command line of vvp. + +set -eu +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +# shellcheck disable=SC1090 +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e + +repo_name=$(runfiles_current_repository) +repo_name=${repo_name:-_main} +dir="$0.runfiles/$repo_name" +if [[ ! -d "$dir" ]]; then + dir=$(dirname $0) # use current directory it not launched directly from the :vvp target. +fi + +exec "$dir/vvp-bin" -M"$dir" "$@"