Repository navigation
Conversation
…does (X1)
DRC-015 listed LEF58_WIDTHTABLE's open-ended last width as missing:
allowed_width held every listed width exactly. The LEF/DEF 5.8 Language
Reference ("Width Table Rules") says "all the given widths are exact
width values, except for the last one, which is equal to or greater
than the value", and its Figure 1-32 admits 0.42 under a last 0.40
unless MAXWIDTH 0.40 is also given.
width(L; allowed: [..], open_last: true) is a second form of
allowed_width: a figure's narrowest width must equal a listed width or
be at least the last one. The plain form is unchanged. The deck library
carries it: RuleRow::open_last on the allowed_width constructor, the
decompiler writes open_last only when set, and the query
allowed_widths_from gives the width from which every width is legal.
The KLayout mirror keeps the last with_width2 range open.
The fracture into rectangles stays missing, now with the reason: LEF
names no method (Figure 1-32 only shows an L's two arms) and OpenROAD's
TritonRoute reads only an ORTHOGONAL table's first width, so
WRONGDIRECTION, which needs a wire's direction from that fracture, is
missing too (catalog DRC-015 notes; AllowedWidth's Limits).
Tests and oracles:
- tests/exhaustive (DRC-015): bars swept one step around 100 (exact) and
200 (open), a 1000 square, a 150 square between the two, an L of an
exact and a wide arm; the LEF text, under all eight symmetries at two
offsets. Breaks if the last width is read exactly (201 and the wide
square fail) or if the open end leaks below it (199 passes).
- crates/check/tests/deck/kinds.rs: the open form in text and in Rust,
equal decks, the printer round trip, and allowed_widths_from (150 on
the open list, none on the exact one), oracle the deck text.
… as LEF58 wrong-direction spacing does (X1) DRC-016 left the PRL and NONEOL qualifiers of LEF58_SPACING ... WRONGDIRECTION missing. No public LEF text defines them; OpenROAD's TritonRoute checks them in checkMetalSpacing_wrongDir: the edges whose orientation is not the layer's, either one shorter than the NONEOL width skipped, a pair exempt when its projections overlap by at most PRL (a positive overlap at the default 0), and a violation when the two segments are closer than the spacing. facing_space(E; prl: len) >= len is a second form of edge_facing_space that judges only pairs overlapping by more than prl. NONEOL needs nothing new: the edge layer already selects by length, so the LEF58 rule SPACING 0.12 WRONGDIRECTION NONEOL 0.15 PRL 0.1 on a horizontal layer is facing_space(met1.edges().vertical().with_length(>= 150nm); prl: 100nm) >= 120nm. The deck library carries it (RuleRow::prl, the decompiler writes prl only when positive), and the KLayout mirror adds projection_limits(2 prl + 1, nil). LENGTH stays missing: no public text defines it and TritonRoute drops a rule that states it (DRT-333), as it drops a negative PRL (DRT-334). Tests and oracles: - tests/exhaustive (DRC-016): the gap swept around 120, the run around 100 and the edge length around 150, a tall bar facing a short one, two bars end to end and a diagonal pair, hand-derived from TritonRoute's reading, under all eight symmetries at two offsets with the layer's direction turned with the quarter turns. Breaks if the run is read as at-least (100 fails), if the length filter is ignored (149 fails), or if the gap is compared with <= (120 fails). - crates/check/tests/deck/kinds.rs: the run form in text and in Rust, equal decks and the printer round trip.
… as TritonRoute reads LEF58_MINSTEP (X1) DRC-020 left LEF58_MINSTEP's MINADJACENTLENGTH, MINBETWEENLENGTH, NOADJACENTEOL and NOBETWEENEOL missing. No public LEF text defines them. OpenROAD parses all four; TritonRoute checks two (checkMetalShape_lef58MinStep_minAdjLength and _noBetweenEol): - a short edge (under minStepLength) whose edge before or after is shorter than minAdjLength, or with NOADJACENTEOL is an end of line (both corners convex) shorter than eolWidth; EXCEPTRECTANGLE skips a figure whose outer ring has four corners; - a short edge, then an end of line under eolWidth, then a short edge. New kind min_step_adjacent, deck min_step(L; adjacent: len, except_rectangle: bool) >= len, the same with adjacent_eol: len, or min_step(L; between_eol: len) >= len, on the merged layer's rings, holes included. One finding per offending short edge, at the centre of the box of it and the edges judged with it, as TritonRoute marks it. StepNeighbour states the two forms. The deck library carries it (kind table, constructor, decompiler, printer); KLayout has no ring order, so the mirror reports it as not mirrored. MINADJACENTLENGTH's CONVEXCORNER, CONCAVECORNER and second length, MINBETWEENLENGTH with EXCEPTSAMECORNERS, and NOADJACENTEOL alone stay missing: OpenROAD parses them, TritonRoute never checks them, and no public text defines them (catalog DRC-020). Tests and oracles: - tests/exhaustive (DRC-020): a bump's top swept around 60 and its height around 50, a 40 x 56 rectangle with and without EXCEPTRECTANGLE, a tab's end of line and a tip's end swept around 120, each finding hand-derived from TritonRoute's two functions, under all eight symmetries at two offsets. Breaks if the neighbour test is <= (60 fails), if the short test is <= (50 fails), if EXCEPTRECTANGLE is ignored, or if an end of line is read without both convex corners (the tab's top would offend at every end). - crates/check/tests/deck/kinds.rs: the three forms in text and Rust, equal decks and the printer round trip.
…gged, as OpenROAD reads LEF58_MAXSPACING (X1) DRC-034 was missing: H1 found LEF58_MAXSPACING's grammar but no semantics. No public LEF text defines it; OpenROAD reads it in its router's repair pass (FlexDR::fixMaxSpacing, getLonelyVias): a via of the CUTCLASS is lonely when no other via cut on the layer, of any class or net, has its centre within the spacing (KDTree radius search, distance squared at most the spacing squared). TritonRoute's checker never reports it, so this reading is the only public one; the rustdoc and catalog say so. New kind max_cut_spacing, deck max_space(C) <= len, or max_space(C, A) <= len for a class C selected out of the cut layer A, whose neighbours are A's cuts other than its own box. Cuts are drawn rows read by their box centres (summed sides, so half-unit centres are exact). One finding per lonely cut at its centre, measuring the nearest centre distance rounded up, or a count of 0 against 1 when the layer has no other cut. The deck library carries it, and the KLayout mirror is scripted (EXACT, keyed by the cut's box). Tests and oracles: - tests/exhaustive (DRC-034): two cuts 999, 1000 and 1001 apart, a 600 x 800 and a 600 x 801 diagonal, a lone cut, a chain 1000 then 1500 apart, and with a class a big cut near, far from and without a small one; centres by construction, under all eight symmetries at two offsets. Breaks if the comparison is strict (1000 fails), if the distance is per axis (the 801 diagonal passes), or if a class cut finds itself on the whole layer (the lone big cut passes). - crates/check/tests/deck/kinds.rs: both forms in text and Rust, equal decks and the printer round trip.
…ws no public source defines say why (X1)
Four rows' gaps are written with existing kinds once read the way the
foundry's own public deck reads them; each is now a fixture:
- DRC-051, sky130 difftap.6 ("diff and tap are not allowed to extend
beyond their abutting edge"): the butting edge lengthened 1 grid past
each end with .extended() and checked for diff or tap there, as
open_pdks sky130.lydrc codes it (it extends 0.01 past both ends).
- DRC-044, IHP Rppd.c's maximum ("min. and max. SalBlock space to Cont
0.20"): a contact not touching the band 200 either side of a SalBlock
edge, as IHP's sg13g2_maximal.drc codes it. Row implemented; GF180
NP.3d's maximum of 0 is GF's own no-overlap check.
- DRC-031, ASAP7 M4.S.3 (tip to tip on adjacent tracks, no common run,
40): lines on adjacent tracks are 24 apart, so the larger axis gap of
their facing corners is the tip gap, convex_corner_spacing at 40.
M4.S.4 stays missing: lines that share a run have no tips facing.
- DRC-064, IHP CntB bars: "any Cont shape not being a square shape is
considered a ContBar", so cont.non_squares() holds bars of any length
and CntB.b, b1, b2 are space, prl_space and space on it. Implemented.
DRC-045 is implemented: a bent gate or a stub inside diffusion measures
0, which is what every foundry requires (IHP Gat.f, GF180 PL.6, sky130
poly.11 forbid bent gates; IHP's deck flags GatPoly inside Activ under
Gat.c).
Rows whose remaining gap has no public definition say so, with what was
checked: DRC-021 (a bent feature's path length: IHP's deck checks a
width, sky130's mf.2 code is near vacuous), DRC-027 (a negative
TWOWIDTHS run: LEF defers to an undefined PARALLELRUNLENGTH reading and
TritonRoute clamps it, a documented difference; LEF58_SPACINGTABLE's
qualifiers are parsed, never checked), DRC-042 (LEF58_ENCLOSURE EOL is
used by OpenROAD only to generate vias), DRC-053 (EXACTALIGNED has no
parser for metal and is skipped for cuts), DRC-055 (open_pdks KLayout
and Magic read lvtn.3b's direction and distance differently: a
documented implementation difference).
Tests and oracles: tests/exhaustive foundry_expressions, each limit
swept one step either side under all eight symmetries at two offsets,
values from the foundry text and the decks quoted in its doc: breaks
if extended() drops its ends (difftap.6 taller passes), if interacting
excludes touching (Rppd.c at 200 fails), if the corner metric is
Euclidean (M4.S.3 at 40 fails at 39 only by sqrt), or if non_squares
keeps squares (CntB.b2's square would be a bar). The crate rule
reference cites the rows that now name min_spacing, prl_spacing,
min_spacing_diff and convex_corner_spacing.
…an, as LEF58 EXCEPTOTHERSPAN does (X1) DRC-036 left SPANLENGTHTABLE's EXCEPTOTHERSPAN missing. The LEF/DEF 5.8 text defines it: "the span length rule only applies if the span length on the perpendicular direction is greater than the specified otherSpanlength. This construct must be defined on a layer with RECTONLY." span_length(L; x: [..], y: [..], x_except: len | none, y_except: len | none) carries one exception per list (SpanTable::x_except, y_except): a rectangle's horizontal span is held on x only when its height exceeds x_except, its vertical span on y only when its width exceeds y_except. Any other figure, which LEF leaves undefined, is held with no exception (fails closed). The deck library carries it (RuleRow::except_other, the decompiler writes only the stated exceptions, the printer writes none for the other). ORTHOGONAL stays missing: LEF's "length between two inside facing corners" names no measure, and OpenROAD does not parse the property. Tests and oracles: - tests/exhaustive (DRC-036): a 150 wide rectangle with its height swept around 200 (its 150 held only above 200, its height always) and an L held with no exception; the LEF text, under the symmetries that keep the axes. Breaks if the exception is >= (200 holds the 150), if it applies to the wrong list, or if non-rectangles are exempted. - crates/check/tests/deck/kinds.rs: the exception form in text and in Rust, equal decks and the printer round trip.
…7 is written (X1)
DRC-007 had pin-in-drawing only: a floating label had no rule (one on a
declared net-label layer aborts extraction, which is LVS's concern) and
pin centre spacing was "not expressible".
New derived operation T.texts_outside(L) (DerivedOp::TextsOutside):
each TEXT drawn on the GDS layer T whose anchor lies on no shape of L,
neither on its material nor on its edge, as a one-grid-unit box from
the anchor up and right. forbidden of it is sky130 x.17 ("all labels
must be within the drawing polygons of the layer"), as KLayout's
texts.not_interacting(L). Parser, printer, source checks (T must be a
drawn layer), the Rust builder (LayerExpr::texts_outside, forwarded on
LayerRef) and the KLayout mirror (texts(pattern("*")).not_interacting(
L).extents.moved(1, 1), probed against KLayout 0.30.8: extents makes
a 2 x 2 box centred on the text) carry it.
sky130 x.20 ("min spacing between pins on the same layer, center to
center") is space(pin, center) >= len with its value deck-supplied:
the public manual's value cell is empty and no public deck codes it.
x.5 and IHP Pin.a-h are inside(pin, drawing). DRC-007 is implemented.
Tests and oracles:
- tests/exhaustive floating_labels (DRC-007): a label inside, on the
edge and on the corner of a plate (clean), one unit past its edge, in
a ring's hole and on the hole's edge, two labels at one floating
point; two pins with centres 499, 500 and 501 apart. The rule text,
points by construction, all eight symmetries at two offsets. Breaks
if the boundary is outside (on_edge flags), if holes are material
(in_hole passes) or if texts at one point collapse to one box.
- The KLayout mirror agrees on every exhaustive fixture (local run of
the_exhaustive_drc_fixtures_agree_with_the_klayout_mirror).
- crates/check/tests/deck/kinds.rs: the operation in text and in Rust,
equal decks and the printer round trip.
…LEF MINIMUMCUT LENGTH WITHIN says (X1) DRC-066 left MINIMUMCUT's LENGTH length WITHIN distance form missing. LEF/DEF 5.8 defines it: the rule "applies for thin wires directly connected to wide wires, if the wide wire has a width that is greater than width and a length that is greater than length, and the vias on the thin wire are less than distance from the wide wire", and "does not check the wide wire itself" (Example 1-14, Figure 1-11). min_cuts(cut, wide, other; width: len, length: len, distance: len) >= n, with or without within:, is a form of minimum_cut (field thin). A wide wire is a connected region of the wide part (where a width + 1 square fits) whose box's longer side exceeds length; a via is held when none of its cuts lies on the wide part, its wide figure is the wire's (directly connected), and a cut's box is closer than distance to the wire. The query minimum_cuts leaves these rows out (they hold the thin wires, not the wire). The deck library carries it (RuleRow::thin_wires), and the scripted KLayout mirror takes the same reading. LEF58_MINIMUMCUT's CUTCLASS is the rule on a class's cut layer; its AREA, SAMEMETALOVERLAP and FULLYENCLOSED have no public definition (absent from LEF 5.8, skipped by TritonRoute) and stay missing. Tests and oracles: - tests/exhaustive minimum_cut_thin (DRC-066): LEF's Example 4 scaled by a tenth, a stub off a bar with a one-cut via; the distance swept around 500, the bar's length around 2000 and its height at 110/111, a via on the bar, a two-cut via and a wire not joined to the bar; the LEF text, all eight symmetries at two offsets. Breaks if any bound is read inclusively, if the wide wire's own vias are held, or if a wire of another figure counts as joined. - The KLayout mirror agrees on every exhaustive fixture (local run). - crates/check/tests/deck/kinds.rs: the form in text and Rust, equal decks and the printer round trip.
…ts are exempt from cross-layer spacing, as LEF says (X1) DRC-065 had two gaps, both defined by the LEF/DEF 5.8 text: - MAXVIASTACK counts "single-cut stacked vias ... A double-cut or larger via interrupts the stack", but via_stack counted every cut, so it read a stack LEF splits as one (failing closed). - SPACING cutSpacing [SAMENET] LAYER second STACK: "same-net cuts on two different layers can be stacked if they are aligned. If the cuts are not the same size, the smaller cut must be completely covered by the larger cut ... If both cuts are the same size, the centers of the cuts must be aligned ... otherwise, the cuts must have cutSpacing between them" was not modelled. via_stack(m1, cut1, m2, cut2, .., mN, single) <= n names the metals between the cuts (Rule::ViaStack single): a via is the cuts on one layer joining one figure below to one above, and a cut of a via of two or more stacks with nothing. The plain form is unchanged. The query max_via_stack skips the metals of a single-cut stack. New kind stack_spacing, deck stack_space(A, B) >= len or with same_net: true (SAMENET): a cut on A and one on B closer than the limit (overlap 0) unless they are one net's and one box covers the other (equal boxes are aligned centres). Nets come from extraction, through net_pair_spacing's walk, now given each shape's row beside its net (net_row_spacing). The KLayout mirror extracts no per-cut nets, so it reports stack_spacing as not mirrored; via_stack's scripted mirror drops the cuts of multi-cut vias. DRC-065 is implemented. Tests and oracles: - tests/exhaustive via_stack_single: LEF's own example (single via12, via23, double via34, single via45: heights 2 and 1, legal at 2), three single cuts (3 reported), the middle via doubled (no stack), a cut alone on its metal pad (still single, 4 reported). Breaks if every cut is a single via (the LEF example reads 4). - tests/exhaustive stack_spacing: aligned and covered same-net cuts (legal), half-offset equal cuts (0), a gap swept around 200, and two nets 150 apart held by the plain form only; the LEF text, all eight symmetries at two offsets. Breaks if overlap is exempt without coverage or if SAMENET is ignored. - The KLayout mirror agrees on every exhaustive fixture it mirrors (local run). - crates/check/tests/deck/kinds.rs: both forms in text and Rust, equal decks, the printer round trip, and max_via_stack(m) still none.
…on (X1) The stack_spacing rule of the previous commit judged a pair's nets with NetTable::net_of on the cut rows, but extraction gives a cut no net of its own (only conductor and global shapes have one), so every rule on two cut layers was Refused. The fixtures for it did not run in that commit's local check. stack_space(A, B, M) >= len now names the metal both cut layers land on (metal2 for LEF's cut23 over cut12): each cut takes the lowest net of the M shapes it overlaps, a cut on no M shape is on no net and stacks with nothing. The rule validates and pairs its layers itself, so the base's net_pair_spacing is unchanged again. The rebase on the base also writes the plain via_stack row's implied `single=false` into its parsed parameters, which deck_text now expects. Tests and oracles: tests/exhaustive stack_spacing (the LEF text, as before, now through M) runs and holds under all eight symmetries; breaks if a cut's net is read off its own row (Refused) or if a cut on no metal counts as one net with another. crates/check/tests/deck/kinds states the three-layer form in text and Rust.
…t, as OpenROAD reads LEF58_METALWIDTHVIAMAP (X1) DRC-067 was missing: H2 judged the metal-width via map too router- specific to define. No public LEF text defines it, but OpenROAD does: MetalWidthViaMapParser reads `VIA cutLayer w1 w2 [w3 w4] viaName` as the via to use where the metal below is w1 wide and above w2 (or below in [w1, w2] and above in [w3, w4]), and TritonRoute's checkMetalWidthViaTable_main flags a cut on such wires whose box is not that via's cut box. New kind metal_width_via, deck via_map(C, B, A; below_min, below_max, above_min, above_max, cut: w x h): a drawn cut on a B wire and an A wire whose widths lie in their bands (read as an enclosure's WIDTH band: the part where a min-wide square fits covers the cut, the part where a max + 1 square fits does not) must be a w x h box, either way round. The deck library carries it, and the KLayout mirror is scripted (EXACT, keyed by the cut's box). A documented difference: TritonRoute passes above=true to both of its metal lookups, so it never compares the metal below, and it reads a width off maximal rectangles; this rule holds both metals, as the parser's grammar states. PGVIA and USEVIACUTCLASS are not read, as TritonRoute does not read them. DRC-067 is implemented. Tests and oracles: - tests/exhaustive metal_width_via (DRC-067): OpenROAD's own test entry `VIA via1 0.5 0.8 M2_M1_via` scaled by a tenth, and a range entry with a 30 x 40 cut; the mapped cut, its turned form, a 40 x 40 cut with the lower wire swept around 50 and the upper around 80, and a cut off the wires; the parser's grammar, all eight symmetries at two offsets. Breaks if a band edge is exclusive (50 or 80 passes), if the cut is compared one way round only (the turned cut fails), or if the metal below is ignored, as TritonRoute's check does (49 fails). - crates/check/tests/deck/kinds.rs: the kind in text and Rust, equal decks and the printer round trip.
… as LEF EXCEPTEXTRACUT says (X1) Unfinished, stopped on request. DRC-043's LEF ENCLOSURE ... WIDTH minWidth EXCEPTEXTRACUT cutWithin: MinEnclosure and AsymmetricEnclosure gain extra_cut: Option<ExtraCut> (within, other metal); deck form enclosure(cut, metal; width: len, except_extra_cut: len, other: layer) (kinds rows WIRE_EXTRA); overlay::redundant_cuts exempts a cut with another cut on the same two metal figures at most cutWithin away; decompiler, builder (RuleRow::except_extra_cut) and layers() updated. Known not done / possibly broken: not compiled after the last two textual fixes (bbox_gap2 import, AdjacentEnclosure's enclosure call); tests/klayout/translate.rs and query.rs patterns for MinEnclosure / AsymmetricEnclosure and the struct literals in crates/check/tests/drc/overlay_rules.rs still lack the new field; no fixture, mirror, docs or catalog change yet for DRC-043.
Contributor
Author
|
Landed on verification-hardening without its uncompiled DRC-043 WIP commit (filed as an issue); rebased over X2's spacing core; 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 X1: every DRC row DRC-001..069 that is partial or missing (except DRC-002, 037, 038, which are H12's). Each row gets what public sources define (LEF/DEF 5.8 text, OpenROAD lefin/TritonRoute, foundry manuals and decks), with fixtures under all eight symmetries, a KLayout mirror where KLayout can express it, the deck-library parity, and the catalog row; what no public source defines is recorded with the reason in the catalog notes and limitations.md.