param.pin_relation

a datasheet constraint BETWEEN two pins of one part: bounds on (subject - reference) in the SI base unit, with the vendor's modality (required/recommended). The pin order is load-bearing, so swapping the two inverts the requirement (needs datasheet parameters)

What it is

param.pin_relation(mpn, subject_pin, reference_pin, modality, min, max) is a datasheet constraint that holds between two pins of one part, rather than about either pin on its own. min and max bound the quantity subject - reference, in the SI base unit whatever the vendor printed, and an absent bound on a side means unbounded there.

modality is the vendor’s own modal verb reduced to a token: required for “shall never exceed”, recommended for “should be at least 1 V higher for best operation”, and unspecified for a spec that did not record one. Every row carries a citation back to the page and table.

The pin order is the fact, not a presentation choice. The bound is on subject minus reference, so a query that swaps the two columns reads the opposite requirement. They occupy two distinct slots for that reason.

Only tracking relations are projected. PinRelationKind has one member today. The proto’s own comment says a second arrives only once a second vendor can populate it, so the kind gets no column. A second kind has to revisit this projection.

For hardware engineers

A part with several supplies routinely constrains them against each other. A voltage translator requires one side’s supply to stay at or below the other’s. A PHY requires one analog supply never to exceed another by more than half a volt. A level shifter recommends an enable sit a volt above its reference. Each terminal can be comfortably inside its own rating while the pair is still wrong, and no per-pin relation can see that, because the fact is not about a pin.

The bound is a value, not a comparison operator. “Less than or equal to” is a maximum of zero, “never exceed by more than 0.5 V” is a maximum of 0.5, and a symmetric tolerance is a minimum and a maximum together. Most real instances carry a non-zero allowance, so an operator-shaped relation could not hold them.

modality is worth filtering on. A requirement broken is a stress violation; a recommendation broken is lost margin. They are different conversations and the relation keeps them apart.

For software engineers

This borrows param.pin_range’s field layout for a different fact. There, Object and Value are a pin and a symbol; here they are two pin ids, and Min/Num bound the difference between them rather than one terminal’s own quantity.

The pin ids join to param.pin, and that join turns them into the names a datasheet prints. param.ResolvePin resolves a design terminal onto one of these ids. It is deliberately not a datalog join, because it can refuse and a join cannot. It refuses an ambiguous name, or a name and number that disagree.

Suppose a relation’s unit has no known scale. The row keeps its pins, modality and citation with both bounds absent, as the sibling projections do, because an unmeasurable bound must not become orderable.

Go projector

paramPinRelationFacts in stdlib/relations/facts.go shares the per-MPN join and dedup of the other param projectors and emits through specParamPinRelationRows. Object and Value are the subject and reference pin ids, Qualifier the modality token, Min and Num the reduced bounds, and Cites the relation’s datasheet provenance. Empty without --params, and empty for every spec that declares no relations.

Datalog

All queries need --params. Every pin-to-pin bound in the corpus, named the way the datasheet prints the terminals:

param.pin_relation(?mpn, ?s, ?r, ?mod, ?min, ?max),
param.pin(?mpn, ?s, ?sname, ?sfn), param.pin(?mpn, ?r, ?rname, ?rfn)
  => ?mpn, ?sname, ?rname, ?mod, ?min, ?max

The requirements alone. A CI gate usually checks these:

param.pin_relation(?mpn, ?s, ?r, "required", ?min, ?max) => ?mpn, ?s, ?r, ?min, ?max

The ordering constraints specifically, where one supply must not rise above another:

param.pin_relation(?mpn, ?s, ?r, ?mod, ?min, ?max), absent(?min), ?max <= 0
  => ?mpn, ?s, ?r, ?max