contact/via DRC : min enclosure on 2 opposite sides


How to write a DRC check for contact/via with a minimum enclosure on at least 2 opposite side ?
For instance, a via has to be enclosed by metal by 0.01µm on 2 opposite sides and can be 0 or whatever positive value on the2 other sides.

Best regards,


  • edited March 2019

    Hi Laurent,

    there is no out-of-the-box function yet, but there are several solutions based on the available features.

    I hope this code explains two of them:

    report("Via enclosure demo")
    via = input(5)
    metal = input(1)
    # this ensures there is no "negative" enclosure
    (via - metal).output("Via needs metal")
    # select those via edges (or parts) with less enclosure
    via_edges_with_less_enclosure = metal.enclosing(via, 10.nm, projection).second_edges
    # Option 1:
    # we know that via's are of a dimension so we can use "width"+"projection" to select
    # opposite edges (here: via size =
    good_via_edges = via.edges - via_edges_with_less_enclosure
    opposite = good_via_edges.width( + 1.dbu, projection).polygons
    solution1 = via.not_interacting(opposite)
    solution1.output("Min enclosure 10nm on at least two opposite edges - solution 1")
    # Option 2:
    # (does not need a value for the via size):
    # There is a problem if two edges with different orientation 
    # touch. There is no "interact" on the same edge set yet, but
    # you can use "width" with an "ignore_angle" of more than 90
    # degree to detect such touching corners:
    error_corners = via_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu)
    solution2 = via.interacting(error_corners.polygons(1.dbu))
    solution2.output("Min enclosure 10nm on at least two opposite edges - solution 2")

    Best regards,


  • Hi all,
    I see 4 ways to satisfy contact / via enclosure rule (as shown below). I am trying to write a DRC check for contact / via with enclosure but I have not thought of a way to check these 4 cases. Can you help me ?
    Thank you so much

  • Have you tried to options mentioned in my first reply?


  • Hi Matthias,
    I tried to options mentioned in your first reply. But it does not cover 2 case that I circle below.

    Best regards,


  • edited September 2020


    Maybe you need to explain what's the expected outcome.

    I rebuilt your sample (file attached) and with the script above I get this result:

    which looks perfectly fine to me. According to your description only the rightmost one violates the rule because it's the one where only one side encloses the via more than 10nm.


  • Hi sir,
    Sorry for my ambiguity. According to rules file, I can draw metal enclose via by 2 ways: (enclosure 4 edge >= 0.02 um) or (2 opposite sides> = 0.025um, other 2 edges> = 0.005um)

    I have created the wrong case in the attachment.

    Thanks sir

  • Hi Nam,

    Here is the way I have encoded it and used for some time in an other process, so I have adjusted the sizes to your process :

    cont_edges_with_less_enclosure = metal1.enclosing(cont, 0.025, projection).second_edges.extents(0.0125)
    contwithout025 = cont.interacting(cont.not(cont_edges_with_less_enclosure).with_area(nil,0.003))
    cont.interacting((metal1.enclosing(contwithout025, 0.02, euclidian).polygons).or(metal1.enclosing(cont, 0.005, euclidian).polygons)).output("M1_enc_CO", "Metal1 enclosing Contact : enclosure 4 edges >= 0.02 um or 2 opposite sides> = 0.025um with other 2 edges> = 0.005um")

    I cannot remember exactly the layout case that push me to add "with_area" during the debug, but I guess it was to find the opposite edges.
    Maybe, our master Matthias has a more efficient way to code it ;) ?


  • I wish I had ...

    I am considering the code a special option inside the enclosure check. I think that is basically the most efficient way. I'm just wondering how much variations there are and how flexible such an option has to be.

    Best regards,


  • hi laurent_c
    I tried with yours but it wrong flag as like this picture:
    1: should be not flag.
    2: should be flag.

    can you find out why?

    Thank you in advance.

  • edited February 2021

    Hi dai,

    I think you need to adjust the values according to your process.

    You can always debug such kind of code by emitting intermediate layers as debug output. There are many solutions sketched in the discussion above. Try them and pick the one that works for you.

    I have added now a built-in option to code this case without any coding around. It's going to be released in 0.27. You can give it a try with the continuous builds:

    The notation will be like this:

    enc = l1.enclosing(l2, 0.025, not_opposite, projection)


  • Thank your helping, Matthias
    I have done this. here is what i did:

    via = input(5)
    metal = input(1)
    # this ensures there is no "negative" enclosure
    (via - metal).output("Via needs metal")
    via_edges_with_less_enclosure_025 = metal.enclosing(via, 25.nm, projection).second_edges
    via_edges_with_less_enclosure_0005 = metal.enclosing(via, 5.nm, projection).second_edges
    good_via_edges = via.edges - via_edges_with_less_enclosure_025
    en_c0 = via.interacting(via_edges_with_less_enclosure_0005)
    en_c1 = via.interacting(metal.enclosing(via, 20.nm, projection).polygons)
    en_c2 = via.interacting(metal.enclosing(via, 5.nm).polygons)
    opposite = good_via_edges.width( + 1.dbu, projection).polygons
    en_c3 = via.not_interacting(opposite)
    en_c3.interacting(en_c1).or(en_c0).output("M1_enc_CO", "Metal1 enclosing Contact : enclosure 4 edges >= 0.02 um or 2 opposite sides> = 0.025um with other 2 edges> = 0.005um")


  • Hi Matthias,
    I don't know how to use layer.each { |object| ... }
    can you give me an example about this?

    Thank you very much

  • Hi Dai,

    It allows you to do "something" with each object (data structure) on that layer, for instance if you want to extract only the squares of a layer to a new layer:

    Layer01 = input(1,0)
    Layer02 = polygon_layer # new empty layer

    Layer01.rectangles.each {|rectangle|

    if rectangle.bbox.height == rectangle.bbox.width







  • Thank you very much, Tomas


  • Is there a way to use the waivers options like for the separation check ?

    For example, for 2 opposite sides :

    METAL.enclosing(VIA, 0.01, projection, one_side_allowed, two_sides_allowed).output("METAL_enc_VIA", "rule xy : Min. Metal enclosing Via (on 2 opposite sides) : 0.01um")

    For example, for only 1 side :

    METAL.enclosing(VIA, 0.01, projection, one_side_allowed, two_sides_allowed, three_sides_allowed).output("METAL_enc_VIA", "rule xz : Min. Metal enclosing Via (on at least 1 side) : 0.01um")

    I have tried the second one, but it does not work ...


  • Hi Laurent,

    first of all the rectangle filters work only this way round:

    VIA.enclosed(METAL, 0.01, ...)

    The reason is that filtering happens when rectangle edges are fully flagged. If you check via vs. metal, the via rectangle's edges are flagged along their whole length while in the "metal.enclosing(via, ...)" case, the metal edges are only partially flagged.

    Second unfortunately the options cannot be combined. The last one will basically win. So you'd need something like "one_to_three_sides_allowed", but such an option is not available yet :(


  • Hi Matthias,

    Thank you, then the method for the second case becomes :

    VM1 = VIA.enclosed(METAL, 0.01, projection, one_side_allowed)
    VM2 = VIA.enclosed(METAL, 0.01, projection, two_sides_allowed)
    VM3 = VIA.enclosed(METAL, 0.01, projection, three_sides_allowed)
    VIA.enclosed(METAL, 0.01, projection).edges.not((VM1+VM2+VM3).edges).output("METAL_enc_VIA", "rule xz : Min. Metal enclosing Via (on at least 1 side) : 0.01um")

    The first case is then also easy to write. It is probably faster than the methods at the top this discussion.


  • edited March 15

    I am slightly confused now ...

    Actually, the comma way of adding rectangle filters is already there and seems to work. I just missed it.


    via.enclosed(metal, projection, 20.nm, one_side_allowed, two_sides_allowed, three_sides_allowed).output("Metal enclosing via > 20nm at least on one side")

    gives this:

    Which means it flags only the case where there isn't a single enclosure larger than the threshold.

    So I wonder if there is another issue I don't see as of now.


Sign In or Register to comment.