diff --git a/src/db/db/dbPropertiesRepository.cc b/src/db/db/dbPropertiesRepository.cc index 790b2a919..bba686627 100644 --- a/src/db/db/dbPropertiesRepository.cc +++ b/src/db/db/dbPropertiesRepository.cc @@ -373,7 +373,7 @@ PropertiesRepository::prop_name_id (const tl::Variant &name) } } -property_names_id_type +property_values_id_type PropertiesRepository::prop_value_id (const tl::Variant &value) { tl::MutexLocker locker (&m_lock); @@ -383,9 +383,9 @@ PropertiesRepository::prop_value_id (const tl::Variant &value) m_property_values_heap.push_back (value); const tl::Variant &new_value = m_property_values_heap.back (); m_propvalues.insert (&new_value); - return property_names_id_type (&new_value); + return property_values_id_type (&new_value); } else { - return property_names_id_type (*pi); + return property_values_id_type (*pi); } } diff --git a/src/db/db/dbPropertiesRepository.h b/src/db/db/dbPropertiesRepository.h index a5bbf7a9f..99388e326 100644 --- a/src/db/db/dbPropertiesRepository.h +++ b/src/db/db/dbPropertiesRepository.h @@ -358,7 +358,7 @@ public: * This method will assign a new ID to the given value if required and * return the ID associated with it. */ - property_names_id_type prop_value_id (const tl::Variant &name); + property_values_id_type prop_value_id (const tl::Variant &name); /** * @brief Get the ID for a name diff --git a/src/pex/pex/pexRNetExtractor.cc b/src/pex/pex/pexRNetExtractor.cc index 78f4f6a4b..592d48859 100644 --- a/src/pex/pex/pexRNetExtractor.cc +++ b/src/pex/pex/pexRNetExtractor.cc @@ -33,6 +33,7 @@ #include "dbRegionProcessors.h" #include "dbCompoundOperation.h" #include "dbPolygonNeighborhood.h" +#include "dbPropertiesRepository.h" namespace pex { @@ -121,10 +122,11 @@ class ViaAggregationVisitor : public db::PolygonNeighborhoodVisitor { public: - ViaAggregationVisitor (const RExtractorTechVia *via_tech, std::vector > *conductances, double dbu) - : mp_via_tech (via_tech), mp_conductances (conductances), m_dbu (dbu) + ViaAggregationVisitor (const RExtractorTechVia *via_tech, double dbu) + : mp_via_tech (via_tech), m_dbu (dbu) { - // .. nothing yet .. + // this is just for consistency - we actually do not produce output + set_result_type (db::CompoundRegionCheckOperationNode::Region); } virtual void neighbors (const db::Layout * /*layout*/, const db::Cell * /*cell*/, const db::PolygonWithProperties &polygon, const neighbors_type &neighbors) @@ -145,15 +147,44 @@ public: } } - mp_conductances->push_back (std::make_pair (c, polygon.box ().center ())); + db::PropertiesSet ps; + ps.insert (prop_name_id, tl::Variant (c)); + + output_polygon (db::PolygonWithProperties (polygon, db::properties_id (ps))); } + static db::property_names_id_type prop_name_id; + private: const RExtractorTechVia *mp_via_tech; std::vector > *mp_conductances; + db::property_names_id_type m_prop_name_id; double m_dbu; }; +db::property_names_id_type ViaAggregationVisitor::prop_name_id = db::property_names_id (tl::Variant ()); + +} + +void +RNetExtractor::create_via_port (const pex::RExtractorTechVia &tech, + double conductance, + const db::Polygon &poly, + unsigned int &port_index, + std::map > &vias, + RNetwork &rnetwork) +{ + RNode *a = rnetwork.create_node (RNode::Internal, port_index++); + RNode *b = rnetwork.create_node (RNode::Internal, port_index++); + + db::CplxTrans to_um (m_dbu); + db::Box box = poly.box (); + b->location = a->location = to_um * box; + + rnetwork.create_element (conductance, a, b); + + vias[tech.bottom_conductor].push_back (ViaPort (box.center (), a)); + vias[tech.top_conductor].push_back (ViaPort (box.center (), b)); } void @@ -162,7 +193,7 @@ RNetExtractor::create_via_ports (const RExtractorTech &tech, std::map > &vias, RNetwork &rnetwork) { - std::vector > via_conductances; + unsigned int port_index = 0; for (auto v = tech.vias.begin (); v != tech.vias.end (); ++v) { @@ -171,8 +202,6 @@ RNetExtractor::create_via_ports (const RExtractorTech &tech, continue; } - via_conductances.clear (); - if (v->merge_distance > db::epsilon) { // with merge, follow this scheme: @@ -189,32 +218,23 @@ RNetExtractor::create_via_ports (const RExtractorTech &tech, children.push_back (new db::CompoundRegionOperationPrimaryNode ()); children.push_back (new db::CompoundRegionOperationSecondaryNode (const_cast (&g->second))); - ViaAggregationVisitor visitor (v.operator-> (), &via_conductances, m_dbu); + ViaAggregationVisitor visitor (v.operator-> (), m_dbu); db::PolygonNeighborhoodCompoundOperationNode en_node (children, &visitor, 0); - merged_vias.cop_to_region (en_node); + auto aggregated = merged_vias.cop_to_region (en_node); + + for (auto p = aggregated.begin (); ! p.at_end (); ++p) { + double c = db::properties (p.prop_id ()).value (ViaAggregationVisitor::prop_name_id).to_double (); + create_via_port (*v, c, *p, port_index, vias, rnetwork); + } } else { for (auto p = g->second.begin_merged (); ! p.at_end (); ++p) { - via_conductances.push_back (std::make_pair (via_conductance (*v, *p, m_dbu), p->box ().center ())); + create_via_port (*v, via_conductance (*v, *p, m_dbu), *p, port_index, vias, rnetwork); } } - // create the via resistor elements - unsigned int port_index = 0; - for (auto vc = via_conductances.begin (); vc != via_conductances.end (); ++vc) { - - RNode *a = rnetwork.create_node (RNode::Internal, port_index++); - RNode *b = rnetwork.create_node (RNode::Internal, port_index++); - - rnetwork.create_element (vc->first, a, b); - - vias[v->bottom_conductor].push_back (ViaPort (vc->second, a)); - vias[v->top_conductor].push_back (ViaPort (vc->second, b)); - - } - } } diff --git a/src/pex/pex/pexRNetExtractor.h b/src/pex/pex/pexRNetExtractor.h index a2df7d6aa..20ea0ab77 100644 --- a/src/pex/pex/pexRNetExtractor.h +++ b/src/pex/pex/pexRNetExtractor.h @@ -30,6 +30,7 @@ namespace pex { class RExtractorTech; +class RExtractorTechVia; class RExtractorTechConductor; class RNetwork; class RNode; @@ -37,7 +38,7 @@ class RNode; /** * @brief Implementation of the R extractor for a multi-polygon/multi-layer net */ -class RNetExtractor +class PEX_PUBLIC RNetExtractor { public: /** @@ -74,9 +75,7 @@ public: RNode *node; }; -private: - double m_dbu; - +protected: void create_via_ports (const RExtractorTech &tech, const std::map &geo, std::map > &vias, @@ -90,6 +89,16 @@ private: unsigned int polygon_ports_index_offset, const std::vector &via_ports, RNetwork &rnetwork); + +private: + double m_dbu; + + void create_via_port (const RExtractorTechVia &tech, + double conductance, + const db::Polygon &poly, + unsigned int &port_index, + std::map > &vias, + RNetwork &rnetwork); }; } diff --git a/src/pex/pex/pexRNetwork.cc b/src/pex/pex/pexRNetwork.cc index 0a552e2e2..435590d81 100644 --- a/src/pex/pex/pexRNetwork.cc +++ b/src/pex/pex/pexRNetwork.cc @@ -30,9 +30,10 @@ namespace pex // ----------------------------------------------------------------------------- std::string -RNode::to_string () const +RNode::to_string (bool with_coords) const { std::string res; + switch (type) { default: res += "$" + tl::to_string (port_index); @@ -44,24 +45,29 @@ RNode::to_string () const res += "P" + tl::to_string (port_index); break; } + + if (with_coords) { + res += location.to_string (); + } + return res; } // ----------------------------------------------------------------------------- std::string -RElement::to_string () const +RElement::to_string (bool with_coords) const { std::string na; if (a ()) { - na = a ()->to_string (); + na = a ()->to_string (with_coords); } else { na = "(nil)"; } std::string nb; if (b ()) { - nb = b ()->to_string (); + nb = b ()->to_string (with_coords); } else { nb = "(nil)"; } @@ -88,14 +94,14 @@ RNetwork::~RNetwork () } std::string -RNetwork::to_string () const +RNetwork::to_string (bool with_coords) const { std::string res; for (auto e = m_elements.begin (); e != m_elements.end (); ++e) { if (! res.empty ()) { res += "\n"; } - res += e->to_string (); + res += e->to_string (with_coords); } return res; } diff --git a/src/pex/pex/pexRNetwork.h b/src/pex/pex/pexRNetwork.h index d0fe65a9a..45f4ec36a 100644 --- a/src/pex/pex/pexRNetwork.h +++ b/src/pex/pex/pexRNetwork.h @@ -91,7 +91,7 @@ public: /** * @brief Returns a string representation of the node */ - std::string to_string () const; + std::string to_string (bool with_coords = false) const; /** * @brief Gets the network the node lives in @@ -180,7 +180,7 @@ struct PEX_PUBLIC RElement /** * @brief Returns a string representation of the element */ - std::string to_string () const; + std::string to_string (bool with_coords = false) const; /** * @brief Gets the network the node lives in @@ -357,7 +357,7 @@ public: /** * @brief Returns a string representation of the graph */ - std::string to_string () const; + std::string to_string (bool with_coords = false) const; private: node_list m_nodes; diff --git a/src/pex/pex/pexSquareCountingRExtractor.cc b/src/pex/pex/pexSquareCountingRExtractor.cc index 9170239d0..5c69b1fb3 100644 --- a/src/pex/pex/pexSquareCountingRExtractor.cc +++ b/src/pex/pex/pexSquareCountingRExtractor.cc @@ -29,6 +29,9 @@ namespace pex { +// Value used for number of squares for width 0 (should not happen) +const double infinite_squares = 1e10; + namespace { @@ -103,7 +106,7 @@ double calculate_squares (db::Coord x1, db::Coord x2, const std::set & // integrate the resistance along the axis x1->x2 with w=w1->w2 if (w1 < db::epsilon) { - return 1e9; // @@@ + return infinite_squares; } else if (fabs (w1 - w2) < db::epsilon) { return (x2 - x1) / w1; } else { diff --git a/src/pex/unit_tests/pexRNetExtractorTests.cc b/src/pex/unit_tests/pexRNetExtractorTests.cc new file mode 100644 index 000000000..241ded8df --- /dev/null +++ b/src/pex/unit_tests/pexRNetExtractorTests.cc @@ -0,0 +1,139 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "pexRNetExtractor.h" +#include "pexRExtractorTech.h" +#include "pexRNetwork.h" +#include "dbReader.h" +#include "dbLayout.h" +#include "tlUnitTest.h" + +class TestableRNetExtractor + : public pex::RNetExtractor +{ +public: + TestableRNetExtractor (double dbu) : pex::RNetExtractor (dbu) { } + + using pex::RNetExtractor::create_via_ports; +}; + +TEST(netex_viagen1) +{ + db::Layout ly; + + { + std::string fn = tl::testdata () + "/pex/netex_viagen1.gds"; + tl::InputStream is (fn); + db::Reader reader (is); + reader.read (ly); + } + + TestableRNetExtractor rex (ly.dbu ()); + + auto tc = ly.cell_by_name ("TOP"); + tl_assert (tc.first); + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); + + std::map geo; + geo.insert (std::make_pair (l2, db::Region (db::RecursiveShapeIterator (ly, ly.cell (tc.second), l2)))); + + pex::RNetwork network; + + pex::RExtractorTech tech; + + pex::RExtractorTechVia via1; + via1.bottom_conductor = l1; + via1.cut_layer = l2; + via1.top_conductor = l3; + via1.resistance = 2.0; + tech.vias.push_back (via1); + + std::map > via_ports; + rex.create_via_ports (tech, geo, via_ports, network); + + EXPECT_EQ (via_ports [l1].size (), size_t (4)); + EXPECT_EQ (via_ports [l2].size (), size_t (0)); + EXPECT_EQ (via_ports [l3].size (), size_t (4)); + + EXPECT_EQ (network.to_string (true), + "R $0(1.7,0.1;1.9,0.3) $1(1.7,0.1;1.9,0.3) 50\n" + "R $2(0.4,0.5;0.6,0.7) $3(0.4,0.5;0.6,0.7) 50\n" + "R $4(0.8,0.5;1,0.7) $5(0.8,0.5;1,0.7) 50\n" + "R $6(2.9,0.5;3.1,0.7) $7(2.9,0.5;3.1,0.7) 50" + ); +} + +TEST(netex_viagen2) +{ + db::Layout ly; + + { + std::string fn = tl::testdata () + "/pex/netex_viagen2.gds"; + tl::InputStream is (fn); + db::Reader reader (is); + reader.read (ly); + } + + TestableRNetExtractor rex (ly.dbu ()); + + auto tc = ly.cell_by_name ("TOP"); + tl_assert (tc.first); + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); + + std::map geo; + geo.insert (std::make_pair (l2, db::Region (db::RecursiveShapeIterator (ly, ly.cell (tc.second), l2)))); + + pex::RNetwork network; + + pex::RExtractorTech tech; + + pex::RExtractorTechVia via1; + via1.bottom_conductor = l1; + via1.cut_layer = l2; + via1.top_conductor = l3; + via1.resistance = 2.0; + via1.merge_distance = 0.2; + tech.vias.push_back (via1); + + std::map > via_ports; + rex.create_via_ports (tech, geo, via_ports, network); + + EXPECT_EQ (via_ports [l1].size (), size_t (6)); + EXPECT_EQ (via_ports [l2].size (), size_t (0)); + EXPECT_EQ (via_ports [l3].size (), size_t (6)); + + EXPECT_EQ (network.to_string (true), + "R $0(4.6,2.8;4.8,3) $1(4.6,2.8;4.8,3) 50\n" + "R $2(2.5,3.7;2.7,3.9) $3(2.5,3.7;2.7,3.9) 50\n" + "R $4(3,3.7;3.2,3.9) $5(3,3.7;3.2,3.9) 50\n" + "R $6(2.2,1.2;3.4,3.4) $7(2.2,1.2;3.4,3.4) 2.77778\n" + "R $8(0.4,0.4;2.2,4.2) $9(0.4,0.4;2.2,4.2) 1\n" + "R $10(0.6,4.9;1.2,5.1) $11(0.6,4.9;1.2,5.1) 25" + ); +} diff --git a/src/pex/unit_tests/unit_tests.pro b/src/pex/unit_tests/unit_tests.pro index ad99cd169..6ef8b5f93 100644 --- a/src/pex/unit_tests/unit_tests.pro +++ b/src/pex/unit_tests/unit_tests.pro @@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri) SOURCES = \ pexRExtractorTests.cc \ + pexRNetExtractorTests.cc \ pexSquareCountingRExtractorTests.cc \ pexTriangulationRExtractorTests.cc diff --git a/testdata/pex/netex_viagen1.gds b/testdata/pex/netex_viagen1.gds new file mode 100644 index 000000000..2d7195da2 Binary files /dev/null and b/testdata/pex/netex_viagen1.gds differ diff --git a/testdata/pex/netex_viagen2.gds b/testdata/pex/netex_viagen2.gds new file mode 100644 index 000000000..d218db493 Binary files /dev/null and b/testdata/pex/netex_viagen2.gds differ