Closed FaragElsayed2 closed 5 months ago
Cc @atorkmabrains
@klayoutmatthias @KrzysztofHerman
Hi @FaragElsayed2,
thanks for this nicely prepared test case.
The problem is the following
The body connections are made to "pwell" which is a flat top-level layer, because it is derived from the chip boundary. The way it is defined now, it acts like a flat top-level conductor layer over all gate cells. This creates pins from the device body terminals as you can see here:
Usually, you would use a global connection for this purpose (see https://www.klayout.de/doc-qt5/manual/lvs_connect.html#h2-80). Instead of computing pwell as anything "not nwell" you can include "not well" in the nmos recognition booleans, so you do not need to worry about nwell and can simply connect their bulks to the respective global net.
If you really need to use a pcell layer of some kind, you should try to derive it in some hierarchical way. Remember, that the first operand of a boolean operation determines where the results end up in the hierarchy. So if you do
not_nwell = CHIP.not(nwell_drw.join(pwell_block).join(digisub_drw)))
the results will be flat, because CHIP is a single flat rectangle. But if you use
cell_boundary = input(189, 4) # I am guessing
not_nwell = cell_boundary.not(nwell_drw.join(pwell_block).join(digisub_drw)))
the result will be hierarchical as the cell boundary is drawn in every cell. BTW: with this patch, the LVS passes in my case :)
You can basically also replace "CHIP" by
extent("*")
which places bounding boxes into every cell. This creates a hierarchical layer, but also creates a lot of overlaps. I think this will add a performance penalty.
Matthias
@klayoutmatthias We have adopted the following change:
extent("*")
Thanks for all the help.
@klayoutmatthias Thanks for your help.
I have used this derivation:
CHIP = extent('*')
This derivation passes LVS when using the pwell
as the bulk. However, when I tested it with the digisub
layer at the top level, which is a marker layer used to isolate the substrate and acts as a separate net, the LVS fails. It only passes if I add this digisub
layer in the subcells as well. I believe this issue arises because the substrate net differs between the top cell and the subcells.
Below is the derivation I used for the substrate:
# === CHIP ===
CHIP = case $run_mode
when 'deep'
extent('*')
else
#=== FLAT MODE ===
extent.sized(0.0)
end
# === General Derivations ===
# pwell
pwell_pre_init = CHIP.not(pwell_block).not(digisub_drw)
pwell_pre = pwell_pre_init.not(nwell_drw)
digisub_pre = digisub_drw.sized(-1.nm).not(nwell_drw).not(pwell_block)
pwell = pwell_pre.join(digisub_pre)
@klayoutmatthias Please keep in mind it's a valid use case to have digisub
as single polygon on a large array of standard cells for example.
Happy to discuss.
Hi @FaragElsayed2,
well, by adding a flat shape on digisub_drw ("adding" is what "join" does), you have re-introduced the problem we just solved with extent("*")
.
One solution is to rewrite the pwell expression:
pwell_pre_init = CHIP.not(pwell_block).not(digisub_drw)
pwell_pre = pwell_pre_init.not(nwell_drw)
digisub_pre = digisub_drw.sized(-1.nm).not(nwell_drw).not(pwell_block)
pwell = pwell_pre.join(digisub_pre)
into
pwell_allowed = CHIP.not(pwell_block)
pwell_pre_init = pwell_allowed.not(digisub_drw) # not needed here, but somewhere else?
digisub_gap = digisub_drw.not(digisub_drw.sized(-1.nm))
pwell = pwell_allowed.not(nwell_drw).not(digisub_gap)
This way, we maintain the hierarchical nature of CHIP as this layer forms the first operand of the boolean "not" chain.
Some hints in general:
KLayout's LVS compare and LVS netlist extraction is bottom-up and there needs to be a strict correspondence between layout and schematic cells. This means that a cell needs to be complete in itself - including all marker layers and potential connectivity layers. If that is not given in terms of drawing layers, you need to utilize the behavior of the deep mode booleans to make sure this condition is fulfilled.
A practical hint: you can output debug layers in you LVS script like in DRC, for example using:
target("debug.gds")
# write pwell to 100/0 of "debug.gds"
pwell.output(100, 0)
this may help you understanding how the deep mode functions work.
KLayout does not create marker layer variants for cells. This means, you cannot simply switch one gate's transistors to high-Vt type by drawing some high-Vt marker over this gate. I don't think, this makes sense as models would change etc. But if you really want to do that, you will need to create a copy of the cell and put the marker layer into that cell. In the schematic, this copy would use high-Vt models while the original subcircuit would not.
The same is true for example, if you draw "digisub" over the half of a cell while you do not do so for other instances. This will not create a cell variant with two substrate pins. The solution is again to copy the cell and create a variant with a specific "digisub" shape inside.
Matthias
Perfect @klayoutmatthias
Thank you for your time and assistance. I now understand how to maintain the derived layer hierarchically.
Deep vs. Flat Mode for LVS Test
Setup
0.29.0
IHP-130nm
Issue Description
We are encountering an issue with passing LVS checks in deep mode for tests involving nFETs and pFETs. Below are the details of the layout and netlist, along with the results from both flat and deep runs.
Layout
Netlist
Flat Run
Command:
Deep Run
Command:
Additional Notes
We have ensured that all connections are added at the top level to establish connections to the sub-cells. Despite this, the LVS check fails in deep mode but passes in flat mode.
Steps to Reproduce
0.29.0
and the IHP-130nm technology.Expected Behavior
The LVS check should pass in both flat and deep modes.
Actual Behavior
The LVS check passes in flat mode but fails in deep mode.
Attachments
We would appreciate any insights or suggestions to resolve this issue. Thank you!