mirror of https://github.com/KLayout/klayout.git
WIP: added documentation to LVS script.
This commit is contained in:
parent
a8f8ca0d7d
commit
ed41af9b4b
|
|
@ -13,21 +13,6 @@ module DRC
|
||||||
# as global functions too where they act on a default incarnation
|
# as global functions too where they act on a default incarnation
|
||||||
# of the netter. Usually it's not required to instantiate a Netter
|
# of the netter. Usually it's not required to instantiate a Netter
|
||||||
# object, but it serves as a container for this functionality.
|
# 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
|
# @code
|
||||||
# # create a new Netter object:
|
# # create a new Netter object:
|
||||||
|
|
@ -394,11 +379,11 @@ module DRC
|
||||||
def ensure_data
|
def ensure_data
|
||||||
if !@l2n
|
if !@l2n
|
||||||
@layers = {}
|
@layers = {}
|
||||||
make_data
|
_make_data
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_data
|
def _make_data
|
||||||
|
|
||||||
if @engine._dss
|
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")
|
@engine._dss.is_singular? || raise("The DRC script features more than one or no layout source - network extraction cannot be performed in such configurations")
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,56 @@ module LVS
|
||||||
@output_lvsdb_file = filename
|
@output_lvsdb_file = filename
|
||||||
end
|
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|
|
%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"
|
eval <<"CODE"
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,40 @@ module LVS
|
||||||
# to instantiate a Netter object explicitly.
|
# to instantiate a Netter object explicitly.
|
||||||
#
|
#
|
||||||
# An individual netter object can be created, if the netter results
|
# 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
|
# need to be kept for multiple extractions. If you really need
|
||||||
# a Netter object, use the global \netter function:
|
# a Netter object, use the global \netter function:
|
||||||
#
|
#
|
||||||
# @code
|
# @code
|
||||||
# # create a new Netter object:
|
# # create a new Netter object:
|
||||||
# nx = netter
|
# nx = netter
|
||||||
|
#
|
||||||
|
# # build connectivity
|
||||||
# nx.connect(poly, contact)
|
# 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
|
class LVSNetter < DRCNetter
|
||||||
|
|
||||||
|
|
@ -36,7 +59,7 @@ module LVS
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_data
|
def _make_data
|
||||||
|
|
||||||
if @engine._dss
|
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")
|
@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
|
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
|
def lvs_data
|
||||||
l2n_data
|
l2n_data
|
||||||
@lvs
|
@lvs
|
||||||
|
|
@ -67,6 +97,17 @@ module LVS
|
||||||
data
|
data
|
||||||
end
|
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
|
def compare
|
||||||
@lvs.compare(@comparer)
|
@lvs.compare(@comparer)
|
||||||
end
|
end
|
||||||
|
|
@ -80,6 +121,21 @@ module LVS
|
||||||
|
|
||||||
end
|
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)
|
def same_nets(*args)
|
||||||
|
|
||||||
pins.each do |a|
|
pins.each do |a|
|
||||||
|
|
@ -111,6 +167,17 @@ module LVS
|
||||||
|
|
||||||
end
|
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)
|
def same_circuits(a, b)
|
||||||
|
|
||||||
a.is_a?(String) || b.is_a?(String) || raise("Both arguments of 'same_circuits' need to be strings")
|
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
|
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)
|
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")
|
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
|
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)
|
def equivalent_pins(circuit, *pins)
|
||||||
|
|
||||||
circuit.is_a?(String) || raise("Circuit arguments of 'equivalent_pins' needs to be a string")
|
circuit.is_a?(String) || raise("Circuit arguments of 'equivalent_pins' needs to be a string")
|
||||||
|
|
@ -157,9 +252,26 @@ module LVS
|
||||||
|
|
||||||
end
|
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.
|
||||||
|
|
||||||
filename.is_a?(String) || raise("First argument must be string in 'schematic'")
|
def schematic(schematic, reader = nil)
|
||||||
|
|
||||||
|
if schematic.is_a?(RBA::Netlist)
|
||||||
|
lvs_data.reference = netlist
|
||||||
|
else
|
||||||
|
|
||||||
|
schematic.is_a?(String) || raise("First argument must be string or netlist in 'schematic'")
|
||||||
|
|
||||||
if reader
|
if reader
|
||||||
reader.is_a?(RBA::NetlistReader) || raise("Second argument must be netlist reader object in 'schematic'")
|
reader.is_a?(RBA::NetlistReader) || raise("Second argument must be netlist reader object in 'schematic'")
|
||||||
|
|
@ -167,7 +279,7 @@ module LVS
|
||||||
reader = RBA::NetlistSpiceReader::new
|
reader = RBA::NetlistSpiceReader::new
|
||||||
end
|
end
|
||||||
|
|
||||||
netlist_file = @engine._make_path(filename)
|
netlist_file = @engine._make_path(schematic)
|
||||||
@engine.info("Reading netlist: #{netlist_file} ..")
|
@engine.info("Reading netlist: #{netlist_file} ..")
|
||||||
|
|
||||||
netlist = RBA::Netlist::new
|
netlist = RBA::Netlist::new
|
||||||
|
|
@ -177,11 +289,27 @@ module LVS
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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)
|
def min_caps(value)
|
||||||
lvs_data
|
lvs_data
|
||||||
@comparer.min_capacitance = value.to_f
|
@comparer.min_capacitance = value.to_f
|
||||||
end
|
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)
|
def max_res(value)
|
||||||
lvs_data
|
lvs_data
|
||||||
@comparer.max_resistance = value.to_f
|
@comparer.max_resistance = value.to_f
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue