Skip to content

PDK enablement: declarative cell metadata (pin tables + classifications) instead of per-PDK Rust modules #67

@robtaylor

Description

@robtaylor

Summary

PDK enablement today is per-PDK code + vendored Verilog. Every new cell family — third-party IP memories, hard macros, foundry IP — means re-vendoring Verilog into jacquard/vendor/, extending build.rs's scanner, editing prefix-matchers (is_<pdk>_cell, extract_cell_type), and adding entries to half a dozen hand-curated matches!() lists (is_filler_cell, is_io_pad_cell, is_sequential_cell, is_multi_output_cell, …). That doesn't scale across the ecosystem, and it makes downstream sim runs gated on Jacquard PRs even when the IP could be supported with a small data file.

Concretely: after #64 cleared antennas / corner pads / fillers, the next blocker on jacquard sim against a real gf180mcu-project-template post-P&R chip_top is third-party gf180mcu_ocd_ip_sram__sram1024x8m8wm1 — Tim Edwards' OCD 3.3V port of the GF180MCU SRAM IP. The cell is not in Jacquard's vendor/, not matched by is_gf180mcu_cell (only walks fd_sc_* / fd_io_* / ws_*), and has no pin table. Real ports (CLK, CEN, GWEN, WEN[7:0], A[9:0], D[7:0], Q[7:0], optionally inout VDD/VSS) — not filler-stubbable.

Where the friction sits

For each new cell family Jacquard currently needs:

  1. Pin direction tablebuild.rs::generate_<pdk>_pin_table scans jacquard/vendor/<pdk>/**/*.v, parses input / output, bakes a static table at compile time. (Misses inout, which GF180MCU: power-pin + wired-filler shortcuts for real post-P&R netlists #64 had to short-circuit for power pins.)
  2. Cell-family detectionis_<pdk>_cell hard-coded prefix matchers (e.g. gf180mcu_fd_sc_mcu7t5v0__, gf180mcu_ws_io__).
  3. Classificationsis_filler_cell / is_io_pad_cell / is_sequential_cell / is_multi_output_cell / is_delay_cell, each a curated matches!() list per PDK.
  4. AIG-level special casesgf180mcu_postprocess in aig.rs, IO-pad behavioural rules, multi-output decomposition for addf/addh, etc.

Items 1–3 are mostly mechanical data restating what's already in the cell's Verilog port list + a small "kind" tag. Item 4 is genuine semantics extraction and the harder part (but rare — most new entries to a PDK are IP not new gate families).

What a declarative model could look like

Two-tier; the tiers are cleanly separable and can land independently.

Tier 1 — runtime pin tables (eliminates items 1 + 2)

Drop a --cell-library <path>.v (or cell_library = [...] in a config / [tool.jacquard] table) that points at one or more Verilog files. sverilogparse (already a dep) parses them at startup and populates the LeafPinProvider for every module ... endmodule block found. Handles input / output and inout correctly; replaces the build.rs scanner for std cells and removes the need to vendor third-party IP Verilog into Jacquard at all. Downstream projects pass their existing IP blackbox.v files directly.

Behaviour today (per-PDK module + build.rs) could remain as a built-in default; user-supplied libraries augment / override it. No compile-time work for new families.

Tier 2 — declarative cell metadata (eliminates item 3, partially item 4)

YAML or JSON co-located with each cell library, describing the things port lists can't tell you:

# gf180mcu_ocd_ip_sram.cells.yaml
gf180mcu_ocd_ip_sram__sram1024x8m8wm1:
  kind: ram_block
  depth: 1024
  width: 8
  ports:
    clk: CLK
    chip_enable: CEN          # active-low
    chip_enable_polarity: low
    write_enable: GWEN        # active-low
    write_enable_polarity: low
    byte_enable: WEN          # [7:0], active-low, per-byte
    byte_enable_polarity: low
    addr: A                   # [9:0]
    data_in: D                # [7:0]
    data_out: Q               # [7:0]
  power_pins: [VDD, VSS]      # inout, under USE_POWER_PINS

Other recognised kinds mirror today's classifiers: filler, endcap, tap, io_pad_input, io_pad_output, io_pad_bidir, power_pad, corner_pad, analog_passthrough, clock_gate, dff, latch, sram, rom, delay, multi_output. The built-in SKY130 / GF180MCU classifications could become shipped YAML files — defaults the binary loads from a known path, but anything user-supplied takes precedence.

For kind: ram_block specifically: the port mapping is enough for Jacquard's existing DriverType::RAMBlock slot to pick up the macro without any code change. This is the case for OCD SRAM and would be the case for fd_ip_sram siblings.

What stays per-PDK code

Std-cell AIG decomposition (pdk_decomp.rs reading .functional.v and converting primitive gates → AND-inverter) is genuine semantics work. New std-cell libraries would still need decomp rules. But new IP (memories, analog passthroughs, hardened blocks, foundry-supplied macros) — the common case driving Phase 7-style "we need just one more cell" PRs — would be 100% data-only after this lands.

Migration shape (rough)

  1. Tier-1 first: introduce --cell-library runtime parsing alongside the existing static tables. Existing tests keep passing; user-supplied libraries augment.
  2. Convert one PDK's filler/io-pad/sequential classifications to YAML, prove parity in tests, leave the other as code. gf180mcu is the obvious candidate since GF180MCU: power-pin + wired-filler shortcuts for real post-P&R netlists #64 just touched it.
  3. Convert the other PDK once parity is proven.
  4. Deprecate the build.rs scanner; the per-PDK Rust modules shrink to AIG-decomposition rules + library default-paths.
  5. New PDK / new IP: ship a manifest, no code.

Impact on docs/adding-a-pdk.md

The recipe today is "vendor + write a module + extend several lists." After this lands it becomes "ship a .cells.yaml alongside the library, point --cell-library at it, done — unless you need new std-cell decomposition rules." Existing docs/plans/gf180mcu-enablement.md § Follow-on cleanup items 2 + 3 (sharing decomp infra, moving CellLibrary enum) become natural consequences rather than separate refactors.

Surfaced by

  • #64 — power-pin + wired-filler shortcuts. Each shortcut was a per-PDK workaround for what should have been data.
  • A real gf180mcu-project-template post-P&R chip_top — blocked on gf180mcu_ocd_ip_sram__sram1024x8m8wm1, an IP that Jacquard can't be expected to vendor.
  • docs/plans/gf180mcu-enablement.md § Follow-on cleanup items 1, 2, 3, 4 — all point at the same underlying issue.

Not blocking any active workstream upstream — filing as a design discussion. Happy to take a stab at Tier 1 once there's directional sign-off.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions