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)")