Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,10 @@ chisel.toolchain(
)
use_repo(
chisel,
"chisel_firtool",
"chisel_maven",
)

bazel_dep(name = "rules_python", version = "1.7.0", dev_dependency = True)

bazel_dep(name = "rules_verilog", version = "1.1.1")

circt_repo = use_repo_rule(
"//verilog:circt_repo.bzl",
"circt_repo",
)

circt_repo(
name = "circt",
)
36 changes: 31 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ This repository packages the following helpers as a BCR-friendly module:
- `chisel_binary`
- `chisel_library`
- `chisel_test`
- `fir_library`
- `verilog_file`
- `verilog_directory`
- `verilog_single_file_library`

## Features

- One extension (`chisel.toolchain`) to fetch Chisel/ScalaTest Maven artifacts.
- One extension (`chisel.toolchain`) to fetch Chisel/ScalaTest Maven artifacts and a compatible native firtool.
- Ready-to-use macro defaults via `@chisel_maven` aliases (`:chisel`, `:chisel_plugin`, etc.).
- Automatic firtool version selection from Chisel's own build metadata via `@chisel_firtool`.
- Built-in Verilator runtime wrapper in `chisel_test` for BCR Verilator layout quirks.
- Minimal smoke tests and GitHub CI workflows.

Expand All @@ -38,25 +42,25 @@ scala_deps = use_extension("@rules_scala//scala/extensions:deps.bzl", "scala_dep
scala_deps.scala()
scala_deps.scalatest() # only needed if you use chisel_test

# Chisel dependencies (creates @chisel_maven)
# Chisel dependencies (creates @chisel_maven and @chisel_firtool)
chisel = use_extension("@rules_chisel//chisel:extensions.bzl", "chisel")
chisel.toolchain(
chisel_version = "7.8.0",
scala_version = "2.13.17", # should match rules_scala's scala_version
firtool_resolver_version = "2.0.1", # choose a known compatible resolver for your Chisel release
lock_file = "//:maven_install.json", # run `touch maven_install.json && REPIN=1 bazel run @chisel_maven//:pin` to generate the lock file
)
use_repo(chisel, "chisel_maven")
use_repo(chisel, "chisel_firtool", "chisel_maven")
```

If you are authoring a reusable Bazel module (not an application root) and only need Chisel for that module's own development/tests, use `dev_dependency = True` on `use_extension(...)` so your toolchain tag does not leak to downstream consumers.


## Notes

- Scala toolchain setup is **mandatory** in your own `MODULE.bazel`. This is by design: `rules_chisel` leaves Scala version/toolchain control to users.
- `chisel_test` wraps `scala_test` and sets up a Verilator runtime environment. It expects `@verilator//:bin/verilator` and `@verilator//:verilator_includes`. If you don't use `chisel_test`, you can skip the Verilator dependency.
- Please explicitly set `firtool_resolver_version` in `chisel.toolchain(...)`. Use the Chisel Maven POM as the source of truth (for example: [`chisel_2.13-7.8.0.pom`](https://repo1.maven.org/maven2/org/chipsalliance/chisel_2.13/7.8.0/chisel_2.13-7.8.0.pom), see dependency `firtool-resolver_2.13` with `<version>2.0.1</version>`).
- `@chisel_firtool` reads the configured Chisel artifact's `BuildInfo.firtoolVersion` and asks `firtool-resolver` for that exact native tool. The download happens while Bazel prepares external repositories, not inside each Verilog action.
- To make dependency resolution faster, deterministic and avoid repeated conflict-selection drift/noise across builds, set `lock_file` and pin once: `touch maven_install.json && REPIN=1 bazel run @chisel_maven//:pin`.
- `lock_file` records a resolved result. The first pin still performs dependency resolution; repin when you intentionally change dependency versions.

Expand All @@ -66,7 +70,13 @@ You can check `tests` for examples as well.

```starlark
load("@rules_chisel//chisel:defs.bzl", "chisel_binary", "chisel_library", "chisel_test")
load("@rules_chisel//verilog:defs.bzl", "verilog_single_file_library")
load(
"@rules_chisel//verilog:defs.bzl",
"fir_library",
"verilog_directory",
"verilog_file",
"verilog_single_file_library",
)

chisel_library(
name = "adder_lib",
Expand All @@ -86,6 +96,21 @@ chisel_test(
deps = [":adder_lib"],
)

fir_library(
name = "adder_fir",
generator = ":emit_adder",
)

verilog_file(
name = "adder.sv",
srcs = [":adder_fir"],
)

verilog_directory(
name = "adder_split",
srcs = [":adder_fir"],
)

verilog_single_file_library(
name = "merged_sv",
srcs = [
Expand Down Expand Up @@ -127,6 +152,7 @@ Local smoke targets:
bazel build //...
bazel test //tests/smoke:verilog_concat_test
bazel test //tests/smoke:simple_adder_test --test_output=errors
bazel test //tests/smoke:fir_verilog_test --test_output=errors
tests/version_compat/check_chisel_versions.sh
```

Expand Down
14 changes: 12 additions & 2 deletions chisel/extensions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ load("@rules_jvm_external//:defs.bzl", "maven_install")
load("@rules_jvm_external//private/extensions:download_pinned_deps.bzl", "download_pinned_deps")
load("@rules_jvm_external//private/rules:v1_lock_file.bzl", "v1_lock_file")
load("@rules_jvm_external//private/rules:v2_lock_file.bzl", "v2_lock_file")
load("//verilog:firtool_repo.bzl", "firtool_repo")

_FIRTOOL_REPO_NAME = "chisel_firtool"

_DEFAULT_REPOSITORIES = [
"https://repo1.maven.org/maven2",
Expand Down Expand Up @@ -170,6 +173,13 @@ def _chisel_extension_impl(module_ctx):
pin_repo_name = "unpinned_" + internal_repo_name if settings.lock_file else internal_repo_name,
scala_version = settings.scala_version,
)
firtool_repo(
name = _FIRTOOL_REPO_NAME,
chisel_version = settings.chisel_version,
firtool_resolver_version = settings.firtool_resolver_version,
repositories = settings.repositories,
scala_version = settings.scala_version,
)

root_is_dev = True
for mod in module_ctx.modules:
Expand All @@ -180,8 +190,8 @@ def _chisel_extension_impl(module_ctx):

return module_ctx.extension_metadata(
reproducible = settings.lock_file != None,
root_module_direct_deps = [] if root_is_dev else [settings.repo_name],
root_module_direct_dev_deps = [settings.repo_name] if root_is_dev else [],
root_module_direct_deps = [] if root_is_dev else [settings.repo_name, _FIRTOOL_REPO_NAME],
root_module_direct_dev_deps = [settings.repo_name, _FIRTOOL_REPO_NAME] if root_is_dev else [],
)

toolchain = tag_class(
Expand Down
11 changes: 9 additions & 2 deletions tests/version_compat/check_chisel_versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ chisel.toolchain(
scala_version = "${SCALA_VERSION}",
firtool_resolver_version = "${firtool_version}",
)
use_repo(chisel, "chisel_maven")
use_repo(chisel, "chisel_firtool", "chisel_maven")
MODULE

cat > "${ws}/BUILD.bazel" <<'BUILD'
Expand All @@ -100,6 +100,13 @@ chisel_binary(
deps = [":compat_lib"],
main_class = "compat.Main",
)

genrule(
name = "firtool_version",
outs = ["firtool-version.txt"],
cmd = "$(location @chisel_firtool//:bin/firtool) --version > $@",
tools = ["@chisel_firtool//:bin/firtool"],
)
BUILD

cat > "${ws}/Compat.scala" <<'SCALA'
Expand Down Expand Up @@ -135,7 +142,7 @@ SCALA
--nohome_rc \
--noworkspace_rc \
--output_user_root="${out_root}" \
build //:compat_lib //:compat_bin \
build //:compat_lib //:compat_bin //:firtool_version \
--enable_bzlmod \
--repository_cache="${TMP_ROOT}/repo_cache" \
--disk_cache="${TMP_ROOT}/disk_cache" \
Expand Down
6 changes: 5 additions & 1 deletion verilog/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ package(
default_visibility = ["//visibility:private"],
)

exports_files(["defs.bzl"])
exports_files([
"ResolveFirtool.java",
"defs.bzl",
"firtool_repo.bzl",
])
68 changes: 68 additions & 0 deletions verilog/ResolveFirtool.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public final class ResolveFirtool {
private ResolveFirtool() {}

public static void main(String[] args) throws Exception {
if (args.length != 1) {
throw new IllegalArgumentException("Usage: ResolveFirtool <output-file>");
}

Object buildInfo = Class.forName("chisel3.BuildInfo$").getField("MODULE$").get(null);
Object versionOption = buildInfo.getClass().getMethod("firtoolVersion").invoke(buildInfo);
Method isDefined = versionOption.getClass().getMethod("isDefined");
if (!(Boolean) isDefined.invoke(versionOption)) {
throw new IllegalStateException("The configured Chisel artifact does not declare a firtool version");
}
String version = (String) versionOption.getClass().getMethod("get").invoke(versionOption);

String javaExecutable = Paths.get(
System.getProperty("java.home"),
"bin",
System.getProperty("os.name").toLowerCase().startsWith("windows") ? "java.exe" : "java")
.toString();
ProcessBuilder processBuilder = new ProcessBuilder(
javaExecutable,
"-cp",
System.getProperty("java.class.path"),
"firtoolresolver.Main",
version);
processBuilder.environment().remove("CHISEL_FIRTOOL_PATH");
processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);

Process process = processBuilder.start();
String output;
try (InputStream input = process.getInputStream();
ByteArrayOutputStream bytes = new ByteArrayOutputStream()) {
input.transferTo(bytes);
output = bytes.toString(StandardCharsets.UTF_8.name()).trim();
}
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new IllegalStateException("firtool-resolver failed with exit code " + exitCode);
}
if (output.isEmpty()) {
throw new IllegalStateException("firtool-resolver did not return a firtool path");
}

String[] outputLines = output.split("\\R");
Path source = Paths.get(outputLines[outputLines.length - 1]);
Path destination = Paths.get(args[0]);
Files.createDirectories(destination.getParent());
Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);
File destinationFile = destination.toFile();
if (!destinationFile.setExecutable(true, false) && !destinationFile.canExecute()) {
throw new IllegalStateException("Unable to make firtool executable: " + destination);
}

System.out.println("Resolved firtool " + version + " for the configured Chisel artifact");
}
}
32 changes: 0 additions & 32 deletions verilog/circt_repo.bzl

This file was deleted.

4 changes: 2 additions & 2 deletions verilog/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fir_library = rule(
executable = True,
allow_files = True,
cfg = "exec",
default = Label("@circt//:bin/firtool"),
default = Label("@chisel_firtool//:bin/firtool"),
),
},
)
Expand Down Expand Up @@ -112,7 +112,7 @@ def verilog_attrs():
executable = True,
allow_files = True,
cfg = "exec",
default = Label("@circt//:bin/firtool"),
default = Label("@chisel_firtool//:bin/firtool"),
),
}

Expand Down
Loading
Loading