Netgen version 1.4 Tutorial

Table of Contents

Disclaimer
Netgen introduction
The Netgen LVS algorithm
Generating netlist sources
Setting up for LVS
Running LVS
Batch Mode LVS
Interpreting LVS results
Non-matching element counts
Mixed hierarchy example
Handling non-matching subcell names
Mixed hierarchy at the top level
Non-matching component parameters
Automorphisms in circuit hierarchy
More setup file tricks
Tips for large netlists and messy output
Tutorial history

Disclaimer

This tutorial corresponds to Netgen versions 1.4.75 and newer. The developer attempts to keep it accurate and up-to-date, but due to code fixes and new development, this cannot always be guaranteed. Feel free to contact the developer (email information at the bottom of the page) if you find anything that does not work according to the description in the tutorial text.

Netgen, a netlist manipulation and comparison tool

Netgen is a program with two purposes: One is to convert netlists between different formats, and one is to compare two netlists to determine if they are equivalent, and if not, what makes them different. The netlist conversion is a fairly trivial aspect of the netgen tool, since all netlist formats convey mostly the same information and therefore are all very similar to one another. This tutorial concerns mainly the netlist comparison. Netlist comparison is often called "LVS", or "Layout vs. Schematic", because its primary purpose is to check whether a VLSI layout is equivalent to the schematic from which it is derived.

A circuit designer will start with a circuit schematic of the system being designed. The circuit schematic is generally hierarchical, and starts from the fundamental devices (resistors, capacitors, transistors, etc.), and goes up to the representation of an entire chip. The program in which the circuits are drawn is normally a schematic capture tool as well as a schematic drawing tool. The schematic capture takes the drawn design and converts it into a netlist describing the circuit purely in forms of devices and connectivity. The netlist is typically in a well-known format such as SPICE, and is good both for simulation and for netlist comparison (although one does not necessarily use the same netlist for both).

The layout engineer (who may or may not be the circuit designer), will take the schematic drawing and use it to generate a layout of the circuit, while carefully considering the placement and rotation of elements, the sizing of connecting wires, and all the design rules governing the placement and sizing of geometry in the layout. Depending on the design and the tools being used, this process can be anywhere from fully automated to fully manual. But in VLSI design, especially in analog and mixed-signal (both analog and digital) designs, the layout is often generated independently of the schematic, where layout is still done mainly by hand due to the many considerations that come into play. Once the layout has been made, the layout tool (or sometimes an independent tool) will extract the design, finding all the devices, determining their connectivity to other devices, and dumping a netlist containing the information. So, from the schematic and from the layout, there will be two netlists, and on some level they should represent the same circuit.

Because custom hand layout is difficult, the typical purpose of LVS is to check what errors the layout engineer has introduced in the design during the process of creating the layout. The schematic is generally assumed to be the (correct) standard, largely because the schematic is typically used for simulation, and the simulation results indicate whether the circuit (or entire chip) works or does not work as specified. This is known as functional verification. Even in digital designs, where the layout is automatically generated (called "synthesis"), LVS can be a critical help when, for example, a correction is made in the design for a metal-mask re-spin of the chip. In that case, the rewiring is usually done by hand and must be checked against a schematic to make sure it is correct. Another reason is to check that the circuit synthesis has done the job that it claims to have done. Synthesis is a very complicated process itself, and requires many setup files. It is very easy for something to go wrong; a pin placement in one file may not match the same pin placement in another file, leading the synthesis tool to wire up a circuit at the wrong point, creating an incorrect an non-functional circuit. LVS will help to pinpoint that kind of problem.

To be sure, a chip can be entirely verified through simulation, by extracting the netlist from the top-level layout and confirming that everything works through exhaustive testing of all functions. But that can take years of simulation time, depending on the size and complexity of the chip, and when the simulation fails, it is not always easy to figure out what was wrong with the layout.

Figuring out what is wrong with a mismatched layout requires some knowledge about the matching algorithm, which this tutorial aims to explain.

The Algorithm

The algorithm used by Netgen is quite elegant but can produce puzzling results if you don't understand how it works. It operates by a method called "fracturing", which is done in a series of iterative passes. On the first pass, everything in the design (both circuits, without regard to which is which) is gathered into two groups, one a list of all the devices, and the other a list of all the nets. Then, each pin of each device is given a random identifying value (such that every instance of that device in the design has the same values on the same pins). Each device type is given a unique identifying value. Each net is given an identifying number which is the fanout of that net (the number of device pins to which it connects).

On each pass of the device list, the list is "fractured" into multiple lists ("partitions") containing devices with the same identifying value. So after the first pass, the single device list will be broken up into individual lists for each device type. Likewise, the net list is fractured into multiple lists containing nets with the same identifying value. So after the first pass, the single node list will be broken up into individual lists for each set of nets having the same fanout.

Each device partition is given a unique identifying number, and each net partition is given a unique identifying number.

Now, the tricky part: Each device is given a new identifier that is created by combining the identifiers of each net partition and net for every net that the device connects to (this is done by summing together the results for each pin of an exclusive-or of the net partition's identifier and the net's individual identifier). Each net is given a new identifier that is created by combining the identifiers of each device partition and pin for every device pin that the net connects to (using the same method).

Repeat from the step of fracturing partitions of same-valued devices and nets. Each step greatly reduces the number of elements or nets in each partition. If the two circuits are equivalent, then the end result is that every partition contains exactly two devices or nets, one from the first circuit and one from the second circuit.

Note that in some cases, circuits may have multiple instances of indistinguishable circuits. When the circuits are truly indistinguishable from one another, they will all end up in the same partition no matter how many iterations are made. These are called "automorphisms". They can be dealt with by assigning one pair of devices in the partition with a unique identifier, forcing them into their own partition, and continuing until all devices and nets are uniquely identified.

It is important to understand that while the fracturing algorithm is extremely fast and efficient, it has one significant drawback in that it does not really understand the overall structure of a circuit, and cannot produce a judgement on just how well or how badly a circuit is misconnected. There exist LVS tools that attempt to tell the designer what changes need to be made to "correct" a non-matching circuit, but such advice is all to often useless, or worse, misleading. Often it is quite difficult to figure out what has gone wrong when the error is not a simple one. The purpose of this tutorial is to show how to single out an error and ignore the extraneous information. With a few simple strategies, it is possible to work through even the most horrifically mangled design and quickly correct the problems.

Netgen can run LVS hierarchically. This is useful for very large circuits (like entire chips), preventing the necessity of flattening the whole circuit, producing unmanageably large output. Each subcircuit that can be clearly paired off against an equivalent subcircuit in the circuit being compared, is matched at the level of the subcircuit. If the circuits match, then the comparison moves to the next level of hierarchy, where all instances of that subcircuit are treated as individual devices with pins. If the subcircuit has no match in the other circuit, or if the comparison between subcircuits fails, then the contents of each instance of the subcircuit are pulled into the parent cell, and the subcircuit is removed. Because two netlists may define subcircuits with pins in a different order, the pin lists have to be matched up to one another. Inability to match the pins is another reason to expand the contents of the subcircuits.

Generating Netlists from Schematic and Layout

Netgen can take its source netlists from many different tools; its primary format is SPICE, and it accepts many common extensions to plain Berkeley SPICE3 syntax. It knows a handful of other netlist formats, too, but they are not so complete in their description of fundamental devices, or understand how to parse device properties, and some formats are not hierarchical.

For the purposes of this tutorial, we will work with netlists generated from a schematic using XCircuit and Qflow (where the netlists are automatically generated), and netlists generated from an extracted layout using the layout tool Magic.

The tutorial will use the following files, which should be downloaded now or as needed:

File Revision Size Date
bufferA.spice 0 (378B) October 13, 2012
bufferB.spice 0 (310B) October 13, 2012
runlvs.sh 0 (38B) October 7, 2014
bufferBx.spice 0 (296B) October 13, 2012
hier1.spice 0 (295B) October 13, 2012
hier2.spice 0 (279B) October 13, 2012
x.spice 0 (88B) October 13, 2012
y.spice 0 (123B) October 13, 2012
morph1.spice 0 (398B) October 13, 2012
morph2.spice 1 (398B) October 8, 2014
map9v3.spice 0 (18KB) October 11, 2012
map9v3_test.spice 0 (16KB) October 11, 2012
map9v3_test2.spice 0 (16KB) October 11, 2012
map9v3_test3.spice 0 (16KB) October 11, 2012
map9v3_synth.spice 0 (6.5KB) October 11, 2012
osu035_stdcells.sp 0 (25KB) October 11, 2012
OSU_dig.lps 0 (23KB) October 11, 2012
setup.tcl.save 1 (358B) September 5, 2014
In case downloading these individually is a pain, here is a tarball containing them all:
File Revision Size Date
tutorial.tgz 0 (18kB) May 16, 2016
The file "map9v3.spice" is a netlist generated by the layout tool magic from a VLSI design synthesized from verilog source using Qflow (actually the predecessor to qflow). As digital circuits go, it is relatively small, and good for demonstrating the various features of netgen (see if you can figure out what the circuit does!). The remaining files "map9v3_testn.spice" are hand-manipulated variations of the original netlist, used to break the netlist in ways that demonstrate how to track down and fix LVS errors. The file "map9v3_synth.spice is derived independently from a netlist created by the synthesis, prior to generating the layout (placement and routing). Because the synthesis tools work on the logic gate level, not the transistor level, the netlist contains only logic gate names, and so the file "osu035_stdcells.sp" contains the description of the contents of each logic cell.

Setting up for LVS

The comparison algorithm only understands the topology of the netlist, the connectivity between various devices in the design. Because SPICE is a well-established netlist format, having a netlist in SPICE allows the LVS system to understand a bit more about the devices, such as being able to tell apart transistors, capacitors, and resistors. These low-level devices with pinouts established by SPICE syntax are called "fundamental" devices. SPICE does not go into a great deal of detail over its transistors and other devices in the statements of the netlist where they are defined, often specified by a model name. The name refers to a model definition, which defines the default properties of the device. The model definition is found elsewhere in a (complete, e.g., for simulation) SPICE netlist. In many systems the model is in a separate file and is expected to be appended to the netlist before simulation. This is both good and bad for netlist comparison. On the good side, if both the schematic-derived and layout-derived netlists refer to the same model names for the same devices, then it is easy to compare devices using their model names. If, however, the schematic and layout use different model names, then one must provide the netlist comparator with additional information. For this reason, the LVS uses a "setup file". In cases where the schematic-derived and layout-derived netlists use the same device model names and the same names for subcircuits, and keep the same hierarchy, everything is straightforward and no setup file is needed. Anything more complicated requires a setup file, which is described below.

Netgen has a very simple concept for the setup file. The setup file is simply a file containing commands exactly as they would appear on the netgen command line. The file is sourced like any Tcl script, so Tcl/Tk commands can be used in the setup file as well as any netgen commands.

This tutorial will first run through some simple examples that do not require a setup file, before presenting some more complicated examples that do.

Running LVS

We'll start with a simple example. Download the files bufferA.spice and bufferB.spice. Like all files used in this tutorial, they are SPICE netlists. Examine both files with an editor of your choice. There are numerous differences between the formatting of the two files. bufferA.spice is extracted from a layout in Magic. Magic, for whatever historical reason, counts transistor devices from 1000, and adds information about the transistor area and perimeter that will increase the accuracy of a simulation. bufferB.spice has been created by a schematic capture tool, or possibly has been written by hand. The carriage-return characters and comment line indicate a Windows environment. It uses a non-standard (non-Berkeley SPICE, that is) keyword ".backanno". The order of the pins on the definition of subcircuit "inverter" is different from that of the first netlist. It contains device width and length information, but not area and parameter. But in spite of these syntactical differences, they describe the same circuit. A schematic drawing of the buffer circuit, showing the hierarchy down to the transistor level, is shown below.



Figure 1: Schematic of the buffer circuit used in the first examples.

Start netgen from the command line using:

netgen
You will get a console window that looks something like the following:
At the console window prompt, type the command
lvs bufferA.spice bufferB.spice
You will get a bit of output where netgen describes what it's doing as it goes along, ending with the lines
Result: Circuits match uniquely.
LVS Done
Indicating that netgen agrees that the two netlists describe the same circuit. If you look back through the output, you'll see various things, including where netgen gripes about the unknown ".backanno" command, where it shows each cell containing one nFET transistor and one pFET transistor, counts the nodes and devices, and reorders the pins to the inverter on one circuit to match the other.

The complete output will be found in an output text file dumped by netgen called comp.out. Edit or view this file now. In this file you will find a side-by-side comparison of the two netlists. Each one is decomposed hierarchically. First, the subcell "inverter" is presented, along with the devices it contains and the number of each. Then, there is a comparison result for only the inverter subcircuit. The result being a match, it is followed by a list of pins on the inverter subcircuit, matched up between the two files. Here you will see that most pins have the same name in both files, except that file "bufferA" uses the name "Gnd" for the ground node, while file "bufferB" uses the name "0" for the ground node.

After the pin lists for the inverter subcircuit, the output is repeated for the top-level circuit. The devices in each circuit are shown, along with the number of each kind. In this case, there is only one type of device, the subcircuit "inverter", and each file has two instances of each. The result of comparing the two circuits follows (which again is very short, because the circuits match exactly). Because the top-level circuit does not itself have pins, there is no pin list matchup at the end of the file for the top-level cells.

This is an example of a perfectly matched pair of netlists, and this sort of minimally informative output is the goal of any LVS run. As the number of errors between two circuits rises, the amount of output in the "comp.out" file rises, usually exponentially. Coping with the voluminous output from mismatched circuits is the main goal of the tutorial.

To end netgen, either type "quit" at the console prompt, or select "File->Quit" from the console pull-down menu.

Batch Mode LVS

As a quick aside, it should be noted that while this tutorial shows all sessions being run from the console window, it is possible (and often preferred) to run netgen in batch mode. As a simple example of a batch mode script, download the shell script file "runlvs.sh" from the downloads box above. This script is all of 38 bytes long. All it does is to run netgen with the "-noconsole" option (which then uses the terminal for input, and not a console window), accept two arguments off of the command line, and pass them as arguments to the "lvs" command in netgen, just like was typed into the console in the section above. Put this shell script in the current working directory, with permissions set to executable. From the terminal's shell prompt, do:
runlvs.sh bufferA.spice bufferB.spice
and you will get the same result as before, except that the output is sent to the terminal (and therefore can be redirected, such as into a log file), and at the end of it, netgen quits and returns you to the shell prompt. This batch style of executing netgen can be used with any tutorial example not having any interactive commands.

Another way to run a batch process is from the command line, using the "-batch" option:

netgen -batch lvs bufferA.spice bufferB.spice

Interpreting LVS Results

A perfectly matched netlist is all well and good, but the important thing with LVS is to understand how to interpret the output when two circuits do not match, so as to understand what to correct to make the netlists match.

Assuming that you have the files bufferA.spice and bufferB.spice from the last step, now download bufferBx.spice. If you look at the two files bufferB.spice and bufferBx.spice, you will see that they are identical except for the line ".global Vdd 0", which is missing from the file bufferBx.spice. Because this netlist has failed to declare nodes 0 and Vdd to be globals, the use of these names in the inverter subcircuit makes the nodes local to the subcircuit. The fact that there are nodes of the same names in the top level is irrelevant. These nodes define the bulk terminals of the FET devices (e.g., substrate for the nfet, n-well for the pfet).

The use of node 0 in SPICE files is generally assumed to be global. However, netgen does not make such a generalization, as it handles different formats, and other formats do not have an implicit global node 0. If a netlist uses node 0 but does not explicitly declare it to be global, the best strategy is to set up the node 0 in netgen to be global in the setup file.

Create a file called "setup.tcl" using your favorite editor, and add the following lines:

global bufferBx.spice 0
global bufferBx.spice Vdd
Now run netgen and type "lvs bufferB.spice bufferBx.spice" at the prompt. The output should show that the two netlists are equivalent. The missing ".global" line in the file has been taken care of by the global declarations in the setup file.

Quit netgen, and delete the setup.tcl file. Run netgen again, with the same command "lvs bufferB.spice bufferBx.spice". This time, the output says

Result: Graphs do not match.
We know that the reason they do not match is due to the treatment of the two nodes Vdd and 0 as local nodes. How could we figure this out from the netgen output?

Look at the output file comp.out. In the first few lines of the file, The two inverter subcircuits are compared, and they are declared matching. Within a single subcircuit, it is impossible to know whether a node is local or global. The way netgen deals with global nodes is to treat them as local within a subcircuit, but to pass them up to the parent circuit through pins that it adds to the subcircuit. In the comp.out output, following the subcircuit match, there is a list of pins for the two subcircuits and how they match up to each other. Here, it can be seen that the global nodes "Vdd" and "0" of circuit "bufferB.spice" have been converted to ports of the subcircuit. On the other side, circuit bufferBx.spice has no equivalent pins. This is the first clue, and the problem could be debugged using this information alone. However, we will continue to look at the output file.

After netgen fails to match all the pins from subcircuit "inverter" between the two netlists, it merges the subcircuits into the parent circuit, or, in other words, selectively flattens the hierarchy of the parent circuit. It does this because often, in circuit design, a layout or a schematic may contain an extra level of hierarchy, or a different hierarchical composition. The circuits may be correct, but they aren't correct for every subcircuit at every level of the hierarchy. By selectively flattening circuits where the subcircuits cannot be matched, netgen can cope with such structural differences without abandoning the hiearchical matching altogether. In the case where a global node is used throughout a netlist and has not been declared global, the circuit may end up completely flattened by the end of the netlist matching.

In this output, we first get a "Subcircuit summary:", naming the two circuits (now at the top level, so the circuit name is the same as the filename), and a list of elements (components). Because the inverter subcircuit has been selectively flattened, and each top-level circuit had two inverters, each flattened netlist now has the contents of the two inverters, which is two pfet and two nfet devices each. This list is followed by a total count of elements and nodes (nets) in each cell. The second clue to the error is that Circuit 2 has 9 nodes, while Circuit 1 has only 5 nodes.

The main diagnostic output is what follows the circuit summary. This is split into two sections: The first is a list of "Illegal element partitions", and the second is a list of "Illegal node partitions". All devices that could not be matched up 1:1 between the two circuits being compared will end up in one or more illegal element partitions, and all nets that could not be matched up 1:1 between the two circuits being compared will end up in one or more illegal node partitions. Each partition (either element or node) will have a list of devices/nets, those on the left side belonging to Circuit 1, and those on the right side belonging to Circuit 2. It is very important to understand that there is no implied order in these lists! It should not be assumed that the first entry in the left-hand list is somehow equivalent to the first entry in the right-hand list. (That said, netgen could potentially use heuristic methods to attempt a sensible matchup between the two lists, but that is a project for a future release.)

Generally speaking, the element partition information is the least useful, but here we will explain what it means anyway. Let's look at the first partition output:

Instance: inverterX1/nfetXU2 Instance: inverterX1/nfetXU2
(drain,source) = (4,2) (drain,source) = (2,2)
gate = 4 gate = 4
bulk = 4 bulk = 1
The first line gives the name of the device. Because the hierarchy has been flattened, the name includes the name of the subcircuit in which that device appears. In this case, the names are the same in both circuits. The device is model "nfet", and the SPICE line calling the subcircuit named the instance "XU2". This device was inside the subcircuit called "inverter", whose instance was "X1" on the SPICE line. Each name includes both the model or subcircuit name and the instance name. This naming convention is entirely due to netgen, but is clear enough that one can easily determine what line in the SPICE file the instance comes from.

After the device name, netgen dumps a list of fanouts for each pin of the device. The fanout list is a count of the total number of device pins connected to that pin, including itself (multiple pins on the same device will be counted individually). So the minimum count is one, and if a "1" shows up in the device fanout, then you have a pin that is not connected to anything else, and that is nearly always an error. Here is clue number 3: The illegal element partition list for the second circuit shows every FET device in the circuit with a fanout of "1" on the "bulk" pin, so "bulk" is unconnected on each device, which is clearly an error.

A quick explanation of the line "(drain,source) = (4,2)": FET devices have two terminals called the "source" and the "drain", where typically the source is on the side of the device closest to the supply rail (ground for nFET devices, power for pFET devices). Physically, however, in a VLSI layout, standard FET devices are completely symmetrical, and the use of the terms "source" and "drain" is largely symbolic, because they are electrically and functionally identical (some special FET devices have different properties on source and drain sides, but that is another topic). Without some knowledge about the structure of the circuit and which power supply rail is which, the circuit extractor cannot determine which end of the device may be the source, and which may be the drain. Due to the symmetry of the device, it doesn't matter which end of the device is called the "source" and which end is called the "drain". Therefore, we call these two pins "permutable". There is a command in netgen, "permute default", that is run as part of the script for the procedure/command "lvs". This command tells netgen to make the two endpoint pins of all resistors and the source and drain pins of all devices called "nfet" and "pfet" permutable. With that command issued, a transistor in one circuit may be connected with the source at the top and the drain at the bottom, while the equivalent transistor in the other circuit is connected with the source at the bottom and the drain at the top, and they will still match. Later in this tutorial we will look at other uses for the "permute" command and pin permutations in general. Now, back to the output: The line "(drain,source) = (4,2)" means that on this device, "drain" and "source" are permutable pins. Netgen cannot be sure which is which, but it knows that one of them has a fanout of 4 (connects to three other device pins, therefore 4, including itself), and the other has a fanout of 2. So it writes the fanout according to the syntax shown above, to describe this ambiguity.

Now let's look at the illegal node partition output, which is generally the most useful in pinpointing errors. Here, the first partition starts with the output:

Net: Vdd Net: Vdd
pfet/(drain|source) = 2 pfet/(drain|source) = 2
pfet/bulk = 2
The first line of each block of output is "Net:" and gives a name of the net. This is followed by a fanout, similar to the element partition output, except that each entry in the fanout list is a device type (the instance is not specified) and pin that connects to the named net. Here, it is very easy to see that the net "Vdd" is connected to the drain (or source) and bulk of two pFET devices in Circuit 1, while it is connected only to the drain (or source) of two pFET devices in Circuit 2. Clearly Vdd is not connected to the pFET bulk connections anywhere in Circuit 2, and that is clearly the problem. It is the last and final clue, and all clues point to disconnected bulk connections, which can be traced back to the lack of a global declaration for Vdd.

Note that in the node partition output, if two or more pins on a device are permutable, they are listed together, in parentheses, and separated by "|" to indicate a logical OR, as in the above output "pfet/(drain|source) = 2". This syntax means that the net is connected to 2 pfet pins, each of which may be either a drain or a source connection.

Getting detailed information about components and nets

Suppose that given all the clues, we still could not figure out where the error is? The comp.out file, although full of information about bad element and node partitions, does not give a complete description of everything. For example, the elements list fanout counts on each pin, but not what net names are connected to each pin. The nets list fanout counts of elements connected to the net, but do not specify which instances of those elements are connected. As long as the netgen console window is still up after running LVS, these things can be queried from the netgen command line. In the output file, we have "Instance: inverterX1/pfetXU1" in the column for Circuit 2, with "bulk = 1", which is the disassociated node. If we want detailed information about this element, then type in the console:
nodes inverterX1/pfetXU1 bufferBx.spice bufferBx.spice
Note that "bufferBx.spice" is both the top-level cell and the filename associated with Circuit 2, which is why it shows up twice on the line above. The output of this node query is the following:
Element 'inverterX1/pfetXU1' Pins:
Pin 1 (drain) = Vout
Pin 2 (gate) = N001
Pin 3 (source) = Vdd
Pin 4 (bulk) = inverterX1/Vdd
This gives us all the information we need: The bulk connection on this specific element instance is "inverterX1/Vdd ". Because in this case the name "Vdd" is prefixed with an instance name, the node is not the same as "Vdd" by itself; it is a node local to the instance "inverterX1".

A node can also be queried to find all of the elements connected to it. If we want to know if there are any other device pins connected to that node "inverterX1/Vdd", we can find out using the command:

elements inverterX1/Vdd bufferBx.spice
which yields the output:
Node 'inverterX1/Vdd' in cell 'bufferBx.spice' connects to:
inverterX1/pfetXU1/bulk
showing that the bulk connection of "inverterX1/pfetXU1", is not connected to anything else (which was already stated by the fanout of 1 shown for this connection in the comp.out file).

The netlists as seen by the "nodes" and "elements" commands reflect the final state when LVS is finished. Cells that were unmatched and therefore flattened in the course of netlist comparison can also be queried. For example, use the command:

nodes pfetXU1 inverter bufferB.spice
and the result is:
Element 'pfetXU1' Pins:
Pin 1 (drain) = out (port of inverter)
Pin 2 (gate) = in (port of inverter)
Pin 3 (source) = pos (port of inverter)
Pin 4 (bulk) = Vdd (port of inverter)
while the command:
nodes pfetXU1 inverter bufferBx.spice
yields the result:
Element 'pfetXU1' Pins:
Pin 1 (drain) = out (port of inverter)
Pin 2 (gate) = in (port of inverter)
Pin 3 (source) = pos (port of inverter)
Pin 4 (bulk) = Vdd
This is yet another way that shows that the bulk connection to the transistor is a local node, where it should have been a global node or a port to the cell.

Non-Matching Element Counts

Continuing with the netlists of the last example, let's look at the output for the case of non-matching element counts. Edit the netlist "bufferB.spice", and, at the end, but before the ".end" statement (that is, make sure it's defined in the top-level cell, not in the inverter subcircuit), add the line:
MXU3 Vdd Vdd Vdd Vdd pfet W=1.8u L=0.6u
This is a typical entry for a "dummy" transistor, one which is added to a layout to provide better matching of the characteristics of different transistors in an array, or in a differential pair. It is not uncommon to forget these in a schematic drawing, so it is useful to know what they look like when they cause a netlist to be unmatched. Run netgen again, with the modified netlist, and enter the command "lvs bufferA.spice bufferB.spice.

This time, in the comp.out output file, there are two clues to the error. The first is in the summary of the top-level circuits:

inverter (2) inverter (2)
(no matching element) pfet (1)
Number of elements: 2 **Mismatch** Number of elements: 3 **Mismatch**
Here we have a very clear picture of what's going on: The summary shows that both circuits have two inverters, but Circuit 2 has the additional "pfet" component that does not exist in Circuit 1. Once again, this error plays out in both the illegal element partition list and the illegal node partition list. The illegal element partition list shows the extra pfet, with "(no matching instance)" on the other side for Circuit 1, and the name of the instance ("pfetXU3") is shown, which leads us to look for a line "XXU3 ... pfet ..." in the netlist file. And from the illegal node partition, we can see that the net Vdd has connections to pfet drain (source), gate, and bulk, consistent with a dummy transistor.

A Mixed Hierarchy Example

It was mentioned in the first example that the reason for selectively flattening subcircuits in a netlist is to correctly identify matching in circuits with a "mixed hierarchy", that is, in which the hierarchical structure of one circuit is different from another, even though they describe the same netlist.

Files hier1.spice and hier2.spice show what is meant by a "mixed hierarchy". Download these two files now, if you have not already done so. The circuit is a simple buffer, like the previous examples. If you look at hier1.spice, however, you will see that it has an additional layer of hierarchy by defining a subcircuit called "buffer" and then instantiating it at the top level. File hier2.spice also defines a subcircuit "buffer" and instantiates it at the top level, but it does not define an additional subcircuit called "inverter", but instead implements the two inverters implicitly as a circuit of four transistors.

Run netgen and issue the command "lvs hier1.spice hier2.spice". You can see that netgen declares the two circuits matched. If you look at the output in "comp.out", you will see that there is no comparison at all of the subcell "invert". At the top of the file is the line:

Flattening unmatched subcell invert in circuit buffer
As netgen reads in two netlist files, it tries to match up subcircuits by name, on the assumption that a schematic and layout will keep the same naming conventions of an entire circuit hierarchy (apart from the top-level cell). Usually this is a good assumption. What to do when it is not a good assumption will be covered in the next tutorial. In this case, though, netgen finds a subcircuit named "buffer" in both netlists, and assumes they should be matched. However, it finds a subcircuit called "invert" in one netlist but not in the other. Having nothing to match it to, it selectively flattens the invert subcircuit, quietly, then continues with the comparison of the buffer circuits.

Handling non-matching subcell names

Sometimes cells that are functionally the same are named differently between schematic and layout. Often this is simply a matter of one being lower case and the other upper case; in SPICE, which is case-insensitive, these would be considered the same name. Netgen will ignore problems of case-sensitivity if both cells being compared have come from SPICE netlists. But sometimes, a cell or a fundamental device may just be named differently between the schematic and layout.

Consider the two netlists map9v3.spice and map9v3_test2.spice, which you should download if you have not already. The cell map9v3.spice will be used for the next three examples. It is a standard-cell layout, originally generated from verilog source code. For this example, both netlists were generated from the layout, and the second one has been manipulated by hand for the purpose of the tutorial.

First, take a look at these two files in an editor of your choice. They are nearly identical, but the second netlist has replaced all the cell names with different names, and an error has been introduced into the file.

Note: The original version of this tutorial used lowercase vs. uppercase names. Because the SPICE netlist format is not case-sensitive, netgen code was reworked in version 1.4.55 (February 2014) to do case-insensitive name matching when both input files are in SPICE format. This version and newer versions of netgen will match a cell named, for instance, "NAND2" in one netlist to a cell named "nand2" in the other netlist.

Bring up netgen and enter the command "lvs map9v3.spice map9v3_test2.spice". The result of this is "Graphs do not match". Now, look at the file comp.out. Here you will find a long list at the top where every cell has been flattened. You may also have noticed that the LVS computation took a noticeable amount of time to run. What happened was that netgen did not consider any of the uppercase names to match the lowercase names. Not willing to match up the subcircuits by name, it flattened them all before the comparison, and made the netlist comparison at the transistor level. You will see toward the end of the file a summary of the contents of the two netlists, showing the netlists not as a collection of a number of standard cells, but as a collection of a large number of transistors. Because the error introduced into the second file was a trivial change to an internal net, and because the hierarchy is only two-deep, the output is fairly easy to interpret and the error easy to trace. But imagine trying to trace a complicated error through a circuit of tens of thousands of transistors!

By the way, it should be clear from the comp.out output that there is one network in file map9v3.spice called "OAI22X1_3/Y", and it quite clearly matches two nets in map9v3_test2.spice, and so it is pretty simple to conclude that the second netlist has (purposefully!) chopped one of its nets in two, and those two nets need to be connected back together (because this is a hand-edited netlist, the solution to fix the netlist is to rename the net "BADNODE" to "oai22X1_3/Y").

So netgen isn't matching the cell names. What do we do about it? This is where the setup file becomes very useful. Download the setup file setup.tcl.save if you haven't already, and copy the file to setup.tcl. Take a look at this file. You will see that it is simply a set of commands "equate classes" and each line specifies a cell in the naming convention of the first netlist, and a cell in the naming convention of the second netlist. This tells netgen that the two cells indicated in the command should be considered potentially equal. This will cause the cells to be compared against each other, as opposed to being flattened into the parent cell.

With the setup.tcl file in place, run netgen again with the same command "lvs map9v3.spice map9v3_test2.spice". Look at the file comp.out. In particular, search for the word "Flattening". You won't find it. This indicates two things: that netgen has found a match for each subcell in each circuit, and that the error (assuming you didn't fix it) is not inside a subcell (which would cause the subcell not to match, and therefore force it to be flattened). You may have noticed a substantially faster runtime for netgen, as well. At the end of the file, the contents of each netlist is a collection of standard cells, not transistors. The error is, of course, the same, with the same solution, but it is clear from the output that the error is on the top level of the hierarchy, and not inside a subcell, a fact that helps in finding and correcting the error.

Here's a good exercise to try: (1) correct the error in the netlist and get netgen to generate a "Graphs match uniquely" message, and (2) introduce an error (by hand) into a subcell and see how this affects the output. For example, take any random node name in one of the subcells in map9v3_test2.spice and change it to "BADNODE2". You will probably notice immediately that the error output in file comp.out is much more extensive than before. That's because where a subcircuit is incorrect, that failure is replicated in every instance of the subcircuit. When netgen can't successfully compare the subcircuit in the two netlists, it flattens every instance, replicating the error in the top level cell. When tracing such an error, you will need to find the first occurrance of " ILLEGAL node partitions" in the output file. Noting that this output is produced for one of the subcells, it indicates that the error in the subcell should be attended to (and corrected) first. That will avoid the hassle of having to deal with the copious output for the top-level cell comparison.

If you are looking first at the output for the top-level cells, you would be well advised to notice that the low-level devices "nfet" and "pfet" appear in the summary for both circuits. Because both circuits are made from standard cells, the presence of these low level devices should be an alert that some error occurred in a subcell and the subcell has been flattened.

Mixed hierarchy at the top level

Here is a not-so-uncommon issue, and a more realistic example than hand-edited netlists. Download the netlist file "map9v3_synth.spice" and the library file "osu035_stdcells.sp". In the course of synthesizing a digital circuit from verilog (hardware description language), the synthesis process first generates a netlist, then generates a layout. We have previously looked at a netlist that was created by taking the synthesized layout and extracting a netlist from it. Here, we have a circuit that is converted directly from the netlist created by the synthesis tool. Start up netgen and issue the command: "lvs map9v3.spice map9v3_synth.spice". Netgen will produce a comp.out file, comparing cells from bottom up. But on the console or terminal, the last thing it prints out is:
Contents of circuit 2: Cell: 'map9v3_synth.spice'
Cell map9v3_synth.spice contains 0 instances.
This may seem a bit odd, because the cell "map9v3_synth.spice" seems to have a lot of stuff in it. It's definitely not an empty netlist. But if you look closely at the file, you may notice that while the circuit contains a subcircuit called "map9v3", it does not actually instantiate this circuit anywhere. That is, there is no line in the file beginning with "X" and ending with "map9v3". The file is very much like the library file that it includes ("osu035_stdcells.sp"), in that it defines subcircuits but does not contain (that is, instantiate) any actual circuit itself.

But what we really want to do here is to compare the top-level circuit in the file "map9v3.spice" against the subcircuit defined in the file "map9v3_synth.spice". One way to do this would be to strip the lines ".subckt ..." and ".ends" out of the second netlist file. But there is an easier way to make the comparison without changing the contents of the file. Start up netgen again and this time issue the command: "lvs map9v3.spice {map9v3_synth.spice map9v3}". This time you will get a proper comparison. And you will find out that the two netlists don't match. Can you figure out why?

First hint: Look at the first two nets listed in the "ILLEGAL node partition"

Second hint: Synthesized logic circuits will be placed in rows, and somebody needs to tell the router to connect up power and ground between all the rows. . .

But the main point of this exercise is to show that the use of a (Tcl) list of two names "{filename cellname}" tells netgen to make the comparison against a specific subcircuit named cellname that is in the file filename. The subcircuit could, in fact, be a circuit deeper in the hierarchy. You could, for example, start up netgen and issue the command: "lvs {map9v3.spice BUFX2} {map9v3_synth.spice BUFX2}" and you would get a comparison only between the two subcells named "BUFX2".

NOTE: In the Tcl "tkcon" console window, the {filename cellname} list can also be specified in quotes instead of braces, as this is an alternative way to specify lists in Tcl/Tk. However, for the batch file execution, specifying the Tcl list in a way that doesn't get modified by the shell is a bit of a challenge. The correct way to specify both the file and cell to the batch-mode "runlvs.sh" command is the following:

runlvs.sh map9v3.spice "{map9v3_synth.spice map9v3}"

Non-matching component parameters

Download the file "map9v3_test.spice". Make sure you still have the file "setup.tcl" in place. Run netgen and issue the command "lvs map9v3.spice map9v3_test.spice". Here is the output you should see:
Result: Circuits match uniquely.
The following cells had property errors: BUFX2
LVS Done
The way to interpret this output is that the structure of the two netlists was the same, but that some element or elements within the netlist (in this case, inside the cell BUFX2 as indicated) had properties that were different between the two netlists. A property is a value passed to a device, such as width or length for a transistor, a component value for a resistor or capacitor, and so forth. Netgen will parse most standard parameters like transistor width and length, and parameters whose names match between the two netlists. Netgen will ignore parameters that appear in one netlist but not in the other, assuming that parameters which are missing are not of interest to the netlist comparison.

Look at the file comp.out resulting from this run of netgen. The notice of property errors on the console window is a cue to go looking for the text "Property errors" in the comp.out file. If you do, you will see the full explanation of the error:

Circuits match uniquely.
Property errors were found.
Graphs match uniquely.
There were property errors.
nfet1003 vs. nfet4:
width circuit1: 4e-06 circuit2: 2e-06 (delta=5e+01%, cutoff= 1%)
This pinpoints the error as being a transistor "nfet1003" in cell "BUFX2" in circuit "map9v3.spice" having a width of 4um, while the (structurally) matching transistor "nfet4" in cell "bufX2" of circuit "map9v3_test.spice" has a width of 2um. The remaining text says that the difference is 50% (the transistor in the first circuit has a width 50% that of the transistor in the second circuit); and the netlister has a cutoff criterion of 1%, meaning that differences in width less than 1% will be ignored (considered matching). The cutoff criterion is needed to avoid problems with slight differences in the measurement of, for example, bent devices, or round-off errors in scaling.

These errors can be traced back to the netlists; device "nfet1003" is, in the SPICE netlist, transistor record "M1003" with device model name "nfet", at line 10 of file "map9v3.spice":

M1003 Y a_10_30# gnd Gnd nfet w=4u l=0.4u
+ ad=8.8p pd=18.4u as=4p ps=10u
while device "nfet4" is transistor record "M4" with device model "nfet" at line 7 of file "map9v3_test.spice":
M4 Y a_10_30# gnd Gnd nfet w=2u l=0.4u
Note that the file "map9v3.spice" has additional information for each transistor, including area and perimeter values for transistor source and drain. Because these appear in one file but not the other, netgen ignores them and does not flag this as an error.

Automorphisms in circuit hierarchy

Automorphisms were described above in "The Algorithm" section as portions of a circuit which have the same connectivity and are therefore indistinguishable from one another. It is pretty easy to construct a circuit that has automorphisms. For example, download and inspect the two files morph1.spice and morph2.spice. The contents can be schematically shown as in the figure below:
As you can see, the two circuits are equivalent, but the inputs are connected to different inverters in the same cell. As far as the netlist is concerned, the three inverters are identical, and indistinguishable. This makes the netlist of the two subcells "triinvert" have multiple automorphs. If you run LVS on these two files, the output will report:
Graphs match with 4 automorphisms.
Circuits match correctly.
Reordering pins on instance triinvert1

More setup file tricks

There are occasions when a correct netlist will not be able to pass LVS due to unexpected mismatches in the hierarchy. For example, a resistor network in two cells may contain a subcircuit with four resistors (let's call it "res_array") and an additional lone resistor not in a subcircuit. Both circuits have the same name ("res_array") for the subcircuit containing the four resistors, so those two subcircuits are matched and pass LVS. However, each netlist makes different connections to those resistors. To the LVS tool, each circuit has one instance of "res_array" and one resistor device, so they appear to be matched; but these have different network connectivity in each cell, so the LVS fails. Depending on the circumstance, the end-user may want this situation to fail LVS, such as if the resistors in "res_array" are in a special layout with best-matching practices, and using the lone resistor instead of one in the array would be considered an error.

In the case that it is known not to be an error, the LVS can be made to pass by specifically forcing netgen to flatten the resistor array in both circuits, in setup.tcl:

flatten parent_cell {res_array file1}
flatten parent_cell {res_array file2}
Note that this use requires netgen version 1.5.53 or newer. Previous versions would only allow "flatten {res_array file1}", which would flatten all instances of res_array in the whole file, not just within the cell parent_cell . That works, but at the expense of losing a level of hierarchy in cells where it was not necessary to do so.

In general, properties are compared where both netlists define them for a cell, instance, or (low-level) device. If only one of the netlists defines a property, it is assumed to be meaningful only to that netlist (e.g., relevant to layout or schematic, but not both), and no warning is issued about missing properties in the other netlist. Sometimes, however, properties exist in both netlists but are often in disagreement not due to an error in the netlists, but due to the way different tools generate or use those values. A typical example is the source and drain area and perimeter values for MOSFET devices. In SPICE files, these are given the (fixed) names "AD", "PD", "AS", and "PS". In cases where these are present in both netlists, are often conflicting, and are generating large amounts of unnecessary output, they can be supressed by deleting them from one of the nelists:

property {file1 nmos} remove ad as pd ps
property {file1 pmos} remove ad as pd ps
where "file1" is the name of one of the netlist files. It is not necessary to remove the parameters in both netlists, although it is necessary to have one statement per device that defines those properties. (To be completed)

Tips for large netlists and messy output

It is generally best to avoid flattening netlists unless absolutely necessary. Use hierarchical netlists whenever possible, and keep the hierarchies the same between the two netlists. It will be much easier to track errors when each cell has a handful of subcircuits with pins instead of possibly thousands of devices. If a circuit has to be flattened, use commands in the setup file to flatten only those circuits for which it is needed (see above). Don't flatten any cells until it becomes apparent that LVS will fail without it.

(To be completed)

Tutorial History

November 24, 2007
Placeholder created for netgen tutorial
October 8, 2012
Finally getting around to writing the tutorial. . .
November 1, 2012
Moving on to describing the examples.

email:

Last updated: May 16, 2016 at 9:32pm