param.pin
a pin the part's datasheet declares, keyed by its spec-local id, with the printed name and its function (power_input / ground / bidirectional / no_connect / ...; needs --params)
What it is ¶
param.pin(mpn, pin, name, function) yields one row per pin a datasheet declares for a part that
joined to the design, keyed by manufacturer part number (mpn) and the pin’s spec-local id. The
row carries the pin’s printed name (VCCA, GND, NC) and its function token: power_input,
power_output, ground, input, output, bidirectional, passive, no_connect, or
unspecified.
The key is the id and not the name, and that is deliberate. A part routinely prints one name on several terminals, so a name-keyed relation would merge two pins that may carry different limits, collapsing exactly what the pin contract exists to keep apart. The name is published as a value, so a query can still match on it and a finding can print it.
unspecified is an ordinary answer here, unlike unspecified on param.range’s kind. A pin
function table may have no type column at all, and a pin whose name and number are known is still
worth recording.
This is the datasheet tier of the query surface. It is EMPTY unless agni runs with --params <dir>
pointing at a seeded PartSpec corpus, and empty for a spec seeded before pin binding existed, so a
rule reading it reports not-applicable rather than a false pass.
For hardware engineers ¶
One row is one line of the part’s pin function table. function is that table’s Type column
(I, O, I/O, P, G, NC) as a word, so you can ask questions like “which terminals of this part are
supplies” without knowing the vendor’s naming habits.
What this relation does NOT do is tell you which leg of the package a pin is. A pin here is a
terminal of the die, and its number depends on which body the part ships in: the same terminal is
leg 14 in one package and leg 11 in another. Numbering lives in the contract rather than on this
relation, and mapping a schematic’s pin onto one of these ids is param.ResolvePin’s job, because
that mapping can legitimately REFUSE (an ambiguous name with no package identified, or a name and a
number that disagree) and a datalog join has no way to refuse. See
pins and packages for the physical
picture.
For software engineers ¶
This is the dimension table for the pin tier: a stable id per terminal, plus two descriptive
columns. param.pin_range is the fact table that references it, and the two join on (mpn, pin).
Think of mpn as the type and pin as a field on that type. A design may place fifty instances of
the part; nothing here is per-instance, and no reference designator appears in this relation at all.
Getting from an instance to a pin goes through the netlist tier (component.mpn, then pin.net),
not through this one.
Go projector ¶
paramPinFacts in stdlib/relations/facts.go walks Model.Components(), resolves each component’s
MPN and spec, dedupes by MPN (a PartSpec describes a type, so emitting per component would
multiply every fact by its placement count), and emits one row per spec.Pins entry via
specParamPinRows. Object is Pin.id, Value is Pin.name, Qualifier is the function token,
and Cite is the pin’s own datasheet provenance, which param.Validate requires. Empty without
--params.
Datalog ¶
Both queries need --params. List every supply terminal of every seeded part:
param.pin(?mpn, ?pin, ?name, "power_input") => ?mpn, ?pin, ?name
Find parts that print one name on more than one terminal, the case that makes a name unusable as a key:
param.pin(?mpn, ?a, ?name, ?f), param.pin(?mpn, ?b, ?name, ?g), ?a != ?b => ?mpn, ?name, ?a, ?b