mirror of https://github.com/KLayout/klayout.git
Some enhancements
* Device#net_for_terminal with terminal name * Spice writer now dumps all parameters for resistors and caps (also secondary) * Enabled Spice writer delegate in LVS (spice_format(...)) * Device class factories for built-in device extractors
This commit is contained in:
parent
ba35ac9bfe
commit
e34fc8967a
|
|
@ -117,6 +117,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
|
||||||
os << " ";
|
os << " ";
|
||||||
os << format_name (dev.device_class ()->name ());
|
os << format_name (dev.device_class ()->name ());
|
||||||
}
|
}
|
||||||
|
os << format_params (dev, db::DeviceClassCapacitor::param_id_C);
|
||||||
|
|
||||||
} else if (ind) {
|
} else if (ind) {
|
||||||
|
|
||||||
|
|
@ -129,6 +130,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
|
||||||
os << " ";
|
os << " ";
|
||||||
os << format_name (dev.device_class ()->name ());
|
os << format_name (dev.device_class ()->name ());
|
||||||
}
|
}
|
||||||
|
os << format_params (dev, db::DeviceClassInductor::param_id_L);
|
||||||
|
|
||||||
} else if (res || res3) {
|
} else if (res || res3) {
|
||||||
|
|
||||||
|
|
@ -141,6 +143,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
|
||||||
os << " ";
|
os << " ";
|
||||||
os << format_name (dev.device_class ()->name ());
|
os << format_name (dev.device_class ()->name ());
|
||||||
}
|
}
|
||||||
|
os << format_params (dev, db::DeviceClassResistor::param_id_R);
|
||||||
|
|
||||||
} else if (diode) {
|
} else if (diode) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,24 @@ static void add_other_abstracts (db::Device *device, const db::DeviceAbstractRef
|
||||||
device->other_abstracts ().push_back (ref);
|
device->other_abstracts ().push_back (ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const db::Net *net_for_terminal_by_name_const (const db::Device *device, const std::string &name)
|
||||||
|
{
|
||||||
|
if (! device->device_class () || ! device->device_class ()->has_terminal_with_name (name)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return device->net_for_terminal (device->device_class ()->terminal_id_for_name (name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const db::Net *net_for_terminal_by_name (db::Device *device, const std::string &name)
|
||||||
|
{
|
||||||
|
if (! device->device_class () || ! device->device_class ()->has_terminal_with_name (name)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return device->net_for_terminal (device->device_class ()->terminal_id_for_name (name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Class<db::Device> decl_dbDevice (decl_dbNetlistObject, "db", "Device",
|
Class<db::Device> decl_dbDevice (decl_dbNetlistObject, "db", "Device",
|
||||||
gsi::method ("device_class", &db::Device::device_class,
|
gsi::method ("device_class", &db::Device::device_class,
|
||||||
"@brief Gets the device class the device belongs to.\n"
|
"@brief Gets the device class the device belongs to.\n"
|
||||||
|
|
@ -337,6 +355,18 @@ Class<db::Device> decl_dbDevice (decl_dbNetlistObject, "db", "Device",
|
||||||
"\n\n"
|
"\n\n"
|
||||||
"This constness variant has been introduced in version 0.26.8"
|
"This constness variant has been introduced in version 0.26.8"
|
||||||
) +
|
) +
|
||||||
|
gsi::method_ext ("net_for_terminal", net_for_terminal_by_name_const, gsi::arg ("terminal_name"),
|
||||||
|
"@brief Gets the net connected to the specified terminal.\n"
|
||||||
|
"If the terminal is not connected, nil is returned for the net."
|
||||||
|
"\n\n"
|
||||||
|
"This convenience method has been introduced in version 0.27.3.\n"
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("net_for_terminal", net_for_terminal_by_name, gsi::arg ("terminal_name"),
|
||||||
|
"@brief Gets the net connected to the specified terminal (non-const version).\n"
|
||||||
|
"If the terminal is not connected, nil is returned for the net."
|
||||||
|
"\n\n"
|
||||||
|
"This convenience method has been introduced in version 0.27.3.\n"
|
||||||
|
) +
|
||||||
gsi::method ("connect_terminal", &db::Device::connect_terminal, gsi::arg ("terminal_id"), gsi::arg ("net"),
|
gsi::method ("connect_terminal", &db::Device::connect_terminal, gsi::arg ("terminal_id"), gsi::arg ("net"),
|
||||||
"@brief Connects the given terminal to the specified net.\n"
|
"@brief Connects the given terminal to the specified net.\n"
|
||||||
) +
|
) +
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,15 @@ require 'pathname'
|
||||||
|
|
||||||
module DRC
|
module DRC
|
||||||
|
|
||||||
|
class CustomDeviceClassFactory < RBA::DeviceClassFactory
|
||||||
|
def initialize(cls)
|
||||||
|
@cls = cls
|
||||||
|
end
|
||||||
|
def create_class
|
||||||
|
@cls.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# The DRC engine
|
# The DRC engine
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
|
|
@ -308,22 +317,57 @@ module DRC
|
||||||
# @brief Defines SPICE output format (with options)
|
# @brief Defines SPICE output format (with options)
|
||||||
# @name write_spice
|
# @name write_spice
|
||||||
# @synopsis write_spice([ use_net_names [, with_comments ] ])
|
# @synopsis write_spice([ use_net_names [, with_comments ] ])
|
||||||
|
# @synopsis write_spice(writer_delegate [, use_net_names [, with_comments ] ])
|
||||||
# Use this option in \target_netlist for the format parameter to
|
# Use this option in \target_netlist for the format parameter to
|
||||||
# specify SPICE format.
|
# specify SPICE format.
|
||||||
# "use_net_names" and "with_comments" are boolean parameters indicating
|
# "use_net_names" and "with_comments" are boolean parameters indicating
|
||||||
# whether to use named nets (numbers if false) and whether to add
|
# whether to use named nets (numbers if false) and whether to add
|
||||||
# information comments such as instance coordinates or pin names.
|
# information comments such as instance coordinates or pin names.
|
||||||
|
#
|
||||||
|
# "writer_delegate" allows using a \NetlistSpiceWriterDelegate object to
|
||||||
|
# control the actual writing.
|
||||||
|
|
||||||
|
def write_spice(*args)
|
||||||
|
|
||||||
def write_spice(use_net_names = nil, with_comments = nil)
|
|
||||||
self._context("write_spice") do
|
self._context("write_spice") do
|
||||||
writer = RBA::NetlistSpiceWriter::new
|
|
||||||
|
delegate = nil
|
||||||
|
use_net_names = nil
|
||||||
|
with_comments = nil
|
||||||
|
args.each do |a|
|
||||||
|
if (a == false || a == true) && (use_net_names == nil || with_comments == nil)
|
||||||
|
if use_net_names == nil
|
||||||
|
use_net_names = a
|
||||||
|
else
|
||||||
|
with_comments = a
|
||||||
|
end
|
||||||
|
elsif a.is_a?(RBA::NetlistSpiceWriterDelegate)
|
||||||
|
delegate = a
|
||||||
|
else
|
||||||
|
raise("Too many arguments specified or argument is of wrong type: " + a.inspect)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
writer = RBA::NetlistSpiceWriter::new(delegate)
|
||||||
if use_net_names != nil
|
if use_net_names != nil
|
||||||
writer.use_net_names = use_net_names
|
writer.use_net_names = use_net_names
|
||||||
end
|
end
|
||||||
if with_comments != nil
|
if with_comments != nil
|
||||||
writer.with_comments = with_comments
|
writer.with_comments = with_comments
|
||||||
end
|
end
|
||||||
|
|
||||||
writer
|
writer
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def _make_factory(cls)
|
||||||
|
if !cls
|
||||||
|
return nil
|
||||||
|
elsif !cls.is_a?(Class)
|
||||||
|
raise("Expected a class object for the 'class' argument of device extractors")
|
||||||
|
else
|
||||||
|
CustomDeviceClassFactory::new(cls)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -331,15 +375,16 @@ module DRC
|
||||||
# @brief Supplies the MOS3 transistor extractor class
|
# @brief Supplies the MOS3 transistor extractor class
|
||||||
# @name mos3
|
# @name mos3
|
||||||
# @synopsis mos3(name)
|
# @synopsis mos3(name)
|
||||||
|
# @synopsis mos3(name, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a
|
# Use this class with \extract_devices to specify extraction of a
|
||||||
# three-terminal MOS transistor.
|
# three-terminal MOS transistor.
|
||||||
#
|
#
|
||||||
# See RBA::DeviceExtractorMOS3Transistor for more details
|
# See RBA::DeviceExtractorMOS3Transistor for more details
|
||||||
# about this extractor (non-strict mode applies for 'mos3').
|
# about this extractor (non-strict mode applies for 'mos3').
|
||||||
|
|
||||||
def mos3(name)
|
def mos3(name, cls = nil)
|
||||||
self._context("mos3") do
|
self._context("mos3") do
|
||||||
RBA::DeviceExtractorMOS3Transistor::new(name)
|
RBA::DeviceExtractorMOS3Transistor::new(name, false, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -347,15 +392,16 @@ module DRC
|
||||||
# @brief Supplies the MOS4 transistor extractor class
|
# @brief Supplies the MOS4 transistor extractor class
|
||||||
# @name mos4
|
# @name mos4
|
||||||
# @synopsis mos4(name)
|
# @synopsis mos4(name)
|
||||||
|
# @synopsis mos4(name, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a
|
# Use this class with \extract_devices to specify extraction of a
|
||||||
# four-terminal MOS transistor.
|
# four-terminal MOS transistor.
|
||||||
#
|
#
|
||||||
# See RBA::DeviceExtractorMOS4Transistor for more details
|
# See RBA::DeviceExtractorMOS4Transistor for more details
|
||||||
# about this extractor (non-strict mode applies for 'mos4').
|
# about this extractor (non-strict mode applies for 'mos4').
|
||||||
|
|
||||||
def mos4(name)
|
def mos4(name, cls = nil)
|
||||||
self._context("mos4") do
|
self._context("mos4") do
|
||||||
RBA::DeviceExtractorMOS4Transistor::new(name)
|
RBA::DeviceExtractorMOS4Transistor::new(name, false, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -363,6 +409,7 @@ module DRC
|
||||||
# @brief Supplies the DMOS3 transistor extractor class
|
# @brief Supplies the DMOS3 transistor extractor class
|
||||||
# @name dmos3
|
# @name dmos3
|
||||||
# @synopsis dmos3(name)
|
# @synopsis dmos3(name)
|
||||||
|
# @synopsis dmos3(name, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a
|
# Use this class with \extract_devices to specify extraction of a
|
||||||
# three-terminal DMOS transistor. A DMOS transistor is essentially
|
# three-terminal DMOS transistor. A DMOS transistor is essentially
|
||||||
# the same than a MOS transistor, but source and drain are
|
# the same than a MOS transistor, but source and drain are
|
||||||
|
|
@ -371,9 +418,9 @@ module DRC
|
||||||
# See RBA::DeviceExtractorMOS3Transistor for more details
|
# See RBA::DeviceExtractorMOS3Transistor for more details
|
||||||
# about this extractor (strict mode applies for 'dmos3').
|
# about this extractor (strict mode applies for 'dmos3').
|
||||||
|
|
||||||
def dmos3(name)
|
def dmos3(name, cls = nil)
|
||||||
self._context("dmos3") do
|
self._context("dmos3") do
|
||||||
RBA::DeviceExtractorMOS3Transistor::new(name, true)
|
RBA::DeviceExtractorMOS3Transistor::new(name, true, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -381,6 +428,7 @@ module DRC
|
||||||
# @brief Supplies the MOS4 transistor extractor class
|
# @brief Supplies the MOS4 transistor extractor class
|
||||||
# @name dmos4
|
# @name dmos4
|
||||||
# @synopsis dmos4(name)
|
# @synopsis dmos4(name)
|
||||||
|
# @synopsis dmos4(name, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a
|
# Use this class with \extract_devices to specify extraction of a
|
||||||
# four-terminal DMOS transistor. A DMOS transistor is essentially
|
# four-terminal DMOS transistor. A DMOS transistor is essentially
|
||||||
# the same than a MOS transistor, but source and drain are
|
# the same than a MOS transistor, but source and drain are
|
||||||
|
|
@ -389,9 +437,9 @@ module DRC
|
||||||
# See RBA::DeviceExtractorMOS4Transistor for more details
|
# See RBA::DeviceExtractorMOS4Transistor for more details
|
||||||
# about this extractor (strict mode applies for 'dmos4').
|
# about this extractor (strict mode applies for 'dmos4').
|
||||||
|
|
||||||
def dmos4(name)
|
def dmos4(name, cls = nil)
|
||||||
self._context("dmos4") do
|
self._context("dmos4") do
|
||||||
RBA::DeviceExtractorMOS4Transistor::new(name, true)
|
RBA::DeviceExtractorMOS4Transistor::new(name, true, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -399,15 +447,16 @@ module DRC
|
||||||
# @brief Supplies the BJT3 transistor extractor class
|
# @brief Supplies the BJT3 transistor extractor class
|
||||||
# @name bjt3
|
# @name bjt3
|
||||||
# @synopsis bjt3(name)
|
# @synopsis bjt3(name)
|
||||||
|
# @synopsis bjt3(name, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a
|
# Use this class with \extract_devices to specify extraction of a
|
||||||
# bipolar junction transistor
|
# bipolar junction transistor
|
||||||
#
|
#
|
||||||
# See RBA::DeviceExtractorBJT3Transistor for more details
|
# See RBA::DeviceExtractorBJT3Transistor for more details
|
||||||
# about this extractor.
|
# about this extractor.
|
||||||
|
|
||||||
def bjt3(name)
|
def bjt3(name, cls = nil)
|
||||||
self._context("bjt3") do
|
self._context("bjt3") do
|
||||||
RBA::DeviceExtractorBJT3Transistor::new(name)
|
RBA::DeviceExtractorBJT3Transistor::new(name, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -415,15 +464,16 @@ module DRC
|
||||||
# @brief Supplies the BJT4 transistor extractor class
|
# @brief Supplies the BJT4 transistor extractor class
|
||||||
# @name bjt4
|
# @name bjt4
|
||||||
# @synopsis bjt4(name)
|
# @synopsis bjt4(name)
|
||||||
|
# @synopsis bjt4(name, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a
|
# Use this class with \extract_devices to specify extraction of a
|
||||||
# bipolar junction transistor with a substrate terminal
|
# bipolar junction transistor with a substrate terminal
|
||||||
#
|
#
|
||||||
# See RBA::DeviceExtractorBJT4Transistor for more details
|
# See RBA::DeviceExtractorBJT4Transistor for more details
|
||||||
# about this extractor.
|
# about this extractor.
|
||||||
|
|
||||||
def bjt4(name)
|
def bjt4(name, cls = nil)
|
||||||
self._context("bjt4") do
|
self._context("bjt4") do
|
||||||
RBA::DeviceExtractorBJT4Transistor::new(name)
|
RBA::DeviceExtractorBJT4Transistor::new(name, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -431,15 +481,16 @@ module DRC
|
||||||
# @brief Supplies the diode extractor class
|
# @brief Supplies the diode extractor class
|
||||||
# @name diode
|
# @name diode
|
||||||
# @synopsis diode(name)
|
# @synopsis diode(name)
|
||||||
|
# @synopsis diode(name, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a
|
# Use this class with \extract_devices to specify extraction of a
|
||||||
# planar diode
|
# planar diode
|
||||||
#
|
#
|
||||||
# See RBA::DeviceExtractorDiode for more details
|
# See RBA::DeviceExtractorDiode for more details
|
||||||
# about this extractor.
|
# about this extractor.
|
||||||
|
|
||||||
def diode(name)
|
def diode(name, cls = nil)
|
||||||
self._context("diode") do
|
self._context("diode") do
|
||||||
RBA::DeviceExtractorDiode::new(name)
|
RBA::DeviceExtractorDiode::new(name, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -447,6 +498,7 @@ module DRC
|
||||||
# @brief Supplies the resistor extractor class
|
# @brief Supplies the resistor extractor class
|
||||||
# @name resistor
|
# @name resistor
|
||||||
# @synopsis resistor(name, sheet_rho)
|
# @synopsis resistor(name, sheet_rho)
|
||||||
|
# @synopsis resistor(name, sheet_rho, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a resistor.
|
# Use this class with \extract_devices to specify extraction of a resistor.
|
||||||
#
|
#
|
||||||
# The sheet_rho value is the sheet resistance in ohms/square. It is used
|
# The sheet_rho value is the sheet resistance in ohms/square. It is used
|
||||||
|
|
@ -455,9 +507,9 @@ module DRC
|
||||||
# See RBA::DeviceExtractorResistor for more details
|
# See RBA::DeviceExtractorResistor for more details
|
||||||
# about this extractor.
|
# about this extractor.
|
||||||
|
|
||||||
def resistor(name, sheet_rho)
|
def resistor(name, sheet_rho, cls = nil)
|
||||||
self._context("resistor") do
|
self._context("resistor") do
|
||||||
RBA::DeviceExtractorResistor::new(name, sheet_rho)
|
RBA::DeviceExtractorResistor::new(name, sheet_rho, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -465,6 +517,7 @@ module DRC
|
||||||
# @brief Supplies the resistor extractor class that includes a bulk terminal
|
# @brief Supplies the resistor extractor class that includes a bulk terminal
|
||||||
# @name resistor_with_bulk
|
# @name resistor_with_bulk
|
||||||
# @synopsis resistor_with_bulk(name, sheet_rho)
|
# @synopsis resistor_with_bulk(name, sheet_rho)
|
||||||
|
# @synopsis resistor_with_bulk(name, sheet_rho, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a resistor
|
# Use this class with \extract_devices to specify extraction of a resistor
|
||||||
# with a bulk terminal.
|
# with a bulk terminal.
|
||||||
# The sheet_rho value is the sheet resistance in ohms/square.
|
# The sheet_rho value is the sheet resistance in ohms/square.
|
||||||
|
|
@ -472,9 +525,9 @@ module DRC
|
||||||
# See RBA::DeviceExtractorResistorWithBulk for more details
|
# See RBA::DeviceExtractorResistorWithBulk for more details
|
||||||
# about this extractor.
|
# about this extractor.
|
||||||
|
|
||||||
def resistor_with_bulk(name, sheet_rho)
|
def resistor_with_bulk(name, sheet_rho, cls = nil)
|
||||||
self._context("resistor_with_bulk") do
|
self._context("resistor_with_bulk") do
|
||||||
RBA::DeviceExtractorResistorWithBulk::new(name, sheet_rho)
|
RBA::DeviceExtractorResistorWithBulk::new(name, sheet_rho, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -482,15 +535,16 @@ module DRC
|
||||||
# @brief Supplies the capacitor extractor class
|
# @brief Supplies the capacitor extractor class
|
||||||
# @name capacitor
|
# @name capacitor
|
||||||
# @synopsis capacitor(name, area_cap)
|
# @synopsis capacitor(name, area_cap)
|
||||||
|
# @synopsis capacitor(name, area_cap, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a capacitor.
|
# Use this class with \extract_devices to specify extraction of a capacitor.
|
||||||
# The area_cap argument is the capacitance in Farad per square micrometer.
|
# The area_cap argument is the capacitance in Farad per square micrometer.
|
||||||
#
|
#
|
||||||
# See RBA::DeviceExtractorCapacitor for more details
|
# See RBA::DeviceExtractorCapacitor for more details
|
||||||
# about this extractor.
|
# about this extractor.
|
||||||
|
|
||||||
def capacitor(name, area_cap)
|
def capacitor(name, area_cap, cls = nil)
|
||||||
self._context("capacitor") do
|
self._context("capacitor") do
|
||||||
RBA::DeviceExtractorCapacitor::new(name, area_cap)
|
RBA::DeviceExtractorCapacitor::new(name, area_cap, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -498,6 +552,7 @@ module DRC
|
||||||
# @brief Supplies the capacitor extractor class that includes a bulk terminal
|
# @brief Supplies the capacitor extractor class that includes a bulk terminal
|
||||||
# @name capacitor_with_bulk
|
# @name capacitor_with_bulk
|
||||||
# @synopsis capacitor_with_bulk(name, area_cap)
|
# @synopsis capacitor_with_bulk(name, area_cap)
|
||||||
|
# @synopsis capacitor_with_bulk(name, area_cap, class)
|
||||||
# Use this class with \extract_devices to specify extraction of a capacitor
|
# Use this class with \extract_devices to specify extraction of a capacitor
|
||||||
# with a bulk terminal.
|
# with a bulk terminal.
|
||||||
# The area_cap argument is the capacitance in Farad per square micrometer.
|
# The area_cap argument is the capacitance in Farad per square micrometer.
|
||||||
|
|
@ -505,9 +560,9 @@ module DRC
|
||||||
# See RBA::DeviceExtractorCapacitorWithBulk for more details
|
# See RBA::DeviceExtractorCapacitorWithBulk for more details
|
||||||
# about this extractor.
|
# about this extractor.
|
||||||
|
|
||||||
def capacitor_with_bulk(name, area_cap)
|
def capacitor_with_bulk(name, area_cap, cls = nil)
|
||||||
self._context("capacitor_with_bulk") do
|
self._context("capacitor_with_bulk") do
|
||||||
RBA::DeviceExtractorCapacitorWithBulk::new(name, area_cap)
|
RBA::DeviceExtractorCapacitorWithBulk::new(name, area_cap, _make_factory(cls))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -376,5 +376,33 @@ dc.enable_parameter("L", true)
|
||||||
fully enabled parameters.
|
fully enabled parameters.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Another way of customizing the built-in device extractors is to
|
||||||
|
supply a custom device class. The following code creates a new
|
||||||
|
resistor class which changes the preconfigured device parameter definitions
|
||||||
|
to enable "W" and "L".
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>class MyResistor < RBA::DeviceClassResistor
|
||||||
|
def initialize
|
||||||
|
super
|
||||||
|
enable_parameter("W", true)
|
||||||
|
enable_parameter("L", true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
extract_devices(resistor("RES", 1, MyResistor), ...)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The effect of this code is the same than the first one, but using a custom
|
||||||
|
device class opens the option to supply additional parameters for example
|
||||||
|
or to implement some entirely new device while using the extraction
|
||||||
|
mechanics of the resistor extractor. The only requirement is compatibility of
|
||||||
|
the parameter and terminal definitions.
|
||||||
|
</p>
|
||||||
|
|
||||||
</doc>
|
</doc>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -206,8 +206,14 @@ TEST(23_issue709)
|
||||||
run_test (_this, "empty_subcells", "empty_subcells.gds");
|
run_test (_this, "empty_subcells", "empty_subcells.gds");
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty gds
|
|
||||||
TEST(24_issue806)
|
TEST(24_issue806)
|
||||||
{
|
{
|
||||||
run_test (_this, "custom_compare", "custom_compare.gds");
|
run_test (_this, "custom_compare", "custom_compare.gds");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(25_enableWandL)
|
||||||
|
{
|
||||||
|
run_test (_this, "enable_wl1", "resistor.gds");
|
||||||
|
run_test (_this, "enable_wl2", "resistor.gds");
|
||||||
|
run_test (_this, "enable_wl3", "resistor.gds");
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
* Extracted by KLayout
|
||||||
|
|
||||||
|
* cell Rre
|
||||||
|
* pin gnd!
|
||||||
|
* pin vdd!
|
||||||
|
.SUBCKT Rre 1 2
|
||||||
|
* net 1 gnd!
|
||||||
|
* net 2 vdd!
|
||||||
|
* device instance $1 r0 *1 8.43,1.51 RR1
|
||||||
|
R$1 1 2 RR1 10 W=0.6 L=6
|
||||||
|
.ENDS Rre
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
# test spice writer delegate on this occasion
|
||||||
|
class MyWriterDelegate < RBA::NetlistSpiceWriterDelegate
|
||||||
|
def write_device(device)
|
||||||
|
if device.device_class.name == "RR1"
|
||||||
|
line = "R"
|
||||||
|
line += format_name(device.expanded_name)
|
||||||
|
line += " "
|
||||||
|
line += net_to_string(device.net_for_terminal("A"))
|
||||||
|
line += " "
|
||||||
|
line += net_to_string(device.net_for_terminal("B"))
|
||||||
|
line += " "
|
||||||
|
line += format_name(device.device_class.name)
|
||||||
|
line += " "
|
||||||
|
line += "%.12g" % device.parameter("R")
|
||||||
|
line += " W="
|
||||||
|
line += "%.12g" % device.parameter("W")
|
||||||
|
line += " L="
|
||||||
|
line += "%.12g" % device.parameter("L")
|
||||||
|
emit_line(line)
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
source($lvs_test_source)
|
||||||
|
report_lvs($lvs_test_target_lvsdb, true)
|
||||||
|
target_netlist($lvs_test_target_cir, write_spice(MyWriterDelegate::new), "Extracted by KLayout")
|
||||||
|
|
||||||
|
schematic("resistor.cir")
|
||||||
|
|
||||||
|
deep
|
||||||
|
|
||||||
|
contact = input(15, 0)
|
||||||
|
metal1 = input(16, 0)
|
||||||
|
metal1_ver = input(16, 5)
|
||||||
|
metal1_lbl = labels(16, 3)
|
||||||
|
res = metal1 & metal1_ver
|
||||||
|
metal1_not_res = metal1 - metal1_ver
|
||||||
|
|
||||||
|
dc = extract_devices(resistor("RR1", 1), { "R" => res , "C" => metal1_not_res})
|
||||||
|
dc.enable_parameter("W", true)
|
||||||
|
dc.enable_parameter("L", true)
|
||||||
|
|
||||||
|
connect(contact, metal1_not_res)
|
||||||
|
connect(metal1_not_res, metal1_lbl)
|
||||||
|
|
||||||
|
align
|
||||||
|
netlist.simplify
|
||||||
|
compare
|
||||||
|
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
#%lvsdb-klayout
|
||||||
|
|
||||||
|
# Layout
|
||||||
|
layout(
|
||||||
|
top(Rre)
|
||||||
|
unit(0.001)
|
||||||
|
|
||||||
|
# Layer section
|
||||||
|
# This section lists the mask layers (drawing or derived) and their connections.
|
||||||
|
|
||||||
|
# Mask layers
|
||||||
|
layer(l3 '15/0')
|
||||||
|
layer(l4 '16/3')
|
||||||
|
layer(l1)
|
||||||
|
|
||||||
|
# Mask layer connectivity
|
||||||
|
connect(l3 l3 l1)
|
||||||
|
connect(l4 l1)
|
||||||
|
connect(l1 l3 l4 l1)
|
||||||
|
|
||||||
|
# Device class section
|
||||||
|
class(RR1 RES
|
||||||
|
param(L 1 0)
|
||||||
|
param(W 1 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Device abstracts section
|
||||||
|
# Device abstracts list the pin shapes of the devices.
|
||||||
|
device(D$RR1 RR1
|
||||||
|
terminal(A
|
||||||
|
rect(l1 (-3160 -300) (160 600))
|
||||||
|
)
|
||||||
|
terminal(B
|
||||||
|
rect(l1 (3000 -300) (160 600))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Circuit section
|
||||||
|
# Circuits are the hierarchical building blocks of the netlist.
|
||||||
|
circuit(Rre
|
||||||
|
|
||||||
|
# Circuit boundary
|
||||||
|
rect((5270 1210) (6320 600))
|
||||||
|
|
||||||
|
# Nets with their geometries
|
||||||
|
net(1 name('gnd!')
|
||||||
|
rect(l3 (5295 1230) (120 560))
|
||||||
|
text(l4 'gnd!' (-60 -60))
|
||||||
|
rect(l1 (-70 -505) (125 570))
|
||||||
|
rect(l1 (-140 -585) (160 600))
|
||||||
|
)
|
||||||
|
net(2 name('vdd!')
|
||||||
|
rect(l3 (11455 1240) (120 540))
|
||||||
|
text(l4 'vdd!' (-65 -60))
|
||||||
|
rect(l1 (-65 -495) (125 560))
|
||||||
|
rect(l1 (-140 -575) (160 600))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Outgoing pins and their connections to nets
|
||||||
|
pin(1 name('gnd!'))
|
||||||
|
pin(2 name('vdd!'))
|
||||||
|
|
||||||
|
# Devices and their connections
|
||||||
|
device(1 D$RR1
|
||||||
|
location(8430 1510)
|
||||||
|
param(R 10)
|
||||||
|
param(L 6)
|
||||||
|
param(W 0.6)
|
||||||
|
param(A 3.6)
|
||||||
|
param(P 13.2)
|
||||||
|
terminal(A 1)
|
||||||
|
terminal(B 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Reference netlist
|
||||||
|
reference(
|
||||||
|
|
||||||
|
# Device class section
|
||||||
|
class(RR1 RES)
|
||||||
|
|
||||||
|
# Circuit section
|
||||||
|
# Circuits are the hierarchical building blocks of the netlist.
|
||||||
|
circuit(RRE
|
||||||
|
|
||||||
|
# Nets
|
||||||
|
net(1 name('VDD!'))
|
||||||
|
net(2 name('GND!'))
|
||||||
|
|
||||||
|
# Devices and their connections
|
||||||
|
device(1 RR1
|
||||||
|
name(R0)
|
||||||
|
param(R 10)
|
||||||
|
param(L 6)
|
||||||
|
param(W 0.6)
|
||||||
|
param(A 0)
|
||||||
|
param(P 0)
|
||||||
|
terminal(A 1)
|
||||||
|
terminal(B 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cross reference
|
||||||
|
xref(
|
||||||
|
circuit(Rre RRE match
|
||||||
|
xref(
|
||||||
|
net(1 2 match)
|
||||||
|
net(2 1 match)
|
||||||
|
pin(0 () match)
|
||||||
|
pin(1 () match)
|
||||||
|
device(1 1 match)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
* Extracted by KLayout
|
||||||
|
|
||||||
|
* cell Rre
|
||||||
|
* pin gnd!
|
||||||
|
* pin vdd!
|
||||||
|
.SUBCKT Rre 1 2
|
||||||
|
* net 1 gnd!
|
||||||
|
* net 2 vdd!
|
||||||
|
* device instance $1 r0 *1 8.43,1.51 RR1
|
||||||
|
R$1 1 2 10 RR1 L=6U W=0.6U A=3.6P P=13.2U
|
||||||
|
.ENDS Rre
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
source($lvs_test_source)
|
||||||
|
report_lvs($lvs_test_target_lvsdb, true)
|
||||||
|
target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
|
||||||
|
|
||||||
|
schematic("resistor.cir")
|
||||||
|
|
||||||
|
deep
|
||||||
|
|
||||||
|
contact = input(15, 0)
|
||||||
|
metal1 = input(16, 0)
|
||||||
|
metal1_ver = input(16, 5)
|
||||||
|
metal1_lbl = labels(16, 3)
|
||||||
|
res = metal1 & metal1_ver
|
||||||
|
metal1_not_res = metal1 - metal1_ver
|
||||||
|
|
||||||
|
class MyResistorClass < RBA::DeviceClassResistor
|
||||||
|
def initialize
|
||||||
|
super
|
||||||
|
enable_parameter("W", true)
|
||||||
|
enable_parameter("L", true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
extract_devices(resistor("RR1", 1, MyResistorClass), { "R" => res , "C" => metal1_not_res})
|
||||||
|
|
||||||
|
connect(contact, metal1_not_res)
|
||||||
|
connect(metal1_not_res, metal1_lbl)
|
||||||
|
|
||||||
|
align
|
||||||
|
netlist.simplify
|
||||||
|
compare
|
||||||
|
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
#%lvsdb-klayout
|
||||||
|
|
||||||
|
# Layout
|
||||||
|
layout(
|
||||||
|
top(Rre)
|
||||||
|
unit(0.001)
|
||||||
|
|
||||||
|
# Layer section
|
||||||
|
# This section lists the mask layers (drawing or derived) and their connections.
|
||||||
|
|
||||||
|
# Mask layers
|
||||||
|
layer(l3 '15/0')
|
||||||
|
layer(l4 '16/3')
|
||||||
|
layer(l1)
|
||||||
|
|
||||||
|
# Mask layer connectivity
|
||||||
|
connect(l3 l3 l1)
|
||||||
|
connect(l4 l1)
|
||||||
|
connect(l1 l3 l4 l1)
|
||||||
|
|
||||||
|
# Device class section
|
||||||
|
class(RR1 RES
|
||||||
|
param(L 1 0)
|
||||||
|
param(W 1 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Device abstracts section
|
||||||
|
# Device abstracts list the pin shapes of the devices.
|
||||||
|
device(D$RR1 RR1
|
||||||
|
terminal(A
|
||||||
|
rect(l1 (-3160 -300) (160 600))
|
||||||
|
)
|
||||||
|
terminal(B
|
||||||
|
rect(l1 (3000 -300) (160 600))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Circuit section
|
||||||
|
# Circuits are the hierarchical building blocks of the netlist.
|
||||||
|
circuit(Rre
|
||||||
|
|
||||||
|
# Circuit boundary
|
||||||
|
rect((5270 1210) (6320 600))
|
||||||
|
|
||||||
|
# Nets with their geometries
|
||||||
|
net(1 name('gnd!')
|
||||||
|
rect(l3 (5295 1230) (120 560))
|
||||||
|
text(l4 'gnd!' (-60 -60))
|
||||||
|
rect(l1 (-70 -505) (125 570))
|
||||||
|
rect(l1 (-140 -585) (160 600))
|
||||||
|
)
|
||||||
|
net(2 name('vdd!')
|
||||||
|
rect(l3 (11455 1240) (120 540))
|
||||||
|
text(l4 'vdd!' (-65 -60))
|
||||||
|
rect(l1 (-65 -495) (125 560))
|
||||||
|
rect(l1 (-140 -575) (160 600))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Outgoing pins and their connections to nets
|
||||||
|
pin(1 name('gnd!'))
|
||||||
|
pin(2 name('vdd!'))
|
||||||
|
|
||||||
|
# Devices and their connections
|
||||||
|
device(1 D$RR1
|
||||||
|
location(8430 1510)
|
||||||
|
param(R 10)
|
||||||
|
param(L 6)
|
||||||
|
param(W 0.6)
|
||||||
|
param(A 3.6)
|
||||||
|
param(P 13.2)
|
||||||
|
terminal(A 1)
|
||||||
|
terminal(B 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Reference netlist
|
||||||
|
reference(
|
||||||
|
|
||||||
|
# Device class section
|
||||||
|
class(RR1 RES)
|
||||||
|
|
||||||
|
# Circuit section
|
||||||
|
# Circuits are the hierarchical building blocks of the netlist.
|
||||||
|
circuit(RRE
|
||||||
|
|
||||||
|
# Nets
|
||||||
|
net(1 name('VDD!'))
|
||||||
|
net(2 name('GND!'))
|
||||||
|
|
||||||
|
# Devices and their connections
|
||||||
|
device(1 RR1
|
||||||
|
name(R0)
|
||||||
|
param(R 10)
|
||||||
|
param(L 6)
|
||||||
|
param(W 0.6)
|
||||||
|
param(A 0)
|
||||||
|
param(P 0)
|
||||||
|
terminal(A 1)
|
||||||
|
terminal(B 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cross reference
|
||||||
|
xref(
|
||||||
|
circuit(Rre RRE match
|
||||||
|
xref(
|
||||||
|
net(1 2 match)
|
||||||
|
net(2 1 match)
|
||||||
|
pin(0 () match)
|
||||||
|
pin(1 () match)
|
||||||
|
device(1 1 match)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
* Extracted by KLayout
|
||||||
|
|
||||||
|
* cell Rre
|
||||||
|
* pin gnd!
|
||||||
|
* pin vdd!
|
||||||
|
.SUBCKT Rre 1 2
|
||||||
|
* net 1 gnd!
|
||||||
|
* net 2 vdd!
|
||||||
|
* device instance $1 r0 *1 8.43,1.51 RR1
|
||||||
|
R$1 1 2 10 RR1 L=6U W=0.6U A=3.6P P=13.2U
|
||||||
|
.ENDS Rre
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
source($lvs_test_source)
|
||||||
|
report_lvs($lvs_test_target_lvsdb, true)
|
||||||
|
target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
|
||||||
|
|
||||||
|
schematic("resistor2.cir")
|
||||||
|
|
||||||
|
deep
|
||||||
|
|
||||||
|
contact = input(15, 0)
|
||||||
|
metal1 = input(16, 0)
|
||||||
|
metal1_ver = input(16, 5)
|
||||||
|
metal1_lbl = labels(16, 3)
|
||||||
|
res = metal1 & metal1_ver
|
||||||
|
metal1_not_res = metal1 - metal1_ver
|
||||||
|
|
||||||
|
class MyResistorClass < RBA::DeviceClassResistor
|
||||||
|
def initialize
|
||||||
|
super
|
||||||
|
enable_parameter("W", true)
|
||||||
|
enable_parameter("L", true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
extract_devices(resistor("RR1", 1, MyResistorClass), { "R" => res , "C" => metal1_not_res})
|
||||||
|
|
||||||
|
connect(contact, metal1_not_res)
|
||||||
|
connect(metal1_not_res, metal1_lbl)
|
||||||
|
|
||||||
|
align
|
||||||
|
netlist.simplify
|
||||||
|
compare
|
||||||
|
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
#%lvsdb-klayout
|
||||||
|
|
||||||
|
# Layout
|
||||||
|
layout(
|
||||||
|
top(Rre)
|
||||||
|
unit(0.001)
|
||||||
|
|
||||||
|
# Layer section
|
||||||
|
# This section lists the mask layers (drawing or derived) and their connections.
|
||||||
|
|
||||||
|
# Mask layers
|
||||||
|
layer(l3 '15/0')
|
||||||
|
layer(l4 '16/3')
|
||||||
|
layer(l1)
|
||||||
|
|
||||||
|
# Mask layer connectivity
|
||||||
|
connect(l3 l3 l1)
|
||||||
|
connect(l4 l1)
|
||||||
|
connect(l1 l3 l4 l1)
|
||||||
|
|
||||||
|
# Device class section
|
||||||
|
class(RR1 RES
|
||||||
|
param(L 1 0)
|
||||||
|
param(W 1 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Device abstracts section
|
||||||
|
# Device abstracts list the pin shapes of the devices.
|
||||||
|
device(D$RR1 RR1
|
||||||
|
terminal(A
|
||||||
|
rect(l1 (-3160 -300) (160 600))
|
||||||
|
)
|
||||||
|
terminal(B
|
||||||
|
rect(l1 (3000 -300) (160 600))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Circuit section
|
||||||
|
# Circuits are the hierarchical building blocks of the netlist.
|
||||||
|
circuit(Rre
|
||||||
|
|
||||||
|
# Circuit boundary
|
||||||
|
rect((5270 1210) (6320 600))
|
||||||
|
|
||||||
|
# Nets with their geometries
|
||||||
|
net(1 name('gnd!')
|
||||||
|
rect(l3 (5295 1230) (120 560))
|
||||||
|
text(l4 'gnd!' (-60 -60))
|
||||||
|
rect(l1 (-70 -505) (125 570))
|
||||||
|
rect(l1 (-140 -585) (160 600))
|
||||||
|
)
|
||||||
|
net(2 name('vdd!')
|
||||||
|
rect(l3 (11455 1240) (120 540))
|
||||||
|
text(l4 'vdd!' (-65 -60))
|
||||||
|
rect(l1 (-65 -495) (125 560))
|
||||||
|
rect(l1 (-140 -575) (160 600))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Outgoing pins and their connections to nets
|
||||||
|
pin(1 name('gnd!'))
|
||||||
|
pin(2 name('vdd!'))
|
||||||
|
|
||||||
|
# Devices and their connections
|
||||||
|
device(1 D$RR1
|
||||||
|
location(8430 1510)
|
||||||
|
param(R 10)
|
||||||
|
param(L 6)
|
||||||
|
param(W 0.6)
|
||||||
|
param(A 3.6)
|
||||||
|
param(P 13.2)
|
||||||
|
terminal(A 1)
|
||||||
|
terminal(B 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Reference netlist
|
||||||
|
reference(
|
||||||
|
|
||||||
|
# Device class section
|
||||||
|
class(RR1 RES)
|
||||||
|
|
||||||
|
# Circuit section
|
||||||
|
# Circuits are the hierarchical building blocks of the netlist.
|
||||||
|
circuit(RRE
|
||||||
|
|
||||||
|
# Nets
|
||||||
|
net(1 name('VDD!'))
|
||||||
|
net(2 name('GND!'))
|
||||||
|
|
||||||
|
# Devices and their connections
|
||||||
|
device(1 RR1
|
||||||
|
name(R0)
|
||||||
|
param(R 10)
|
||||||
|
param(L 7)
|
||||||
|
param(W 0.6)
|
||||||
|
param(A 0)
|
||||||
|
param(P 0)
|
||||||
|
terminal(A 1)
|
||||||
|
terminal(B 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cross reference
|
||||||
|
xref(
|
||||||
|
circuit(Rre RRE nomatch
|
||||||
|
xref(
|
||||||
|
net(() 2 mismatch)
|
||||||
|
net(() 1 mismatch)
|
||||||
|
net(1 () mismatch)
|
||||||
|
net(2 () mismatch)
|
||||||
|
pin(0 () match)
|
||||||
|
pin(1 () match)
|
||||||
|
device(() 1 mismatch)
|
||||||
|
device(1 () mismatch)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
.SUBCKT Rre
|
||||||
|
RR0 vdd! gnd! 10 RR1 W=600n L=6u M=1
|
||||||
|
.ENDS
|
||||||
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,4 @@
|
||||||
|
.SUBCKT Rre
|
||||||
|
RR0 vdd! gnd! 10 RR1 W=600n L=7u M=1
|
||||||
|
.ENDS
|
||||||
|
|
||||||
|
|
@ -331,6 +331,8 @@ class DBNetlist_TestClass < TestBase
|
||||||
assert_equal(net.terminal_count, 1)
|
assert_equal(net.terminal_count, 1)
|
||||||
|
|
||||||
assert_equal(d1.net_for_terminal(1).name, "NET")
|
assert_equal(d1.net_for_terminal(1).name, "NET")
|
||||||
|
assert_equal(d1.net_for_terminal("B").name, "NET")
|
||||||
|
assert_equal(d1.net_for_terminal("X").inspect, "nil")
|
||||||
assert_equal(d1.net_for_terminal(0).inspect, "nil")
|
assert_equal(d1.net_for_terminal(0).inspect, "nil")
|
||||||
|
|
||||||
d1.disconnect_terminal("B")
|
d1.disconnect_terminal("B")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue