Repository navigation
Conversation
ERC-D7 was partial: GF180MCU LU.5 asks that a NAT device within 50 um of an n-well be "directly surrounded by PCOMP substrate guard ring. (No other NCOMP, NWELL in between the NAT and PCOMP guard ring)", and guard_ring checked only that a ring surrounds the device. guard_ring gains `clear: layer | none`: the innermost hole round a target may hold no area of `clear` outside the target. The hole is read as its box less the ring figure's rectangles, less the target's: exact for a rectangular hole, and an over-report only when another hole of the same ring lies in that box. A target with clear area between it and its ring measures the count of clear figures there against 0. Every existing guard_ring row states `clear: none`; the deck library, the decompiler and the rule reference carry the parameter. Fixtures (SY, MR): the LU.5 ring round a NAT with `clear` the derived `ncomp or well`; an NCOMP inside the NAT or on the ring's band is clean, one in the gap, one straddling the NAT's edge or a well island in the gap counts 1, two pieces count 2, each under every symmetry and two offsets. Breaks if the target's own area is not subtracted (the straddling and inside cases move), or the ring's band is not (the on-ring case flags). The duplicated sentence in the ERC-G3 and ERC-G7 notes is removed.
ERC-C14 was missing, its limits marked NDA. Public material defines its
two rules as electrical limits, not distances: Bakhali (Siemens,
Semiconductor Engineering 2020) holds a clamp's distance to its pad as
a pin-to-clamp resistance ("Resistance of the bus line from ggnmos to
the closest PowerClamp less than 1 Ohm"), and the Calibre PERC LDL
minimum ESD-path metal width is a current per width. Both are esd_path
limits: max_resistance and max_density.
C14 is partial: max_resistance holds the pin-to-supply path through the
clamp, not the pin-to-clamp bus alone, and no public source states
either limit's value. esd_path's rustdoc, the rule reference and the
catalog say so, and check-sources.md gains the Bakhali2020 tag.
Proof: the esd_path max_resistance fixtures (2.5 ohm series path,
parallel 15/11 and 14/11 ohm, closed form, swept and placed) and the
max_density fixtures (1.33 A over a 1 um and a 0.5 um line) now name
ERC-C14. Breaks if either limit stops being read.
… are flagged (X4) ERC-G9 (Calibre ERC PATHCHK) and ERC-H3 (PERC netlist path checks) were missing: the statement names alone were public. Mentor's programmable ERC patent US20100306720A1 (P12) defines paths and two checks, and the open ICsprout55 PDK's Calibre LVS deck states what its PATHCHK lines select. - supply_path(; both): a path is the nets joined through MOS source/drain and resistor pins (P12 init_1, "the default path definition in LVS"), broken at the declared supplies, whose role it carries (P12 -break). both: false flags a net reaching no supply (P12 check_1); both: true one missing power or ground (check_2, PATHCHK GROUND && !POWER and POWER && !GROUND). Supplies and nets no device reaches are not examined. - gate_path(; ground, max_devices): P12's "every transistor gate ... must have an electrical path to ground that passes through no more than three other devices", the devices on the shortest path through the same pins, no supply breaking it. H3 stays partial: P12 states it as an example without defining the count, and its net types beyond power and ground are not modelled. Both need intent. The deck library, decompiler, rule reference, deck.md, README count and dispatch test carry the kinds. Tests: X4's topology boards (every three-nfet circuit on four nets, sampled at merge depth, every nfet/pfet pair against three rails) now check supply_path both ways and gate_path to ground within 0 and to power within 1 against Board::expect's own walk (NV); a hand-derived circuit (SY, every symmetry) shows a resistor carries a path and a diode does not: B reaches ground through a resistor and a pull-down (2 devices), C behind a diode reaches nothing. Breaks if the resistor is not traversed (B and its gate move), the supplies stop breaking paths (sp2 stops flagging A and B), or a diode carries a path (C clears).
…(X4) ERC-G8 was missing: Yosys `check` defines a logic loop on cells, and no open tool defines one on a transistor netlist. Bryant's ICCAD '91 paper (open author's copy) gives the cell: the channel-connected component, "a set of storage nodes connected by the source-drain terminals of transistors", ranked by which components drive which. combinational_loop(): components are nets joined through MOS source and drain pins, never through a declared supply (an input, not a storage node); a transistor belongs to the component of its channel's non-supply ends, and a component drives another when one of its nets is the gate of a transistor there. A strongly connected set of two or more components, or a component driving itself, is a loop, one finding at its lowest net measuring its components. As Yosys reports a latch built from gates, a latch, keeper, SRAM cell or diode-connected transistor is a loop; the rustdoc and catalog say so. Needs intent. Tests: X4's topology boards check it against Board::expect's own component merge and transitive closure (NV, every sampled circuit), and a hand-derived set (SY, every symmetry): an inverter chain is clean, a ring of three is one loop of 3, a latch one of 2, a diode-connected nfet one of 1. Breaks if supplies join components (the chain becomes a loop) or self-driving components are dropped (the diode case clears).
ERC-E7 was missing: LEF/DEF 5.8 states a layer's AC limits as ACCURRENTDENSITY RMS and PEAK (sky130's tech LEF: 6.1 mA/um on met1 and met2, 14.9 on met3 and met4, 22.34 on met5), but the intent stated only a DC budget per net, so no RMS or peak current reached a check. The intent gains rms_current_ua and peak_current_ua per net (positive and finite, BadLimit otherwise). New kinds em_rms and em_peak take em_current_density's table and spelling: the supply grid is built again with each net's RMS (peak) current in place of its budget, shared among its loads as the budget is, and solved; each wire and cut is held to the row's per-width or per-cut limit. With every load drawing one waveform in phase, the model the budget already makes, a wire's current on the linear resistive grid is that waveform scaled by its DC share, so the DC solve with RMS (peak) loads gives its RMS (peak) exactly. A row is skipped when no net states the current. E7 is partial: LEF's tables by frequency and width are one density per layer here, out-of-phase loads read strict, and signal nets carry no current. Tests: sky130's 6.1 mA/um RMS limit on a 1 um met1 rail whose load draws 6093.9, 6100 and 6106.1 uA (flagged only above), the net's DC budget 1 uA so reading it would flag nothing; random peak ladders (the series ladder's closed form, CF) swept between edges; the other kind skipped in each; intent keys refused at 0. Breaks if the AC rows read the budget (nothing flags) or the RMS and peak grids are swapped (each case's other row runs).
ERC-E9 was partial: unconnected_pin flags conductors no device reaches, but OpenROAD check_power_grid also reports grid shapes its walk from the top layer does not reach (PSM-38) and the instance pins on them (PSM-39). Worse, the grid rules fed each piece of a split supply by itself, so a floating piece read as a healthy rail. floating_supply(): the pieces of a declared supply are the extracted nets carrying its label; the grid is fed at the supply's highest, then widest, shape over every piece (extract_into's feed point, feed_shape now pub(crate)), and every other piece is floating, one finding at its lowest polygon. An unlabelled stripe no device reaches stays unconnected_pin's, and an unlabelled rail devices reach reaches no supply (supply_path). Needs intent. E9 is implemented with both kinds. Tests (SY, every symmetry): a met2 bar strapped to a met1 rail is one piece, clean; unstrapped, the lower rail floats; two unstrapped rails both float; a 0.5 um met2 stub against a 20 um met1 rail is fed, being higher, so the rail floats; without intent the row is skipped. Breaks if the feed piece is chosen by size first (the stub case flags the stub) or a single-piece supply is examined as split.
ERC-F4, D9, A14, A15 and E12's stress-voiding part stay unimplemented, each for a reason the catalog notes (and so limitations.md) now state with what was read: - F4: Siemens WP 81822 Eq. 1 holds for every switching PMOS over static ranges; GF180MCU 14.1.4.1's Vddmax bound is drain_source (F3) and its duty dependence has no static form; JESD28/60 are behind a login; any threshold between stress and switching is a guess. - D9: the Calibre PERC check is named, never defined; every public well-sharing rule found (GF180 LU.9/10, NW.2a/b; sky130 nwell.5b, hvnwell.8/10; IHP NW.b1; a bulk below its source) is already a kind. - A14: LEF/DEF Appendix C defines it, but it needs a LEF macro reader the GDS-only ERC flow does not have; full GDS is checked flat. - A15: no public source defines a required diode area; OpenROAD repairs iteratively, and where a diode joins the net is a router's choice. - E12: the public via rules near wide metal are copper-only (sky130) or DRC spacing (GF180 MSLOT.7/8, IHP Slt.h1-h4).
…gy (X4) ERC-A11 was partial: the antenna kind took a MIM victim, but gf180's topology was untested: the FuseTop top plate is reached from above by Via(n) to Metal(n+1) (MIM.4) over a Metal(n) bottom plate it does not touch (10.4.1), and a non-conductor FuseTop would join that bottom plate. Written as a conductor joined by Via2, it is the victim the DRM means. Fixtures (SY, every symmetry), hand-derived from the DRM's perimeter area 2[(t x z) + (t x y)] with t = 0.54 um: a 1 um wide Metal3 line 369 um from a 1 um2 plate reads 399.6 (clean against ANT.14's 400), 371 um reads 401.76; a Via3 cut 4.4 um square reads 19.36, 4.5 um 20.25 (ANT.15's 20); a Metal2 row never sees the plate. The antenna rustdoc and the catalog say how to write the rows; the shipped gf180 deck gains them in S2. Breaks if FuseTop joins its bottom plate (the Metal2 row flags) or the sidewall measure drops the thickness.
…re checked (X4) ERC-C14 was partial: its two rules were read as esd_path's pin-to-supply resistance and current density, and its limits are NDA. Under "deck-defined over unimplemented" both are now checks of their own, the limits deck-supplied. - esd_clamp_resistance(pad; clamps, max_resistance): the pin-to-clamp resistance of Bakhali (Siemens, 2020: "finds all possible combinations between all pins ... and all specified clamp types ... calculates the parasitic resistance on each combination"), measured as US11714117B2 states (P13, "Rpath = VIO / IESD"): a unit current forced from the pad to the clamp's attach point on the pad's net, the clamp itself not in the path. Needs no intent. - esd_path gains min_width: len | none, a wire segment that carries the stress current (above a millionth of it) narrower than that, the "minimum ESD metal width" of Khazhinsky 2012. Every esd_path row states it. Tests (SY, CF, every symmetry): on esd_layout's strips the pad strip's 0.0625 ohm/sq gives 0.5 ohm to a clamp at 2 um and 0.25 ohm at 14 um, swept; an unlisted model is not measured. 1.33 A through the clamp at 2 um crosses the pad and VSS strips between 2 and 10 um: 1 um strips flag both at 1001 nm, neither at 1000 nm (strict) or 999 nm; a 2 um pad strip leaves only VSS at 1500 nm; dead ends never flag. Breaks if the pin taps the wrong end, the clamp's own resistance enters the path, or zero-current stubs count. The esd_path fixtures no longer claim C14.
em_rms and em_peak took one density per layer, as a single-entry LEF
table. The coordinator's "deck-defined over unimplemented" asks for the
form LEF/DEF 5.8 states: ACCURRENTDENSITY {PEAK | RMS} FREQUENCY ..
WIDTH .. TABLEENTRIES .., current per um of drawn width, interpolated
linearly between the stated points.
- The deck language gains frequencies (Hz, kHz, MHz, GHz; a list) and
rows of currents per width, parsed and printed.
- em_rms/em_peak(layers..; frequency: [..], width: [..], density:
[[..], ..], max_current_per_cut) fill an EmAcTable: one density row
per frequency, one cell per width, both axes rising strictly, the
cells one per pair (BadTable otherwise). A wire is held to its width
times the table at its width and its net's frequency, each axis
interpolated linearly and held at its ends; a cut to the per-cut
value.
- The intent gains frequency_mhz per net; a table of several
frequencies refuses its row when an examined net states none. The
RMS and peak grids keep each net's frequency.
E7 is implemented, its values deck-supplied (no public deck states a
table; sky130's tech LEF states single RMS values).
Tests: a hand-interpolated 2 x 2 table (made-up values): a 1 um rail at
200 MHz reads 2.5 mA/um, so 2500 uA; a 2 um rail at 50 MHz is held at
2 mA/um, 4000 uA; each swept a part in a thousand either side; a net
with no frequency refuses the row; the sky130 and random ladder cases
in the new spelling; a deck-library test (constructors against text,
and the printer round trip) for every kind this branch adds. Breaks if
an axis is not interpolated (midway reads a corner), the ends are
extrapolated (held reads more), or the rows and columns swap.
…s (X4) Confirmed under the deck-defined rule: esd_parasitic's min_spacing is a required parameter with no default, so the check runs on any deck's value; the note now says so in the catalog's wording.
…ntroid (X4)
ERC-H2 was missing: the Calibre, ICV and Pegasus constraint checkers are
named only, and H6 found the patent text unreachable. Public sources do
define three of the checks precisely: GF180MCU DRM 10.6.2 MP.1/MP.2a
(identical units) and MP.7 (parallel, not perpendicular), Cadence's
US10216888B2 (P14: same model, finger width and length), and the common
centroid of Karmokar et al. (ASP-DAC 2022, Eq. 2-3) and Siemens's
Sarhan & Arriordaz 2019 ("If the centers do not match, an error is
reported"), with Hastings's area-weighted centroid of an array.
matching(group; tolerance): each polygon of the group layer marks the
MOS transistors whose marker centre lies in it. A unit of another model,
width or length than the first is flagged (the difference against 0); a
unit whose channel (the marker axis whose extent is its extracted
length) crosses the first's is flagged; units sharing model and nets
are one device, and a device whose area-weighted centroid lies more than
the deck's tolerance from the first's on either axis is flagged. H2 is
partial: anti-parallel current, dummies, surroundings and STI context,
well proximity and axis symmetry are not checked (catalog notes).
Tests (SY, every symmetry): ABBA is clean; ABAB's centroids lie 4000
nm apart, flagged at 3999 nm and clean at 4000 nm; a 1.2 um unit beside
a 1 um one differs by 200 nm; a unit turned 90 degrees crosses; a unit
outside the polygon is not in the group; plus the deck-library
constructor and printer round trip. Breaks if the centroid is unweighted
by membership (ABBA flags), the axis reads the box instead of the
length (the turned unit passes), or group membership ignores the polygon.
… an always-on control (X4) ERC-F14 was missing: it named UPF input and IEEE 1801, unread. Public UPF material states the switch rules checkably: Liu et al. (Samsung and Synopsys, DVCon) "The PG connection of power switch cells should respect the UPF specification" and "Power switch control signal should come from always on path", and the ISLPED 2014 UPF tutorial's create_power_switch with its input and output supply ports. power_switch(; models): the design intent is the power intent, a supply some declared power state turns off being switched and the rest always on. A transistor of a listed model is a switch; a row flags one whose channel does not join an always-on supply to a switched supply of the same role, and one whose gate no supply reaches in some declared state. RunInputs carries the switched supplies (the union of every state's off list). F14 is partial: retention, always-on cells and the real-versus-virtual net of standard cells need cell roles the intent does not state. Tests (SY, every symmetry): VDD to VDDV under a VDD-driven control is clean; VDD to a signal net, or VDD to VSS, flags the wiring; a control driven only from VDD2, which sleep turns off, floats in one state; without states the row is skipped; plus the deck-library constructor and round trip. Breaks if the off lists are ignored (every switch flags), roles are not compared (VDD to VSS passes), or the control is read with every supply on (the VDD2 case passes).
…ance (X4)
ERC-C3 was partial: a gate on the pad net counted as protected by the
primary clamps, so a deck could not ask for the CDM secondary stage.
Public material defines the stage: Industry Council White Paper 2 2.3.1
(a series R1 to the receiver gates with a secondary clamp; "R1 values
from 100-5000 ohm are common"), TR18-01's Rule 6.1.11 title, and
Siemens's US9378324B2 ("presence of series resistance in the signal
path, presence of secondary high/low ESD clamps").
esd_exposed gains min_series: resistance | none. With a value, every
exposed gate's effective resistance from the pad nets (joined) through
the series-resistor devices, each sheet x l / w as its device row
states, must be at least that; a gate on the pad net has 0. The
effective resistance is a dense Gauss-Jordan inverse over the exposed
nets, so parallel resistors combine. A resistor with no value refuses
the row. The local clamps behind a resistor are the walk the kind
already made. C3 is implemented, its value deck-supplied.
Tests (SY, every symmetry): rs states 100 ohm/sq on a 400 x 200 nm
marker, 200 ohm: a gate on the pad net reads 0 (flagged at 150), one
behind a resistor 200 (flagged at 300, clean at 150), behind two in
parallel 100 (flagged at 150), behind two in series 400 (clean at
300); an unvalued resistor refuses. Breaks if parallel paths are not
combined (the parallel case reads 200 and passes) or the pad node is
not grounded.
…stance are checked (X4) ERC-C4 lacked the receiver's series resistor and ERC-C9 the driver/receiver ground resistance. Both are public checks with private limits: the local CDM protection's "series resistor 150 disposed between the output node ... and the input node" (US12021077B2, P15; TSMC's US9035393B2, P16, states 50, 100 or 200 ohm), and Etherton et al.'s "The user defines the maximum resistance (Rmax) allowed between D/R ground pins ... computes the effective resistance between the local ground nodes". esd_cross_domain gains resistors, min_series, max_ground_resistance and coupling_resistance. A receiver's input is its gate net and the nets the series resistors join to it; its drivers have a channel end there. With min_series, the effective resistance from the driving nets (joined) to the gate net, each resistor sheet x l / w, must be at least that (0 when driven directly). With max_ground_resistance, each driver whose other end is a ground and a receiver with a ground end: a unit current from the driver's attach point on its ground to the receiver's, through both grounds and every coupling diode at coupling_resistance, above the limit is flagged; grounds no diode joins are 5.1.3's. Stress gains source_net so a device marker can be the source, tapped where the device attaches. C4 is implemented; C9 stays partial for the bus inductance, which no public source states statically. Tests (SY, CF, every symmetry), on a crossing drawn as 1 um met1 strips at 0.125 ohm per um: driver and receiver grounds joined by two 1 ohm diodes 0.4 um apart read 0.9875 + (1.05 || 1.05) + 0.9625 = 2.475 ohm, swept; SIG driven directly reads 0 ohm for both receivers, through a 200 ohm resistor 200 (flagged at 300, clean at 150); 5.1.3 still flags both receivers since both diodes face one way. Breaks if the parallel diode paths are not combined, the attach points are the strips' centres, or the series region stops at the resistor.
ERC-C6 was partial: esd_path stresses a pin against each supply, so two signal pins met only through the supplies between them. Bakhali (Siemens, 2020) defines the pin-to-pin check, "a full path resistance calculation for each combination", Khazhinsky 2012 Fig. 4 stresses one I/O pad against another, and US11714117B2 (P13) takes the path resistance as the pin's voltage over the forced current. esd_pin_pair(pad; clamps, current, clamp_resistance, max_resistance): for every two signal nets holding a pad polygon whose clamp walks share a supply, the current is forced from each pin of the first to the second's pins (held at 0 V) through every net either reaches, each clamp its on-resistance; a pair above the limit is flagged. Pins that share no supply are not examined. C6 is implemented, its limit deck-supplied. Tests (SY, CF, every symmetry): two pad strips joined by a down diode, a rail clamp and an up diode at 2, 10 and 18 um read 0.5 + 1 + 1 + 1 + 0.5 + 1 + 0.5 = 5.5 ohm, swept; without the rail clamp the pair is not examined; plus the deck-library constructor and round trip. Breaks if the second pin is not held at its own pins, or the walks are not joined (the rail clamp's supply is lost).
…ell (X4) The rebase brought S2's gf180 latch-up rows, written before guard_ring had `clear`: every row now states it, and LU.5 writes the DRM's "No other NCOMP, NWELL in between the NAT and PCOMP guard ring" as `clear: lu5_between`, a derived `ncomp or nwell`, in the deck and its Rust twin. The IO rows state `clear: none`. The generated catalog blocks follow the rebased catalog, and a doc comment backticks FuseTop.
…(X4) ERC-C8 checked the pin's voltage under a forced current through linear clamps: a clamp's turn-on or holding voltage had to be folded into the limit. Industry Council White Paper 2 2.9.3 writes the pad voltage with each clamp's offset: Vpad = Vdiode_on + Rdiode_on I + (RVdd + RVss) I + Vrcclamp_on + Rrcclamp_on I, to stay below the protected device's Vt1. esd_path gains clamp_voltage: voltage | none. After the resistive solve, each clamp becomes a source of that voltage in series with its on-resistance, pointing the way the resistive solve sends current through it (a Norton current pair on its two nodes), and the network is solved again: max_voltage reads that pin voltage, clamp_it2 each clamp's own current; max_resistance stays the resistive path's. A clamp the offsets would drive backwards refuses the row (not modelled). C8 stays partial: a protected device's own terminal voltages and a snapback trigger before conduction are not read (catalog notes). Tests (SY, CF, every symmetry): the down diode alone reads 1.33 A x 2.5 ohm + 700 mV = 4025 mV; an up diode and a rail clamp read 3360 mV to VDD (one offset) and 5390 mV to VSS (two), each swept a part in a thousand. Breaks if the offset is added once per pair instead of per clamp crossed (the VSS case reads 4690), or with the wrong sign. Nightly-depth fixtures and the ERC oracle differentials (KLayout, OpenROAD, PDNSim, Yosys) pass locally.
…bias it (X4)
ERC-D5 chose aggressors by pad connection or layer only. GF180MCU
14.3.2 defines the injection by voltage ("P+ COMP potential exceeding
Vdd ... N+ COMP potential below Ground") and the open CVC checker tests
it from propagated minimum and maximum voltages.
latchup_victim gains bias: layer | none and forward: above | below |
none: with them an aggressor is chosen only when its net can rise above
(or fall below) the voltage of the bias polygon it lies in, by
NetVoltage; such a row needs intent. gf180's IO rows and the test decks
state bias: none. D5 stays partial: the whole victim polygon is held to
the limit, which IO.1 (b) leaves open.
Tests (SY, every symmetry): a pdiff on VDDH in a VDD well is an
aggressor (flagged), on VDD is not, outside any well is not, a VSS
diffusion with forward: below is; no intent skips. Full workspace,
catalog, clippy (no new findings) and docs pass locally.
Contributor
Author
|
Landed on verification-hardening (rebased onto H12b; workspace tests run locally). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Round 2 of the ERC catalog: every partial or missing ERC row outside H13's system ESD, implemented where public sources define it (rustdoc cites the source, fixtures, a second oracle, deck-library parity, catalog row), recorded in the catalog and limitations.md where they do not. Per-row commits.