LVS NetlistSpiceReader: 3-terminal resistor confusion

Using KLayout 0.26.11 on Ubuntu 18.04, I am trying to run LVS with a netlist which has 3-terminal resistors, like so:

 r6 ground n015 ground  r=80k w=0.5u l=50.4u seg=4 m=1

When I use two-terminal resistor extraction as in

extract_devices(resistor("my_res_sab", 794),           {"R" => poly_res_sab, "C" => poly_not_res})

I get some device comparison results that look like this,

Objects                  ST    Layout               Reference
my_res_sab <=> GROUND    /!\   $180 / my_res_sab    3 / GROUND

with a warning about the device class mismatch and it seems the NetlistSpiceReader has interpreted the GROUND as the model name.

If I use three-terminal resistor extraction as in

extract_devices(resistor_with_bulk("my_res_sab", 794),          {"R" => poly_res_sab, "C" => poly_not_res,  "W" => bulk})

the devices won't be matched at all and there are two lines in the Netlist Database Browser (one for layout, one for schematic):

Objects                  ST    Layout               Reference
- <=> GROUND             (-)   /                    6 / GROUND
my_res_sab <=> -         (-)   $125 / my_res_sab    /

One more detail about the last result is that the netlist resistor is shown as a 2-terminal device, while the layout one as having 3 terminals.

Another experiment I did was to add the model name my_res_sab to the Spice netlist - but then the reader throws an error "Too many arguments for two-terminal device (additional argumen is 'MY_RES_SAB')" and I'm not even sure the netlist format allows for R devices with model names.

Is this behaviour expected? How can I get LVS to match?


  • Bearing in mind that I don't have much of any clue
    about how to parse the given error reports...

    ... it seems to me that what's missing is the "capture"
    of the parasitic substrate connection, the third terminal
    (which in many PDKs has no ohmic connection, is only
    a place to attach parasitic capacitance elements). The
    two ends of the poly resistor should be found by the
    logic involving contacts, and the parasitic node often
    demands some recognition layer (e.g. "Bulk") that can
    be logically mashed up with the poly polygon and
    assigned for the resistor instance.

    I recommend you pick apart that 3-terminal extractor
    and find what it uses to recognize the substrate node
    underneath the poly, and make sure the layout has
    the objects the extractor needs to find.

  • Thanks for your comment @dick_freebird. What is interesting about the result I mentioned is that when I use the 3-terminal resistor extraction, the layout (extracted) netlist already has all three terminals A, B and W connected to the correct nets. Therefore I think (but might be wrong, as I am just starting with KLayout LVS) the problem might be in the SPICE netlist reader/interpreter... the fact that the 3rd terminal net (GROUND) of the SPICE netlist ends up being used as the model name (or as KLayout seems to call it, "device class") also is related to the netlist reader. Maybe I need to apply some options to the reader to make it understand 3-terminal resistors correctly?

  • I believe you can have resistors with or without a model
    (certainly, without; forget the syntax for invoking a model
    instead of the built-in primitive).

    It might be that the schematic netlister needs to be
    "educated" to get the format that works with LVS.
    I have worked in a technology recently, where the
    transistors normally are subcircuits including the
    isolation junction parasitics and they have another
    models-tree that is meant solely for LVS and omits
    all the "gingerbread".

    I'm more used to simple resistors (with perhaps
    complex temp & geometry fit functions, but simple
    arguments of ohms and centimeters) -

    r1 1 0 1k tc1=xxx tc2=xxx

    but this doesn't support LVS type-match because
    it doesn't declare a type.

    In the ngspice33 manual in the resistor section
    is shown this example:

    RE1 1 2 800 newres dtemp=5

    where newres is the model. This appears in the fourth
    argument position, so maybe your second GROUND -is-
    being interpreted as a model.

    It may be that the 3T resistor should be netlisted
    as a subcircuit, where the third terminal has C/2
    elements connected to the first and second.
    But then you'd have even more elements to check.

    For basic connectivity of explicitly placed devices
    I think the parasitics should be dispensed with.
    Unless you care where those parasitics' return path is,
    like in RF. Then you do want the third terminal to be
    explicit, and then dealt with. If the schematic netlist
    incorporates those shunt-C parasitics then the layout
    netlist must as well, or else they need to be "refined"

  • I have tried to extract a resistor_with_bulk with an empty netlist. And ... KLayout extracts a resistor with only 2 terminals :'(
    Furthermore, if I try to add the reference netlist with a 3 terminal resistor, it complains that a resistor should only have 2.

    I also could not find it in the documentation. Resistor and capacitor with bulk are often used in PDK, and especially in spice models file, BUT as a subckt, so the extraction syntax should be as sub-circuit : XR PLUS MINUS BULK R=1K RPOLY_SALICIDED

    @cgelinek_radlogic : it is probably the syntax of your original netlist, is't it ?


  • edited May 8

    Might be of some help

    In order to connect the body of the resistor, you simply place it nearby a substrate connection (like the bulk connection of a transistor). You should not put the pdiff contact on top of the resistor, but somewhere next to it, dont worry too much about the distance you place it from the resistor, just make sure that it is far enough to prevent DRC errors, and obviously it should not be too far. Multiple resistors can share the same body connection. I would guess that the body should be connected to ground.

  • Dear all,

    thanks for the discussion.

    Actually, KLayout does not read three-terminal devices from Spice netlist. It's possible to extract devices, but how to describe them with the plain "R" syntax escapes me. You can model them as subcircuits though.

    Maybe someone can enlighten me on the Syntax. My reference is ngspice which only has 2-terminal resistors.

    There is

    Rname netA netB value
    Rname netA netB value model
    Rname netA netB model

    How will it be possible to introduce a third net without ambiguities?

    BTW: the same is true for capacitors.


  • Hi everyone, thanks for your comments.

    @laurent_c you're correct, one original netlist format is subcircuit-based as you said, but slightly different from your example:

    XR netA netB bulk model R=value

    As far as I understand (but haven't tried yet) the clean way to handle these in KLayout would be via the a custom NetlistSpiceReaderDelegate class.

    In another technology, I have also seen the following format for 2-terminal resistors with model, not subcircuit based:

    RN netA netB model R=value

    @Matthias, KLayout's netlist reader still doesn't understand this correctly as the value isn't simply a number but a parameter, though I could easily work around this using gawk to pull the value out of the parameter and put it after the 2 terminals.

    Unfortunately, it seems like almost every technology/simulator/LVS tool seems to have its own format preference on how resistors and capacitors are represented, so maybe we'd need something a bit more flexible for parsing various formats.

    I tried writing a custom NetlistSpiceReaderDelegate for the 3-terminal resistor, but the problem was that the NetlistSpiceReader threw an error because it didn't like that extra bulk terminal and didn't even attempt to call my NetlistSpiceReaderDelegate.

    The only workaround I can currently think of is a combination of an external tool to transform the netlist (so it is accepted by NetlistSpiceReader) and a custom NetlistSpiceReaderDelegate to then translate this (new custom format) into a KLayout netlist, as follows:

    1. Translate devices R & C into one of the 2-terminal formats Matthias mentioned (this may require pulling the value out of a parameter like R=value). If a 3rd terminal is present, make it a parameter, like $SUB=bulk (I have seen this format in one of the technologies we're working with).
    2. Write a custom NetlistSpiceReaderDelegate to get all this information into KLayout.

    Once I've got a flow that works, I'll see if I can post it here.

    @Matthias , next time you work on the NetlistSpiceReader code, may I suggest you consider whether it'd be feasible to change the logic such that a NetlistSpiceReaderDelegate controls whether the input format for a particular device is acceptable, rather than refusing to read the netlist altogether if it doesn't match any of the (hard) coded variants you mentioned above? This is just a low-priority suggestion because (as I said) this can probably rather easily worked around.

    By the way, I really like the idea of having a something like NetlistSpiceReaderDelegate to control how a particular input case is handled... these design decisions are one of the things that make KLayout so attractive!

  • I believe two things want changed.

    The schematic SPICE netlister needs to be "harmonized"
    with whatever a "normal" layout might produce for
    extracted device netlist lines. It would add a lot of
    flexibility if you made all devices netlist to X (subcircuit)
    abstraction layer under which you can manage multiple
    "views" (content-versions) just by the include-chain -
    one full parasitic detail, one for core device only that
    LVS might like, one for general SPICE where the
    simulator doesn't want to know from third terminals,
    different xyzSPICE dialects, etc.

    Now I am working in a JI technology and my Pbase
    resistors sure do want to know where the TANK
    potential is. That's a 3-terminal resistor with a
    distributed junction diode. I think this once-common,
    still-used layout object deserves an extractor if
    indeed there is not one (?).

  • Thanks for your comments, they are very welcome!

    Actually the intention of the ReaderDelegate wasn't to support any kind of Spice dialekt, but mainly to adapt X-based device models to one of the device models supported by KLayout.

    I have created a ticket to track this issue: Please feel free to comment.

    @dick_freebird Will the device extractor from be sufficient for your application? It's taking two terminals and some resistor area in between which also renders the bulk terminal. Or will you need a separate bulk terminal?



  • Reviewing the doc link, I am a bit confused.

    "For the resistor with bulk, the wire area is output on the "tW" terminal layer as the "W" terminal:"

    is all that the resistor_with_bulk section declares (w/ pic)
    but it is unclear to me how that "tW" layer may (or may not)
    interact connectivity-wise with the actual bulk or diffusion
    below. The description implies to me that this is a derived
    layer created, rather than picking the existing layer in which
    the resistor body is sunk. But maybe I am just confused
    by the description.

    For example (and this is common in old-timey JI linears
    like LM-series) a Pbase resistor might be placed in a
    TANK which is also the collector of a vertical NPN,
    if that NPN has a convenient circuit connectivity.

    Now will "tW" for the resistor somehow end up showing
    connection to the NPN "C" terminal? And if so, how is
    "somehow"? Is there perhaps a device-specific "connect"
    statement needed, to connect tW to TANK for a Pbase
    resistor, or tW to ISO for a Nemit resistor?

    I need a bulk terminal which will establish the same
    connectivity as the schematic; however I connect the
    body terminal in the schematic, if the layout polygons
    match that then so should the extracted netlist.

  • Here's a pic of what I'm wanting to address. This is
    a TANK region which serves as collector for two
    NPNs (with distinct B, E regions, Es wired together),
    one lateral PNP and two distinct Pbase resistors.

    The LPNP "B", VNPN "C"s and RPbase "tW" all need
    to connect to, call out the same TANK region's
    assigned node.

    The foundry maintains two sets of SPICE "model
    deck" - one with full junctions detail, which would
    in this case demand some engineer "input" as this
    is none of the single-device-models' but rather a
    shared-bottom-plate structure, and one which
    puts out only the "explicit" device which they use
    special "recognition layers" to extract in poor-man's
    Caliber (Tanner version). I'll be moving them off
    that kludge, if I can. They share too many different
    (say) NPN layouts into a single model with AREA=
    for my liking; either use a true fitted geometry model
    (which can never support the kooky you see here),
    or do the work of maintaining model-per-layout and
    then you also get to do symbol-per (not a big deal,
    already well down that road).

  • @Matthias

    I have created a ticket to track this issue: Please feel free to comment.

    Thank you so much for this, your proposed changes to the Spice reader would certainly ease the netlist preparation. This reminded me, another "feature" of many Spice netlists is the "line continuation" using the + sign, like so:

    * This
    R$6 3 4 5 RMODEL2 
    + R=1.7k
    + W=16.3u 
    + L=192.4u
    * is equivalent to this
    R$6 3 4 5 RMODEL2 R=1.7k W=16.3u L=192.4u

    Again, easy to preprocess away, so just a suggestion.

  • @dick_freebird

    I like you nice real silicon photos. Much better than polygons :)

    I should explain what I mean by "tW": when KLayout extracts a device, it creates pins on layers you specify in the "extract_devices" call. This can be any layer, but it needs to become part of the connectivity so the pin gets connected. The lower case "t" stands for "target" and means this is a layer on which pins are generated. You don't need to specify such a target layer, but then KLayout will pick one of the inputs.

    So in your case I assume you have some layer, e.g. "tank" describing the TANK area. I also assume you can identify some tap connecting to it. In CMOS, "tap" is something like "n+ AND n-well" or "p+ AND substrate". So the basic connectivity is something like:

    # creates a connection of metal to TANK
    connect(tank, tap)
    connect(tap, metal)

    You'll also need a resistor layer - maybe that is polysilicon. Often there is a marker on the resistor marking the resistive path but not the heads. So a typical expression is:

    resistor = poly & resistor_marker

    The resistor heads are still poly but outside the marker area. And we need to create a contact to them, so we can use:

    poly_not_resistor = poly - resistor_marker
    connect(poly_not_resistor, contact)
    connect(contact, metal)

    to generate the connectivity for the head.

    With this you can essentially use "tank" as target for the resistor's BULK pin and write the resistor extraction like this:

    extract_devices(resistor("model", ohms_per_square), { "R" => resistor, "C" => poly_not_resistor, "tW" => tank  })

    Note that I did not specify where the head pins go to (that would be "tC") - KLayout will put them on the "C" layer by default. This is poly_not_resistor and as this layer is part of the connectivity, the pins will get connected to these nets.

    @cgelinek_radlogic You mean "+" isn't supported in Spice netlists in KLayout? I'm fairly sure it does already. Do you have a case where this does not work?

    Best regards,


  • edited May 19


    You mean "+" isn't supported in Spice netlists in KLayout? I'm fairly sure it does already. Do you have a case where this does not work?

    Hmmm, I just tried it and it did in fact work. Either I was looking at a different netlist (potentially yet another format), or I was still using KLayout version 0.26 ... either way, I'll let you know once I come across a problem like this again.

Sign In or Register to comment.