update Klayout MR DRC deck
diff --git a/sky130/klayout/sky130A_mr.drc b/sky130/klayout/sky130A_mr.drc
index e01de04..96fa34e 100755
--- a/sky130/klayout/sky130A_mr.drc
+++ b/sky130/klayout/sky130A_mr.drc
@@ -26,20 +26,34 @@
backend_flow = AL
# enable / disable rule groups
-if $feol == "0"
- FEOL = false # front-end-of-line checks
+if $feol == "1" || $feol == "true"
+ FEOL = true # front-end-of-line checks
else
- FEOL = true # front-end-of-line checks
+ FEOL = false
end
-if $beol == "0"
- BEOL = false # back-end-of-line checks
+
+if $beol == "1" || $beol == "true"
+ BEOL = true # back-end-of-line checks
else
- BEOL = true # back-end-of-line checks
+ BEOL = false
end
-if $offgrid == "0"
- OFFGRID = false # manufacturing grid/angle checks
+
+if $offgrid == "1" || $offgrid == "true"
+ OFFGRID = true # manufacturing grid/angle checks
else
- OFFGRID = true # manufacturing grid/angle checks
+ OFFGRID = false
+end
+
+if $seal == "1" || $seal == "true"
+ SEAL = true # SEAL RING checks
+else
+ SEAL = false
+end
+
+if $floating_met == "1" || $floating_met == "true"
+ FLOATING_MET = true # back-end-of-line checks
+else
+ FLOATING_MET = false
end
# klayout setup
@@ -241,7 +255,7 @@
diff_width = diff.rectangles.width(0.15, euclidian).polygons
diff_cross_areaid_ce = diff_width.edges.outside_part(areaid_ce).not(diff_width.outside(areaid_ce).edges)
diff_cross_areaid_ce.output("difftap.1", "difftap.1 : min. diff width across areaid:ce : 0.15um")
-diff.not(areaid_ce).width(0.15, euclidian).output("difftap.1_a", "difftap.1_a : min. diff width in periphery : 0.15um")
+diff.outside(areaid_ce).width(0.15, euclidian).output("difftap.1_a", "difftap.1_a : min. diff width in periphery : 0.15um")
log("END: 65/20 (diff)")
log("START: 65/44 (tap)")
@@ -285,8 +299,12 @@
# licon
log("START: 66/44 (licon)")
-ringLICON = licon.drc(with_holes > 0)
-rectLICON = licon.not(ringLICON)
+if SEAL
+ ringLICON = licon.drc(with_holes > 0)
+ rectLICON = licon.not(ringLICON)
+else
+ rectLICON = licon
+end
xfom = difftap.not(poly)
licon1ToXfom = licon.interacting(licon.and(xfom))
licon1ToXfom_PERI = licon1ToXfom.not(areaid_ce)
@@ -333,7 +351,7 @@
linotace = li.not(areaid_ce)
linotace.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um")
# This rule is taking a long time in some slots
-linotace.space(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um")
+linotace.edges.space(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um")
licon_peri = licon.not(areaid_ce)
li_edges_with_less_enclosure = li.enclosing(licon_peri, 0.08, projection).second_edges
error_corners = li_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu)
@@ -345,17 +363,23 @@
# ct
log("START: 67/44 (mcon)")
mconnotace = mcon.not(areaid_ce)
-ringMCON = mcon.drc(with_holes > 0)
-rectMCON = mcon.not(ringMCON)
+if SEAL
+ ringMCON = mcon.drc(with_holes > 0)
+ rectMCON = mcon.not(ringMCON)
+else
+ rectMCON = mcon
+end
rectMCON_peri = rectMCON.not(areaid_ce)
rectMCON.non_rectangles.output("ct.1", "ct.1: non-ring mcon should be rectangular")
# rectMCON_peri.edges.without_length(0.17).output("ct.1_a/b", "ct.1_a/b : minimum/maximum width of mcon : 0.17um")
rectMCON_peri.drc(width < 0.17).output("ct.1_a", "ct.1_a : minimum width of mcon : 0.17um")
rectMCON_peri.drc(length > 0.17).output("ct.1_b", "ct.1_b : maximum length of mcon : 0.17um")
mcon.space(0.19, euclidian).output("ct.2", "ct.2 : min. mcon spacing : 0.19um")
-ringMCON.width(0.17, euclidian).output("ct.3", "ct.3 : min. width of ring-shaped mcon : 0.17um")
-ringMCON.drc(width >= 0.175).output("ct.3_a", "ct.3_a : max. width of ring-shaped mcon : 0.175um")
-ringMCON.not(areaid_sl).output("ct.3_b", "ct.3_b: ring-shaped mcon must be enclosed by areaid_sl")
+if SEAL
+ ringMCON.width(0.17, euclidian).output("ct.3", "ct.3 : min. width of ring-shaped mcon : 0.17um")
+ ringMCON.drc(width >= 0.175).output("ct.3_a", "ct.3_a : max. width of ring-shaped mcon : 0.175um")
+ ringMCON.not(areaid_sl).output("ct.3_b", "ct.3_b: ring-shaped mcon must be enclosed by areaid_sl")
+end
mconnotace.not(li).output("ct.4", "ct.4 : mcon should covered by li")
log("END: 67/44 (mcon)")
@@ -385,6 +409,9 @@
m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²")
m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 with holes area : 0.14um²")
+if FLOATING_MET
+ m1.not_interacting(via.or(mcon)).output("m1.x", "floating met1, must interact with via1")
+end
if backend_flow = AL
#Could flag false positive, fix would be to add .rectangles for m1
@@ -398,8 +425,13 @@
# via
log("START: 68/44 (via)")
if backend_flow = AL
- ringVIA = via.drc(with_holes > 0)
- rectVIA = via.not(ringVIA)
+ if SEAL
+ ringVIA = via.drc(with_holes > 0)
+ rectVIA = via.not(ringVIA)
+ else
+ rectVIA = via
+ end
+
via_not_mt = rectVIA.not(areaid_mt)
via_not_mt.non_rectangles.output("via.1a", "via.1a : via outside of moduleCut should be rectangular")
@@ -409,10 +441,11 @@
via.space(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um")
- ringVIA.width(0.2, euclidian).output("via.3", "via.3 : min. width of ring-shaped via : 0.2um")
- ringVIA.drc(width >= 0.205).output("via.3_a", "via.3_a : max. width of ring-shaped via : 0.205um")
-
- ringVIA.not(areaid_sl).output("via.3_b", "via.3_b: ring-shaped via must be enclosed by areaid_sl")
+ if SEAL
+ ringVIA.width(0.2, euclidian).output("via.3", "via.3 : min. width of ring-shaped via : 0.2um")
+ ringVIA.drc(width >= 0.205).output("via.3_a", "via.3_a : max. width of ring-shaped via : 0.205um")
+ ringVIA.not(areaid_sl).output("via.3_b", "via.3_b: ring-shaped via must be enclosed by areaid_sl")
+ end
m1.edges.enclosing(rectVIA.drc(width == 0.15), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um")
rectVIA.squares.drc(width == 0.15).not(m1).output("via.4a_a", "via.4a_a : 0.15um via must be enclosed by met1")
@@ -440,7 +473,9 @@
m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²")
m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²")
-
+if FLOATING_MET
+ m2.not_interacting(via.or(via2)).output("m2.x", "floating met2, must interact with via1 or via2")
+end
if backend_flow = AL
m2.enclosing(via_outside_periphery, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um")
via_outside_periphery.not(m2).output("m2.4_a", "m2.4_a : via in periphery must be enclosed by met2")
@@ -455,16 +490,25 @@
# via2
log("START: 69/44 (via2)")
if backend_flow = AL
- ringVIA2 = via2.drc(with_holes > 0)
- rectVIA2 = via2.not(ringVIA2)
+ if SEAL
+ ringVIA2 = via2.drc(with_holes > 0)
+ rectVIA2 = via2.not(ringVIA2)
+ else
+ rectVIA2 = via2
+ end
+
via2_not_mt = rectVIA2.not(areaid_mt)
via2_not_mt.non_rectangles.output("via2.1a", "via2.1a : via2 outside of moduleCut should be rectangular")
via2_not_mt.width(0.2, euclidian).output("via2.1a_a", "via2.1a_a : min. width of via2 outside of moduleCut : 0.2um")
via2_not_mt.edges.without_length(nil, 0.2 + 1.dbu).output("via2.1a_b", "via2.1a_b : maximum length of via2 : 0.2um")
via2.space(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um")
- ringVIA2.width(0.2, euclidian).output("via2.3", "via2.3 : min. width of ring-shaped via2 : 0.2um")
- ringVIA2.drc(width >= 0.205).output("via2.3_a", "via2.3_a : max. width of ring-shaped via2 : 0.205um")
- ringVIA2.not(areaid_sl).output("via2.3_b", "via2.3_b: ring-shaped via2 must be enclosed by areaid_sl")
+
+ if SEAL
+ ringVIA2.width(0.2, euclidian).output("via2.3", "via2.3 : min. width of ring-shaped via2 : 0.2um")
+ ringVIA2.drc(width >= 0.205).output("via2.3_a", "via2.3_a : max. width of ring-shaped via2 : 0.205um")
+ ringVIA2.not(areaid_sl).output("via2.3_b", "via2.3_b: ring-shaped via2 must be enclosed by areaid_sl")
+ end
+
m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um")
via2.not(m2).output("via2.4_a", "via2.4_a : via must be enclosed by met2")
@@ -486,7 +530,9 @@
non_huge_m3.space(0.3, euclidian).output("m3.2", "m3.2 : min. m3 spacing : 0.3um")
(huge_m3.separation(non_huge_m3, 0.4, euclidian) + huge_m3.space(0.4, euclidian)).output("m3.3cd", "m3.3cd : min. 3um.m3 spacing m3 : 0.4um")
-
+if FLOATING_MET
+ m3.not_interacting(via2.or(via3)).output("m3.x", "floating met3, must interact with via2 or via3")
+end
if backend_flow = AL
m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um")
via2.not(m3).output("m3.4_a", "m3.4_a : via2 must be enclosed by met3")
@@ -496,9 +542,13 @@
# via3
log("START: 70/44 (via3)")
if backend_flow = AL
+ if SEAL
+ ringVIA3 = via3.drc(with_holes > 0)
+ rectVIA3 = via3.not(ringVIA3)
+ else
+ rectVIA3 = via3
+ end
- ringVIA3 = via3.drc(with_holes > 0)
- rectVIA3 = via3.not(ringVIA3)
via3_not_mt = rectVIA3.not(areaid_mt)
via3_not_mt.non_rectangles.output("via3.1", "via3.1 : via3 outside of moduleCut should be rectangular")
via3_not_mt.width(0.2, euclidian).output("via3.1_a", "via3.1_a : min. width of via3 outside of moduleCut : 0.2um")
@@ -528,7 +578,9 @@
m4.with_area(0..0.240).output("m4.4a", "m4.4a : min. m4 area : 0.240um²")
(huge_m4.separation(non_huge_m4, 0.4, euclidian) + huge_m4.space(0.4, euclidian)).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um")
-
+if FLOATING_MET
+ m4.not_interacting(via3.or(via4)).output("m4.x", "floating met3, must interact with via3 or via4")
+end
if backend_flow = AL
m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um")
via3.not(m4).output("m4.3_a", "m4.3_a : via3 must be enclosed by met4")
@@ -537,17 +589,26 @@
# via4
log("START: 71/44 (via4)")
-ringVIA4 = via4.drc(with_holes > 0)
-rectVIA4 = via4.not(ringVIA4)
+if SEAL
+ ringVIA4 = via4.drc(with_holes > 0)
+ rectVIA4 = via4.not(ringVIA4)
+else
+ rectVIA4 = via4
+end
+
via4_not_mt = rectVIA4.not(areaid_mt)
via4_not_mt.non_rectangles.output("via4.1", "via4.1 : via4 outside of moduleCut should be rectangular")
rectVIA4.width(0.8, euclidian).output("via4.1_a", "via4.1_a : min. width of via4 outside of moduleCut : 0.8um")
rectVIA4.drc(length > 0.8).output("via4.1_b", "via4.1_b : maximum length of via4 : 0.8um")
via4.space(0.8, euclidian).polygons.output("via4.2", "via4.2 : min. via4 spacing : 0.8um")
-ringVIA4.width(0.8, euclidian).output("via4.3", "via4.3 : min. width of ring-shaped via4 : 0.8um")
-ringVIA4.drc(width >= 0.805).output("via4.3_a", "via4.3_a : max. width of ring-shaped via4 : 0.805um")
-ringVIA4.not(areaid_sl).output("via4.3_b", "via4.3_b: ring-shaped via4 must be enclosed by areaid_sl")
+
+if SEAL
+ ringVIA4.width(0.8, euclidian).output("via4.3", "via4.3 : min. width of ring-shaped via4 : 0.8um")
+ ringVIA4.drc(width >= 0.805).output("via4.3_a", "via4.3_a : max. width of ring-shaped via4 : 0.805um")
+ ringVIA4.not(areaid_sl).output("via4.3_b", "via4.3_b: ring-shaped via4 must be enclosed by areaid_sl")
+end
+
m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um")
rectVIA4.not(m4).output("via4.4_a", "via4.4_a : m4 must enclose all via4")
log("END: 71/44 (via4)")
@@ -560,7 +621,9 @@
m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m5.3 : min. m5 enclosure of via4 : 0.31um")
via4.not(m5).output("m5.3_a", "m5.3_a : via must be enclosed by m5")
-
+if FLOATING_MET
+ m5.not_interacting(via4).output("m5.x", "floating met5, must interact with via4")
+end
m5.with_area(0..4.0).output("m5.4", "m5.4 : min. m5 area : 4.0um²")
log("END: 72/20 (m5)")