diff --git a/src/db/db/dbCircuit.cc b/src/db/db/dbCircuit.cc index 1ca2d79c7..735f6116b 100644 --- a/src/db/db/dbCircuit.cc +++ b/src/db/db/dbCircuit.cc @@ -105,6 +105,14 @@ Circuit &Circuit::operator= (const Circuit &other) m_cell_index = other.m_cell_index; m_pins = other.m_pins; + m_pin_by_id.clear (); + for (pin_list::iterator p = m_pins.begin (); p != m_pins.end (); ++p) { + if (m_pin_by_id.size () <= p->id ()) { + m_pin_by_id.resize (p->id () + 1, pin_list::iterator ()); + } + m_pin_by_id [p->id ()] = p; + } + std::map device_table; for (const_device_iterator i = other.begin_devices (); i != other.end_devices (); ++i) { Device *d = new Device (*i); @@ -157,17 +165,22 @@ void Circuit::set_netlist (Netlist *netlist) const Pin *Circuit::pin_by_id (size_t id) const { - if (id >= m_pins.size ()) { + if (id >= m_pin_by_id.size ()) { return 0; } else { - return &m_pins [id]; + pin_list::iterator pi = m_pin_by_id [id]; + if (pi == pin_list::iterator ()) { + return 0; + } else { + return pi.operator-> (); + } } } void Circuit::rename_pin (size_t id, const std::string &name) { - if (id < m_pins.size ()) { - m_pins [id].set_name (name); + if (id < m_pin_by_id.size () && m_pin_by_id [id] != pin_list::iterator ()) { + m_pin_by_id [id]->set_name (name); } } @@ -207,6 +220,7 @@ void Circuit::clear () { m_name.clear (); m_pins.clear (); + m_pin_by_id.clear (); m_devices.clear (); m_nets.clear (); m_subcircuits.clear (); @@ -290,22 +304,33 @@ Circuit::const_child_circuit_iterator Circuit::end_parents () const void Circuit::clear_pins () { m_pins.clear (); + m_pin_by_id.clear (); } const Pin &Circuit::add_pin (const Pin &pin) { m_pins.push_back (pin); - m_pins.back ().set_id (m_pins.size () - 1); + m_pins.back ().set_id (m_pin_by_id.size ()); + m_pin_by_id.push_back (--m_pins.end ()); return m_pins.back (); } const Pin &Circuit::add_pin (const std::string &name) { m_pins.push_back (Pin (name)); - m_pins.back ().set_id (m_pins.size () - 1); + m_pins.back ().set_id (m_pin_by_id.size ()); + m_pin_by_id.push_back (--m_pins.end ()); return m_pins.back (); } +void Circuit::remove_pin (size_t id) +{ + if (id < m_pin_by_id.size () && m_pin_by_id [id] != pin_list::iterator ()) { + m_pins.erase (m_pin_by_id [id]); + m_pin_by_id [id] = pin_list::iterator (); + } +} + void Circuit::add_net (Net *net) { m_nets.push_back (net); @@ -554,13 +579,38 @@ void Circuit::purge_nets () { std::vector nets_to_be_purged; for (net_iterator n = begin_nets (); n != end_nets (); ++n) { - if (n->is_floating ()) { + if (n->is_passive ()) { nets_to_be_purged.push_back (n.operator-> ()); } } + + std::set pins_to_delete; + for (std::vector::const_iterator n = nets_to_be_purged.begin (); n != nets_to_be_purged.end (); ++n) { + for (db::Net::pin_iterator p = (*n)->begin_pins (); p != (*n)->end_pins (); ++p) { + pins_to_delete.insert (p->pin_id ()); + } delete *n; } + + // remove the pin references of the pins we're going to delete + for (refs_iterator r = begin_refs (); r != end_refs (); ++r) { + db::SubCircuit *subcircuit = r.operator-> (); + for (std::set::const_iterator p = pins_to_delete.begin (); p != pins_to_delete.end (); ++p) { + db::Net *net = subcircuit->net_for_pin (*p); + for (db::Net::subcircuit_pin_iterator sp = net->begin_subcircuit_pins (); sp != net->end_subcircuit_pins (); ++sp) { + if (sp->pin_id () == *p && sp->subcircuit () == subcircuit) { + net->erase_subcircuit_pin (sp); + break; + } + } + } + } + + // and actually remove those pins + for (std::set::const_iterator p = pins_to_delete.begin (); p != pins_to_delete.end (); ++p) { + remove_pin (*p); + } } /** diff --git a/src/db/db/dbCircuit.h b/src/db/db/dbCircuit.h index c8bcac695..5fa298ea0 100644 --- a/src/db/db/dbCircuit.h +++ b/src/db/db/dbCircuit.h @@ -89,7 +89,7 @@ class DB_PUBLIC Circuit : public db::NetlistObject, public gsi::ObjectBase { public: - typedef tl::vector pin_list; + typedef std::list pin_list; typedef pin_list::const_iterator const_pin_iterator; typedef pin_list::iterator pin_iterator; typedef tl::shared_collection device_list; @@ -330,6 +330,11 @@ public: */ const Pin &add_pin (const Pin &pin); + /** + * @brief Removes the pin with the given ID + */ + void remove_pin (size_t id); + /** * @brief Begin iterator for the pins of the circuit (non-const version) */ @@ -751,6 +756,7 @@ private: db::cell_index_type m_cell_index; net_list m_nets; pin_list m_pins; + std::vector m_pin_by_id; device_list m_devices; subcircuit_list m_subcircuits; Netlist *mp_netlist; diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index 62056542c..1f7ab2fe8 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -472,7 +472,7 @@ void Netlist::remove_device_abstract (DeviceAbstract *device_abstract) void Netlist::purge_nets () { - for (circuit_iterator c = begin_circuits (); c != end_circuits (); ++c) { + for (bottom_up_circuit_iterator c = begin_bottom_up (); c != end_bottom_up (); ++c) { c->purge_nets (); } } diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 6d2ca28cd..f6dd51ce8 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -1131,6 +1131,11 @@ Class decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit", "to the outside through such a pin. The pin is added after all existing " "pins. For more details see the \\Pin class." ) + + gsi::method ("remove_pin", &db::Circuit::remove_pin, gsi::arg ("id"), + "@brief Removes the pin with the given ID from the circuit\n" + "\n" + "This method has been introduced in version 0.26.2.\n" + ) + gsi::iterator ("each_child", (db::Circuit::child_circuit_iterator (db::Circuit::*) ()) &db::Circuit::begin_children, (db::Circuit::child_circuit_iterator (db::Circuit::*) ()) &db::Circuit::end_children, "@brief Iterates over the child circuits of this circuit\n" "Child circuits are the ones that are referenced from this circuit via subcircuits." diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index fd64adaa0..d1bad5e47 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -2573,3 +2573,134 @@ TEST(12_FloatingSubcircuitExtraction) ); } +TEST(13_RemoveDummyPins) +{ + db::Layout ly; + db::LayerMap lmap; + + unsigned int nwell = define_layer (ly, lmap, 1); + unsigned int active = define_layer (ly, lmap, 2); + unsigned int poly = define_layer (ly, lmap, 3); + unsigned int poly_lbl = define_layer (ly, lmap, 3, 1); + unsigned int diff_cont = define_layer (ly, lmap, 4); + unsigned int poly_cont = define_layer (ly, lmap, 5); + unsigned int metal1 = define_layer (ly, lmap, 6); + unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1); + unsigned int via1 = define_layer (ly, lmap, 7); + unsigned int metal2 = define_layer (ly, lmap, 8); + unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1); + + { + 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, "issue-425.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 rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss); + db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss); + db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss); + db::Region rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss); + db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss); + db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss); + db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss); + db::Region rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss); + db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss); + db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss); + db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss); + + // derived regions + + db::Region rpactive = ractive & rnwell; + db::Region rpgate = rpactive & rpoly; + db::Region rpsd = rpactive - rpgate; + + db::Region rnactive = ractive - rnwell; + db::Region rngate = rnactive & rpoly; + db::Region rnsd = rnactive - rngate; + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); + db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &rpsd; + dl["G"] = &rpgate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + pmos_ex.extract (dss, 0, dl, nl, cl); + + dl["SD"] = &rnsd; + dl["G"] = &rngate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + nmos_ex.extract (dss, 0, dl, nl, cl); + + // perform the net extraction + + db::Connectivity conn; + // Intra-layer + conn.connect (rpsd); + conn.connect (rnsd); + conn.connect (rpoly); + conn.connect (rdiff_cont); + conn.connect (rpoly_cont); + conn.connect (rmetal1); + conn.connect (rvia1); + conn.connect (rmetal2); + // Inter-layer + conn.connect (rpsd, rdiff_cont); + conn.connect (rnsd, rdiff_cont); + conn.connect (rpoly, rpoly_cont); + conn.connect (rpoly_cont, rmetal1); + conn.connect (rdiff_cont, rmetal1); + conn.connect (rmetal1, rvia1); + conn.connect (rvia1, rmetal2); + conn.connect (rpoly, rpoly_lbl); // attaches labels + conn.connect (rmetal1, rmetal1_lbl); // attaches labels + conn.connect (rmetal2, rmetal2_lbl); // attaches labels + + // extract the nets + + db::NetlistExtractor net_ex; + net_ex.set_include_floating_subcircuits (true); + net_ex.extract_nets (dss, 0, conn, nl, cl); + + nl.simplify (); + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, nl, + "circuit RINGO (FB=FB,VSS=VSS,VDD=VDD);\n" + " subcircuit INV2 $1 (IN=FB,OUT=$I25,$3=VSS,$4=VDD);\n" + " subcircuit INV2 $2 (IN=$I25,OUT=$I1,$3=VSS,$4=VDD);\n" + " subcircuit INV2 $3 (IN=$I1,OUT=$I2,$3=VSS,$4=VDD);\n" + " subcircuit INV2 $4 (IN=$I2,OUT=$I3,$3=VSS,$4=VDD);\n" + "end;\n" + "circuit INV2 (IN=IN,OUT=OUT,$3=$4,$4=$5);\n" + " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + "end;\n" + ); +} + diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index c3056e4aa..06e1eea1b 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -360,6 +360,17 @@ TEST(3_CircuitBasic) EXPECT_EQ (c2.pin_by_id (0)->name (), "p1"); EXPECT_EQ (c2.pin_by_id (1)->name (), "p2"); EXPECT_EQ (c2.pin_by_id (2), 0); + + c2.remove_pin (1); + EXPECT_EQ (c2.pin_by_id (0)->name (), "p1"); + EXPECT_EQ (c2.pin_by_id (1), 0); + EXPECT_EQ (c2.pin_by_id (2), 0); + + db::Pin p3 = c2.add_pin ("p3"); + EXPECT_EQ (c2.pin_by_id (0)->name (), "p1"); + EXPECT_EQ (c2.pin_by_id (1), 0); + EXPECT_EQ (c2.pin_by_id (2)->name (), "p3"); + EXPECT_EQ (c2.pin_by_id (3), 0); } TEST(4_CircuitDevices) diff --git a/testdata/lvs/invchain_for_cheat.cir b/testdata/lvs/invchain_for_cheat.cir index 1aae680d3..50e75dba1 100644 --- a/testdata/lvs/invchain_for_cheat.cir +++ b/testdata/lvs/invchain_for_cheat.cir @@ -1,85 +1,29 @@ * cell INVCHAIN .SUBCKT INVCHAIN -* cell instance $1 r0 *1 -1.5,-0.8 X$1 9 7 8 6 9 5 1 5 3 2 13 14 INV3 -* cell instance $2 r0 *1 2.6,-0.8 X$2 8 11 9 10 8 11 2 12 2 12 5 4 13 14 INV2 -* cell instance $3 m90 *1 7.4,0 X$3 14 13 11 12 4 4 10 10 INV .ENDS INVCHAIN * cell INV3 -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin .SUBCKT INV3 1 2 3 4 5 6 7 8 9 10 11 12 -* cell instance $1 r0 *1 4.8,0.8 X$1 12 11 3 10 8 6 1 5 INV -* cell instance $2 r0 *1 1.5,0.8 X$2 12 11 4 7 9 9 2 2 INV -* cell instance $3 m90 *1 2.3,0.8 X$3 12 11 2 9 7 7 4 4 INV .ENDS INV3 * cell INV2 -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin .SUBCKT INV2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 -* cell instance $1 m90 *1 1.5,0.8 X$1 14 13 3 11 9 7 1 5 INV -* cell instance $2 r0 *1 4,0.8 X$2 14 13 4 12 10 8 2 6 INV .ENDS INV2 * cell INV -* pin -* pin -* pin -* pin -* pin -* pin -* pin -* pin .SUBCKT INV 1 2 3 4 5 6 7 8 -* cell instance $1 r0 *1 0,0 -X$1 4 1 3 TRANS -* cell instance $2 r0 *1 0,2.8 -X$2 4 2 3 TRANS -* device instance $1 r0 *1 0,2.8 PMOS M$1 4 3 2 4 PMOS L=0.25U W=0.95U AS=0.79325P AD=0.26125P PS=3.57U PD=1.5U -* device instance $2 r0 *1 0.8,2.8 PMOS M$2 2 7 5 2 PMOS L=0.25U W=0.95U AS=0.26125P AD=0.03325P PS=1.5U PD=1.97U -* device instance $3 r0 *1 0,0 NMOS M$3 4 3 1 4 NMOS L=0.25U W=0.95U AS=0.79325P AD=0.26125P PS=3.57U PD=1.5U -* device instance $4 r0 *1 0.8,0 NMOS M$4 1 8 6 1 NMOS L=0.25U W=0.95U AS=0.26125P AD=0.03325P PS=1.5U PD=1.97U .ENDS INV -* cell TRANS -* pin -* pin -* pin -.SUBCKT TRANS 1 2 3 -.ENDS TRANS diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 695eb4e38..879939444 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -170,6 +170,21 @@ class DBNetlist_TestClass < TestBase c.each_pin { |p| names << p.name } assert_equal(names, [ "A", "B" ]) + assert_equal(c.pin_by_id(0) == nil, false) + assert_equal(c.pin_by_id(1) == nil, false) + assert_equal(c.pin_by_id(0).name, "A") + assert_equal(c.pin_by_id(1).name, "B") + + c.remove_pin(0) + + names = [] + c.each_pin { |p| names << p.name } + assert_equal(names, [ "B" ]) + + assert_equal(c.pin_by_id(0) == nil, true) + assert_equal(c.pin_by_id(1) == nil, false) + assert_equal(c.pin_by_id(1).name, "B") + end def test_4_Device