NPN transistor extraction issue

Hi,
I'm writing a LVS script to check my layout and I want to see if someone can help with this issue.
I try to extract a vertical NPN transistor in the layout. The following is the structure of the NPN transistor

I'm using the following script to extract the NPN transistor

emitter = active_outside_nwell & nplus
base = active_outside_nwell & bury_n
collector = bury_n
collector_contact = bury_n & nwell
base_contact = base & pplus

npn_model_name = "NPN"
extract_devices(bjt3(npn_model_name), { "C" => collector, "B" => base, "E" => emitter,
"tC" => collector_contact, "tB" => base_contact, "tE" => emitter})

NPN connect ======================

connect(emitter, contact)
connect(collector_contact, contact)
connect(base_contact, contact)

metal connection

connect(contact, metal1)
connect(metal1, via1)
connect(via1, metal2)

But I can't extract the transistor and it always show me the error message as follows:

Please give me some advise to handle the above issue! Thanks!

Comments

  • Please format your code using Markdown: a line with three backticks before and after the code will format it

    like this
    

    Matthias

  • Your collector contact should be the stack of contact, Nplus, Nwell, buriedN. You do not have the N+ and contact in your logic. It's possible that contact to NWell could be a Schottky contact depending on surface doping unless you impose N+. Also (can't see) the connect chain from metal to the "contacts" should include the contact layer as a stepping-stone, how else can metal connect to the "contact regions" as-defined?

  • Thank you very much for all your support.
    Hi Matthias,
    I can't see the format look like. I use ~~~ before and after the code. Please help to take a look. Many thanks! :)

    Here is my code for NPN extraction


    # Read about LVS scripts in the User Manual in "Layout vs. Schematic (LVS)" # Enable hierarchical mode deep # Produce LVS report report_lvs # ------------------------------------------------------------------- # Layers # Drawing layers nwell = input(1, 0) #(TB) active = input(2, 0) #(TO) poly1 = input(3, 0) pplus = input(4, 0) #(P+) nplus = input(5, 0) #(N+) poly2 = input(14, 0) contact = input(6, 0) metal1 = input(7, 0) # includes labels via1 = input(93, 0) metal2 = input(86, 0) # includes labels bury_n = input(20, 0) # Bulk layer for terminal provisioning bulk = polygon_layer # Computed layers active_in_nwell = active & nwell active_outside_nwell = active - nwell emitter = active_outside_nwell & nplus base = active_outside_nwell & bury_n collector = bury_n collector_contact = bury_n & nwell base_contact = base & pplus emitter.output(181, 0) base_contact.output(182, 0) base.output(185, 0) collector_contact.output(183, 0) collector.output(184, 0) #Device Extaction npn_model_name = "NPN" extract_devices(bjt3(npn_model_name), { "C" => collector, "B" => base, "E" => emitter, "tC" => collector_contact, "tB" => base_contact, "tE" => emitter}) #Connection Define #NPN connect ====================== connect(emitter, contact) connect(collector_contact, nwell) connect(nwell, nplus) connect(nplus, contact) connect(base_contact, contact) ###metal connection connect(contact, metal1) connect(metal1, via1) connect(via1, metal2) # ------------------------------------------------------------------- # Netlist and compare # Netlist normalization netlist.simplify target_netlist("layout_simply.cir", write_spice, "Extracted by KLayout") # Hierarchy alignment (flatten out unmatched cells) align # Netlist vs. netlist compare
  • Hi dick_freebird,
    Thanks for your information. I have tried different connection methods. But it is fail to extract the NPN device also. Could you please take a look of the above coding and give me more advises. Thanks!

    Terry

  • @eeterry11 I think you should think simple. Without a sample, it's quite difficult to debug, but I'd propose to change the collector connection to simply:

    # instead of:
    connect(emitter, contact)
    connect(collector_contact, nwell)
    connect(nwell, nplus)
    connect(nplus, contact)
    connect(base_contact, contact)
    
    # use
    connect(emitter, contact)
    connect(collector_contact, contact)
    connect(base_contact, contact)
    

    This should eventually give you the terminals. You have correctly identified non-overlapping regions fro collector_contact and base_contact, so these three connects should give your the three terminals separately.

    But as mentioned, an example layout will be helpful.

    Matthias

  • @Matthias the following link can download the layout gds file. Please help to take a look! Thank you very much!
    https://www.dropbox.com/s/9dputxuhrlwbdm6/P200241_sample_layout_test.gds?dl=0

    Terry

  • Can you somehow display each of those logical
    layers that you are outputting, and see whether
    any of them are not giving you what you think?

    Maybe one is "malformed" and breaking the
    device extraction?

  • edited October 12

    Another thought - I see the extraction of
    connectivity, but isn't there some need to
    "recognize" the device as such? I don't see
    logic for that (what makes the NPN an
    NPN, to the extraction?).

    In more elaborate kits and tools I'm used
    to seeing both type-extraction and
    connectivity-extraction to that type's
    terminals. Of course I could easily be
    confused.

  • @dick_freebird I did output the logical layers and it is exactly what I want! The following code output the logical layer

    # Computed layers
    active_in_nwell       = active & nwell 
    active_outside_nwell  = active - nwell
    
    
    emitter = active_outside_nwell & nplus
    base = active_outside_nwell & bury_n
    collector = bury_n 
    collector_contact = bury_n & nwell 
    base_contact = base & pplus
    
    emitter.output(181, 0)
    base_contact.output(182, 0)
    base.output(185, 0)
    collector_contact.output(183, 0)
    collector.output(184, 0)
    

    But now, I don't know how to create a contact to the collector , base and emitter which the extractor can recognize the device! Thanks!
    Terry

  • edited October 15

    Hi @eeterry11,

    I'm afraid there seems to be a bug related to collector region. Looks like my test base is too weak on this spot.

    I need to debug the problem.

    But there is a workaround. I think it's not required to include the collector into the device recognition as base and emitter should be specific enough.

    "collector" is optional, so you can replace it by an empty "polygon_layer". This does not give you that errors.

    However, the "collector" terminal then will not be the collector region but the base region only. You can make the connection to "collector_contact" via the original collector region though:

    # NOTE: "C" is empty, "tC" puts the terminal on the original collector region
    extract_devices(bjt3(npn_model_name), { "C" => polygon_layer, "B" => base, "E" => emitter, 
                                            "tC" => collector, "tB" => base_contact, "tE" => emitter})
    
    #Connection Define
    #NPN connect ======================
    connect(emitter, contact)
    # NOTE: collector connects to collector_contact outside base
    connect(collector_contact, collector)
    connect(collector_contact, nwell)
    connect(nwell, nplus)
    connect(nplus, contact)
    connect(base_contact, contact)
    

    I have created an issue for this with an artificial test case: https://github.com/KLayout/klayout/issues/921

    Matthias

  • Hi @Matthias,

    I have tried to replace the collector to an "empty" polygon_layer, but the error is here. The following is my updated code. Could you please help to take a look. Do I misunderstanding your meaning? Thank your very much !!


    # Read about LVS scripts in the User Manual in "Layout vs. Schematic (LVS)" # Enable hierarchical mode deep # Produce LVS report report_lvs # ------------------------------------------------------------------- # Layers # Drawing layers nwell = input(1, 0) #(TB) active = input(2, 0) #(TO) poly1 = input(3, 0) pplus = input(4, 0) #(P+) nplus = input(5, 0) #(N+) poly2 = input(14, 0) contact = input(6, 0) metal1 = input(7, 0) # includes labels via1 = input(93, 0) metal2 = input(86, 0) # includes labels bury_n = input(20, 0) # Bulk layer for terminal provisioning bulk = polygon_layer bulk.output(198, 0) # Computed layers active_in_nwell = active & nwell active_outside_nwell = active - nwell emitter = active_outside_nwell & nplus base = active_outside_nwell & bury_n collector = bury_n collector_contact = bury_n & nwell base_contact = base & pplus emitter.output(181, 0) base_contact.output(182, 0) base.output(185, 0) collector_contact.output(183, 0) collector.output(184, 0) npn_model_name = "NPN" # NOTE: "C" is empty, "tC" puts the terminal on the original collector region extract_devices(bjt3(npn_model_name), { "C" => polygon_layer, "B" => base, "E" => emitter, "tC" => collector, "tB" => base_contact, "tE" => emitter}) #Connection Define #NPN connect ====================== connect(emitter, contact) # NOTE: collector connects to collector_contact outside base connect(collector_contact, collector) connect(collector_contact, nwell) connect(nwell, nplus) connect(nplus, contact) connect(base_contact, contact) ###metal connection connect(contact, metal1) connect(metal1, via1) connect(via1, metal2) # ------------------------------------------------------------------- # Netlist and compare # Netlist normalization netlist.simplify target_netlist("layout_simply.cir", write_spice, "Extracted by KLayout") # Hierarchy alignment (flatten out unmatched cells) align # Netlist vs. netlist compare
  • It still bothers me that there is no logic to recognize the device itself. The terminals, OK. But terminals of what? I see where you assign the model name "arbitrarily".

    Maybe it's just that I'm used to working in bipolar technologies where there were PCells for a variety of emitter, base, collector combinations - from simple single (1B 1E 1C) through permutations of dual base, dual emitter, ring collector, etc. - 6 each of NPN and PNP in one flow I used a lot. Distinguishing the geometries to point the extraction at the appropriate model, was the first step of the logic, to derive that modelName.

    Perhaps in this case there's only one style and only one model so no thinking is required. But maybe that logic would have yielded a finite collector region, or the terms for creating it logically?

Sign In or Register to comment.