Chipyard Nodes

API reference for the Chipyard library nodes in chia.chipyard. These pages are generated automatically from the docstrings in the source, so they stay in sync with the code.

State definitions

class chia.chipyard.state_def.BuildTarget(*values)[source]

Bases: str, Enum

Which Chipyard simulator flavor ChiselBuildNode builds. Maps to make targets in ``chipyard/sims/verilator`

VERILATOR

Default fast Verilator sim (make in sims/verilator). No waveform capability; binary simulator-<pkg>.harness-<config>.

VERILATOR_DEBUG

Waveform/VCD-capable Verilator sim (make debug). Binary suffixed -debug. Required for wf_scopes (build-time spatial trace filter) and runtime wave windows / VCD capture.

FIRESIM_METASIM_VERILATOR

A FireSim metasim (VFireSim) built under sims/firesim/sim; binary name uses the FireSim quintuplet <PLATFORM>-firesim-<DESIGN>-<config>-<PLATFORM_CONFIG>.

class chia.chipyard.state_def.WaveWindow(pc: int, cyc: int, n: int = 1)[source]

Bases: object

One PC-triggered waveform-capture window.

Waveform collection is captured on the Nth retired commit of pc happens and dumps for cyc BOOM-core cycles thereafter. Each window fires at most once; overlapping windows merge into a single contiguous dump segment.

class chia.chipyard.state_def.BuildArtifact(name: str, simulator_binary_content: bytes, simulator_binary_name: str, config: str, config_package: str, target: BuildTarget, success: bool, stdout: str, stderr: str, returncode: int, generated_src_files: list[tuple[str, str]]=<factory>)[source]

Bases: object

Result of a ChiselBuildNode.build(): a compiled simulator + metadata.

The compiled simulator is shipped by value (the ELF bytes travel inside this object).

name

Free-form label carried from ChiselBuildNode.name (default "chipyard") for downstream identification.

Type:

str

simulator_binary_content

Raw ELF bytes of the compiled simulator binary. Empty (b"") when the build failed or timed out.

Type:

bytes

simulator_binary_name

Filename of the simulator, e.g. "simulator-chipyard.harness-MegaBoomV3Config".

Type:

str

config

Chipyard CONFIG the binary was built for (e.g. "MegaBoomV3Config").

Type:

str

config_package

Chipyard CONFIG_PACKAGE (Scala package, e.g. "chipyard").

Type:

str

target

The BuildTarget that produced this binary.

Type:

chia.chipyard.state_def.BuildTarget

success

True iff the build’s make exited 0 and the binary exists.

Type:

bool

stdout

Captured stdout of the build command.

Type:

str

stderr

Captured stderr of the build command.

Type:

str

returncode

Exit code of the build command; -1 on timeout.

Type:

int

generated_src_files

(filename, contents) pairs of generated .v/.sv and .top.mems.conf collateral: populated only when the build was run with collect_generated_src=True.

Type:

list[tuple[str, str]]

class chia.chipyard.state_def.RiscvBuildArtifact(binary_name: str, binary_content: bytes, target: str, success: bool, stdout: str, stderr: str, returncode: int, dump: str = '')[source]

Bases: object

Result of a RiscvBuildNode.build(): a cross-compiled RISC-V ELF.

binary_name

Output filename, e.g. "hello.riscv" or "hello".

Type:

str

binary_content

Raw ELF bytes of the produced binary. Empty (b"") when the build failed or timed out.

Type:

bytes

target

Which toolchain/output convention was used: "verilator" (baremetal) or "linux" (userspace).

Type:

str

success

True iff make exited 0 and a non-empty binary was produced.

Type:

bool

stdout

Captured stdout of the build command.

Type:

str

stderr

Captured stderr of the build command (includes a timeout note on expiry).

Type:

str

returncode

Exit code of the build command; -1 on timeout.

Type:

int

dump

objdump -D disassembly of the ELF; "" unless build() was called with include_dump=True.

Type:

str

class chia.chipyard.state_def.RiscvObjdumpArtifact(binary_name: str, dump: str, target: str, success: bool, stdout: str, stderr: str, returncode: int)[source]

Bases: object

Result of a RiscvObjdumpNode.dump(): a RISC-V ELF disassembly.

binary_name

Filename of the input ELF.

Type:

str

dump

The disassembly (stdout of the objdump invocation); "" on failure.

Type:

str

target

Which toolchain prefix was used: "verilator" (riscv64-unknown-elf-) or "linux" (riscv64-unknown-linux-gnu-).

Type:

str

success

True iff objdump exited 0 and produced non-empty output.

Type:

bool

stdout

Captured stdout of the objdump invocation (same content as dump).

Type:

str

stderr

Captured stderr (includes a timeout note on expiry).

Type:

str

returncode

Exit code of the objdump invocation; -1 on timeout.

Type:

int

class chia.chipyard.state_def.RunResult(test_binary_name: str, log: str, out: str, returncode: int, success: bool, vcd_s3_path: str = '', vcd_size_bytes: int = 0, out_s3_path: str = '', log_s3_path: str = '', wave_windows: list[WaveWindow] = <factory>)[source]

Bases: object

Result of a VerilatorRunNode.run(): captured simulator output.

test_binary_name

Filename of the input test ELF that was run.

Type:

str

log

Simulator stdout captured to <stem>.log (program / HTIF output).

Type:

str

out

the .out file, contains spike-dasm disassembly of the simulator’s stderr (the human-readable committed-instruction trace).

Type:

str

returncode

Exit code of the simulator process.

Type:

int

success

True iff returncode == 0.

Type:

bool

vcd_s3_path

Full s3://… URI of the uploaded VCD; "" when no waveform was captured or no upload occurred (the VCD is too large to return inline).

Type:

str

vcd_size_bytes

Local VCD size at upload time; 0 when no upload.

Type:

int

out_s3_path

s3://… URI of the uploaded .out; "" when not uploaded.

Type:

str

log_s3_path

s3://… URI of the uploaded .log; "" when not uploaded.

Type:

str

wave_windows

Echo of the WaveWindow list the run was configured with.

Type:

list[chia.chipyard.state_def.WaveWindow]

class chia.chipyard.state_def.CosimResult(elf_name: str, match: bool, matched: int, completed: bool, first_divergence: dict | None, sim_cycles: int | None, failing_trace_gz: bytes | None)[source]

Bases: object

Result of a CosimNode.run(): the lockstep cospike verdict for one ELF.

elf_name

Filename of the ELF that was co-simulated.

Type:

str

match

True iff the DUT agreed with Spike (no divergence aborted the run).

Type:

bool

matched

Committed instructions Spike checked before the run stopped.

Type:

int

completed

True iff the program reached its end-of-test marker.

Type:

bool

first_divergence

{line, spike, dut} describing the first mismatch, or None on a match.

Type:

dict | None

sim_cycles

Simulation cycles executed, or None if not reported.

Type:

int | None

failing_trace_gz

gzip’d tail window around the abort (DUT + Spike commit logs interleaved); None on a match.

Type:

bytes | None

class chia.chipyard.state_def.SpikeResult(test_binary_name: str, isa: str, log: str, commit_log: str, returncode: int, success: bool)[source]

Bases: object

Result of running a RISC-V ELF on the Spike ISA simulator.

test_binary_name

Filename of the input ELF that was executed.

Type:

str

isa

The --isa=<...> string Spike ran with (e.g. "rv64gc").

Type:

str

log

Spike stdout, i.e. the program / HTIF output.

Type:

str

commit_log

Committed-instruction trace. Empty ("") unless the run requested it via log_commits=True.

Type:

str

returncode

Exit code of the Spike process.

Type:

int

success

True iff the run succeeded. For self-checking riscv-tests this is exit code 0 reported over HTIF.

Type:

bool

class chia.chipyard.state_def.SpikeBuildArtifact(success: bool, spike_bin: str, stdout: str, stderr: str, returncode: int)[source]

Bases: object

Result of (re)building the Spike simulator binary from source.

success

True iff ``make``+install succeeded and the binary exists.

Type:

bool

spike_bin

Path to the (re)built spike binary (in-container).

Type:

str

stdout

Captured stdout of the build command.

Type:

str

stderr

Captured stderr of the build command.

Type:

str

returncode

Exit code of the build command.

Type:

int

class chia.chipyard.state_def.TortureMode(*values)[source]

Bases: str, Enum

How a RISC-V Torture run generates and checks tests.

SINGLE

Generate one test, run it, and diff signatures (make rgentest).

OVERNIGHT

Generate-and-test loop until N failures or T minutes elapse (make rnight).

REPLAY

Take a pre-supplied test.S, run it, and diff signatures (make rtest).

class chia.chipyard.state_def.TortureTestRun(name: str, success: bool, test_s: str, test_dump: str, spike_sig: str, rtlsim_sig: str, pseg_test_s: str | None = None)[source]

Bases: object

Artifacts produced for one generated Torture test, pass or fail.

A test passes when the Spike reference signature matches the DUT (RTL simulation) signature.

name

Basename of the test, e.g. "test" or "test_1714571234".

Type:

str

success

True iff the Spike signature matched the DUT signature.

Type:

bool

test_s

The generated assembly source (.S).

Type:

str

test_dump

objdump output, if Torture produced one (else "").

Type:

str

spike_sig

The Spike reference signature.

Type:

str

rtlsim_sig

The DUT (RTL simulation) signature.

Type:

str

pseg_test_s

The narrowed program segment from testrun’s seek mode. Populated for failures only; None otherwise.

Type:

str | None

class chia.chipyard.state_def.TortureResult(name: str, config: str, config_package: str, mode: TortureMode, success: bool, num_tests: int, num_failures: int, tests: list[TortureTestRun], stdout: str, stderr: str, returncode: int, build_artifact: BuildArtifact | None = None)[source]

Bases: object

Result of a RISC-V Torture run against a built simulator.

name

Free-form label carried from the run for downstream identification.

Type:

str

config

Chipyard CONFIG the simulator was built for (e.g. "MegaBoomV3Config").

Type:

str

config_package

Chipyard CONFIG_PACKAGE (Scala package, e.g. "chipyard").

Type:

str

mode

The TortureMode the run used.

Type:

chia.chipyard.state_def.TortureMode

success

True iff all signatures matched and the run completed.

Type:

bool

num_tests

Number of tests run — 1 for SINGLE/REPLAY, N for OVERNIGHT.

Type:

int

num_failures

Number of tests whose signatures mismatched.

Type:

int

tests

Per-test artifacts. Includes passing and failing tests for SINGLE/REPLAY; failing tests only for OVERNIGHT.

Type:

list[chia.chipyard.state_def.TortureTestRun]

stdout

Captured stdout of the Torture run.

Type:

str

stderr

Captured stderr of the Torture run.

Type:

str

returncode

Exit code of the Torture run.

Type:

int

build_artifact

The BuildArtifact that produced the simulator. Populated by torture_from_config; None otherwise.

Type:

chia.chipyard.state_def.BuildArtifact | None

Chisel build

class chia.chipyard.chisel_build_node.ChiselBuildNode(chipyard_path: str, config: str, config_package: str = 'chipyard', target: BuildTarget = BuildTarget.VERILATOR, make_jobs: int = 32, timeout_seconds: int = 600, extra_make_args: dict = {}, collect_generated_src: bool = False, clean_sim: bool = False, clean: bool = True, wf_scopes: list[str] | tuple[str, ...] = (), clean_wf_stamp: bool = True, logging_level: int = 10, name: str = 'chipyard')[source]

Bases: object

Elaborates a Chipyard config into a Verilator simulator binary.

Wraps the Chipyard sims/verilator (and FireSim sims/firesim/sim) Make flow: it shells out to make inside the appropriate sims directory to run the Chisel generator and Verilator, then reads the resulting simulator ELF back into a BuildArtifact so it can be shipped to a VerilatorRunNode for execution. By default runs on cluster nodes tagged with chipyard=1 resource.

Configure a single Chipyard Verilator build.

Parameters:
  • chipyard_path – Absolute path to the Chipyard checkout (the chia_artifact branch) on the build node. Set to /home/ray/chipyard when using the CHIA chipyard container. The Make flow runs inside <chipyard_path>/sims/verilator (or, for FireSim metasims, <chipyard_path>/sims/firesim/sim).

  • config – Chipyard CONFIG: the Chisel Config class name that parametrizes the SoC to elaborate (e.g. "RocketConfig", "MegaBoomV3Config"). Passed to Make as CONFIG=<config> and becomes the suffix of the produced binary’s name.

  • config_package – Chipyard CONFIG_PACKAGE: the Scala package the Config class lives in (passed as CONFIG_PACKAGE=). Defaults to "chipyard"; the generated binary is named simulator-<config_package>.harness-<config>.

  • target – Which simulator to build (see BuildTarget): VERILATOR (fast, no waveforms), VERILATOR_DEBUG (make debug; VCD/waveform-capable, required for wf_scopes and runtime wave windows), or FIRESIM_METASIM_VERILATOR (a FireSim metasim VFireSim binary built under sims/firesim/sim).

  • make_jobs – Value passed to make -j controlling build parallelism (number of concurrent compile jobs).

  • timeout_seconds – Wall-clock limit for the main make build. On expiry the build is killed and a failed BuildArtifact (returncode=-1) is returned. The preceding clean steps have their own fixed 600s timeouts.

  • extra_make_args – Additional KEY=value Make variables to append to the build command (e.g. {"VERILATOR_THREADS": 4}). For FIRESIM_METASIM_VERILATOR these may include DESIGN / PLATFORM / PLATFORM_CONFIG and are merged over the FireSim defaults. Note: passing WF_SCOPES here conflicts with wf_scopes (below).

  • collect_generated_src – If True, after a successful build read every generated .v/.sv file (skipping TestDriver.v and any DPI-C files) plus the .top.mems.conf from the gen-collateral directory into BuildArtifact.generated_src_files.

  • clean_sim – If True, run make clean-sim before building. This removes the simulator binaries but leaves the cached chipyard.jar and generated FIRRTL/Verilog (gen_dir) in place: so it can relink against stale Verilog.

  • clean – If True (default), run make clean before building. This also clears the Chisel-generator cache (chipyard.jar) and gen_dir, guaranteeing the build reflects the current Scala sources. Slower but correct.

  • wf_scopes – chia_artifact-specific spatial waveform filter: a list of module-hierarchy scope paths (e.g. "TestHarness.chiptop0.system...") restricting which modules Verilator traces into the VCD. Joined with spaces into the WF_SCOPES Make variable. At most _MAX_WF_SCOPES (8) paths, and only valid with target=VERILATOR_DEBUG (the Makefile wires the filter only into the debug model).

  • clean_wf_stamp – If True and wf_scopes is set, delete sims/verilator/.wf_scopes.stamp before building so Make re-applies the scope filter even when it would otherwise consider nothing changed (mirrors run_wave.sh).

  • logging_level – Python logging level for this node’s logger.

  • name – Label copied into the resulting BuildArtifact.name; purely for downstream identification/traceability.

build() BuildArtifact[source]

Run the Chipyard Make flow and return the compiled simulator.

Takes no arguments: every input comes from the attributes set in __init__. Selects the sims directory, binary name and make command line from self.target/self.config/self.config_package (plus self.extra_make_args), optionally clears the WF_SCOPES stamp and runs make clean/clean-sim, then invokes the build under self.timeout_seconds.

Returns:

On success, carries the simulator ELF bytes plus config/config_package/target and (if collect_generated_src) the generated source files. On a build failure or timeout, success=False with empty binary content and the captured stdout/stderr and returncode (-1 on timeout).

Return type:

BuildArtifact

CIRCT

General-purpose CIRCT chia nodes — firtool lowering, circt-opt invocation, custom-pass rebuild, ninja builds, lit runs, plus async MCP tool wrappers — usable from any chia flow.

These primitives wrap the CIRCT toolchain (firtool, circt-opt) plus chipyard’s Chisel elaboration target so that any CHIA user can compose a CIRCT-driven flow without re-implementing subprocess glue. They run as @ChiaFunction tasks on a worker with the circt resource (advertised by the chia-circt image, which ships /opt/circt-sdk and a source tree at /workspace/circt). chisel_elaborate_to_chirrtl additionally needs Java + sbt; pair it with a chia-chipyard worker or layer chipyard’s build deps into chia-circt if you need it co-located.

Usage example:

fir = chisel_elaborate_to_chirrtl(chipyard_path, "RocketConfig")["fir_text"]
hw  = firtool_lower_chirrtl_to_hw(fir, repl_seq_mem=True)["hw_mlir"]
sv  = circt_opt_lower_hw_to_verilog(hw)["verilog"]
chia.chipyard.circt.firtool_lower_chirrtl_to_hw(chirrtl_text: str, repl_seq_mem: bool = True, extra_args: tuple[str, ...] = (), timeout_seconds: int = 600) dict[str, str][source]

Lower CHIRRTL FIRRTL text to HW-dialect MLIR via firtool.

Wraps firtool --ir-hw [--repl-seq-mem --repl-seq-mem-file=<path>] against /opt/circt-sdk/bin/firtool. With repl_seq_mem=True the sequential memories are split off into a .mems.conf file (the same file Chipyard’s MacroCompiler consumes) and that text is returned in the mems_conf key; otherwise it is the empty string.

Parameters:
  • chirrtl_text – Contents of a .fir (CHIRRTL) file.

  • repl_seq_mem – Pass --repl-seq-mem --repl-seq-mem-file=... so seq-mems become external instances + a mems.conf sidecar.

  • extra_args – Additional CLI flags appended verbatim to the firtool command line (e.g. ("--disable-all-randomization",)).

  • timeout_seconds – subprocess timeout.

Returns:

Dict with keys hw_mlir (transformed MLIR text), mems_conf (empty if repl_seq_mem=False), stdout, stderr, returncode, and success.

Example:

out = firtool_lower_chirrtl_to_hw(open("Top.fir").read())
assert out["success"]; print(out["hw_mlir"][:200])
chia.chipyard.circt.circt_opt_run(mlir_text: str, pass_pipeline: str, extra_args: tuple[str, ...] = (), timeout_seconds: int = 600) dict[str, str][source]

Run circt-opt --pass-pipeline='<pipeline>' on MLIR text.

Thin wrapper that prefers /workspace/circt/build/bin/circt-opt (so custom passes linked via rebuild_circt_opt_with_custom_pass() are picked up) and falls back to /opt/circt-sdk/bin/circt-opt.

Parameters:
  • mlir_text – Input MLIR (any dialect circt-opt understands).

  • pass_pipeline – Pipeline string passed verbatim to --pass-pipeline (e.g. "builtin.module(hw.module(canonicalize))").

  • extra_args – Additional CLI flags appended after the pipeline.

  • timeout_seconds – subprocess timeout.

Returns:

Dict with keys stdout (transformed MLIR), stderr, returncode, and success.

Example:

out = circt_opt_run(hw_mlir, "builtin.module(canonicalize)")
print(out["stdout"])
chia.chipyard.circt.circt_opt_lower_hw_to_verilog(hw_mlir_text: str, extra_args: tuple[str, ...] = (), timeout_seconds: int = 600) dict[str, str][source]

Lower HW-dialect MLIR to SystemVerilog via firtool’s --ir-hw -> sv path.

Convenience wrapper that runs firtool with --format=mlir to consume HW MLIR and emit Verilog with the standard lowering options applied (mirrors what chipyard’s flow uses by default).

Parameters:
  • hw_mlir_text – HW-dialect MLIR (as produced by firtool_lower_chirrtl_to_hw()).

  • extra_args – Additional CLI flags appended verbatim.

  • timeout_seconds – subprocess timeout.

Returns:

Dict with keys verilog (emitted SV text on success, empty otherwise), stdout, stderr, returncode, success.

Example:

out = circt_opt_lower_hw_to_verilog(hw_mlir)
print(out["verilog"][:200])
chia.chipyard.circt.rebuild_circt_opt_with_custom_pass(pass_cpp_path: str, td_snippet_path: str | None = None, transforms_subdir: str = 'lib/Dialect/HW/Transforms', passes_td_path: str = 'include/circt/Dialect/HW/Passes.td', num_cpus: int = 16, timeout_seconds: int = 3600) dict[str, str][source]

Drop a user .cpp into the CIRCT source tree, patch Passes.td, rebuild circt-opt.

  1. Copy pass_cpp_path into /workspace/circt/<transforms_subdir>/.

  2. Append the filename to the matching CMakeLists.txt if not present.

  3. If td_snippet_path is given, splice it into Passes.td right before the closing #endif guard (idempotent).

  4. ninja -C /workspace/circt/build circt-opt (with -j ninja_jobs when nonzero, else ninja’s default).

Parameters:
  • pass_cpp_path – Absolute host path to the .cpp to inject.

  • td_snippet_path – Optional .td snippet to splice into Passes.td. If None, Passes.td is left untouched (useful when the pass already has its own .td definition).

  • transforms_subdir – Subdirectory under /workspace/circt/ where the .cpp should land (and its CMakeLists.txt lives). Defaults to the HW Transforms dir.

  • passes_td_path – Path under /workspace/circt/ to the Passes.td file to patch.

  • num_cpus-j value for ninja. Default 16 keeps headroom on a 32-core host. Pair with .options(num_cpus=N) at the call site if you also want Ray to reserve N CPUs per dispatch.

  • timeout_seconds – subprocess timeout for the ninja build.

Returns:

Dict with keys success ("True"/"False"), log (combined stdout/stderr from ninja), and binary_path (the rebuilt circt-opt location on success, empty otherwise).

Example:

r = rebuild_circt_opt_with_custom_pass("/work/passes/MyPass.cpp",
                                       "/work/my_pass_def.td")
print(r["success"], r["binary_path"])
chia.chipyard.circt.list_circt_passes(category: str | None = None, timeout_seconds: int = 60) list[str][source]

List available circt-opt passes, optionally filtered by dialect prefix.

Runs circt-opt --help and parses out lines beginning with -- that look like pass flags (single-token, no spaces, not a built-in option).

Parameters:
  • category – Optional pass-name prefix to filter by (e.g. "hw-", "firrtl-"). None returns every parsed pass.

  • timeout_seconds – subprocess timeout.

Returns:

Sorted list of pass names (without the leading --).

Example:

hw_passes = list_circt_passes(category="hw-")
print(hw_passes[:5])
chia.chipyard.circt.chisel_elaborate_to_chirrtl(chipyard_path: str, config: str, config_package: str = 'chipyard', num_cpus: int = 16, timeout_seconds: int = 1800) dict[str, str][source]

Elaborate a chipyard Chisel config and return its CHIRRTL .fir text.

Drives the chipyard make target that produces the .fir and .anno.json for a given CONFIG / CONFIG_PACKAGE pair, so the output is ready to pipe straight into firtool_lower_chirrtl_to_hw(). Runs in <chipyard>/sims/verilator (the canonical entry point that re-exports firrtl).

Parameters:
  • chipyard_path – Path to the chipyard installation.

  • config – Chisel config name (e.g. "RocketConfig").

  • config_package – Scala package holding the config (default "chipyard").

  • num_cpus-j for the make invocation. Default 16 keeps headroom on a 32-core host. Pair with .options(num_cpus=N) at the call site if you also want Ray to reserve N CPUs per dispatch.

  • timeout_seconds – subprocess timeout.

Returns:

Dict with keys fir_text (CHIRRTL contents on success, empty otherwise), anno_json (annotations JSON, empty otherwise), stdout, stderr, returncode, success.

Example:

r = chisel_elaborate_to_chirrtl("/scratch/chipyard", "RocketConfig")
print(r["fir_text"][:200])
chia.chipyard.circt.circt_ninja_build(targets: tuple[str, ...] = ('circt-opt',), num_cpus: int = 16, timeout_seconds: int = 1800) dict[source]

Build CIRCT targets with ninja -C /workspace/circt/build [-j N].

Generalises the build step of rebuild_circt_opt_with_custom_pass() to any target set (circt-opt, firtool, arcilator, …). Incremental: only the touched objects + the affected tools relink.

Runs ninja in its OWN process group (start_new_session) and SIGKILLs the whole group on timeout. Without this, a lingering child (clang/lld) that keeps the stdout pipe open wedges communicate() forever — even after ninja exits. Returns {success: bool, returncode: int, log_tail: str}.

chia.chipyard.circt.circt_warm_build(targets: tuple[str, ...] = ('circt-opt', 'firtool'), num_cpus: int = 16, timeout_seconds: int = 5400) dict[source]

Idempotent per-container warm-up: ensure lit is installed and targets are built, then drop a sentinel so repeat calls are no-ops.

The chia-circt image bakes only circt-opt; warming the other tool targets here is cheap (shared dialect libs are already built). Safe to call at the start of every task — only the first call on a given container does work.

Returns {success: bool, warmed: bool, log_tail: str} (warmed=False means the sentinel already existed).

chia.chipyard.circt.circt_run_lit(test_paths: tuple[str, ...], extra_args: tuple[str, ...] = (), timeout_seconds: int = 1800, filter_out: str = '') dict[source]

Run lit on build/test path(s) (relative to /workspace/circt/build).

Resolves the py_worker lit (installed by circt_warm_build()), falls back to PATH. FileCheck/not/count come from the SDK on PATH. Empty test_paths → success with zero tests (nothing to regress). filter_out is a regex passed to lit’s --filter-out to skip matching test names.

Returns {success: bool, passed: int, failed: int, failures: list[str], log_tail: str}.

class chia.chipyard.circt.BuildTool(name: str, num_cpus: int = 16, task_options=None)[source]

Bases: AsyncJobTool

MCP tool: rebuild CIRCT tool target(s) with ninja, ASYNCHRONOUSLY.

Initializes ChiaTool with a name and optional resource requirements.

build(targets: list[str] | None = None) dict[source]

Start a ninja build of CIRCT target(s) in the BACKGROUND and return IMMEDIATELY (does NOT wait). Then poll <name>_build_status until it returns done=true to get {success, returncode, log_tail}.

Parameters:

targets – e.g. [“circt-opt”] (default) or [“firtool”].

build_status(wait_seconds: int = 60) dict[source]

Await the in-flight build (blocks up to wait_seconds, capped at 120). Returns done=true with {success, returncode, log_tail} once finished.

class chia.chipyard.circt.LitTool(name: str, task_options=None)[source]

Bases: AsyncJobTool

MCP tool: run lit regression tests, ASYNCHRONOUSLY (same rationale as build — a whole-dialect lit run can take minutes).

Initializes ChiaTool with a name and optional resource requirements.

run_lit(test_paths: list[str]) dict[source]

Start a lit run on build/test path(s) (e.g. [“test/Dialect/Comb”]) in the BACKGROUND and return IMMEDIATELY. Then poll <name>_lit_status until it returns done=true to get {success, passed, failed, failures, log_tail}.

lit_status(wait_seconds: int = 60) dict[source]

Await the in-flight lit run (blocks up to wait_seconds, capped at 120). Returns done=true with the parsed lit result once finished.

Macro compiler

Chipyard MacroCompiler glue for SRAMs.

Parses the Chipyard/firtool .top.mems.conf into SRAMSpecs, generates the MacroCompiler MDF JSON library describing each macro, and runs Chipyard’s tapeout.jar MacroCompiler to remap the synflop SRAMs onto those macros.

class chia.chipyard.macrocompiler.SRAMSpec(name: str, depth: int, width: int, ports: str, mask_gran: int | None, num_rw_ports: int = 0, num_read_ports: int = 0, num_write_ports: int = 0, parsed_ports: list[tuple[str, bool]]=<factory>)[source]

Bases: object

chia.chipyard.macrocompiler.rename_ports(ports_str: str) tuple[list[tuple[str, bool]], int, int, int][source]

Parse a comma-separated port string into named ports with counts.

Mirrors Chipyard ConfReader.renamePorts(). Each token becomes a (prefix, masked) tuple with incrementing per-type counters.

Example: “write,write,read” -> ([(“W0”, False), (“W1”, False), (“R0”, False)], 1, 2, 0)

chia.chipyard.macrocompiler.parse_mems_conf(content: str) list[SRAMSpec][source]

Parse a .top.mems.conf file into a list of SRAMSpec.

chia.chipyard.macrocompiler.generate_macrocompiler_lib(sram_specs: list[SRAMSpec], cell_prefix: str = 'mapped_') str[source]

Generate MDF JSON library for MacroCompiler from SRAM specs.

Each SRAM gets a library entry named <cell_prefix><name> with exact-match depth/width/ports/mask_gran so MacroCompiler maps 1:1 without splitting.

chia.chipyard.macrocompiler.remap_with_macrocompiler(mems_conf_content: str, macrocompiler_lib_json: str, chipyard_path: str) str | None[source]

Run MacroCompiler to remap synflop SRAMs to library macros.

Runs on a chipyard node where Java + tapeout.jar are available. This is the only function in this module that touches a Chipyard resource (it shells out to java -cp <chipyard>/.classpath_cache/tapeout.jar tapeout.macros.MacroCompiler), so it is the only one decorated with @ChiaFunction(resources={"chipyard": 1}). The generators above (parse/lib/stub/assemble) are pure Python and stay plain callables.

Parameters:
  • mems_conf_content – Contents of .top.mems.conf

  • macrocompiler_lib_json – MDF JSON library with SRAM entries

  • chipyard_path – Path to chipyard installation (for tapeout.jar)

Returns:

Remapped .top.mems.v content, or None on failure.

chia.chipyard.macrocompiler.assemble_generated_src_with_macros(generated_src_files: list[tuple[str, str]], remapped_mems_v: str, macro_stubs: list[tuple[str, str]]) list[tuple[str, str]][source]

Swap in the MacroCompiler-remapped .top.mems.v and add macro stubs.

Library-agnostic: works for any MacroCompiler remap output (CACTI, SRAM22, etc.), since it only matches on module names, not the macro contents.

Parameters:
  • generated_src_files – Original generated_src from build.

  • remapped_mems_v – MacroCompiler output instantiating the library macros.

  • macro_stubs – List of (filename, content) blackbox stub modules for the mapped macros.

Returns:

Modified generated_src with the remapped .top.mems.v swapped in, any gen-collateral .sv files that redefine the remapped modules removed, and the macro stubs appended. The .top.mems.conf is left untouched.

chia.chipyard.macrocompiler.generate_macro_stubs(sram_specs: list[SRAMSpec], cell_prefix: str = 'mapped_') list[tuple[str, str]][source]

Generate blackbox Verilog stubs for mapped SRAM macros.

Each stub declares the port interface matching the MacroCompiler instantiation (and the Liberty cell) with no body. Library-agnostic: the cell_prefix selects the macro family (e.g. "cacti_", "sram22_").

Chipyard / Hammer

chia.chipyard.chipyard_hammer — Chipyard VLSI (hammer) makefile nodes.

Chipyard wraps hammer-vlsi behind make in <chipyard>/vlsi: the buildfile target elaborates the design and generates $(OBJ_DIR)/ hammer.d, a make fragment that is -include``d to provide the flow targets (``syn, par, drc, lvs, power, redo-<action>, …). Everything is parameterized by make variables — CONFIG, tech_name, TOOLS_CONF / TECH_CONF / INPUT_CONFS, VLSI_TOP, OBJ_DIR, HAMMER_EXTRA_ARGS, … — so one generic target runner covers the whole flow. ChipyardHammerNode.make() is that runner.

The chipyard checkout, its generated RTL, and the OBJ_DIR are PATH-BASED on the worker, so chained targets (buildfile -> syn -> par) and report fetches (ChipyardHammerNode.collect()) must land on the SAME worker. ChipyardHammerNode enforces that via a placement group (see chia.base.colocated.ColocatedNode for the given / reserved / no-PG construction modes). ChipyardHammerNode.<fn>.chia_remote(...) (the class attribute) is the raw, unpinned form for callers that handle placement themselves.

Like chia.chipyard.chisel_build_node, this module assumes the worker’s environment is already chipyard-ready (the chipyard docker images source the env in their setup commands); use the env argument for per-call overrides.

This module is deliberately independent of chia.vlsi.hammer, which wraps bare hammer-vlsi CLI calls: here hammer is an implementation detail behind chipyard’s Makefile.

class chia.chipyard.chipyard_hammer.ChipyardHammerResult(success: bool, returncode: int, target: str, vlsi_dir: str, obj_dir: str | None, stdout: str, stderr: str, listing: dict[str, int]=<factory>)[source]

Bases: object

class chia.chipyard.chipyard_hammer.ChipyardHammerCollectResult(base_dir: str, files: dict[str, str], skipped: dict[str, int], listing: dict[str, int])[source]

Bases: object

class chia.chipyard.chipyard_hammer.ChipyardHammerNode(placement_group=None, require_colocated: bool = True, *, bundle_index: int = 0, reserve_bundle: dict | None = None, pg_strategy: str = 'STRICT_PACK', wait_for_pg: bool = True, pg_ready_timeout_s: float | None = None)[source]

Bases: ColocatedNode

Chipyard VLSI make / collect primitives sharing one placement.

The members are @staticmethod @ChiaFunction(resources={"chipyard": 1}); __init__ re-binds each into a per-instance pinned form so node.<fn>.chia_remote(...) lands on this node’s bundle:

with ChipyardHammerNode() as node:   # reserves {"CPU": 1, "chipyard": 1}
    obj_dir = "/scratch/vlsi-build/run1"
    bf = get(node.make.chia_remote(
        "/home/ray/chipyard", "buildfile", config="RocketConfig",
        obj_dir=obj_dir, make_vars={"tech_name": "sky130"}))
    syn = get(node.make.chia_remote(
        "/home/ray/chipyard", "syn", config="RocketConfig",
        obj_dir=obj_dir, make_vars={"tech_name": "sky130"}))
    rpts = get(node.collect.chia_remote(
        obj_dir, ["syn-rundir/reports/**"]))   # same worker, guaranteed

Set up placement and bind the member functions.

Parameters:
  • placement_group – an existing Ray PlacementGroup to schedule onto. If given, require_colocated is moot (placement is already fixed) and this node will not remove the PG on close.

  • require_colocated – when no PG is given, reserve one so all members co-locate. When False, leave placement to the caller.

  • bundle_index – which bundle of the (given or reserved) PG to pin to.

  • reserve_bundle – resource shape of a self-reserved bundle (default _DEFAULT_BUNDLE). A bundle too small for some members is allowed — those members just can’t dispatch through this node (a construction-time warning lists them).

  • pg_strategy – placement strategy for a self-reserved PG.

  • wait_for_pg – block on pg.ready() for a self-reserved PG so the node is usable immediately.

  • pg_ready_timeout_s – optional timeout for that wait.

static make(chipyard_path: str, target: str, config: str | None = None, obj_dir: str | None = None, make_vars: dict[str, str] | None = None, jobs: int = 1, env: dict[str, str] | None = None, timeout_seconds: int = 86400) ChipyardHammerResult[source]

Run one make -C <chipyard>/vlsi <target> on a worker.

Parameters:
  • chipyard_path – Chipyard checkout root on the worker.

  • target – Any vlsi Makefile target: “buildfile”, “syn”, “par”, “drc”, “lvs”, “power”, “redo-syn”, “clean”, … (the flow targets exist after “buildfile” has generated hammer.d).

  • config – Chipyard CONFIG (e.g. “RocketConfig”). Convenience for make_vars={"CONFIG": ...}.

  • obj_dir – Hammer build directory, passed as OBJ_DIR= and used for listing. When None, chipyard derives its default (vlsi/build/<long_name>-<TOP>) and listing is empty. Pass the same value across buildfile/syn/par calls.

  • make_vars – Any other vlsi Makefile variables, e.g. {"tech_name": "sky130", "VLSI_TOP": "ChipTop", "INPUT_CONFS": "a.yml b.yml", "HAMMER_EXTRA_ARGS": "-p x.yml"}. Appended last, so they win over config/obj_dir.

  • jobs – make -j level (elaboration in “buildfile” benefits; the hammer flow targets manage their own parallelism).

  • env – Extra environment variables layered over the worker’s (assumed chipyard-ready) environment.

  • timeout_seconds – Wall-clock limit for the subprocess.

static collect(base_dir: str, patterns: list[str], max_bytes_per_file: int | None = None) ChipyardHammerCollectResult[source]

Fetch text files from a previous make’s OBJ_DIR (or any directory) on this worker.

Dispatch via the pinned instance member (node.collect.chia_remote) so it lands on the worker that owns the files — an unpinned call may not.

Parameters:
  • base_dir – Directory a previous target ran in (typically the obj_dir passed to make()).

  • patterns – Globs relative to base_dir (** is recursive), e.g. ["syn-rundir/reports/**", "*.log"]. Files matched by multiple patterns appear once.

  • max_bytes_per_file – When set, files over this size are recorded in skipped instead of shipped through the object store — protects against a glob accidentally matching a netlist. None (and 0, the falsy edge) means no cap: everything matched is shipped.

RISC-V build

Cross-compile a C/asm source into a RISC-V ELF.

Environment this node needs:
  • riscv64-unknown-elf-* baremetal toolchain on PATH (target=verilator).

  • riscv64-unknown-linux-gnu-* Linux toolchain on PATH (target=linux).

  • The harness Makefile at /opt/riscv-harness/Makefile plus its include/ headers (rocc.h, mmio.h, marchid.h).

All three are provisioned by the chia-riscv-cross Docker image (dockerfiles/RiscvCrossDockerfile).

Where it sits in the pipeline:

Source bytes gets passed into RiscvBuildNode.build(target=”verilator” | “linux”), which calls make -f /opt/riscv-harness/Makefile …

RiscvBuildNode.build returns RiscvBuildArtifact (binary_content + target + success + std{out,err} + rc)

class chia.chipyard.riscv_build_node.RiscvBuildNode(timeout_seconds: int = 300, logging_level: int = 10)[source]

Bases: object

Cross-compiles a C/asm source into a RISC-V ELF via the harness Makefile.

Each build() writes its source into an isolated per-call task dir and shells out to the baked-in harness Makefile. Runs inside the chia-riscv-cross image on workers tagged with the riscv_build resource (see module docstring for the toolchain/Makefile it depends on).

Parameters:
  • timeout_seconds – Wall-clock limit applied to each make invocation in build(). On expiry the build returns returncode=-1 (never raises); defaults to 300s.

  • logging_level – Python logging level for this node’s logger.

build(source_content: bytes, program_name: str, work_dir: str, target: Literal['verilator', 'linux'] = 'verilator', extra_cflags: str = '', extra_ldflags: str = '', include_dump: bool = False, cleanup_task_dir: bool = True, lang: Literal['c', 'asm'] = 'c') RiscvBuildArtifact[source]

Cross-compile source_content into a RISC-V ELF.

Parameters:
  • source_content – Raw bytes of the source file to compile.

  • program_name – Base name of the program. Names the source file (<program_name>.c / .S), the PROGRAM= Make variable, and the output binary.

  • work_dir – Base directory; a uuid-namespaced task subdir is created under it so concurrent builds on one worker don’t collide.

  • target"verilator" for a baremetal ELF (output <program_name>.riscv) or "linux" for a userspace ELF (output <program_name>). Selects the toolchain prefix.

  • extra_cflags – Forwarded verbatim as EXTRA_CFLAGS= to the harness Makefile (e.g. "-march=rv64gc_zba_zbb" for extension ISAs).

  • extra_ldflags – Forwarded verbatim as EXTRA_LDFLAGS=.

  • include_dump – If True, also run the Makefile’s dump target and read the objdump -D output back into the artifact’s dump.

  • cleanup_task_dir – If True (default), remove the task dir after the build (and after reading back the binary/dump).

  • lang"c" writes <program_name>.c; "asm" writes <program_name>.S (preprocessed assembly). Both compile via the same Makefile rules.

Returns:

Carries the compiled ELF bytes, output binary_name, target, and (if include_dump) the disassembly. On compile failure/timeout, success=False with empty binary_content and the captured stdout/stderr/returncode.

Return type:

RiscvBuildArtifact

Raises:

ValueError – If target or lang is not a recognized value.

RISC-V objdump

Disassemble a RISC-V ELF with objdump.

Environment this node needs:

  • riscv64-unknown-elf-objdump on PATH (target=verilator).

  • riscv64-unknown-linux-gnu-objdump on PATH (target=linux).

Both are provisioned by the chia-riscv-cross Docker image (dockerfiles/RiscvCrossDockerfile).

Where it sits in the pipeline:

Binary bytes (from RiscvBuildNode, S3, or anywhere else) get passed into RiscvObjdumpNode.dump(target="verilator" | "linux"), which
shells out to `<TOOL_PREFIX>objdump <flags> <binary>`.

RiscvObjdumpNode.dump returns RiscvObjdumpArtifact (dump + target + success + std{out,err} + rc)

This is the standalone counterpart to RiscvBuildNode.build(include_dump=True): use the build flag when you’re compiling and want both outputs in one step, use this node when you already have an ELF and just want its disassembly.

class chia.chipyard.riscv_objdump_node.RiscvObjdumpNode(timeout_seconds: int = 120, logging_level: int = 10)[source]

Bases: object

Disassembles a RISC-V ELF with objdump.`

Parameters:
  • timeout_seconds – Wall-clock limit applied to each objdump invocation in dump(). On expiry the dump returns returncode=-1 (never raises); defaults to 120s.

  • logging_level – Python logging level for this node’s logger.

dump(binary_content: bytes, binary_name: str, work_dir: str, target: Literal['verilator', 'linux'] = 'verilator', objdump_flags: str = '-D', cleanup_task_dir: bool = True) RiscvObjdumpArtifact[source]

Disassemble binary_content with <TOOL_PREFIX>objdump.

Parameters:
  • binary_content – Raw bytes of the RISC-V ELF to disassemble.

  • binary_name – Filename to give the ELF on disk (echoed into the returned artifact for traceability).

  • work_dir – Base directory; a uuid-namespaced task subdir is created under it so concurrent runs on one worker don’t collide.

  • target"verilator" selects the riscv64-unknown-elf- prefix (baremetal ELF); "linux" selects riscv64-unknown-linux-gnu- (userspace ELF).

  • objdump_flags – Flags forwarded verbatim to objdump (split on whitespace); defaults to "-D" (disassemble all sections).

  • cleanup_task_dir – If True (default), remove the task dir after the disassembly is captured.

Returns:

Carries the disassembly (dump), the echoed binary_name and target, and stdout/stderr/returncode. success=False (with empty dump) on failure or timeout.

Return type:

RiscvObjdumpArtifact

Raises:

ValueError – If target is not a recognized value.

RISC-V DV generation

Generate random RISC-V test ELFs with riscv-dv (run.py –steps gen,gcc_compile: generate assembly, then link with the riscv64-unknown-elf toolchain in chia-riscv-dv).

Backends (the simulator arg): pyflow is free (no license) but covers only the base ISA plus partial/draft bitmanip; xlm/vcs/questa run the full SV flow (bitmanip/vector/crypto) and each need their CAD tool plus a FlexLM seat, sourced from cad_setup.

class chia.chipyard.riscv_dv_gen_node.GenSpec(test: str, iterations: int = 1, instr_cnt: int | None = None, plusargs: dict[str, object]=<factory>, gen_timeout: int | None = None, seed: int | None = None, extra_args: tuple[str, ...]=())[source]

Bases: object

One riscv-dv test to generate: a testlist.yaml entry name plus optional per-run overrides. instr_cnt and plusargs are appended as –sim_opts, overriding the entry’s gen_opts without editing the yaml; extra_args is raw run.py CLI for anything not modelled here. A None plusarg value is a bare flag (+foo).

test

Name of the testlist.yaml entry to generate (the instruction mix, e.g. "riscv_arithmetic_basic_test", "riscv_b_ext_test"). Passed as --test.

Type:

str

iterations

Number of test programs to generate (--iterations).

Type:

int

instr_cnt

Optional override for the instruction count per program; emitted via --sim_opts +instr_cnt=<n> when set.

Type:

int | None

plusargs

Extra generator plusargs emitted via --sim_opts. {k: v} becomes +k=v; a None value becomes a bare +k.

Type:

dict[str, object]

gen_timeout

Optional per-generation timeout forwarded as --gen_timeout to run.py.

Type:

int | None

seed

Optional fixed RNG seed (--seed) for reproducible generation; None lets riscv-dv pick.

Type:

int | None

extra_args

Raw additional run.py CLI tokens, appended verbatim, for flags not modelled here.

Type:

tuple[str, …]

sim_opts() str[source]

Render instr_cnt + plusargs into a --sim_opts string.

Returns:

A space-joined string of +key[=value] tokens (empty if neither instr_cnt nor plusargs is set).

class chia.chipyard.riscv_dv_gen_node.RiscvDvGenNode(riscv_dv_dir: str = '/home/ray/riscv-dv', simulator: str = 'pyflow', target: str | None = None, custom_target: str | None = None, testlist: str | None = None, isa: str | None = None, mabi: str | None = None, user_extension_dir: str | None = None, custom_instr_dir: str | None = None, cad_setup: str = '/ecad/tools/vlsi.bashrc', timeout_seconds: int = 900, logging_level: int = 10)[source]

Bases: object

Generates random RISC-V test ELFs with riscv-dv as cosim stimulus.

Thin pass-through to riscv-dv’s run.py: each flag is forwarded only when set. Use GenSpec.extra_args for any flag we don’t surface.

Configs are presented as filepaths that are expected to exist in the node’s environment:

custom_target: your core config (dir holding riscv_core_setting.sv)

testlist: your test catalog (a testlist.yaml)

user_extension_dir: your custom generator .sv (a riscv-dv user_extension/ layout); referenced by class name from the testlist and compiled in during gen

custom_instr_dir: your custom-instruction .sv (an isa/custom/ layout: riscv_instr_name_t enum entries + instr classes), overlaid into the generator’s src/isa/custom/ so they generate. Defaults to <custom_target>/isa/custom/. (NOT a run.py flag — the enum is sealed before the include hooks, so it must land in src/; see _install_custom_instrs.)

The rest map 1:1 to run.py flags: simulator (pyflow=free, xlm/vcs/questa= CAD+FlexLM), target (a built-in core-config name), isa, mabi.

Parameters:
  • riscv_dv_dir – Path to the riscv-dv checkout containing run.py (defaults to the location inside the chia-riscv-dv image).

  • simulator – riscv-dv backend / --simulator: "pyflow" (no license; base ISA + partial bitmanip) or "xlm"/"vcs"/ "questa" (SV flow; full bitmanip/vector/crypto, needs the CAD tool + a FlexLM seat sourced from cad_setup).

  • target – Built-in core-config name (--target); None to omit.

  • custom_target – Path to a directory holding your riscv_core_setting.sv (--custom_target). Shipped to the worker via the Ray working dir. Takes precedence over target.

  • testlist – Path to a custom testlist.yaml (--testlist); overrides the target dir’s default test catalog.

  • isa – Target ISA string (--isa, e.g. "rv64gc"); None omits.

  • mabi – Target ABI string (--mabi, e.g. "lp64d"); None omits.

  • user_extension_dir – Path to a riscv-dv user_extension/ layout with your custom generator .sv (--user_extension_dir), referenced by class name from the testlist.

  • custom_instr_dir – Path to an isa/custom/ layout (riscv_instr_name_t enum entries + instr classes) overlaid into the generator’s src/isa/custom/ before compile so the instructions generate. Defaults to <custom_target>/isa/custom/. NOT a run.py flag — the enum is sealed before the include hooks, so it must land in src/ (see _install_custom_instrs()).

  • cad_setup – Path to the bashrc sourced before SV-flow runs to put the CAD tool + FlexLM license on PATH (ignored for pyflow).

  • timeout_seconds – Wall-clock limit per run.py invocation; on expiry the process group is killed (never raises).

  • logging_level – Python logging level for this node’s logger.

compile_generator(build_dir: str, test: str) str[source]

Compile the generator testbench once into build_dir (riscv-dv -co), so later generate(sim_only=True) runs skip the testbench recompile and just simulate against it. test is any entry in the active testlist. Returns build_dir, to pass to generate() as build_dir. Multiple generate(sim_only=True) runs can reuse one build concurrently.

Parameters:
  • build_dir – Directory to compile the generator testbench into (--output with -co); created if absent. This same path is later passed to generate() as build_dir.

  • test – Any entry in the active testlist. run.py needs one to load the list, but the -co build itself is test-independent.

Returns:

The build_dir path, ready to hand to generate(sim_only=True).

generate(spec: GenSpec, work_dir: str, cleanup_task_dir: bool = True, sim_only: bool = False, build_dir: str | None = None) list[tuple[str, bytes, str]][source]

Generate + compile spec and return [(name, elf_bytes, asm_text)] for every ELF produced. Never raises: on failure it returns the (possibly empty) list found.

sim_only=True skips the testbench compile (riscv-dv -so) and reuses the build from a prior compile_generator(), passed as build_dir. Multiple sim_only gens can share one build_dir concurrently without colliding.

Parameters:
  • spec – The GenSpec describing the test, iteration count, and any per-run overrides to generate.

  • work_dir – Base directory; a uuid-namespaced task subdir is created under it per call for isolation.

  • cleanup_task_dir – If True (default), remove the task dir after collecting ELFs (unlinks any symlinks; the shared build is left intact).

  • sim_only – If True, skip the testbench compile (-so) and reuse a prebuilt generator from build_dir. Requires build_dir.

  • build_dir – Path returned by compile_generator(); symlinked read-only into the task dir when sim_only=True. Must be local to this worker.

Returns:

A list of (name, elf_bytes, asm_text) tuples — one per ELF riscv-dv produced (the sibling .S source, or "" if absent). Never raises: on failure returns the (possibly empty) list found.

Raises:

ValueError – If sim_only=True but no build_dir was provided.

Torture

Run RISC-V Torture against a compiled Chipyard/BOOM RTL simulator and diff the Spike vs RTL architectural signatures.

class chia.chipyard.torture_run_node.TortureRunNode(chipyard_path: str, sbt_override: str = 'java -Djava.security.manager=allow -Xmx2G -Xss8M -jar sbt-launch.jar', timeout_seconds: int = 1800, logging_level: int = 10)[source]

Bases: object

Runs RISC-V Torture against a compiled Chipyard/BOOM RTL simulator.

Torture randomly generates RISC-V assembly tests, runs each on both Spike (the ISA reference model) and the RTL simulator under test (the DUT), and diffs their architectural signatures. This node drives the make flow in <chipyard_path>/tools/torture: it writes the simulator binary from a BuildArtifact to disk, passes it as the Torture R_SIM, invokes the appropriate target for the requested TortureMode, and collects the generated test, disassembly, and Spike/RTL signatures for each run.

Because Torture writes into a shared tools/torture/output directory, concurrent runs on the same checkout are serialized with a file lock.

Configure a Torture runner against a Chipyard checkout.

Parameters:
  • chipyard_path – Absolute path to the Chipyard checkout on the build node. Torture is driven out of <chipyard_path>/tools/torture (with its shared output/ subdirectory). Path for the CHIA chipyard container is /home/ray/chipyard

  • sbt_override – The SBT= command handed to make, overriding the Makefile’s default launcher.

  • timeout_seconds – Wall-clock timeout for the make subprocess (default 30 min). For TortureMode.OVERNIGHT the effective timeout is raised to at least overnight_minutes * 60 + 600 so the make process outlives the overnight loop.

  • logging_level – Logging level for this node’s logger.

torture(artifact: BuildArtifact, mode: TortureMode = TortureMode.SINGLE, work_dir: str = '/tmp/chia-torture', torture_config_file: str | None = None, overnight_minutes: int = 30, overnight_max_failures: int = 1, replay_test_s: str | None = None) TortureResult[source]

Run Torture against a pre-built simulator and collect the results.

The simulator binary from artifact is written to a per-run task directory under work_dir and passed to Torture as R_SIM. The make target invoked depends on mode:

  • TortureMode.SINGLEmake rgentest — generate one test, run it on the DUT and Spike, and diff signatures.

  • TortureMode.OVERNIGHTmake rnight — loop generating and running tests until overnight_max_failures failures accumulate or overnight_minutes elapse; failing tests are saved under failedtests/.

  • TortureMode.REPLAYmake rtest — run a caller-supplied assembly test (replay_test_s) instead of generating one.

If artifact.success is False the run is skipped and an unsuccessful TortureResult is returned immediately. Runs are serialized on a per-checkout file lock.

Parameters:
  • artifact – Compiled RTL simulator to test, from a ChiselBuildNode build. Its ELF bytes become the Torture R_SIM (the DUT); Spike is the implicit reference model.

  • mode – Which Torture flow to run — see TortureMode.

  • work_dir – Base directory under which a fresh per-run task directory (random 8-hex name) is created to hold the simulator binary and collected artifacts.

  • torture_config_file – Optional Torture generator config, passed as -C <file> (Torture’s --config). Controls the generated instruction mix / sequences. None uses Torture’s default.

  • overnight_minutes – OVERNIGHT only — how long the generate-and-test loop runs, passed as -m <minutes>. Also extends the make subprocess timeout. Ignored in other modes.

  • overnight_max_failures – OVERNIGHT only — stop after this many failing tests, passed as Torture’s -t <count> threshold. Ignored in other modes.

  • replay_test_s – REPLAY only — the assembly source to replay. Written to replay.S and passed as TEST= (Torture’s -a). Required for REPLAY; raises ValueError if missing.

Returns:

A TortureResult with overall success, the test/failure counts, per-test artifacts (TortureTestRun), and the raw make stdout/stderr/returncode. build_artifact is left None here; torture_from_config() populates it.

Verilator run

class chia.chipyard.verilator_run_node.VerilatorRunNode(logging_level: int = 10)[source]

Bases: object

Runs one test ELF on a prebuilt chipyard Verilator simulator.

Construct a run node.

Parameters:

logging_level – Python logging level for this node’s logger. The node is otherwise stateless at construction time; per-run state (task dir, binary path) is created in _setup when run is invoked.

run(artifact: BuildArtifact, test_binary_content: bytes, test_binary_name: str, work_dir: str, plusargs: dict = {}, timeout_cycles: int | None = None, timeout_seconds: int | None = None, dramsim_ini_files: dict[str, bytes] = {}, capture_waveform: bool = False, verbose: bool = True, cleanup_task_dir: bool = True, numactl: bool = False, wave_windows: list[WaveWindow] = (), dump_all_waveform: bool = False, upload_to_s3: bool = False, s3_path: str = '', aws_access_key_id: str = '', aws_secret_access_key: str = '', aws_session_token: str = '', aws_region: str = '') RunResult[source]

Run one test ELF on the prebuilt Chipyard Verilator simulator.

Writes the simulator and test binaries into an isolated per-task directory, assembles the simulator’s +plusarg command line, executes it (piping the committed-instruction stderr through spike-dasm), and returns the captured output. By default, runs on nodes tagged with the verilator_run resource.

Parameters:
  • artifact – The BuildArtifact produced by ChiselBuildNode.build(). Supplies the simulator ELF bytes and its name; the binary is materialized into the task dir and marked executable.

  • test_binary_content – Raw bytes of the RISC-V test ELF to run (the program the simulator loads over the front-end server / HTIF).

  • test_binary_name – Filename to give that ELF on disk; its stem also names the .log and .out output files.

  • work_dir – Base working directory. A unique 8-hex-char subdirectory is created under it per run so concurrent runs sharing the same container/work_dir don’t collide.

  • plusargs – Extra simulator +plusargs as a dict. Each entry is emitted as +key when the value is falsy, else +key=value (e.g. {"+loadmem": path} or {"+verbose": ""}).

  • timeout_cycles – Simulated-cycle budget; passed as +max-cycles=<n>. The simulator self-terminates when reached. None omits the plusarg (no cycle limit).

  • timeout_seconds – Wall-clock limit. On expiry the simulator process is killed and whatever was captured so far is returned.

  • dramsim_ini_files – DRAMSim2 model config as {filename: bytes}. When non-empty they’re written to a dramsim_ini dir and the sim is launched with +dramsim +dramsim_ini_dir=<dir> to use the cycle-accurate DRAM model instead of the simple memory.

  • capture_waveform – If True, emit a VCD via +vcdfile=<task>/<stem>.vcd. Requires the simulator to have been built with target=VERILATOR_DEBUG. Auto-enabled if wave_windows or dump_all_waveform is set.

  • verbose – If True, append +verbose (commit-log / verbose sim output).

  • cleanup_task_dir – If True (default), delete the per-task directory after the run (and after any S3 upload) to bound disk usage.

  • numactl – If True, prefix the simulator argv with the platform’s numactl binding (from get_numa_prefix()) to pin it to a NUMA node.

  • wave_windows – chia_artifact-specific temporal waveform filter — a list of WaveWindow PC-triggered dump windows. Each is emitted as +wf_pc_<i>=<hex> +wf_n_<i> +wf_cyc_<i>: dump for cyc testbench cycles starting at the n-th retired commit of pc. At most _MAX_WAVE_WINDOWS (64); each is validated for pc>0, n>=1, cyc>0.

  • dump_all_waveform – If True, append +wf_dump_all=1 to bypass the window filter and dump the entire run (combine with wf_scopes at build time to still bound it spatially).

  • upload_to_s3 – If True (and s3_path is set), upload the produced .vcd (if any), .out and .log to S3 before the task dir is cleaned up. A missing VCD is a soft skip.

  • s3_path – Destination s3://bucket/prefix for uploads. Files land under <s3_path>/<basename>. Required when upload_to_s3=True.

  • aws_access_key_id – Explicit AWS access key for the upload. If set, aws_secret_access_key must also be set; otherwise boto3’s default credential chain (env vars / profile / instance role) is used.

  • aws_secret_access_key – Explicit AWS secret key (see above).

  • aws_session_token – Optional session token for temporary (STS) credentials; only used when explicit keys are given.

  • aws_region – Optional AWS region name for the S3 client.

Returns:

Captured log (simulator stdout) and out (spike-dasm disassembly of stderr), the process returncode/success, any S3 URIs for uploaded artifacts, and an echo of the configured wave_windows.

Return type:

RunResult

run_metasim(artifact: BuildArtifact, test_binary_content: bytes, test_binary_name: str, work_dir: str, fesvr_step_size: int = 128, plusargs: dict = {}, timeout_cycles: int | None = None, timeout_seconds: int | None = None, verbose: bool = True, cleanup_task_dir: bool = True, numactl: bool = False) RunResult[source]

Run a FireSim metasim (VFireSim) binary.

Unlike run, this method:

  • omits +loadmem, +dramsim, and +dramsim_ini_dir (metasim uses FASED memory modeling)

  • omits waveform capture (metasim uses +waveformfile with a -debug build variant, not +vcdfile)

  • always passes +fesvr-step-size (required for metasim)

Spike cosim

Spike<->Verilator lockstep co-simulation of one ELF via chipyard’s Cospike.

Spike is compiled into the simulator (WithCospike + WithTraceIO) and checks every committed instruction in-process; the run aborts at the first architectural divergence. The embedded spike takes its ISA from the DUT’s isaDTS, so this node needs no isa argument. Cosim requires a zero-initialized DUT (a RANDOM=0 build predefine) so unspecified reset state matches spike’s zeros; Cospike forwards the legitimately non-deterministic reads (counters, IDs, LR/SC, device loads).

On a mismatch the run is repeated with +verbose to capture the interleaved DUT/spike commit logs around the abort (the ctx-line debug window). Composes VerilatorRunNode for the simulation, adding the cospike plusargs, divergence parsing, and the verbose re-run.