WIP: added documentation to LVS script.

This commit is contained in:
Matthias Koefferlein 2019-06-28 12:50:55 +02:00
parent a8f8ca0d7d
commit ed41af9b4b
3 changed files with 196 additions and 34 deletions

View File

@ -13,21 +13,6 @@ module DRC
# as global functions too where they act on a default incarnation
# of the netter. Usually it's not required to instantiate a Netter
# object, but it serves as a container for this functionality.
# %LVS%
# @scope
# @name Netter
# @brief LVS Reference: Netter object
# The Netter object provides services related to network extraction
# from a layout plus comparison against a reference netlist.
# Similar to the DRC netter (which lacks the compare ability), the
# relevant method of this object are available as global functions too
# where they act on a default incarnation. Usually it's not required
# to instantiate a Netter object explicitly.
#
# An individual netter object can be created, if the netter results
# need to be kept for multiple extractions. If you really need
# a Netter object, use the global \netter function:
#
# @code
# # create a new Netter object:
@ -394,11 +379,11 @@ module DRC
def ensure_data
if !@l2n
@layers = {}
make_data
_make_data
end
end
def make_data
def _make_data
if @engine._dss
@engine._dss.is_singular? || raise("The DRC script features more than one or no layout source - network extraction cannot be performed in such configurations")

View File

@ -66,7 +66,56 @@ module LVS
@output_lvsdb_file = filename
end
# ...
# %DRC%
# @name schematic
# @brief Reads the reference netlist
# @synopsis schematic(filename)
# @synopsis schematic(filename, reader)
# @synopsis schematic(netlist)
# See \Netter#schematic for a description of that function.
# %DRC%
# @name compare
# @brief Compares the extracted netlist vs. the schematic
# @synopsis compare
# See \Netter#compare for a description of that function.
# %DRC%
# @name same_nets
# @brief Establishes an equivalence between the nets
# @synopsis same_nets(circuit, net_a, net_b)
# @synopsis same_nets(circuit_a, net_a, circuit_b, net_b)
# See \Netter#same_nets for a description of that function.
# %DRC%
# @name same_circuits
# @brief Establishes an equivalence between the circuits
# @synopsis same_circuits(circuit_a, circuit_b)
# See \Netter#same_circuits for a description of that function.
# %DRC%
# @name same_device_classes
# @brief Establishes an equivalence between the device_classes
# @synopsis same_device_classes(class_a, class_b)
# See \Netter#same_device_classes for a description of that function.
# %DRC%
# @name equivalent_pins
# @brief Marks pins as equivalent
# @synopsis equivalent_pins(circuit, pins ...)
# See \Netter#equivalen_pins for a description of that function.
# %LVS%
# @name min_caps
# @brief Ignores capacitors with a capacitance below a certain value
# @synopsis min_caps(threshold)
# See \Netter#min_caps for a description of that function.
# %LVS%
# @name max_res
# @brief Ignores resistors with a resistance above a certain value
# @synopsis max_res(threshold)
# See \Netter#max_res for a description of that function.
%w(schematic compare same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity).each do |f|
eval <<"CODE"

View File

@ -16,6 +16,17 @@ module LVS
# relevant method of this object are available as global functions too
# where they act on a default incarnation. Usually it's not required
# to instantiate a Netter object explicitly.
#
# An individual netter object can be created, if the netter results
# need to be kept for multiple extractions or when different configurations
# need to be used in the same script. If you really want
# a Netter object, use the global \netter function:
# The Netter object provides services related to network extraction
# from a layout plus comparison against a reference netlist.
# Similar to the DRC netter (which lacks the compare ability), the
# relevant method of this object are available as global functions too
# where they act on a default incarnation. Usually it's not required
# to instantiate a Netter object explicitly.
#
# An individual netter object can be created, if the netter results
# need to be kept for multiple extractions. If you really need
@ -24,11 +35,23 @@ module LVS
# @code
# # create a new Netter object:
# nx = netter
#
# # build connectivity
# nx.connect(poly, contact)
# ...
# @/code
#
# # read the reference netlist
# nx.schematic("reference.cir")
#
# # configure the netlist compare
# nx.same_circuits("A", "B")
# ...
#
# # runs the compare
# if ! nx.compare
# puts("no equivalence!")
# end
# @/code
class LVSNetter < DRCNetter
@ -36,7 +59,7 @@ module LVS
super
end
def make_data
def _make_data
if @engine._dss
@engine._dss.is_singular? || raise("The LVS script features more than one or no layout source - network extraction cannot be performed in such configurations")
@ -51,6 +74,13 @@ module LVS
end
# %LVS%
# @name lvs_data
# @brief Gets the internal RBA::LayoutVsSchematic object
# @synopsis lvs_data
# The RBA::LayoutVsSchematic object provides access to the internal details of
# the netter object.
def lvs_data
l2n_data
@lvs
@ -67,6 +97,17 @@ module LVS
data
end
# %LVS%
# @name compare
# @brief Compares the extracted netlist vs. the schematic
# @synopsis compare
# Before using this method, a schematic netlist has to be loaded with \schematic.
# The compare can be configured in more details using \same_nets, \same_circuits,
# \same_device_classes and \equivalent_pins.
#
# This method will return true, if the netlists are equivalent and false
# otherwise.
def compare
@lvs.compare(@comparer)
end
@ -80,6 +121,21 @@ module LVS
end
# %LVS%
# @name same_nets
# @brief Establishes an equivalence between the nets
# @synopsis same_nets(circuit, net_a, net_b)
# @synopsis same_nets(circuit_a, net_a, circuit_b, net_b)
# This method will force an equivalence between the net_a and net_b from circuit_a
# and circuit_b (circuit in the three-argument form is for both circuit_a and circuit_b).
# Circuit and nets are string giving a circuit and net by name.
# After using this function, the compare algorithm will consider these nets equivalent.
# Use this method to provide hints for the comparer in cases which are difficult to
# resolve otherwise.
#
# Before this method can be used, a schematic netlist needs to be loaded with
# \schematic.
def same_nets(*args)
pins.each do |a|
@ -111,6 +167,17 @@ module LVS
end
# %LVS%
# @name same_circuits
# @brief Establishes an equivalence between the circuits
# @synopsis same_circuits(circuit_a, circuit_b)
# This method will force an equivalence between the two circuits.
# By default, circuits are identified by name. If names are different, this
# method allows establishing an explicit correspondence.
#
# Before this method can be used, a schematic netlist needs to be loaded with
# \schematic.
def same_circuits(a, b)
a.is_a?(String) || b.is_a?(String) || raise("Both arguments of 'same_circuits' need to be strings")
@ -124,6 +191,18 @@ module LVS
end
# %LVS%
# @name same_device_classes
# @brief Establishes an equivalence between the device classes
# @synopsis same_device_classes(class_a, class_b)
# This method will force an equivalence between the two device classes.
# Device classes are also known as "models".
# By default, device classes are identified by name. If names are different, this
# method allows establishing an explicit correspondence.
#
# Before this method can be used, a schematic netlist needs to be loaded with
# \schematic.
def same_device_classes(a, b)
a.is_a?(String) || b.is_a?(String) || raise("Both arguments of 'same_device_classes' need to be strings")
@ -137,6 +216,22 @@ module LVS
end
# %LVS%
# @name equivalent_pins
# @brief Marks pins as equivalent
# @synopsis equivalent_pins(circuit, pins ...)
# This method will mark the given pins as equivalent. This gives the compare algorithm
# more degrees of freedom when establishing net correspondence. Typically this method
# is used to declare inputs from gates are equivalent where are are logically, but not
# physically (e.g. in a CMOS NAND gate):
#
# @code
# netter.equivalent_pins("NAND2", "A", "B")
# @/code
#
# Before this method can be used, a schematic netlist needs to be loaded with
# \schematic.
def equivalent_pins(circuit, *pins)
circuit.is_a?(String) || raise("Circuit arguments of 'equivalent_pins' needs to be a string")
@ -157,31 +252,64 @@ module LVS
end
def schematic(filename, reader = nil)
# %LVS%
# @name schematic
# @brief Reads the reference netlist
# @synopsis schematic(filename)
# @synopsis schematic(filename, reader)
# @synopsis schematic(netlist)
# If a filename is given (first two forms), the netlist is read from the given file.
# If no reader is provided, Spice format will be assumed. The reader object is a
# RBA::NetlistReader object and allows detailed customization of the reader process.
#
# Alternatively, a RBA::Netlist object can be given which is obtained from any other
# source.
def schematic(schematic, reader = nil)
filename.is_a?(String) || raise("First argument must be string in 'schematic'")
if reader
reader.is_a?(RBA::NetlistReader) || raise("Second argument must be netlist reader object in 'schematic'")
if schematic.is_a?(RBA::Netlist)
lvs_data.reference = netlist
else
reader = RBA::NetlistSpiceReader::new
schematic.is_a?(String) || raise("First argument must be string or netlist in 'schematic'")
if reader
reader.is_a?(RBA::NetlistReader) || raise("Second argument must be netlist reader object in 'schematic'")
else
reader = RBA::NetlistSpiceReader::new
end
netlist_file = @engine._make_path(schematic)
@engine.info("Reading netlist: #{netlist_file} ..")
netlist = RBA::Netlist::new
netlist.read(netlist_file, reader)
lvs_data.reference = netlist
end
netlist_file = @engine._make_path(filename)
@engine.info("Reading netlist: #{netlist_file} ..")
netlist = RBA::Netlist::new
netlist.read(netlist_file, reader)
lvs_data.reference = netlist
end
# %LVS%
# @name min_caps
# @brief Ignores capacitors with a capacitance below a certain value
# @synopsis min_caps(threshold)
# After using this method, the netlist compare will ignore capacitance devices
# with a capacitance values below the given threshold (in Farad).
def min_caps(value)
lvs_data
@comparer.min_capacitance = value.to_f
end
# %LVS%
# @name max_res
# @brief Ignores resistors with a resistance above a certain value
# @synopsis max_res(threshold)
# After using this method, the netlist compare will ignore resistor devices
# with a resistance value above the given threshold (in Farad).
def max_res(value)
lvs_data
@comparer.max_resistance = value.to_f