The actual compare step is rather simple. Provided you have set up the extraction (extract_devices), the connectivity (connect, connect_global, connect_implicit) and provided a reference netlist (schematic), this function will perform the actual compare:
compare
This method (compare will extract the netlist (if not already done) and compare it against the schematic. It returns true on success and false otherwise, in case you like to take specific actions on success or failure.
The compare step can configured by providing hints.
It can be useful to declare two nets as identical, at least for debugging. The compare algorithm will then be able to deduce the real causes for mismatches. It is helpful for example to provide equivalence for the power nets, because netlist compare fails will often cause the power nets no to be mapped. This in turn prevents matching of other, good parts of the circuit. To supply a power net equivalence for "VDD" within a circuit (e.g. "LOGIC"), use this statement:
same_nets("LOGIC", "VDD", "VDD:P")
In this example it is assumed that the power net is labeled "VDD" in the layout and called "VDD:P" in the schematic. Don't leave this statement in the script for final verification as it may mask real errors.
"same_nets" can also be used to require a matching between specific nets. This is useful on top level to check for matching nets assigned to specific pads. This allows checking correct pad assignment. For example to check whether the same net is attached to the "VDD" pad, label the net "VDD" in the layout and specify:
same_nets!("CHIP", "VDD", "VDD")
The exclamation-mark version will report a net mismatch if either there is no "VDD" net in either layout or schematic or if these nets to not match. The above specification can be abbreviated as layout and schematic net name are identical:
same_nets!("CHIP", "VDD")
It's also possible to specify pattern for circuit names or net names. This example requires all nets starting with "PAD" to have a counterpart in layout and schematic for circuit "TOP" and each of these pairs has to match:
same_nets!("TOP", "PAD*")
So it is an error if there is a PAD1 net in layout but none in the schematic. It is also an error if a net called PAD2 is there is layout and schematic but they do not match.
"same_nets" and "same_nets!" can appear anywhere in the LVS script.
For more information about "same_nets" see same_nets and same_nets!.
By default, circuits with the same name are considered equivalent. If this is not the case, equivalence can be established using the same_circuit function:
same_circuits("CIRCUIT_IN_LAYOUT", "CIRCUIT_IN_SCHEMATIC")
Declaring circuits as 'same' means they will still be compared. The function is just a hint where to look for the compare target.
By default, device classes with the same name are considered equivalent. If this is not the case, equivalence can be established using the same_device_classes function:
same_device_classes("PMOS_IN_LAYOUT", "PMOS_IN_SCHEMATIC") same_device_classes("NMOS_IN_LAYOUT", "NMOS_IN_SCHEMATIC")
This method can be used also multiple times to establish a many-to-many equivalence:
same_device_classes("POLYRES", "RES") same_device_classes("WELLRES", "RES")
If one target is "nil", the corresponding devices are basically ignored:
# ignores "POLYRES" devices: same_device_classes("POLYRES", nil)
When comparing device parameters, by default strict equivalence is required. However, when drawing a device like a resistor, it's usually difficult to match the exact value unless the resistor calibration is consistent with drawing grids and the resistor geometry is not confined by design rule constraints. So sometimes the target value or a device parameter can only be approximated in the layout. This will by default lead to a mismatch.
The solution is to specify parameter tolerances. Tolerances can be specified in an absolute or relative fashion. If an absolute tolerance is given, the layout parameter may deviate from the target value by this tolerance either to lower or higher values. So the unit of the tolerance is the same than the unit of the parameter.
If a relative tolerance is given, the deviation is computed from the target value times the tolerance. So the relative tolerance is a factor and a value of 0.05 for example specifies an allowed deviation of plus or minus 5%. Relative tolerances are unit-less.
It's also possible to specify both an absolute and a relative tolerance. In this case, both tolerances add and the allowed deviation becomes larger.
To specify an absolute tolerance, use the tolerance function:
tolerance("NMOS", "L", 0.05)
The two arguments are the name of the device class and the name of the parameter for which the tolerance will be applied. In the case above, a tolerance of 50nm (the unit of L is micrometer) is applied to the length parameter of "NMOS" devices.
A relative tolerance is specified as an additional forth parameter. You can set the absolute tolerance to zero to specify only relative tolerances. This will specify 1% tolerance for the "L" parameter of "NMOS" devices:
tolerance("NMOS", "L", 0.0, 0.01)
There is also a more explicit notation for the tolerance:
tolerance("NMOS", "L", :absolute => 0.05)
or
tolerance("NMOS", "L", :relative => 0.01)
An absolute plus relative tolerance can be specified by giving both. The following calls will give you 50nm absolute and 1% relative tolerance for the "L" parameter of "NMOS" devices:
tolerance("NMOS", "L", 0.05, 0.01) tolerance("NMOS", "L", :absolute => 0.05, :relative => 0.01)
It is possible to ignore certain parameters from certain devices in the netlist compare. For example, if you don't want to compare the "L" parameter of the "NMOS" devices, use this statement:
ignore_parameter("NMOS", "L")
This statement can be put into the script anywhere before the "compare" statement.
By default, only "primary" parameters are compared. For a resistor for example, "R" is a primary parameter, the other ones like "L", "W", "A" and "P" are not. Using "tolerance" will implicitly enable a parameter - even if it is not a primary one - while "ignore_parameter" will disable a parameter for compare - even if it is a primary one.
As mentioned before, some device parameters are primary while other are not. For example, for the resistor device, "R" (the resistance value) is a primary parameter while the device length ("L") is not. You can make the "L" parameter primary for a device class called "RES" by using:
enable_parameter("RES", "L")
This has two effects: first, the "L" parameter is written into the Spice output netlist and in addition it is compared against the schematic "L" parameter.
Correspondingly, a primary parameter can be disabled using:
disable_parameter("RES", "R")
This behavior is overridden by a "tolerance" or "ignore_parameter" specification for that parameter or if a custom device comparer is installed. Netlisting is affected only for the elementary devices (R, C and L) and any Spice writer delegate can choose to ignore the primary flag. A custom device comparer may also ignore this flag. So after all, enabling or disabling a parameter is not a strong concept but rather a hint.
Pin swapping can be useful in cases, where a logic element has logically equivalent, but physically different inputs. This is the case for example for a CMOS NAND gate where the logic inputs are equivalent in function, but not in the circuit and physical implementation. For such circuits, the compare function needs to be given a degree of freedom and be allowed to swap the inputs. This is achieved with the equivalent_pins function:
equivalent_pins("NAND_GATE", "A", "B")
The first argument is the name of the circuit in the layout netlist. You can only specify equivalence in layout, not in the reference schematic. Multiple pins can be listed after the circuit name. All of them will be considered equivalent.
This feature allows eliminating "open" resistors and capacitors. Serial resistors cannot be elimiated currently (shorted).
To eliminate all resistors with a resistance value above a certain threshold, use the max_res function. This will eliminate all resistors with a value >= 1kOhm:
max_res(1000)
To eliminate all capacitors with a capacitance value below a certain threshold, use the min_caps function. This will eliminate all capacitances with a value <= 0.1fF:
min_caps(1e-16)
Good layouts are built hierarchically and the netlist compare can make use of hierarchy. "Hierarchically" means that a circuit is built from cells which itself map to subcircuits of the schematic netlist. The netlist extractor tries hard to maintain the hierarchy and the netlist compare will utilize the hierarchy to provide more meaningful reports and enable a bottom-up design approach.
Given a hierarchical layout and schematic netlist, the compare algorithm will work bottom-up: it will first compare the leaf circuits (circuits without subcircuit calls) and if those match, it will continue with the calling circuits. This approach is more efficient and fosters a clean relationship between layout and schematic netlist.
To enable hierarchical extraction, you must use "deep" mode (deep). If the deep mode statement is missing, the layout netlist will be flat (i.e. without subcircuits).
The second useful feature is "align" (align). This statement will remove circuits from the layout or schematic netlist which are unknown in the other netlist. Often, layouts contain helper cells which are not corresponding to a circuit (e.g. via cells). These are removed in this step. Eventually, this step will also flatten the schematic netlist if the layout has been extracted in a flat way.
In general, it's a good idea to include "align" before "netlist.simplify" or similar netlist manipulation and the "compare" step.
A very useful side effect of "align" is this: it will remove circuits above the top level circuit of either side. So it will eventually render a sub-tree from the circuit tree and use that for compare. This enables subcell verification: by selecting a subcell in the layout hierarchy, an "align"-enabled LVS script will compare this cell against the corresponding subcircuit in the schematic netlist. It will ignore the parent hierarchy of this subcircuit. This way, you can work yourself upwards in the hierarchy and fix LVS errors cell by cell with the same schematic netlist.
The coarse flow of the netlist compare algorithm is this:
foreach circuit bottom up: if matching circuit found in reference netlist: if all subcircuits have been matched and pin matching has been established for them: compare net graph locally from this circuit else: skip circuit with warning else: issue a circuit mismatch error
A consequence of this flow is that the compare will stop treating parent circuits when one circuit's pins can't be matched to pins from the corresponding reference circuit or the corresponding circuit can't be found in the reference netlist. This behaviour fosters a bottom-up debugging approach: first fix the issues in subcircuits, then proceed to the parent circuits.
The local net graph compare algorithm is a backtracking algorithm with hinting through topological net classification. Topological net classification is based on nearest-net neighborhood. The following image illustrates this:
Here the IN net's neighborhood is VDD via a traversal of gate to source/drain over M1, to OUT via a twofold traversal of gate to source/drain over M1 and M2 and to VSS via another single traversal of gate to source/drain over M2. This uniquely identifies IN in this simple circuit. In effect, OUT, VDD and VSS can be identified uniquely because their transitions from the IN net are unambigously identifying them. The topological neighborhood is a simple metrics which allows identifying matching nets from two netlists and deducing further relations.
In big netlists, the algorithm will first try to match nets unambigously according to their neighborhood metrics and register them as paired nets. Such pairs often allow deducing further matching pairs. This deduction is continued until all non-ambiguous pairing options are exhausted. For resolving ambiguities, backtracking is employed: the algorithm proposes a match and tentatively proceeds with this assumption. If this execution path leads to a mismatch or logical contradiction, the algorith will go back to the beginning and restart with a new proposal. Backtracking is usually required mainly to match networks with a high symmetry such as clock trees.