From 64c2548ab8432bc5d345942a5480a2bfb76ea4a5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 6 Jan 2019 15:28:40 +0100 Subject: [PATCH] WIP: first steps towards global nets. --- src/db/db/db.pro | 3 +- src/db/db/dbHierNetworkProcessor.cc | 54 ++++++++++++++ src/db/db/dbHierNetworkProcessor.h | 29 ++++++++ src/db/db/dbLayoutToNetlist.cc | 21 ++++++ src/db/db/dbLayoutToNetlist.h | 11 +++ src/db/db/dbNetlist.cc | 14 ++++ src/db/db/dbNetlist.h | 31 ++++++++ src/db/db/dbNetlistExtractor.cc | 74 ++++++++++++++++--- src/db/db/dbNetlistExtractor.h | 2 +- src/db/db/gsiDeclDbHierNetworkProcessor.cc | 12 +++ src/db/db/gsiDeclDbLayoutToNetlist.cc | 8 ++ src/db/db/gsiDeclDbNetlist.cc | 62 +++++++++++++++- .../unit_tests/dbHierNetworkProcessorTests.cc | 33 +++++++++ src/db/unit_tests/dbNetlistTests.cc | 51 ++++++++++++- testdata/ruby/dbLayoutToNetlist.rb | 4 + testdata/ruby/dbNetlist.rb | 10 +++ 16 files changed, 406 insertions(+), 13 deletions(-) diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 9d78787ca..9d22a4990 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -269,7 +269,8 @@ HEADERS = \ dbNetlistDeviceExtractor.h \ dbNetlistExtractor.h \ dbNetlistDeviceExtractorClasses.h \ - dbLayoutToNetlist.h + dbLayoutToNetlist.h \ + dbHierNetworkProcessor.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 155e76e92..a8862ef39 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -77,6 +77,60 @@ Connectivity::connect (const db::DeepLayer &la, const db::DeepLayer &lb) connect (la.layer (), lb.layer ()); } +Connectivity::global_nets_type s_empty_global_nets; + +Connectivity::global_nets_iterator +Connectivity::begin_global_connections (unsigned int l) const +{ + std::map::const_iterator g = m_global_connections.find (l); + if (g != m_global_connections.end ()) { + return g->second.begin (); + } else { + return s_empty_global_nets.begin (); + } +} + +Connectivity::global_nets_iterator +Connectivity::end_global_connections (unsigned int l) const +{ + std::map::const_iterator g = m_global_connections.find (l); + if (g != m_global_connections.end ()) { + return g->second.end (); + } else { + return s_empty_global_nets.end (); + } +} + +size_t +Connectivity::connect_global (unsigned int l, const std::string &gn) +{ + for (std::vector::const_iterator i = m_global_net_names.begin (); i != m_global_net_names.end (); ++i) { + if (*i == gn) { + size_t id = i - m_global_net_names.begin (); + m_global_connections [l].insert (id); + return id; + } + } + + size_t id = m_global_net_names.size (); + m_global_connections [l].insert (id); + m_global_net_names.push_back (gn); + return id; +} + +size_t +Connectivity::connect_global (const db::DeepLayer &l, const std::string &gn) +{ + return connect_global (l.layer (), gn); +} + +const std::string & +Connectivity::global_net_name (size_t id) const +{ + tl_assert (id < m_global_net_names.size ()); + return m_global_net_names [id]; +} + Connectivity::layer_iterator Connectivity::begin_layers () const { diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index e1e670b82..ca551c731 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -52,6 +52,8 @@ class DB_PUBLIC Connectivity public: typedef std::set layers_type; typedef layers_type::const_iterator layer_iterator; + typedef std::set global_nets_type; + typedef global_nets_type::const_iterator global_nets_iterator; /** * @brief Creates a connectivity object without any connections @@ -68,6 +70,11 @@ public: */ void connect (unsigned int la, unsigned int lb); + /** + * @brief Adds a connection to a global net + */ + size_t connect_global (unsigned int l, const std::string &gn); + /** * @brief Adds intra-layer connectivity for layer l * This is a convenience method that takes a db::DeepLayer object. @@ -82,6 +89,16 @@ public: */ void connect (const db::DeepLayer &la, const db::DeepLayer &lb); + /** + * @brief Adds a connection to a global net + */ + size_t connect_global (const db::DeepLayer &la, const std::string &gn); + + /** + * @brief Gets the global net name per ID + */ + const std::string &global_net_name (size_t id) const; + /** * @brief Begin iterator for the layers involved */ @@ -102,6 +119,16 @@ public: */ layer_iterator end_connected (unsigned int layer) const; + /** + * @brief Begin iterator for the global connections for a specific layer + */ + global_nets_iterator begin_global_connections (unsigned int layer) const; + + /** + * @brief End iterator for the layers connected to a specific layer + */ + global_nets_iterator end_global_connections (unsigned int layer) const; + /** * @brief Returns true, if the given shapes on the given layers interact * @@ -123,6 +150,8 @@ public: private: layers_type m_all_layers; std::map m_connected; + std::vector m_global_net_names; + std::map m_global_connections; }; /** diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 5a3bcfe8a..2c4a09424 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -149,6 +149,27 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b) m_conn.connect (dla.layer (), dlb.layer ()); } +size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string &gn) +{ + if (m_netlist_extracted) { + throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); + } + if (! is_deep (l)) { + throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in intra-layer connectivity for netlist extraction")))); + } + + // we need to keep a reference, so we can safely delete the region + db::DeepLayer dl (l); + m_dlrefs.insert (dl); + + return m_conn.connect_global (dl.layer (), gn); +} + +const std::string &LayoutToNetlist::global_net_name (size_t id) const +{ + return m_conn.global_net_name (id); +} + void LayoutToNetlist::extract_netlist () { if (m_netlist_extracted) { diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 7e7f40689..c43cac8fb 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -165,6 +165,17 @@ public: */ void connect (const db::Region &a, const db::Region &b); + /** + * @brief Connects the given layer with a global net with the given name + * Returns the global net ID + */ + size_t connect_global (const db::Region &l, const std::string &gn); + + /** + * @brief Gets the global net name for a given global net ID + */ + const std::string &global_net_name (size_t id) const; + /** * @brief Runs the netlist extraction * See the class description for more details. diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index 914f6a882..eeb88a042 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -113,8 +113,22 @@ const Net *Device::net_for_terminal (size_t terminal_id) const return 0; } +void Device::connect_terminal_global (size_t terminal_id, size_t global_net_id) +{ + connect_terminal (terminal_id, 0); + m_global_connections.push_back (std::make_pair (terminal_id, global_net_id)); +} + void Device::connect_terminal (size_t terminal_id, Net *net) { + for (size_t i = 0; i < m_global_connections.size (); ) { + if (m_global_connections [i].first == terminal_id) { + m_global_connections.erase (m_global_connections.begin () + i); + } else { + ++i; + } + } + if (net_for_terminal (terminal_id) == net) { return; } diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index 7d048db5a..3af81c79c 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -806,6 +806,9 @@ class DB_PUBLIC Device : public tl::Object { public: + typedef std::vector > global_connections; + typedef global_connections::const_iterator global_connections_iterator; + /** * @brief Default constructor */ @@ -881,6 +884,31 @@ public: return m_name; } + /** + * @brief Gets the global connections iterator (begin) + * Global connections are terminals attached to a global net. + * This iterator delivers a pair of terminal ID (first) + * and global net ID (second). + * See Connectivity for the definition of the global net ID. + */ + global_connections_iterator begin_global_connections () const + { + return m_global_connections.begin (); + } + + /** + * @brief Gets the global connections iterator (end) + */ + global_connections_iterator end_global_connections () const + { + return m_global_connections.end (); + } + + /** + * @brief Connects the given terminal to the given global net + */ + void connect_terminal_global (size_t terminal_id, size_t global_net_id); + /** * @brief Gets the net attached to a specific terminal * Returns 0 if no net is attached. @@ -901,6 +929,8 @@ public: * If the net is 0 the terminal is disconnected. * If non-null, a NetTerminalRef object will be inserted into the * net and connected with the given terminal. + * If the terminal is connected to a global net, it will be + * disconnected from there. */ void connect_terminal (size_t terminal_id, Net *net); @@ -936,6 +966,7 @@ private: std::vector m_parameters; size_t m_id; Circuit *mp_circuit; + global_connections m_global_connections; /** * @brief Sets the terminal reference for a specific terminal diff --git a/src/db/db/dbNetlistExtractor.cc b/src/db/db/dbNetlistExtractor.cc index 6dfd810eb..02fcdaa0f 100644 --- a/src/db/db/dbNetlistExtractor.cc +++ b/src/db/db/dbNetlistExtractor.cc @@ -64,7 +64,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect circuits.insert (std::make_pair (c->cell_index (), c.operator-> ())); } - std::map > pins_per_cluster; + std::map > pins_per_cluster_per_cell; + std::map > global_nets_per_cell; for (db::Layout::bottom_up_const_iterator cid = layout.begin_bottom_up (); cid != layout.end_bottom_up (); ++cid) { @@ -88,7 +89,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect circuit = k->second; } - std::map &c2p = pins_per_cluster [*cid]; + std::map &global_nets = global_nets_per_cell [*cid]; + std::map &c2p = pins_per_cluster_per_cell [*cid]; std::map subcircuits; @@ -98,8 +100,19 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect net->set_cluster_id (*c); circuit->add_net (net); + // make global net connections for clusters which connect to such + std::set global_net_ids; + std::vector layers = clusters.cluster_by_id (*c).layers (); + for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { + global_net_ids.insert (conn.begin_global_connections (*l), conn.end_global_connections (*l)); + } + for (std::set::const_iterator g = global_net_ids.begin (); g != global_net_ids.end (); ++g) { + global_nets.insert (std::make_pair (*g, net)); + assign_net_name (conn.global_net_name (*g), net); + } + // make subcircuit connections (also make the subcircuits if required) from the connections of the clusters - make_and_connect_subcircuits (circuit, clusters, *c, net, subcircuits, circuits, pins_per_cluster, layout.dbu ()); + make_and_connect_subcircuits (circuit, clusters, *c, net, subcircuits, circuits, pins_per_cluster_per_cell, layout.dbu ()); // collect the properties - we know that the cluster attributes are property ID's because the // cluster processor converts shape property IDs to attributes @@ -110,7 +123,7 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect if (terminal_annot_name_id.first && j->first == terminal_annot_name_id.second) { make_device_terminal_from_property (j->second, circuit, net); } else if (text_annot_name_id.first && j->first == text_annot_name_id.second) { - make_net_name_from_property (j->second, net); + assign_net_name (j->second.to_string (), net); } } } @@ -123,6 +136,49 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect } + // make global net connections for devices + for (db::Circuit::device_iterator d = circuit->begin_devices (); d != circuit->end_devices (); ++d) { + + for (db::Device::global_connections_iterator g = d->begin_global_connections (); g != d->end_global_connections (); ++g) { + + db::Net *&net = global_nets [g->second]; + if (! net) { + net = new db::Net (conn.global_net_name (g->second)); + circuit->add_net (net); + } + + net->add_terminal (db::NetTerminalRef (d.operator-> (), g->first)); + + } + + } + + // make the global net connections into subcircuits - if necessary by creating pins into the subcircuit + for (db::Circuit::subcircuit_iterator sc = circuit->begin_subcircuits (); sc != circuit->end_subcircuits (); ++sc) { + + db::Circuit *subcircuit = sc->circuit_ref (); + + const std::map &sc_gn = global_nets_per_cell [subcircuit->cell_index ()]; + for (std::map::const_iterator g = global_nets.begin (); g != global_nets.end (); ++g) { + + std::map::const_iterator gg = sc_gn.find (g->first); + if (gg != sc_gn.end ()) { + + size_t pin_id = 0; + if (gg->second->pin_count () > 0) { + pin_id = gg->second->begin_pins ()->pin_id (); + } else { + pin_id = subcircuit->add_pin (conn.global_net_name (gg->first)).id (); + subcircuit->connect_pin (pin_id, gg->second); + } + g->second->add_subcircuit_pin (db::NetSubcircuitPinRef (sc.operator-> (), pin_id)); + + } + + } + + } + } } @@ -192,14 +248,14 @@ void NetlistExtractor::make_device_terminal_from_property (const tl::Variant &v, } } -void NetlistExtractor::make_net_name_from_property (const tl::Variant &v, db::Net *net) +void NetlistExtractor::assign_net_name (const std::string &n, db::Net *net) { - std::string n = v.to_string (); - if (! n.empty ()) { + std::string nn = n; + if (! nn.empty ()) { if (! net->name ().empty ()) { - n = net->name () + "," + n; + nn = net->name () + "," + nn; } - net->set_name (n); + net->set_name (nn); } } diff --git a/src/db/db/dbNetlistExtractor.h b/src/db/db/dbNetlistExtractor.h index b95953ecf..2e87113c8 100644 --- a/src/db/db/dbNetlistExtractor.h +++ b/src/db/db/dbNetlistExtractor.h @@ -95,7 +95,7 @@ private: hier_clusters_type m_net_clusters; void make_device_terminal_from_property (const tl::Variant &v, db::Circuit *circuit, db::Net *net); - void make_net_name_from_property (const tl::Variant &v, db::Net *net); + void assign_net_name (const std::string &n, db::Net *net); /** * @brief Make a pin connection from clusters diff --git a/src/db/db/gsiDeclDbHierNetworkProcessor.cc b/src/db/db/gsiDeclDbHierNetworkProcessor.cc index 4514f0084..3537bf7e1 100644 --- a/src/db/db/gsiDeclDbHierNetworkProcessor.cc +++ b/src/db/db/gsiDeclDbHierNetworkProcessor.cc @@ -32,6 +32,13 @@ Class decl_dbConnectivity ("db", "Connectivity", ) + gsi::method ("connect", (void (db::Connectivity::*) (unsigned int, unsigned int)) &db::Connectivity::connect, gsi::arg ("layer_a"), gsi::arg ("layer_b"), "@brief Specifies inter-layer connectivity.\n" + ) + + gsi::method ("connect_global", (size_t (db::Connectivity::*) (unsigned int, const std::string &)) &db::Connectivity::connect_global, gsi::arg ("layer"), gsi::arg ("global_net_name"), + "@brief Connects the given layer to the global net given by name.\n" + "Returns the ID of the global net." + ) + + gsi::method ("global", &db::Connectivity::global_net_name, gsi::arg ("global_net_id"), + "@brief Gets the name for a given global net ID.\n" ), "@brief This class specifies connections between different layers." "Connections are build using \\connect. There are basically two flavours of connections: intra-layer and inter-layer.\n" @@ -45,6 +52,11 @@ Class decl_dbConnectivity ("db", "Connectivity", "\n" "All layers are specified in terms of layer indexes. Layer indexes are layout layer indexes (see \\Layout class).\n" "\n" + "The connectivity object also manages the global nets. Global nets are substrate for example " + "and they are propagated automatically from subcircuits to circuits. " + "Global nets are defined by name and are managed through IDs. To get the name for a given ID, use " + "\\global_net_name." + "\n" "This class has been introduced in version 0.26.\n" ); diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index a9e50a9be..6b7d4ea0d 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -123,6 +123,14 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "@brief Defines an inter-layer connection for the given layers.\n" "The conditions mentioned with intra-layer \\connect apply for this method too.\n" ) + + gsi::method ("connect_global", (void (db::LayoutToNetlist::*) (const db::Region &, const std::string &)) &db::LayoutToNetlist::connect_global, gsi::arg ("l"), gsi::arg ("global_net_name"), + "@brief Defines a connection of the given layer with a global net.\n" + "This method returns the ID of the global net. Use \\global_net_name to get " + "the name back from the ID." + ) + + gsi::method ("global_net_name", &db::LayoutToNetlist::global_net_name, gsi::arg ("global_net_id"), + "@brief Gets the global net name for the given global net ID." + ) + gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist, "@brief Runs the netlist extraction\n" "See the class description for more details.\n" diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 86b357b54..716f909fd 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -61,6 +61,44 @@ static void device_disconnect_terminal_by_name (db::Device *device, const std::s device_connect_terminal_by_name (device, terminal_name, 0); } +static tl::Variant device_terminal_for_global_net (const db::Device *device, size_t global_net) +{ + for (db::Device::global_connections_iterator g = device->begin_global_connections (); g != device->end_global_connections (); ++g) { + if (g->second == global_net) { + return tl::Variant (g->first); + } + } + return tl::Variant (); +} + +static tl::Variant device_global_net_for_terminal (const db::Device *device, size_t terminal_id) +{ + for (db::Device::global_connections_iterator g = device->begin_global_connections (); g != device->end_global_connections (); ++g) { + if (g->first == terminal_id) { + return tl::Variant (g->second); + } + } + return tl::Variant (); +} + +static tl::Variant device_global_net_for_terminal_name (const db::Device *device, const std::string &terminal_name) +{ + if (! device->device_class ()) { + throw tl::Exception (tl::to_string (tr ("Device does not have a device class"))); + } + size_t terminal_id = device->device_class ()->terminal_id_for_name (terminal_name); + return device_global_net_for_terminal (device, terminal_id); +} + +static void device_connect_terminal_global_by_name (db::Device *device, const std::string &terminal_name, size_t global_net) +{ + if (! device->device_class ()) { + throw tl::Exception (tl::to_string (tr ("Device does not have a device class"))); + } + size_t terminal_id = device->device_class ()->terminal_id_for_name (terminal_name); + device->connect_terminal_global (terminal_id, global_net); +} + Class decl_dbDevice ("db", "Device", gsi::method ("device_class", &db::Device::device_class, "@brief Gets the device class the device belongs to.\n" @@ -91,15 +129,37 @@ Class decl_dbDevice ("db", "Device", ) + gsi::method_ext ("disconnect_terminal", &device_disconnect_terminal, gsi::arg ("terminal_id"), "@brief Disconnects the given terminal from any net.\n" + "If the terminal has been connected to a global, this connection will be disconnected too." ) + gsi::method_ext ("connect_terminal", &device_connect_terminal_by_name, gsi::arg ("terminal_name"), gsi::arg ("net"), "@brief Connects the given terminal to the specified net.\n" - "This version accepts a terminal name. If the name is not a valid terminal name, an exception is raised." + "This version accepts a terminal name. If the name is not a valid terminal name, an exception is raised.\n" + "If the terminal has been connected to a global net, it will be disconnected from there." ) + gsi::method_ext ("disconnect_terminal", &device_disconnect_terminal_by_name, gsi::arg ("terminal_name"), "@brief Disconnects the given terminal from any net.\n" "This version accepts a terminal name. If the name is not a valid terminal name, an exception is raised." ) + + gsi::method ("connect_terminal_global", &db::Device::connect_terminal_global, gsi::arg ("terminal_id"), gsi::arg ("global_net_id"), + "@brief Connects the given terminal to the given global net.\n" + "The global net ID is taken from \\Connectivity (connect_global, etc.).\n" + "If the terminal was already connected to another net, it will be disconnected from there." + ) + + gsi::method_ext ("connect_terminal_global", &device_connect_terminal_global_by_name, gsi::arg ("terminal_name"), gsi::arg ("global_net_id"), + "@brief Connects the given terminal to the given global net.\n" + "This version accepts a terminal name. If the name is not a valid terminal name, an exception is raised." + ) + + gsi::method_ext ("terminal_on_global_net", &device_terminal_for_global_net, gsi::arg ("global_net_id"), + "@brief Gets the terminal ID for the given global net or nil if no terminal is not that global net.\n" + "The global net ID is managed by the \\Connectivity object." + ) + + gsi::method_ext ("global_net_on_terminal", &device_global_net_for_terminal, gsi::arg ("terminal_id"), + "@brief Gets the global net ID for the given terminal ID or nil if the terminal is not connected to a global net.\n" + ) + + gsi::method_ext ("global_net_on_terminal", &device_global_net_for_terminal_name, gsi::arg ("terminal_name"), + "@brief Gets the global net ID for the given terminal name or nil if the terminal is not connected to a global net.\n" + "If the name is not a valid terminal name, an exception is raised." + ) + gsi::method ("parameter", (double (db::Device::*) (size_t) const) &db::Device::parameter_value, gsi::arg ("param_id"), "@brief Gets the parameter value for the given parameter ID." ) + diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc index a16a73294..96c7d7563 100644 --- a/src/db/unit_tests/dbHierNetworkProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -44,6 +44,18 @@ static std::string l2s (db::Connectivity::layer_iterator b, db::Connectivity::la return s; } +static std::string gn2s (db::Connectivity::global_nets_iterator b, db::Connectivity::global_nets_iterator e) +{ + std::string s; + for (db::Connectivity::global_nets_iterator i = b; i != e; ++i) { + if (! s.empty ()) { + s += ","; + } + s += tl::to_string (*i); + } + return s; +} + TEST(1_Connectivity) { db::Connectivity conn; @@ -69,6 +81,27 @@ TEST(1_Connectivity) EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0,1,2"); EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "0,1"); EXPECT_EQ (l2s (conn.begin_connected (2), conn.end_connected (2)), "0,2"); + + EXPECT_EQ (conn.connect_global (0, "GLOBAL"), size_t (0)); + EXPECT_EQ (gn2s (conn.begin_global_connections (2), conn.end_global_connections (2)), ""); + EXPECT_EQ (gn2s (conn.begin_global_connections (0), conn.end_global_connections (0)), "0"); + EXPECT_EQ (conn.connect_global (2, "GLOBAL2"), size_t (1)); + EXPECT_EQ (gn2s (conn.begin_global_connections (2), conn.end_global_connections (2)), "1"); + EXPECT_EQ (conn.connect_global (0, "GLOBAL2"), size_t (1)); + EXPECT_EQ (gn2s (conn.begin_global_connections (0), conn.end_global_connections (0)), "0,1"); + + EXPECT_EQ (conn.global_net_name (0), "GLOBAL"); + EXPECT_EQ (conn.global_net_name (1), "GLOBAL2"); + + db::Connectivity conn2 = conn; + + EXPECT_EQ (l2s (conn2.begin_connected (0), conn2.end_connected (0)), "0,1,2"); + EXPECT_EQ (l2s (conn2.begin_connected (1), conn2.end_connected (1)), "0,1"); + EXPECT_EQ (l2s (conn2.begin_connected (2), conn2.end_connected (2)), "0,2"); + + EXPECT_EQ (gn2s (conn2.begin_global_connections (0), conn2.end_global_connections (0)), "0,1"); + EXPECT_EQ (conn2.global_net_name (0), "GLOBAL"); + EXPECT_EQ (conn2.global_net_name (1), "GLOBAL2"); } TEST(2_ShapeInteractions) diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index 0b88052fa..08ede9d34 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -74,7 +74,6 @@ TEST(1_DeviceTerminalDefinition) dc.clear_parameter_definitions (); EXPECT_EQ (dc.parameter_definitions ().empty (), true); - } TEST(2_DeviceClass) @@ -1025,3 +1024,53 @@ TEST(12_NetlistTopology) EXPECT_EQ (td2string (nl.get ()), "c1,c3,c2"); EXPECT_EQ (bu2string (nl.get ()), "c2,c3,c1"); } + +TEST(13_DeviceGlobalNets) +{ + db::DeviceTerminalDefinition pd; + pd.set_name ("name"); + pd.set_description ("nothing yet"); + + db::DeviceTerminalDefinition pd2; + pd2.set_name ("name2"); + pd2.set_description ("now it has something"); + + db::DeviceClass dc; + dc.set_name ("devname"); + dc.set_description ("devdesc"); + dc.add_terminal_definition (pd); + dc.add_terminal_definition (pd2); + + db::Device d (&dc); + db::Net n; + + d.connect_terminal_global (0, 17); + + db::Device::global_connections_iterator g; + + g = d.begin_global_connections (); + EXPECT_EQ (g != d.end_global_connections (), true); + EXPECT_EQ (g->first, size_t (0)); + EXPECT_EQ (g->second, size_t (17)); + + ++g; + EXPECT_EQ (g == d.end_global_connections (), true); + + d.connect_terminal (0, &n); + g = d.begin_global_connections (); + EXPECT_EQ (g == d.end_global_connections (), true); + EXPECT_EQ (d.net_for_terminal (0) == &n, true); + + d.connect_terminal_global (0, 17); + EXPECT_EQ (d.net_for_terminal (0) == 0, true); + + g = d.begin_global_connections (); + EXPECT_EQ (g != d.end_global_connections (), true); + EXPECT_EQ (g->first, size_t (0)); + EXPECT_EQ (g->second, size_t (17)); + + d.connect_terminal (0, 0); + g = d.begin_global_connections (); + EXPECT_EQ (g == d.end_global_connections (), true); + EXPECT_EQ (d.net_for_terminal (0) == 0, true); +} diff --git a/testdata/ruby/dbLayoutToNetlist.rb b/testdata/ruby/dbLayoutToNetlist.rb index d1a37ef11..3ca02cc67 100644 --- a/testdata/ruby/dbLayoutToNetlist.rb +++ b/testdata/ruby/dbLayoutToNetlist.rb @@ -61,6 +61,10 @@ class DBLayoutToNetlist_TestClass < TestBase assert_equal(l2n.internal_layout.cell(ci).name, ly2.cell(cm.cell_mapping(ci)).name) end + rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) ) + bulk_id = l2n.connect_global(rmetal1, "BULK") + assert_equal(l2n.global_net_name(bulk_id), "BULK") + end def test_2_ShapesFromNet diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 4f8a3e1c1..86e1954c7 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -257,6 +257,16 @@ class DBNetlist_TestClass < TestBase assert_equal(d1.net_for_terminal(1).inspect, "nil") assert_equal(d1.net_for_terminal(0).inspect, "nil") + d2.connect_terminal(0, net) + assert_equal(net.terminal_count, 1) + d2.connect_terminal_global(0, 1) + assert_equal(net.terminal_count, 0) + + assert_equal(d2.terminal_on_global_net(1), 0) + assert_equal(d2.terminal_on_global_net(17).inspect, "nil") + assert_equal(d2.global_net_on_terminal(0), 1) + assert_equal(d2.global_net_on_terminal(1).inspect, "nil") + end def test_5_SubCircuit