diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index aa5b9f84a..7bc0d4caf 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -481,6 +481,10 @@ void NetlistDeviceExtractor::extract_devices (const std::vector & /* void NetlistDeviceExtractor::register_device_class (DeviceClass *device_class) { + std::auto_ptr holder (device_class); + tl_assert (device_class != 0); + tl_assert (m_netlist.get () != 0); + if (mp_device_class != 0) { throw tl::Exception (tl::to_string (tr ("Device class already set"))); } @@ -488,12 +492,22 @@ void NetlistDeviceExtractor::register_device_class (DeviceClass *device_class) throw tl::Exception (tl::to_string (tr ("No device extractor/device class name set"))); } - tl_assert (device_class != 0); - mp_device_class = device_class; - mp_device_class->set_name (m_name); + DeviceClass *existing = m_netlist->device_class_by_name (m_name); + if (existing) { - tl_assert (m_netlist.get () != 0); - m_netlist->add_device_class (device_class); + if (typeid (*existing) != typeid (*device_class)) { + throw tl::Exception (tl::to_string (tr ("Different device class already registered with the same name"))); + } + mp_device_class = existing; + + } else { + + mp_device_class = holder.get (); + mp_device_class->set_name (m_name); + + m_netlist->add_device_class (holder.release ()); + + } } const db::NetlistDeviceExtractorLayerDefinition &NetlistDeviceExtractor::define_layer (const std::string &name, const std::string &description) diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index e04637320..1dbdd0b25 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -2303,3 +2303,110 @@ TEST(10_DeviceExtractionWithBreakoutCells) db::compare_layouts (_this, ly, au); } + +TEST(11_DeviceExtractionWithSameClass) +{ + db::Layout ly; + db::LayerMap lmap; + + unsigned int rmarker = define_layer (ly, lmap, 1); + unsigned int poly = define_layer (ly, lmap, 2); + unsigned int diff = define_layer (ly, lmap, 3); + unsigned int contact = define_layer (ly, lmap, 4); + unsigned int metal = define_layer (ly, lmap, 5); + + { + db::LoadLayoutOptions options; + options.get_options ().layer_map = lmap; + options.get_options ().create_other_layers = false; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "device_extract_l11.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region rrmarker (db::RecursiveShapeIterator (ly, tc, rmarker), dss); + db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss); + db::Region rdiff (db::RecursiveShapeIterator (ly, tc, diff), dss); + db::Region rcontact (db::RecursiveShapeIterator (ly, tc, contact), dss); + db::Region rmetal (db::RecursiveShapeIterator (ly, tc, metal), dss); + + // derived regions + + db::Region rpoly_cap = rpoly - rrmarker; + db::Region rpoly_res = rpoly & rrmarker; + db::Region rdiff_cap = rdiff - rrmarker; + db::Region rdiff_res = rdiff & rrmarker; + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorResistor polyres_ex ("RES", 50.0); + db::NetlistDeviceExtractorResistor diffres_ex ("RES", 150.0); + + db::NetlistDeviceExtractor::input_layers dl; + dl["R"] = &rpoly_res; + dl["C"] = &rpoly_cap; + polyres_ex.extract (dss, 0, dl, nl, cl); + + dl.clear (); + dl["R"] = &rdiff_res; + dl["C"] = &rdiff_cap; + diffres_ex.extract (dss, 0, dl, nl, cl); + + // perform the net extraction + + db::NetlistExtractor net_ex; + + db::Connectivity conn; + // Intra-layer + conn.connect (rpoly_cap); + conn.connect (rdiff_cap); + conn.connect (rcontact); + // Inter-layer + conn.connect (rpoly_cap, rcontact); + conn.connect (rdiff_cap, rcontact); + conn.connect (rmetal, rcontact); + + // extract the nets + + net_ex.extract_nets (dss, 0, conn, nl, cl); + + std::string nl_au_string = + "circuit TOP ();\n" + " device RES $1 (A=$1,B=$2) (R=175,L=2.8,W=0.8,A=0.56,P=3.6);\n" + " device RES $2 (A=$2,B=$3) (R=175,L=2.8,W=0.8,A=0.56,P=3.6);\n" + " device RES $3 (A=$3,B=$4) (R=525,L=2.8,W=0.8,A=0.56,P=3.6);\n" + "end;\n" + ; + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, nl, nl_au_string); + + nl.combine_devices (); + + std::string nl_au_string_post = + "circuit TOP ();\n" + " device RES $3 (A=$1,B=$4) (R=875,L=8.4,W=0.8,A=1.68,P=10.8);\n" + "end;\n" + ; + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, nl, nl_au_string_post); +} diff --git a/testdata/algo/device_extract_l11.gds b/testdata/algo/device_extract_l11.gds new file mode 100644 index 000000000..23e65f7d8 Binary files /dev/null and b/testdata/algo/device_extract_l11.gds differ