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