Device extracted at wrong level of hierarchy

tnttnt
edited October 2024 in Verification

Hi,

I'm trying to run LVS on a design using the iHP PDK.
( base script at https://github.com/IHP-GmbH/IHP-Open-PDK/blob/dev/ihp-sg13g2/libs.tech/klayout/tech/lvs/sg13g2_full.lylvs )

My issue is that the sg13g2_antennanp cell which contains two diodes ends up extracted wrongly.
For some reason the diodes end up in the top level cell rather than in the extraced sg13g2_antennanp subcell.

That of course makes LVS fail unless running in flat mode, or explicitly flattening that cell or excluding it from extraction all together.
But all those are work arounds, and I'd like to know why the issue arises in the first place and fix it.

Cheers,

Sylvain

Comments

  • edited October 2024

    Hi @tnt,

    I would need a simple example to debug the issue.

    There is a specific issue with extracting devices that may make devices appear on the wrong hierarchy level. Here is one related discussion: https://www.klayout.de/forum/discussion/comment/11290#Comment_11290

    In short, the problem is how devices are assembled over the hierarchy. If a device is stitched together from different parts (in the above example, the source and drain regions of the overlapping FETs), the device is "complete" only on the hierarchy level where these parts meet. As a consequence, the device will be created only at this level.

    It is a tricky question how to improve here. "Completeness" is a difficult topic. For example, it is not strictly required to collect the full drain and source areas - although they are listed in the extracted device parameters. But if the gate area is not complete, the device parameters will simply be wrong. Currently I assume that every region involved in the device recognition and extraction needs to be complete - i.e. all parts have to be collected to make the device "complete" and that defines the level of hierarchy where the device appears.

    I have tried to improve the code to handle such cases in a less strict way, but before I release that I'd like to test it one more examples.

    Is that helpful?

    Matthias

  • But the device isn't assembled over hierarchy. The sg13g2_antennanp is self contained. And actually running LVS on itself only works fine.

    I've attached an example.

  • edited October 2024

    Perfect. Thanks a lot! :)

    I was able to debug the problem and here is my conclusion: the problem comes from the computation of the recognition layers for dantenna and dpantenna devices. They are computed this way (lines 3532++ in the XML file):

    # ==== dantenna diode ====
    dantenna_n = activ.and(antenna_d_mk).not(psd_drw).not(nwell_drw)
    dantenna_p = pwell.and(antenna_d_mk).covering(dantenna_n)
    
    # ==== dpantenna diode ====
    dpantenna_p = pactiv.and(antenna_d_mk)
    dpantenna_n = nwell_drw.covering(dpantenna_p)
    

    First problem is that "dantenna_p" takes pwell as the first argument. As a general rule, KLayout's booleans use the first argument's hierarchy as reference. "pwell" is computed from the chip boundary, so eventually flat, hence the "dantenna_p" shapes are flat and this is why the device is "complete" only on top level of the hierarchy.

    Side note: to debug this, I added the following lines of code after this computation:

    debug = new_target("debug.gds")
    activ.output(debug, 1, 0)
    pwell.output(debug, 2, 0)
    dantenna_n.output(debug, 100, 0)
    dantenna_p.output(debug, 101, 0)
    

    This simple patch solves the issue:

    replace:
    dantenna_n = activ.and(antenna_d_mk).not(psd_drw).not(nwell_drw)
    dantenna_p = pwell.and(antenna_d_mk).covering(dantenna_n)
    
    by:
    dantenna_n = antenna_d_mk.and(activ).not(psd_drw).not(nwell_drw)
    dantenna_p = antenna_d_mk.and(pwell).covering(dantenna_n)
    

    This way, the function is preserved, but the hierarchy is guided by the "antenna_d_mk" layer which is a drawing layer and the shapes sit at their right place in the hierarchy. This makes the "dantenna" devices being recognized down in the hierarchy.

    Second, for the "dpantenna" diodes, the computation uses "covering". Problem is that covering - as being of the full region selection operation family - implicitly merges the input (here: "nwell_drw"). As these are large regions, the merged polygon is propagated up in the hierarchy.

    I'd propose the following patch to prevent this:

    replace:
    dpantenna_p = pactiv.and(antenna_d_mk)
    dpantenna_n = nwell_drw.covering(dpantenna_p)
    
    by:
    dpantenna_p = antenna_d_mk.and(pactiv)
    dpantenna_n = dpantenna_p.inside(nwell_drw)
    

    This patch should be functionally equivalent, but uses "dpantenna_p" for the first input. As these shapes are local islands rather than large grids, merging does not spoil the hierarchy.

    With these two patches, your testcase matches for me :)

    ...
    2024-10-16 23:41:35 +0200: Memory Usage (411760 KB) : Starting SG13G2 LVS Options Preparations
    2024-10-16 23:41:35 +0200: Memory Usage (411760 KB) : Starting SG13G2 LVS Alignment
    2024-10-16 23:41:35 +0200: Memory Usage (411760 KB) : Starting SG13G2 LVS Simplification
    2024-10-16 23:41:36 +0200: Memory Usage (411760 KB) : Starting SG13G2 LVS Comparison
    2024-10-16 23:41:36 +0200: Memory Usage (411888 KB) : ==========================================
    2024-10-16 23:41:36 +0200: Memory Usage (411888 KB) : INFO : Congratulations! Netlists match.
    2024-10-16 23:41:36 +0200: Memory Usage (411888 KB) : ==========================================
    2024-10-16 23:41:36 +0200: Memory Usage (411888 KB) : LVS Total Run time 7.047782 seconds
    

    Maybe it's worth reporting this to the LVS authors.

    Best regards,

    Matthias

  • Hi Matthias,

    Thanks a lot, that indeed fixes the issue and now I understand more where they stemmed from.

    I opened a PR for upstream to merge the patch ( https://github.com/IHP-GmbH/IHP-Open-PDK/pull/225 ).

    Cheers,

    Sylvain

Sign In or Register to comment.