Adapter contract¶
A PDK or an interconnect vendor ships an adapter so that the ADK can check an
assembly without baking that vendor’s layer numbers into the rule deck. The
adapter is the only place a fabrication layer number may enter the rule path.
Two registries still record layer numbers outside it: config/layers.json,
for the legacy --legacy-exchange0 boundary source, and
config/chiplet_pads.json, for the producer-side black-box pad vocabulary.
There are two axes, and they are independent:
the interposer adapter, required, declares where chiplet attachment lands on the substrate;
the interconnect adapter, optional, supplies the method rules, the bump-to-bump pitch and spacing.
The interconnect axis is purely additive. With no interconnect adapter and no per-method file, the eval chain and the output are identical to the interposer-only deck. See The eval chain.
Tip
Adapters are plain Ruby, concatenated into the deck source and evaluated in
the same scope as the rule decks. That is why they can assign to
drc_rules directly, and also why they must stay self-contained: there is
no module boundary protecting the deck from what an adapter does.
Interposer adapter¶
Location and selection¶
An interposer adapter is a single file:
pdk_adapters/interposer/<basename>.drc
The --interposer-adapter flag of the DRC runner accepts either form:
a shortname, resolved against
pdk_adapters/interposer/, sointm4tm2loadspdk_adapters/interposer/intm4tm2.drc;an explicit path to a
.drcfile, absolute or relative, used as-is.
The resolver tries the literal path first, and only if that is not an existing
.drc file does it fall back to the shortname lookup. A trailing .drc on a
shortname is stripped, so intm4tm2 and intm4tm2.drc both work. If neither
resolves, the runner reports both the literal path and the directory candidate it
looked for, and exits.
The same resolution is implemented in the KiCad DRU generator,
kicad/dru/generate_assembly_dru.py, so both toolchains select an adapter by
the same name.
Through the KiCad plugin orchestrator the adapter comes from the assembly file
instead of the command line: a top-level interposer.adapter field in the
.chiplet, falling back to intm4tm2 when the file, the block or the field
is absent.
interposer:
adapter: "intm4tm2"
Shipped interposer adapters¶
Adapter |
Interposer |
Declares |
|---|---|---|
intm4tm2 |
IHP 130-nm IntM4TM2 aluminum BEOL interposer adapter |
passiv_pillar, dfpad_pillar, chiplet_attachment_input |
Required abstract inputs¶
Every interposer adapter MUST declare the required abstract inputs as KLayout layer expressions in its top-level scope. Today the list has exactly one entry.
chiplet_attachment_inputThe region representing the area on the interposer through which chiplet attachment happens. The physical mechanism is unspecified: Cu pillars, solder bumps, hybrid-bonding pad arrays are all acceptable, as long as the resulting region accurately models where attachment can land.
passiv_pillar = polygons(9, 35)
dfpad_pillar = polygons(41, 35)
chiplet_attachment_input = passiv_pillar.and(dfpad_pillar)
The KLayout deck validates this, not the runner. The runner only resolves the
adapter path and shells out to KLayout. After the adapter source is evaluated,
the deck raises unless every required input is both defined? and non-nil,
aborting the run with an error that names the missing input and the adapter file
that should have declared it. The required list itself is one line in
klayout/drc/adk_assembly.drc:
required_inputs = ['chiplet_attachment_input']
Optional rule-parameter overrides¶
An adapter MAY override entries in the drc_rules dictionary, which the deck
loads from config/rule_params.json before the adapter runs:
drc_rules['ASM_b'] = 30.0 # tighter chiplet spacing on this interposer
Both consumers honour the override, but by different mechanisms. The KLayout
deck simply reads the mutated dictionary. The KiCad DRU generator does not
evaluate Ruby: it scans the adapter file for literal numeric assignments of the
form drc_rules['NAME'] = NUMBER and merges what it finds on top of the
registry defaults, and it does so only when invoked with
--interposer-adapter <name>. Two consequences follow:
a computed override, for example
drc_rules['ASM_b'] = base * 0.6, is honoured by KLayout and silently ignored by the DRU generator;an override targeting a key that is not in
config/rule_params.json, or a negative value, is rejected by the generator with an error rather than passed through.
Keep overrides to plain positive numeric literals on keys the registry already defines. See KiCad DRU generation.
What interposer adapters must NOT do¶
Declare rules. Rules belong exclusively to the ADK deck. An adapter that emits its own
outputcalls puts vendor-specific verdicts into an assembly report that is supposed to be vendor-neutral.Declare or modify the chiplet boundary.
chiplet_boundaryis injected by the ADK from the per-assembly boundary manifest and is built inlayers_def.drcbefore the adapter runs. It is not a layer adapters may touch.Import other .drc files. Adapters are self-contained. The deck reads the adapter file’s text and concatenates it; anything it pulls in from elsewhere is invisible to the contract and to the generators that parse it.
Interconnect adapter¶
The optional second axis carries the bump-to-bump method rules. Select it with
--interconnect-adapter <name> at the runner, or with the .chiplet
interconnect.adapter field through the orchestrator. Omit it and, unless a
per-method interconnect file is passed, the axis is disabled: no IXN rules
run, and the output matches an interposer-only run. A --interconnect-methods
file activates the axis on its own, without any adapter.
interconnect:
adapter: "ihp_cupillar"
Selecting an interconnect adapter¶
pdk_adapters/interconnect/<basename>.drc
--interconnect-adapter uses exactly the same resolver as the interposer
flag: a shortname resolved against pdk_adapters/interconnect/, or an
explicit path to a .drc file.
Shipped interconnect adapters¶
Adapter |
Description |
IXN_spacing (um) |
IXN_pitch (um) |
IXN_pad_size (um) |
|---|---|---|---|---|
ihp_cupillar |
IHP SG13G2 Cu-pillar interconnect adapter |
40 |
75 |
35 |
ihp_sbump |
IHP SG13G2 solder-bump interconnect adapter |
70 |
130 |
60 |
vendorx_microbump |
VendorX fine-pitch microbump interconnect adapter (DEMO, non-IHP) |
15 |
50 |
35 |
ihp_cupillar and ihp_sbump mirror the corresponding interposer-stage
rules, so the interposer stage and the assembly stage of the two-stage DRC
check the same numbers.
vendorx_microbump is a demonstration adapter for a fictional non-IHP vendor:
it exists to show that swapping the interconnect axis retightens the checks on
the same interposer geometry without touching the interposer adapter.
The parameter pack¶
An interconnect adapter is a parameter pack, nothing more. It MUST set these
three keys on the interconnect_rules dictionary, whose defaults the deck
loads from config/interconnect.json before the adapter runs.
Key |
Meaning |
|---|---|
|
Minimum edge-to-edge spacing between attachment points, in micrometres. |
|
Minimum centre-to-centre pitch, in micrometres. |
|
Representative pad size, in micrometres, used for the pitch-to-spacing conversion. |
The whole of pdk_adapters/interconnect/ihp_cupillar.drc, comments aside, is:
interconnect_rules['IXN_spacing'] = 40.0 # edge-to-edge between pillar pads
interconnect_rules['IXN_pitch'] = 75.0 # centre-to-centre pitch
interconnect_rules['IXN_pad_size'] = 35.0 # passivation opening
The deck validates the three keys after the adapter is evaluated, and aborts
naming the missing key. It also enforces IXN_pitch > IXN_pad_size at rule
time, because the pitch check is implemented as a spacing of
pitch - pad_size: KLayout has no native pitch check, so a pitch that does not
exceed the pad size would produce a non-positive spacing and a meaningless rule.
Interconnect rules (IXN) explains that conversion and its conservatism.
Optional region narrowing¶
An interconnect adapter MAY declare interconnect_region to narrow the region
the IXN rules check. If it does not, the deck falls back to
chiplet_attachment_input, the region the interposer adapter already exposes,
so no fabrication layer is duplicated across the two axes:
ixn_region = (defined?(interconnect_region) && !interconnect_region.nil?) ?
interconnect_region : chiplet_attachment_input
All three shipped adapters omit it deliberately.
What interconnect adapters must NOT do¶
Redeclare
chiplet_attachment_inputor any fabrication layer. Those belong to the interposer axis. An interconnect adapter that names a GDS layer has bound a bumping method to one substrate, which is the coupling this axis exists to remove.Declare rules. The
IXNrules live inrule_decks/8_2_interconnect.drc.Import other .drc files.
Per-method refinement¶
A single assembly may mix interconnect methods of the active interconnect PDK,
because each die’s connection: selects its own method. Passing
--interconnect-methods <gds-stem>.ixn_methods.json scopes the IXN checks
per method instead of assembly-globally.
The exporter derives that sidecar from the .chiplet’s per-die connections
plus the interconnect PDK manifest, which remains the single source of truth for
the numbers. Every method entry MUST carry IXN_spacing, IXN_pitch,
IXN_pad_size and dies, the list of boundary-manifest instance names using
that method; the wrapper checks all four keys on every entry before evaluating
anything.
In this mode the deck:
builds one region per method, as the attachment pads intersected with the boundaries of the dies that use it, and fails loudly if a method references a die instance that the boundary manifest does not contain;
checks each method’s own numbers inside its own region, reported as
IXN.b.<method>andIXN.e.<method>;checks a conservative cross-method spacing between the regions of every pair of methods, the larger of the two spacings, reported as
IXN.x.<m1>.<m2>, because neither method’s own check can see the other’s pads;checks attachment pads that fall outside every method region against the assembly-global adapter numbers, reported as
IXN.b.unclaimedandIXN.e.unclaimed, and only when an interconnect adapter is also loaded. If there is no adapter, those pads are simply not checked on this axis, and the deck logs that fact.
Because the method regions are resolved through per-die instance names, this
mode requires the boundary manifest: legacy exchange0 mode carries no
per-die identity, and the wrapper refuses the combination. One interconnect PDK
applies per assembly; what varies per die is the method within it.
Without the file, the axis stays assembly-global, so adapter-only runs are unchanged. Interconnect methods manifest is the normative description of the sidecar.
Evolving the contract¶
Adding a required interposer input. The required list is hardcoded in the
deck as required_inputs in klayout/drc/adk_assembly.drc. Add the new name
there and update every shipped adapter in the same commit. The deck’s
post-evaluation validator then makes any stale adapter fail loudly, by name,
rather than silently skipping a check. Bumping the version key in
config/layers.json has no effect here: that file is legacy-compat, and only
its layers key is read, only on the --legacy-exchange0 path.
Adding an optional input. Guard the consuming rule with if defined?(...)
in the deck, so adapters that do not declare it still run. This is the pattern
8_2_interconnect.drc uses for interconnect_region and layers_def.drc
uses for the injected boundary manifest.
Versioning. The interconnect axis is additive: runs without an interconnect
adapter, and interposer adapters written before that axis existed, behave exactly
as the pre-interconnect deck. CHANGELOG.md in the ADK is the authoritative
per-release record of the contract; the VERSION file and the version keys
in every config/*.json track its latest released entry, and a test enforces
that they agree.
Writing an adapter for a new interposer¶
The shipped intm4tm2 adapter is the whole worked example, because a
conforming adapter really is this small. Here it is in full, comment header
included:
# SPDX-License-Identifier: Apache-2.0
#
# IHP 130-nm IntM4TM2 aluminum BEOL interposer adapter.
#
# Declares ADK abstract inputs in terms of IHP-specific layers. IntM4TM2's
# chiplet-attachment mechanism is the Cu pillar, formed where the
# passivation opening (9/35) and the final Cu pad (41/35) overlap.
passiv_pillar = polygons(9, 35)
dfpad_pillar = polygons(41, 35)
chiplet_attachment_input = passiv_pillar.and(dfpad_pillar)
Line by line:
# SPDX-License-Identifier: Apache-2.0Every ADK source file carries an SPDX header. Keep it.
- The comment block
States the substrate the adapter is for and, more usefully, what physical mechanism the attachment region models and which layers encode it. This is the only documentation a reader of the assembly report has for why the region is what it is. Write it.
passiv_pillar = polygons(9, 35)A KLayout layer expression for the passivation opening, in the interposer’s own GDS layer and datatype numbers. These are the numbers the ADK deck must never see, which is why they live here.
dfpad_pillar = polygons(41, 35)The final Cu pad.
chiplet_attachment_input = passiv_pillar.and(dfpad_pillar)The required abstract input. A Cu pillar exists only where both the passivation opening and the pad metal are present, so the attachment region is their intersection, not either layer alone. Choosing the intersection rather than the pad layer is the modelling decision: it makes
ASM.fand theIXNrules operate on the geometry that actually forms a joint.
Note what is absent: no rule, no output call, no include of another file
and no parameter override. The two intermediate locals are a readability choice;
the contract cares only that chiplet_attachment_input ends up defined and
non-nil.
To support a new interposer, a vendor must produce exactly this:
One file,
pdk_adapters/interposer/<name>.drc, where<name>is the short name designers will pass to--interposer-adapter.A definition of
chiplet_attachment_inputin terms of that interposer’s own layers, modelling the region where attachment can physically land. If the mechanism is not a Cu pillar, say so in the header comment and build the region from whatever layers do encode it.Optionally, numeric overrides of
drc_ruleskeys where the substrate genuinely demands different assembly numbers than the registry defaults. Write them as plain literals so the KiCad generator sees them too.
Nothing else. No change to any rule deck, no change to any registry, no change to the runner. Verify the result by running the assembly DRC on a known-good and a known-bad layout for that substrate: see Running the assembly DRC. The two axes are independent, so an interposer adapter can be validated on its own before any interconnect adapter exists for that substrate.