VLSI

API reference for chia.vlsi. These pages are generated from the docstrings in the source, so they stay in sync with the code.

Hammer

chia.vlsi.hammer — Hammer-vlsi nodes.

HammerNode.run() wraps one hammer-vlsi CLI call. Hammer’s CLI is uniform across actions (syn, par, drc, lvs, sim, power, and the -to- bridge actions): configs in via repeated -p, an --obj_dir for build output, an -o output config that feeds the next action, and the action name. One node therefore covers the whole flow, with the action as a parameter.

obj_dir is PATH-BASED: it lives on the worker that ran the action, so chained actions (syn -> syn-to-par -> par) and report fetches (HammerNode.collect()) must land on the SAME worker. HammerNode enforces that via a placement group (see chia.base.colocated .ColocatedNode for the given / reserved / no-PG construction modes). HammerNode.<fn>.chia_remote(...) (the class attribute) is the raw, unpinned form for callers that handle placement themselves.

This module knows nothing about technologies, tools, or sites — all of that arrives via the project’s configs.

class chia.vlsi.hammer.HammerResult(success: bool, returncode: int, action: str, obj_dir: str, stdout: str, stderr: str, output: dict = <factory>, listing: dict[str, int]=<factory>)[source]

Bases: object

class chia.vlsi.hammer.HammerCollectResult(obj_dir: str, files: dict[str, str], skipped: dict[str, int], listing: dict[str, int])[source]

Bases: object

class chia.vlsi.hammer.HammerMatchResult(obj_dir: str, matches: list[tuple[str, int]], skipped: dict[str, int])[source]

Bases: object

class chia.vlsi.hammer.HammerCollectFsResult(obj_dir: str, dest_dir: str, copied: dict[str, int], skipped: dict[str, int])[source]

Bases: object

class chia.vlsi.hammer.HammerNode(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

Hammer run / collect primitives sharing one placement.

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

with HammerNode() as node:    # reserves a {"CPU": 1, "hammer": 1} PG
    syn = get(node.run.chia_remote(
        "syn", configs=[...], obj_dir="/scratch/build/run1"))
    rpts = get(node.collect.chia_remote(
        syn.obj_dir, ["syn-rundir/reports/**"]))
    par = get(node.run.chia_remote("syn-to-par", ...))  # same worker

collect requires the default bundle’s hammer slot, so a collect dispatched while a run executes on this bundle waits for it in the default case — it cannot read half-written reports.

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 run(action: str, configs: list[str] | None = None, config_contents: dict[str, str] | None = None, obj_dir: str = 'build', extra_args: list[str] | None = None, hammer_bin: str = 'hammer-vlsi', timeout_seconds: int = 86400) HammerResult[source]

Run one hammer-vlsi action on a worker.

Parameters:
  • action – Any action hammer-vlsi accepts: “syn”, “par”, “syn-to-par”, …

  • configs – Paths to config YAML/JSON files that exist on the worker (baked into the image or mounted), passed as -p in order (later files override earlier ones).

  • config_contents – filename -> YAML/JSON text, written into obj_dir/configs/ on the worker and appended as -p after configs. This is how a flow ships configs (or a previous action’s output) by value to a remote worker.

  • obj_dir – Hammer build directory on the worker.

  • extra_args – Extra CLI args, inserted before the action.

  • hammer_bin – The hammer executable, or a custom CLIDriver script.

  • timeout_seconds – Wall-clock limit for the subprocess.

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

Fetch text files from a previous action’s obj_dir on this worker.

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

Parameters:
  • obj_dir – The build directory a previous action ran in.

  • patterns – Globs relative to obj_dir (** is recursive), e.g. ["syn-rundir/reports/**", "syn-rundir/*.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.

static list_matches(obj_dir: str, patterns: list[str], max_bytes_per_file: int | None = None) HammerMatchResult[source]

Resolve patterns against obj_dir on the worker and return the manifest of matching files (relpath + size) without reading contents.

The planning half of collect_fs(): it tells the caller what to stream and how big each file is. Same glob/dedup/cap rules as collect().

static read_chunk(obj_dir: str, rel: str, offset: int, length: int) bytes[source]

Read length bytes at offset from obj_dir/rel on the worker. The transfer primitive behind collect_fs(); returns b"" at or past EOF. rel is confined to obj_dir.

collect_fs(obj_dir: str, patterns: list[str], dest_dir: str, max_bytes_per_file: int | None = None, chunk_bytes: int = 16777216) HammerCollectFsResult[source]

Stream matching files from a previous action’s obj_dir onto the filesystem of THIS (the calling) process, a chunk at a time.

Unlike collect(), which returns every file’s contents in one object-store payload, this writes each file to dest_dir on the caller’s local disk incrementally — peak memory is ~``chunk_bytes``, not the size of the whole collection. Use it to pull large report trees / gate-level netlists back from the worker to a machine that does NOT share a filesystem with it.

This is a caller-side orchestrator, not a @ChiaFunction: it runs wherever you call it and writes to that machine’s disk, pulling bytes from the obj_dir worker via the node’s pinned list_matches() / read_chunk() members. It therefore needs a placement group so both members hit the one worker that owns obj_dir — construct the node with require_colocated=True or pass placement_group=....

Files keep their path relative to obj_dir: a match at obj_dir/syn-rundir/reports/x.rpt lands at dest_dir/syn-rundir/reports/x.rpt.

Parameters:
  • obj_dir – The build directory a previous action ran in (on the worker).

  • patterns – Globs relative to obj_dir (** recursive); same matching/dedup/cap rules as collect().

  • dest_dir – Destination directory on the calling machine; created as needed.

  • max_bytes_per_file – When set, files over this size are recorded in skipped and not streamed. None (and 0) means no cap.

  • chunk_bytes – Bytes per worker read — the memory bound per file.

SRAM characterization (CACTI)

CACTI Runner

Methods to run CACTI 7, and return characterization results.

class chia.vlsi.sram_cacti.cacti_runner.CACTIResult(access_time_ns: float, cycle_time_ns: float, read_energy_nj: float, leakage_power_mw: float, height_mm: float, width_mm: float, area_um2: float, full_out: str)[source]

Bases: object

chia.vlsi.sram_cacti.cacti_runner.run_cacti(spec: SRAMSpec, technology_um: float = 0.13, cacti_path: str = 'cacti') CACTIResult | None[source]

Run CACTI for a single SRAM spec and return parsed results.

Returns None if CACTI fails.

chia.vlsi.sram_cacti.cacti_runner.analytical_area_estimate(spec: SRAMSpec, cell_area_per_bit_um2: float = 1.0) CACTIResult[source]

Fallback area estimate when CACTI fails.

Uses a simple model: area = depth * width * cell_area_per_bit. Timing is estimated from simple RC scaling.

CACTI Macrocompiler

CACTI-specific adapter over the generic Chipyard MacroCompiler glue.

The generic MacroCompiler support — MDF library generation and the tapeout.jar remap step — lives in chia.chipyard.macrocompiler. This module just wraps it with the cacti_ cell-name prefix used by the CACTI characterization flow.

chia.vlsi.sram_cacti.cacti_macrocompiler.generate_cacti_macrocompiler_lib(sram_specs: list[SRAMSpec], cell_prefix: str = 'cacti_') str[source]

Generate the MacroCompiler MDF library for CACTI-characterized SRAMs.

Thin wrapper over generate_macrocompiler_lib() that defaults the cell-name prefix to cacti_.

SRAM Characterize

Top-level orchestration: characterize SRAMs with CACTI and generate Liberty files.

Parses .top.mems.conf from generated_src, runs CACTI for large SRAMs, generates Liberty files, and optionally runs MacroCompiler to remap synflop _ext modules to CACTI-characterized library macros.

class chia.vlsi.sram_cacti.sram_characterize.CharacterizedSRAM(name: str, spec: SRAMSpec, result: CACTIResult, lib_contents: dict[str, str], lef_content: str)[source]

Bases: object

A single CACTI-characterized SRAM and its generated collateral.

to_lib_dict() dict[source]

Legacy dict shape.

class chia.vlsi.sram_cacti.sram_characterize.CactiCharacterization(generated_src_files: list[tuple[str, str]], srams: list[~chia.vlsi.sram_cacti.sram_characterize.CharacterizedSRAM] = <factory>)[source]

Bases: object

Result of characterize_top_mems_conf_with_cacti().

The sram_libs / sram_names views are derived from srams so the existing dict-based consumers keep working, while srams exposes the full per-SRAM CACTI result.

chia.vlsi.sram_cacti.sram_characterize.characterize_top_mems_conf_with_cacti(generated_src_files: list[tuple[str, str]], cacti_path: str, synflop_threshold_bytes: int = 256, technology_um: float = 0.13, cell_prefix: str = 'cacti_', corners: Sequence[LibertyCorner] = (LibertyCorner(name='ff', temperature=-40, voltage=1.95, pvt_name='PVT_1P95V_-40C', lib_suffix='ff_n40C_1v95'), LibertyCorner(name='ss', temperature=100, voltage=1.6, pvt_name='PVT_1P6V_100C', lib_suffix='ss_100C_1v60'), LibertyCorner(name='tt', temperature=25, voltage=1.8, pvt_name='PVT_1P8V_25C', lib_suffix='tt_025C_1v80'))) CactiCharacterization[source]

Firtool specific characterize SRAMs with CACTI and generate Liberty files.

Finds .top.mems.conf in generated_src_files, runs CACTI for each large SRAM, generates .lib files, and replaces .top.mems.v to remove synflop definitions for SRAMs that become library cells.

Small SRAMs (< synflop_threshold_bytes) keep their synflop implementations and are synthesized as flip-flop arrays by Genus.

Parameters:
  • generated_src_files – List of (filename, contents) from the build.

  • cacti_path – Path to the CACTI binary.

  • synflop_threshold_bytes – SRAMs smaller than this stay as synflops.

  • technology_um – Technology node in microns (default 0.130 for Sky130).

  • cell_prefix – Prefix on the Liberty/LEF cell name. Default cacti_ disambiguates from chipyard’s .top.mems.v synflop wrapper for the MacroCompiler remap step. Pass “” when the caller’s Verilog refers to the bare _ext module directly (e.g. firtool –repl-seq-mem), so Genus can link the extmodule reference to the Liberty cell without an intervening rewrite.

  • corners – Liberty corners to characterize each SRAM at. Defaults to SKY130_CORNERS (ff/ss/tt). Each corner produces one entry in the per-SRAM lib_contents dict, keyed by its lib_suffix.

Returns:

  • generated_src_files: the (unmodified) input files

  • srams: a CharacterizedSRAM per large SRAM (name, spec, CACTI result, per-corner Liberty contents, and LEF content)

It also exposes .sram_libs (legacy list-of-dicts) and .sram_names views.

Return type:

A CactiCharacterization with

chia.vlsi.sram_cacti.sram_characterize.characterize_srams_with_cacti(sram_specs: list[SRAMSpec], generated_src_files: list[tuple[str, str]], cacti_path: str, synflop_threshold_bytes: int = 256, technology_um: float = 0.13, cell_prefix: str = 'cacti_', corners: Sequence[LibertyCorner] = (LibertyCorner(name='ff', temperature=-40, voltage=1.95, pvt_name='PVT_1P95V_-40C', lib_suffix='ff_n40C_1v95'), LibertyCorner(name='ss', temperature=100, voltage=1.6, pvt_name='PVT_1P6V_100C', lib_suffix='ss_100C_1v60'), LibertyCorner(name='tt', temperature=25, voltage=1.8, pvt_name='PVT_1P8V_25C', lib_suffix='tt_025C_1v80'))) CactiCharacterization[source]

Characterize SRAM specs with CACTI and generate Liberty/LEF.

Splits sram_specs into tiny SRAMs (kept as synflops, below synflop_threshold_bytes) and large SRAMs (CACTI-characterized), runs CACTI for the large ones, and returns a CactiCharacterization. generated_src_files is passed through into the result unchanged.

See characterize_top_mems_conf_with_cacti for the variant that first parses the specs out of a .top.mems.conf in generated_src_files.

Liberty Gen

Generate minimal Liberty (.lib) files for SRAM macros from CACTI results.

Produces Liberty files with area, timing arcs, and pin definitions that match the Chisel-generated _ext module port names. Uses scalar delay model (no NLDM tables) — sufficient for synthesis area estimation and basic timing.

class chia.vlsi.sram_cacti.liberty_gen.LibertyCorner(name: str, temperature: int, voltage: float, pvt_name: str, lib_suffix: str)[source]

Bases: object

chia.vlsi.sram_cacti.liberty_gen.generate_liberty(spec: SRAMSpec, result: CACTIResult, corner: LibertyCorner | None = None, cell_prefix: str = 'cacti_') str[source]

Generate a Liberty .lib file for an SRAM macro at a specific corner.

The cell name and pin names match the Chisel-generated _ext module so Genus can use this as a drop-in library cell.

If corner is None, defaults to typical (tt_025C_1v80).

cell_prefix defaults to cacti_ so the Liberty cell name doesn’t collide with the synflop wrapper named <spec.name> in chipyard’s .top.mems.v (MacroCompiler then rewrites synflop refs to point at cacti_<name>). Pass “” when the upstream Verilog references <spec.name> directly as an extmodule (e.g. firtool –repl-seq-mem) so the Liberty cell name lines up.

LEF Gen

Generate minimal LEF (.lef) files for SRAM macros from CACTI results.

Produces LEF files with macro dimensions, pin shapes, and obstruction layers matching the CACTI-characterized SRAM area. Pin names match the Liberty cell and Verilog blackbox stubs (cacti_<name>).

LEF is geometry-only (no timing) so ONE file is generated per SRAM, not per corner like Liberty.

Uses CLASS BLOCK BLACKBOX per LEF 5.7 spec – designed for blocks that contain a SIZE statement estimating total area with approximate pin locations.

chia.vlsi.sram_cacti.lef_gen.generate_lef(spec: SRAMSpec, result: CACTIResult, pin_layer: str = 'met4', obs_layers: list[str] | None = None, cell_prefix: str = 'cacti_') str[source]

Generate a minimal LEF file for an SRAM macro.

Parameters:
  • spec – SRAM specification (pin names, depth, width, ports).

  • result – CACTI characterization result (physical dimensions).

  • pin_layer – Metal layer name for pin geometry (default “met4” for Sky130).

  • obs_layers – Metal layers for obstruction block. Defaults to [“met1”, “met2”, “met3”] for Sky130.

  • cell_prefix – Prefix on the LEF MACRO name (must match Liberty cell name). See generate_liberty for the disambiguation rationale.

Returns:

Complete LEF file content as a string.