Skip to content

HDL export & NAND2-equivalent gate count

The bitlogic.hdl submodule turns a trained model into SystemVerilog, runs Yosys against the Nangate 45 nm Open Cell Library, and reports the primary hardware-cost metric: NAND2-equivalent gate count (GE) = total chip area / NAND2_X1 area. The emitter reads truth tables straight off each layer via LogicDense.get_luts_and_ids.

Pipeline

flowchart LR
    M[Trained model<br/>nn.Sequential] -->|emit_hdl| SV[hdl_NN/top.sv<br/>flat combinational]
    L[Nangate 45 nm .lib<br/>cached / auto-DL] --> Y
    SV --> Y[synth_yosys<br/>synth + abc + stat]
    Y --> R[yosys_NN/nand2.json<br/>nand2_ge, area, cells]
  1. Emit. Walk the nn.Sequential (encoder + Flatten optional), extract one (luts, ids) pair per LogicDense layer, emit a flat combinational module logic_net. The GroupSum head becomes a per-group $countones popcount plus a behavioral always_comb argmax; the module's output is the predicted class_id.
  2. Resolve Liberty. NangateOpenCellLibrary_typical.lib is auto-downloaded once from the OpenROAD platform tree and cached under $XDG_CACHE_HOME/bitlogic/nangate45/. Pass --liberty /path/to/.lib to override.
  3. Synthesize. Run Yosys with synth -flatten + abc -liberty + stat -liberty. Parse the Chip area for module ... line and the per-cell table, divide area by NAND2_X1 area (itself parsed out of the .lib).

Library API

Both phases run through the bitlogic.hdl Python API. Emit, then synthesize — keep the top.sv between the two if you want to compare synthesis configurations without re-emitting.

from pathlib import Path

from bitlogic.hdl import (
    HDLExportOptions,
    emit_systemverilog,
    resolve_liberty,
    synthesize,
)

# 1. Emit a flat combinational SystemVerilog module.
opts = HDLExportOptions(pipeline_logic_layers=True, groupsum_style="iterative")
sv = emit_systemverilog(model, options=opts)
out_dir = Path("hdl_out")
out_dir.mkdir(exist_ok=True)
(out_dir / "top.sv").write_text(sv)

# 2. Synthesize and report NAND2-equivalent gate count.
metrics = synthesize(out_dir / "top.sv", out_dir=out_dir, liberty_path=resolve_liberty())
print(metrics.nand2_ge)

HDLExportOptions exposes every emission knob (encoder_style, groupsum_style, pipeline_encoder, pipeline_logic_layers, pipeline_groupsum) — flip them and re-emit into a fresh directory to side-by-side compare e.g. parallel-vs-iterative groupsum.

synthesize returns an SynthMetrics dataclass with nand2_ge, total / NAND2 area, per-cell counts, and the Liberty path it used. The Yosys flow's intermediate artifacts (flow.ys, mapped.v, area.rpt, yosys.log) are written into out_dir.

Environment tweaks

  • BITLOGIC_YOSYS_CMD — override the Yosys invocation when a dispatcher wrapper is in use (e.g. BITLOGIC_YOSYS_CMD="yosys yosys").
  • XDG_CACHE_HOME — controls the Liberty cache location; defaults to ~/.cache/bitlogic/nangate45/.

Split training from synthesis

Training has no Yosys dependency; only the synthesize(...) call does. Train on a GPU host, save the trained model with torch.save, copy it to a host with yosys on PATH, and call emit_systemverilog + synthesize there. top.sv is the wire-format between the two phases.