Skip to content

feat: declarative cell metadata (Tier 1 + minimal Tier 2, issue #67)#68

Merged
robtaylor merged 6 commits into
mainfrom
feat/declarative-cell-metadata
May 19, 2026
Merged

feat: declarative cell metadata (Tier 1 + minimal Tier 2, issue #67)#68
robtaylor merged 6 commits into
mainfrom
feat/declarative-cell-metadata

Conversation

@robtaylor
Copy link
Copy Markdown
Contributor

@robtaylor robtaylor commented May 19, 2026

Implements #67's Tier 1 + minimal Tier 2 slice.

Summary

  • `--cell-library .v` (repeatable) on `jacquard sim` and `cosim`: runtime Verilog parsing via `sverilogparse` for third-party IP pin tables, no vendoring needed.
  • `.cells.toml` manifest (TOML, autoloaded sibling): per-cell `kind` discriminator with v1.0 vocabulary (`std` / `dff` / `latch` / `clock_gate` / `ram` / `filler` / `endcap` / `tap` / `io_pad_` / `delay` / `multi_output` / `tie_`).
  • Opaque-RAM semantics for `kind = "ram"` in v1.0 — `RAMBlock` allocated, outputs routed to X-source slots, no port resolution. Sufficient for the heartbeat-verification use case driving this work. Real memory modelling deferred to a future schema version with explicit port mapping.

Built-in classifiers (`sky130.rs`, `gf180mcu.rs`, `build.rs` scanner) stay as fallback through the whole transition.

Phases (all landed)

Phase Commit What
docs `ae6cfa8` ADR 0010 + plan doc
P1+P2 `258707d` `src/cell_library.rs` — `RuntimeCellLibrary` + `ChainedPinProvider` + 10 unit tests
P3a `642e5ab` CLI `--cell-library` flag + `load_design` integration
P3b `ffc0b4c` AIG `from_netlistdb_with_cells` opaque-RAM path + `compute_x_sources` relaxation + narrow-RAM unit test
P4 `84b2187` End-to-end integration test mirroring `gf180mcu_ocd_ip_sram__sram1024x8m8wm1`
P5 `7f3a3ea` `adding-a-pdk.md` manifest-pathway section + `gf180mcu-enablement.md` follow-on cleanup marked superseded

Test plan

  • Unit tests for TOML manifest parsing (schema_version, kind vocabulary, autoload discovery, conflict warnings) — 10 tests in `src/cell_library.rs`
  • Unit tests for chained `LeafPinProvider` precedence (runtime wins, fallback for unknown cells)
  • Unit test for narrow-RAM `compute_x_sources` (8-bit Q output, 24 unused slots)
  • End-to-end integration test: synthetic OCD SRAM Verilog + manifest → `NetlistDB::from_sverilog_source` → `AIG::from_netlistdb_with_cells` → `compute_x_sources` returns 8 X-sources
  • Full lib test suite: 240 passed (was 239 before this PR; +1 for the integration test)

What's deferred

  • Port-mapping schema (`[cells.NAME.ports]` sub-tables). Future ADR after Tier 1 + minimal Tier 2 see real adoption.
  • Migration of built-in `sky130.rs` / `gf180mcu.rs` classifiers to manifest data. They stay load-bearing as the fallback. ADR 0010 § "Deferred to a future ADR" calls this out explicitly.
  • `build.rs` pin-table scanner removal. Same rule — removed LAST, after manifests are the source of truth for at least one PDK in production.

Closes #67 (directional sign-off + spike) — the port-mapping schema work is a separate issue.

@robtaylor robtaylor marked this pull request as ready for review May 19, 2026 16:24
robtaylor added 6 commits May 19, 2026 20:37
ADR captures the directional decision from issue #67's thread:

- Tier 1 (--cell-library <PATH>.v at runtime, sverilogparse-backed
  pin tables for third-party IP without vendoring) +
- Minimal Tier 2 (per-cell `kind` discriminator in TOML, no
  port-mapping schema yet) +
- Opaque-RAM semantics for `kind = "ram"` in v1.0 (RAMBlock
  allocated, outputs routed to X-source slots, no port
  resolution — enough to unblock the downstream wafer.space
  tapeout currently blocked on gf180mcu_ocd_ip_sram_*).

Built-in classifiers (sky130.rs, gf180mcu.rs, build.rs scanner)
stay as fallback through the whole transition. Port-mapping schema
gets its own ADR after real adoption.

Plan doc breaks the work into P1-P5 phases. Each phase is its own
commit; no squashing until the implementation feedback loop
confirms shape.

Co-developed-by: Claude Code v2.1.143 (claude-opus-4-7)
Introduce src/cell_library.rs:

- `RuntimeCellLibrary::from_files(paths)` parses one or more
  user-supplied `.v` files via sverilogparse (already in tree) and
  populates a runtime pin-direction + bus-width table.
- Sibling `<file>.cells.toml` manifests are autoloaded; each may
  carry per-cell `kind` annotations (Tier-2 minimal slice — kind
  discriminator only, port mapping deliberately deferred).
- `ChainedPinProvider` wraps a built-in `LeafPinProvider`
  (SKY130LeafPins, GF180MCULeafPins, AIGPDKLeafPins) and consults
  the runtime library first. Built-in providers stay load-bearing
  for cells the runtime doesn't know about.
- `CellKind` enum covers v1.0 vocabulary (`std` / `dff` / `latch` /
  `clock_gate` / `ram` / `filler` / `endcap` / `tap` / `io_pad_*` /
  `delay` / `multi_output` / `tie_*`). Unknown values fail the
  manifest parse — no silent degradation.
- `schema_version = "1.0"` is mandatory; future schema versions
  upgrade in lockstep with semantic changes.

No CLI wiring or AIG-construction integration yet — those land in
P2/P3. Module is self-contained and tested in isolation (10 unit
tests covering pin parsing, inout-as-Unknown, manifest kind, schema
rejection, kind-vocabulary rejection, autoload, no-manifest case,
chained provider precedence, and the autoload-extension helper).

Adds `toml = "0.8"` as a new dep (one transitive: toml_edit).

ADR 0010 § Tier 1 + Tier 2 minimal slice.
Plan: docs/plans/declarative-cell-metadata.md P1.

Co-developed-by: Claude Code v2.1.143 (claude-opus-4-7)
Add --cell-library <PATH> (repeatable) to `jacquard sim` and
`jacquard cosim`. load_design parses each path via
RuntimeCellLibrary::from_files and wraps the appropriate built-in
LeafPinProvider (SKY130 / GF180MCU / AIGPDK) with
ChainedPinProvider, making third-party IP modules visible to the
netlist reader without vendoring.

The AIG-construction-side consultation of the manifest
(`kind = "ram"` → opaque RAMBlock allocation) is the next slice
(P3b). Until that lands the cell library buys us pin-direction
resolution for previously-unrecognised cells but the AIG still
falls back to AIGPDK for unknown cell types — sufficient to make
the CLI surface compile and to verify the parsing path, not yet
sufficient to unblock third-party SRAM macros.

Three DesignArgs construction sites updated (cmd_sim, cmd_cosim
in the under-feature-flag path, cmd_dump_paths) — dump_paths
defaults to an empty Vec since timing analysis doesn't currently
need runtime cell libraries.

Co-developed-by: Claude Code v2.1.143 (claude-opus-4-7)
When PdkVariant::classify returns None during AIG construction (i.e.
the cell isn't a vendored sky130 / gf180mcu standard cell), consult
the runtime cell-library manifest. For cells declared `kind = "ram"`
(ADR 0010 § "kind = ram semantics in v1.0"), allocate a per-output
SRAM driver and route through the existing `srams` map for X-source
enumeration — the same mechanism `$__RAMGEM_SYNC_` and `CF_SRAM_*`
use, just without the port_r/port_w resolution those paths require.

Thread an `Option<&RuntimeCellLibrary>` through
AIG::from_netlistdb_with_cells → from_netlistdb_impl →
dfs_netlistdb_build_aig. The existing public `AIG::from_netlistdb`
becomes a thin delegate passing `None`; all existing call sites and
tests stay green.

`compute_x_sources` previously asserted `rd_pin >= 1` for every
slot in `port_r_rd_data`. Opaque RAMs are narrower than the fixed
32-bit array — unused slots stay default-zero. Relax the assert to
skip rd_pin == 0 rather than panic. New unit test
`test_x_sources_narrow_opaque_ram` covers an 8-bit opaque RAM
through compute_x_sources and compute_x_capable_pins.

setup.rs `load_design` now passes the runtime library to
`AIG::from_netlistdb_with_cells` when non-empty, completing the
end-to-end wiring from --cell-library on the CLI to opaque-RAM
allocation in AIG construction.

Co-developed-by: Claude Code v2.1.143 (claude-opus-4-7)
`test_opaque_ram_end_to_end` exercises the full ADR-0010 pipeline:

  Verilog blackbox + TOML manifest
    → RuntimeCellLibrary::from_files
    → ChainedPinProvider
    → NetlistDB::from_sverilog_source
    → AIG::from_netlistdb_with_cells
    → opaque-RAM RAMBlock allocation
    → compute_x_sources

Fixture mirrors gf180mcu_ocd_ip_sram__sram1024x8m8wm1 — the cell
that drove issue #67. The 8-bit Q output ends up in
srams[cellid].port_r_rd_data[0..8] with the upper 24 slots
default-zero (the narrow-width case the P3b assert relaxation
made safe). compute_x_sources returns 8 X-sources for the 8
allocated read-data aigpins.

Without this PR's plumbing, the same fixture failed at netlist
load (no pin table for `gf180mcu_ocd_ip_sram_*`) and even with
pin tables would have fallen through to the AIGPDK AND2/INV/BUF
fallback (wrong output behaviour). The driving wafer.space
tapeout's `chip_top.pnl.v` is materially the same shape at a
larger scale — should clear once a `.cells.toml` manifest entry
for the OCD SRAM is added.

Co-developed-by: Claude Code v2.1.143 (claude-opus-4-7)
Two doc updates closing out the declarative-cell-metadata plan:

1. `adding-a-pdk.md`: new "Adding third-party IP via runtime
   manifest" section at the end. Points users at the
   `--cell-library` + `.cells.toml` pathway for non-Rust-PR enablement
   of memory macros, IO pads, fillers, and other behaviourally-opaque
   cells. The overview gains a "two pathways" note so readers pick
   the right route up front.

2. `gf180mcu-enablement.md` § Follow-on cleanup: items 1, 2, 4 are now
   subsumed by ADR 0010 (build.rs scanner removal, IO/PR-library
   enablement). Item 3 (CellLibrary enum relocation) and item 5
   (Liberty install in CI) remain independent. Strikethrough
   notation makes the supersession explicit while keeping the
   historical record intact.

Closes out the P5 (final phase) of the declarative-cell-metadata
plan. PR is now feature-complete for the Tier 1 + minimal Tier 2
slice; port-mapping schema is documented as the next ADR.

Co-developed-by: Claude Code v2.1.143 (claude-opus-4-7)
@robtaylor robtaylor force-pushed the feat/declarative-cell-metadata branch from d0046c1 to 7f3a3ea Compare May 19, 2026 19:41
@robtaylor robtaylor merged commit a92eee5 into main May 19, 2026
14 checks passed
@robtaylor robtaylor deleted the feat/declarative-cell-metadata branch May 19, 2026 20:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant