mirror of
https://github.com/KLayout/klayout.git
synced 2026-08-29 01:14:35 +02:00
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:
@@ -117,6 +117,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
|
||||
os << " ";
|
||||
os << format_name (dev.device_class ()->name ());
|
||||
}
|
||||
os << format_params (dev, db::DeviceClassCapacitor::param_id_C);
|
||||
|
||||
} else if (ind) {
|
||||
|
||||
@@ -129,6 +130,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
|
||||
os << " ";
|
||||
os << format_name (dev.device_class ()->name ());
|
||||
}
|
||||
os << format_params (dev, db::DeviceClassInductor::param_id_L);
|
||||
|
||||
} else if (res || res3) {
|
||||
|
||||
@@ -141,6 +143,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
|
||||
os << " ";
|
||||
os << format_name (dev.device_class ()->name ());
|
||||
}
|
||||
os << format_params (dev, db::DeviceClassResistor::param_id_R);
|
||||
|
||||
} else if (diode) {
|
||||
|
||||
|
||||
@@ -251,6 +251,24 @@ static void add_other_abstracts (db::Device *device, const db::DeviceAbstractRef
|
||||
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",
|
||||
gsi::method ("device_class", &db::Device::device_class,
|
||||
"@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"
|
||||
"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"),
|
||||
"@brief Connects the given terminal to the specified net.\n"
|
||||
) +
|
||||
|
||||
@@ -4,6 +4,15 @@ require 'pathname'
|
||||
|
||||
module DRC
|
||||
|
||||
class CustomDeviceClassFactory < RBA::DeviceClassFactory
|
||||
def initialize(cls)
|
||||
@cls = cls
|
||||
end
|
||||
def create_class
|
||||
@cls.new
|
||||
end
|
||||
end
|
||||
|
||||
# The DRC engine
|
||||
|
||||
# %DRC%
|
||||
@@ -308,22 +317,57 @@ module DRC
|
||||
# @brief Defines SPICE output format (with options)
|
||||
# @name write_spice
|
||||
# @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
|
||||
# specify SPICE format.
|
||||
# "use_net_names" and "with_comments" are boolean parameters indicating
|
||||
# whether to use named nets (numbers if false) and whether to add
|
||||
# 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
|
||||
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
|
||||
writer.use_net_names = use_net_names
|
||||
end
|
||||
if with_comments != nil
|
||||
writer.with_comments = with_comments
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
@@ -331,15 +375,16 @@ module DRC
|
||||
# @brief Supplies the MOS3 transistor extractor class
|
||||
# @name mos3
|
||||
# @synopsis mos3(name)
|
||||
# @synopsis mos3(name, class)
|
||||
# Use this class with \extract_devices to specify extraction of a
|
||||
# three-terminal MOS transistor.
|
||||
#
|
||||
# See RBA::DeviceExtractorMOS3Transistor for more details
|
||||
# about this extractor (non-strict mode applies for 'mos3').
|
||||
|
||||
def mos3(name)
|
||||
def mos3(name, cls = nil)
|
||||
self._context("mos3") do
|
||||
RBA::DeviceExtractorMOS3Transistor::new(name)
|
||||
RBA::DeviceExtractorMOS3Transistor::new(name, false, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -347,15 +392,16 @@ module DRC
|
||||
# @brief Supplies the MOS4 transistor extractor class
|
||||
# @name mos4
|
||||
# @synopsis mos4(name)
|
||||
# @synopsis mos4(name, class)
|
||||
# Use this class with \extract_devices to specify extraction of a
|
||||
# four-terminal MOS transistor.
|
||||
#
|
||||
# See RBA::DeviceExtractorMOS4Transistor for more details
|
||||
# about this extractor (non-strict mode applies for 'mos4').
|
||||
|
||||
def mos4(name)
|
||||
def mos4(name, cls = nil)
|
||||
self._context("mos4") do
|
||||
RBA::DeviceExtractorMOS4Transistor::new(name)
|
||||
RBA::DeviceExtractorMOS4Transistor::new(name, false, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -363,6 +409,7 @@ module DRC
|
||||
# @brief Supplies the DMOS3 transistor extractor class
|
||||
# @name dmos3
|
||||
# @synopsis dmos3(name)
|
||||
# @synopsis dmos3(name, class)
|
||||
# Use this class with \extract_devices to specify extraction of a
|
||||
# three-terminal DMOS transistor. A DMOS transistor is essentially
|
||||
# the same than a MOS transistor, but source and drain are
|
||||
@@ -371,9 +418,9 @@ module DRC
|
||||
# See RBA::DeviceExtractorMOS3Transistor for more details
|
||||
# about this extractor (strict mode applies for 'dmos3').
|
||||
|
||||
def dmos3(name)
|
||||
def dmos3(name, cls = nil)
|
||||
self._context("dmos3") do
|
||||
RBA::DeviceExtractorMOS3Transistor::new(name, true)
|
||||
RBA::DeviceExtractorMOS3Transistor::new(name, true, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -381,6 +428,7 @@ module DRC
|
||||
# @brief Supplies the MOS4 transistor extractor class
|
||||
# @name dmos4
|
||||
# @synopsis dmos4(name)
|
||||
# @synopsis dmos4(name, class)
|
||||
# Use this class with \extract_devices to specify extraction of a
|
||||
# four-terminal DMOS transistor. A DMOS transistor is essentially
|
||||
# the same than a MOS transistor, but source and drain are
|
||||
@@ -389,9 +437,9 @@ module DRC
|
||||
# See RBA::DeviceExtractorMOS4Transistor for more details
|
||||
# about this extractor (strict mode applies for 'dmos4').
|
||||
|
||||
def dmos4(name)
|
||||
def dmos4(name, cls = nil)
|
||||
self._context("dmos4") do
|
||||
RBA::DeviceExtractorMOS4Transistor::new(name, true)
|
||||
RBA::DeviceExtractorMOS4Transistor::new(name, true, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -399,15 +447,16 @@ module DRC
|
||||
# @brief Supplies the BJT3 transistor extractor class
|
||||
# @name bjt3
|
||||
# @synopsis bjt3(name)
|
||||
# @synopsis bjt3(name, class)
|
||||
# Use this class with \extract_devices to specify extraction of a
|
||||
# bipolar junction transistor
|
||||
#
|
||||
# See RBA::DeviceExtractorBJT3Transistor for more details
|
||||
# about this extractor.
|
||||
|
||||
def bjt3(name)
|
||||
def bjt3(name, cls = nil)
|
||||
self._context("bjt3") do
|
||||
RBA::DeviceExtractorBJT3Transistor::new(name)
|
||||
RBA::DeviceExtractorBJT3Transistor::new(name, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -415,15 +464,16 @@ module DRC
|
||||
# @brief Supplies the BJT4 transistor extractor class
|
||||
# @name bjt4
|
||||
# @synopsis bjt4(name)
|
||||
# @synopsis bjt4(name, class)
|
||||
# Use this class with \extract_devices to specify extraction of a
|
||||
# bipolar junction transistor with a substrate terminal
|
||||
#
|
||||
# See RBA::DeviceExtractorBJT4Transistor for more details
|
||||
# about this extractor.
|
||||
|
||||
def bjt4(name)
|
||||
def bjt4(name, cls = nil)
|
||||
self._context("bjt4") do
|
||||
RBA::DeviceExtractorBJT4Transistor::new(name)
|
||||
RBA::DeviceExtractorBJT4Transistor::new(name, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -431,15 +481,16 @@ module DRC
|
||||
# @brief Supplies the diode extractor class
|
||||
# @name diode
|
||||
# @synopsis diode(name)
|
||||
# @synopsis diode(name, class)
|
||||
# Use this class with \extract_devices to specify extraction of a
|
||||
# planar diode
|
||||
#
|
||||
# See RBA::DeviceExtractorDiode for more details
|
||||
# about this extractor.
|
||||
|
||||
def diode(name)
|
||||
def diode(name, cls = nil)
|
||||
self._context("diode") do
|
||||
RBA::DeviceExtractorDiode::new(name)
|
||||
RBA::DeviceExtractorDiode::new(name, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -447,6 +498,7 @@ module DRC
|
||||
# @brief Supplies the resistor extractor class
|
||||
# @name resistor
|
||||
# @synopsis resistor(name, sheet_rho)
|
||||
# @synopsis resistor(name, sheet_rho, class)
|
||||
# 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
|
||||
@@ -455,9 +507,9 @@ module DRC
|
||||
# See RBA::DeviceExtractorResistor for more details
|
||||
# about this extractor.
|
||||
|
||||
def resistor(name, sheet_rho)
|
||||
def resistor(name, sheet_rho, cls = nil)
|
||||
self._context("resistor") do
|
||||
RBA::DeviceExtractorResistor::new(name, sheet_rho)
|
||||
RBA::DeviceExtractorResistor::new(name, sheet_rho, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -465,6 +517,7 @@ module DRC
|
||||
# @brief Supplies the resistor extractor class that includes a bulk terminal
|
||||
# @name resistor_with_bulk
|
||||
# @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
|
||||
# with a bulk terminal.
|
||||
# The sheet_rho value is the sheet resistance in ohms/square.
|
||||
@@ -472,9 +525,9 @@ module DRC
|
||||
# See RBA::DeviceExtractorResistorWithBulk for more details
|
||||
# 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
|
||||
RBA::DeviceExtractorResistorWithBulk::new(name, sheet_rho)
|
||||
RBA::DeviceExtractorResistorWithBulk::new(name, sheet_rho, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -482,15 +535,16 @@ module DRC
|
||||
# @brief Supplies the capacitor extractor class
|
||||
# @name capacitor
|
||||
# @synopsis capacitor(name, area_cap)
|
||||
# @synopsis capacitor(name, area_cap, class)
|
||||
# Use this class with \extract_devices to specify extraction of a capacitor.
|
||||
# The area_cap argument is the capacitance in Farad per square micrometer.
|
||||
#
|
||||
# See RBA::DeviceExtractorCapacitor for more details
|
||||
# about this extractor.
|
||||
|
||||
def capacitor(name, area_cap)
|
||||
def capacitor(name, area_cap, cls = nil)
|
||||
self._context("capacitor") do
|
||||
RBA::DeviceExtractorCapacitor::new(name, area_cap)
|
||||
RBA::DeviceExtractorCapacitor::new(name, area_cap, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -498,6 +552,7 @@ module DRC
|
||||
# @brief Supplies the capacitor extractor class that includes a bulk terminal
|
||||
# @name capacitor_with_bulk
|
||||
# @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
|
||||
# with a bulk terminal.
|
||||
# The area_cap argument is the capacitance in Farad per square micrometer.
|
||||
@@ -505,9 +560,9 @@ module DRC
|
||||
# See RBA::DeviceExtractorCapacitorWithBulk for more details
|
||||
# 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
|
||||
RBA::DeviceExtractorCapacitorWithBulk::new(name, area_cap)
|
||||
RBA::DeviceExtractorCapacitorWithBulk::new(name, area_cap, _make_factory(cls))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -376,5 +376,33 @@ dc.enable_parameter("L", true)
|
||||
fully enabled parameters.
|
||||
</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>
|
||||
|
||||
|
||||
@@ -206,8 +206,14 @@ TEST(23_issue709)
|
||||
run_test (_this, "empty_subcells", "empty_subcells.gds");
|
||||
}
|
||||
|
||||
// empty gds
|
||||
TEST(24_issue806)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user