diff --git a/src/db/db/dbNetlistSpiceWriter.cc b/src/db/db/dbNetlistSpiceWriter.cc index 5bf03d678..b5893bee3 100644 --- a/src/db/db/dbNetlistSpiceWriter.cc +++ b/src/db/db/dbNetlistSpiceWriter.cc @@ -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) { diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index cfdc5a341..0941d63c3 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -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 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 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" ) + diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 51f44c266..6359bff21 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -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 diff --git a/src/lay/lay/doc/manual/lvs_device_extractors.xml b/src/lay/lay/doc/manual/lvs_device_extractors.xml index e1200800f..7cf6449e2 100644 --- a/src/lay/lay/doc/manual/lvs_device_extractors.xml +++ b/src/lay/lay/doc/manual/lvs_device_extractors.xml @@ -376,5 +376,33 @@ dc.enable_parameter("L", true) fully enabled parameters.

+

+ 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". +

+ +
class MyResistor < RBA::DeviceClassResistor
+  def initialize
+    super
+    enable_parameter("W", true)
+    enable_parameter("L", true)
+  end
+end
+
+...
+
+extract_devices(resistor("RES", 1, MyResistor), ...)
+
+ +

+ 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. +

+ diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 6d054e461..304aa9dd5 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -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"); +} diff --git a/testdata/lvs/enable_wl1.cir b/testdata/lvs/enable_wl1.cir new file mode 100644 index 000000000..2dbc8c321 --- /dev/null +++ b/testdata/lvs/enable_wl1.cir @@ -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 diff --git a/testdata/lvs/enable_wl1.lvs b/testdata/lvs/enable_wl1.lvs new file mode 100644 index 000000000..a58903723 --- /dev/null +++ b/testdata/lvs/enable_wl1.lvs @@ -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 + diff --git a/testdata/lvs/enable_wl1.lvsdb b/testdata/lvs/enable_wl1.lvsdb new file mode 100644 index 000000000..67695b612 --- /dev/null +++ b/testdata/lvs/enable_wl1.lvsdb @@ -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) + ) + ) +) diff --git a/testdata/lvs/enable_wl2.cir b/testdata/lvs/enable_wl2.cir new file mode 100644 index 000000000..5ce133250 --- /dev/null +++ b/testdata/lvs/enable_wl2.cir @@ -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 diff --git a/testdata/lvs/enable_wl2.lvs b/testdata/lvs/enable_wl2.lvs new file mode 100644 index 000000000..945a89294 --- /dev/null +++ b/testdata/lvs/enable_wl2.lvs @@ -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 + diff --git a/testdata/lvs/enable_wl2.lvsdb b/testdata/lvs/enable_wl2.lvsdb new file mode 100644 index 000000000..67695b612 --- /dev/null +++ b/testdata/lvs/enable_wl2.lvsdb @@ -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) + ) + ) +) diff --git a/testdata/lvs/enable_wl3.cir b/testdata/lvs/enable_wl3.cir new file mode 100644 index 000000000..5ce133250 --- /dev/null +++ b/testdata/lvs/enable_wl3.cir @@ -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 diff --git a/testdata/lvs/enable_wl3.lvs b/testdata/lvs/enable_wl3.lvs new file mode 100644 index 000000000..8f5405307 --- /dev/null +++ b/testdata/lvs/enable_wl3.lvs @@ -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 + diff --git a/testdata/lvs/enable_wl3.lvsdb b/testdata/lvs/enable_wl3.lvsdb new file mode 100644 index 000000000..947fc54ac --- /dev/null +++ b/testdata/lvs/enable_wl3.lvsdb @@ -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) + ) + ) +) diff --git a/testdata/lvs/resistor.cir b/testdata/lvs/resistor.cir new file mode 100644 index 000000000..c210ac37c --- /dev/null +++ b/testdata/lvs/resistor.cir @@ -0,0 +1,4 @@ +.SUBCKT Rre +RR0 vdd! gnd! 10 RR1 W=600n L=6u M=1 +.ENDS + diff --git a/testdata/lvs/resistor.gds b/testdata/lvs/resistor.gds new file mode 100644 index 000000000..aa2b5869b Binary files /dev/null and b/testdata/lvs/resistor.gds differ diff --git a/testdata/lvs/resistor2.cir b/testdata/lvs/resistor2.cir new file mode 100644 index 000000000..38882671e --- /dev/null +++ b/testdata/lvs/resistor2.cir @@ -0,0 +1,4 @@ +.SUBCKT Rre +RR0 vdd! gnd! 10 RR1 W=600n L=7u M=1 +.ENDS + diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index bb1d34570..dc09d7f4b 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -331,6 +331,8 @@ class DBNetlist_TestClass < TestBase assert_equal(net.terminal_count, 1) 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") d1.disconnect_terminal("B")